From f581774649e95263ec93268353c602133b648c2b Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Sun, 19 Apr 2026 19:38:30 +0200 Subject: [PATCH] Add function to get the path segments of a path relative to another --- docs/CHANGELOG.md | 3 +- src/jcloud_docsgen/utils.py | 23 +++++- .../utils/test_get_relative_path_segments.py | 76 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/unit/utils/test_get_relative_path_segments.py diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 203ccb9..ee906d5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -23,4 +23,5 @@ - Add class for Python docstrings - Add feature to parse Python docstrings - Add function to ensure a non-empty string. -- Add Python definition documentation generator \ No newline at end of file +- Add Python definition documentation generator +- Add function to get the path segments of a path relative to another \ No newline at end of file diff --git a/src/jcloud_docsgen/utils.py b/src/jcloud_docsgen/utils.py index 0c0d644..fdd80d4 100644 --- a/src/jcloud_docsgen/utils.py +++ b/src/jcloud_docsgen/utils.py @@ -151,4 +151,25 @@ def non_empty_str(value: Union[str, None]) -> Union[str, None]: if value.strip() == '': return None - return value \ No newline at end of file + return value + +def get_relative_path_segments(path: pathlib.Path, root: pathlib.Path) -> list[str]: + ''' + Returns the path segments relative to ``root``. + + :param path: The path. + :type path: pathlib.Path + :param root: The root path. + :type root: pathlib.Path + + :return: The path segments relative to ``root``. + :rtype: list[str] + ''' + + return list( + path.resolve() + .relative_to( + root.resolve() + ) + .parts + ) \ No newline at end of file diff --git a/tests/unit/utils/test_get_relative_path_segments.py b/tests/unit/utils/test_get_relative_path_segments.py new file mode 100644 index 0000000..1b19990 --- /dev/null +++ b/tests/unit/utils/test_get_relative_path_segments.py @@ -0,0 +1,76 @@ +# Copyright 2026 jCloud Services GbR + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from src.jcloud_docsgen.utils import get_relative_path_segments +import pytest +import pathlib + +@pytest.mark.parametrize('path,root,expected', [ + (pathlib.Path('/'), pathlib.Path('/'), []), + (pathlib.Path('/a'), pathlib.Path('/'), ['a']), + (pathlib.Path('/a/'), pathlib.Path('/'), ['a']), + (pathlib.Path('/a'), pathlib.Path('/a'), []), + (pathlib.Path('/a/'), pathlib.Path('/a'), []), + (pathlib.Path('/a'), pathlib.Path('/a/'), []), + (pathlib.Path('/a/'), pathlib.Path('/a/'), []), + (pathlib.Path('/a/b'), pathlib.Path('/'), ['a', 'b']), + (pathlib.Path('/a/b/'), pathlib.Path('/'), ['a', 'b']), + (pathlib.Path('/a/b'), pathlib.Path('/a'), ['b']), + (pathlib.Path('/a/b/'), pathlib.Path('/a'), ['b']), + (pathlib.Path('/a/b'), pathlib.Path('/a/'), ['b']), + (pathlib.Path('/a/b/'), pathlib.Path('/a/'), ['b']), + (pathlib.Path('/a/b'), pathlib.Path('/a/b'), []), + (pathlib.Path('/a/b/'), pathlib.Path('/a/b'), []), + (pathlib.Path('/a/b'), pathlib.Path('/a/b/'), []), + (pathlib.Path('/a/b/'), pathlib.Path('/a/b/'), []), + + (pathlib.Path('./'), pathlib.Path('./'), []), + (pathlib.Path('./a'), pathlib.Path('./'), ['a']), + (pathlib.Path('./a/'), pathlib.Path('./'), ['a']), + (pathlib.Path('./a'), pathlib.Path('./a'), []), + (pathlib.Path('./a/'), pathlib.Path('./a'), []), + (pathlib.Path('./a'), pathlib.Path('./a/'), []), + (pathlib.Path('./a/'), pathlib.Path('./a/'), []), + (pathlib.Path('./a/b'), pathlib.Path('./'), ['a', 'b']), + (pathlib.Path('./a/b/'), pathlib.Path('./'), ['a', 'b']), + (pathlib.Path('./a/b'), pathlib.Path('./a'), ['b']), + (pathlib.Path('./a/b/'), pathlib.Path('./a'), ['b']), + (pathlib.Path('./a/b'), pathlib.Path('./a/'), ['b']), + (pathlib.Path('./a/b/'), pathlib.Path('./a/'), ['b']), + (pathlib.Path('./a/b'), pathlib.Path('./a/b'), []), + (pathlib.Path('./a/b/'), pathlib.Path('./a/b'), []), + (pathlib.Path('./a/b'), pathlib.Path('./a/b/'), []), + (pathlib.Path('./a/b/'), pathlib.Path('./a/b/'), []), + + (pathlib.Path(''), pathlib.Path(''), []), + (pathlib.Path('a'), pathlib.Path(''), ['a']), + (pathlib.Path('a/'), pathlib.Path(''), ['a']), + (pathlib.Path('a'), pathlib.Path('a'), []), + (pathlib.Path('a/'), pathlib.Path('a'), []), + (pathlib.Path('a'), pathlib.Path('a/'), []), + (pathlib.Path('a/'), pathlib.Path('a/'), []), + (pathlib.Path('a/b'), pathlib.Path(''), ['a', 'b']), + (pathlib.Path('a/b/'), pathlib.Path(''), ['a', 'b']), + (pathlib.Path('a/b'), pathlib.Path('a'), ['b']), + (pathlib.Path('a/b/'), pathlib.Path('a'), ['b']), + (pathlib.Path('a/b'), pathlib.Path('a/'), ['b']), + (pathlib.Path('a/b/'), pathlib.Path('a/'), ['b']), + (pathlib.Path('a/b'), pathlib.Path('a/b'), []), + (pathlib.Path('a/b/'), pathlib.Path('a/b'), []), + (pathlib.Path('a/b'), pathlib.Path('a/b/'), []), + (pathlib.Path('a/b/'), pathlib.Path('a/b/'), []), + +]) +def test_get_relative_path_segments(path, root, expected): + assert get_relative_path_segments(path, root) == expected \ No newline at end of file