diff --git a/mutapath/immutapath.py b/mutapath/immutapath.py index e26080c..742d13d 100644 --- a/mutapath/immutapath.py +++ b/mutapath/immutapath.py @@ -27,6 +27,7 @@ SerializableType = object POSIX_ENABLED_DEFAULT = False +STRING_REPR = False @path_wrapper @@ -34,12 +35,15 @@ class Path(SerializableType): """Immutable Path""" _contained: Union[path.Path, pathlib.PurePath, str] = path.Path("") __always_posix_format: bool + __string_repr: bool __mutable: ClassVar[object] - def __init__(self, contained: Union[Path, path.Path, pathlib.PurePath, str] = "", - posix: bool = POSIX_ENABLED_DEFAULT): + def __init__(self, contained: Union[Path, path.Path, pathlib.PurePath, str] = "", *, + posix: bool = POSIX_ENABLED_DEFAULT, string_repr: bool = STRING_REPR): self.__always_posix_format = posix + self.__string_repr = string_repr self._set_contained(contained, posix) + super().__init__() def _set_contained(self, contained: Union[Path, path.Path, pathlib.PurePath, str], posix: Optional[bool] = None): if contained: @@ -62,6 +66,12 @@ def _set_contained(self, contained: Union[Path, path.Path, pathlib.PurePath, str def __dir__(self) -> Iterable[str]: return sorted(super(Path, self).__dir__()) + dir(path.Path) + def __getitem__(self, item): + return self._contained.__getitem__(item) + + def __getattr__(self, item): + return getattr(self._contained, item) + def __setattr__(self, key, value): if key == "_contained": lock = self.__dict__.get("lock", None) @@ -74,12 +84,14 @@ def __setattr__(self, key, value): if isinstance(value, Path): value = value._contained self._set_contained(value) - elif key in ["_Path__mutable", "_Path__always_posix_format"]: + elif key in ["_Path__mutable", "_Path__always_posix_format", "_Path__string_repr"]: super(Path, self).__setattr__(key, value) else: raise AttributeError(f"attribute {key} can not be set because mutapath.Path is an immutable class.") def __repr__(self): + if self.__string_repr: + return self.__str__() return repr(self._contained) def __str__(self): @@ -121,9 +133,30 @@ def __lt__(self, other): if isinstance(other, Path): return self.splitall() < other.splitall() left = self.posix_string() - right = str(other).replace("\\\\", "\\").replace("\\", "/") + right = Path.posix_string(str(other)) return left < right + def __le__(self, other): + if isinstance(other, Path): + return self.splitall() <= other.splitall() + left = self.posix_string() + right = Path.posix_string(str(other)) + return left <= right + + def __gt__(self, other): + if isinstance(other, Path): + return self.splitall() > other.splitall() + left = self.posix_string() + right = Path.posix_string(str(other)) + return left > right + + def __ge__(self, other): + if isinstance(other, Path): + return self.splitall() >= other.splitall() + left = self.posix_string() + right = Path.posix_string(str(other)) + return left >= right + def __add__(self, other) -> str: return str(self.clone(self._contained.__add__(Path(other)._contained))) @@ -152,7 +185,7 @@ def __fspath__(self): def __invert__(self): """Create a cloned :class:`~mutapath.MutaPath` from this immutable Path.""" from mutapath import MutaPath - return MutaPath(self._contained, self.posix_enabled) + return MutaPath(self._contained, posix=self.posix_enabled) def _serialize(self) -> str: return str(self._contained) diff --git a/mutapath/mutapath.py b/mutapath/mutapath.py index 4e5121e..99f668d 100644 --- a/mutapath/mutapath.py +++ b/mutapath/mutapath.py @@ -7,18 +7,18 @@ import mutapath from mutapath.decorator import mutable_path_wrapper -from mutapath.immutapath import POSIX_ENABLED_DEFAULT +from mutapath.immutapath import POSIX_ENABLED_DEFAULT, STRING_REPR @mutable_path_wrapper class MutaPath(mutapath.Path): """Mutable Path""" - def __init__(self, contained: Union[MutaPath, mutapath.Path, path.Path, pathlib.PurePath, str] = "", - posix: Optional[bool] = POSIX_ENABLED_DEFAULT): + def __init__(self, contained: Union[MutaPath, mutapath.Path, path.Path, pathlib.PurePath, str] = "", *, + posix: Optional[bool] = POSIX_ENABLED_DEFAULT, string_repr: bool = STRING_REPR): if isinstance(contained, MutaPath): contained = contained._contained - super(MutaPath, self).__init__(contained, posix) + super(MutaPath, self).__init__(contained, posix=posix, string_repr=string_repr) def __eq__(self, other): return super(MutaPath, self).__eq__(other) diff --git a/tests/test_immutapath.py b/tests/test_immutapath.py index 1c673fc..f9c20d3 100644 --- a/tests/test_immutapath.py +++ b/tests/test_immutapath.py @@ -170,6 +170,11 @@ def test_repr(self): actual = Path("\\A\\B", posix=True) self.assertEqual(repr(actual), expected) + def test_string_repr(self): + expected = "/A/B" + actual = Path("\\A\\B", posix=True, string_repr=True) + self.assertEqual(repr(actual), expected) + def test_str(self): expected = "/A/B" actual = Path("\\A\\B", posix=True) @@ -226,15 +231,35 @@ def test_hash(self): actual = hash(Path("/A/B/")) self.assertEqual(expected, actual) - def test_lt_last(self): + def test_lt_gt_last(self): lesser = Path("/A/B/") + lesser2 = Path("/A/B") greater = Path("/A/C") + # lt gt + self.assertFalse(lesser < lesser2) + self.assertFalse(lesser > lesser2) self.assertLess(lesser, greater) - - def test_lt_first(self): + self.assertGreater(greater, lesser) + # le ge + self.assertLessEqual(lesser, lesser2) + self.assertGreaterEqual(lesser, lesser2) + self.assertLessEqual(lesser, greater) + self.assertGreaterEqual(greater, lesser) + + def test_lt_gt_le_ge_first(self): lesser = Path("/A/D") + lesser2 = Path("/A/D/") greater = Path("/B/C") + # lt gt + self.assertFalse(lesser < lesser2) + self.assertFalse(lesser > lesser2) self.assertLess(lesser, greater) + self.assertGreater(greater, lesser) + # le ge + self.assertLessEqual(lesser, lesser2) + self.assertGreaterEqual(lesser, lesser2) + self.assertLessEqual(lesser, greater) + self.assertGreaterEqual(greater, lesser) def test_sort(self): first = Path("/A/B/C") @@ -244,10 +269,26 @@ def test_sort(self): actual = sorted([third, first, second]) self.assertEqual(expected, actual) - def test_lt_str(self): - lesser = Path("/A/B/") + def test_lt_gt_le_ge_str(self): + path = Path("/A/B/") greater = "/A/C" - self.assertLess(lesser, greater) + lesser = "/A/A" + equal = "/A/B" + self.assertGreater(path, lesser) + self.assertGreaterEqual(path, lesser) + self.assertLess(path, greater) + self.assertLessEqual(path, greater) + self.assertLessEqual(path, equal) + self.assertLessEqual(path, greater) + self.assertGreaterEqual(path, equal) + self.assertGreaterEqual(path, lesser) + + def test_getitem(self): + expected = "A" + actual_root = Path("/A/B/")[1] + actual_name = Path("/B/A/").name[0] + self.assertEqual(expected, actual_root) + self.assertEqual(expected, actual_name) def test_static_posix_string(self): expected = "/A/B/C" @@ -256,8 +297,8 @@ def test_static_posix_string(self): def test_posix_string(self): expected = "/A/B/C" - actual = Path("\\A\\B/C", False).posix_string() - actual2 = Path("/A\\B\\C", True).posix_string() + actual = Path("\\A\\B/C", posix=False).posix_string() + actual2 = Path("/A\\B\\C", posix=True).posix_string() self.assertEqual(expected, actual) self.assertEqual(expected, actual2) diff --git a/tests/test_mutapath.py b/tests/test_mutapath.py index 11a9e9f..47ef957 100644 --- a/tests/test_mutapath.py +++ b/tests/test_mutapath.py @@ -10,7 +10,7 @@ def __init__(self, *args): super().__init__(*args) def _gen_start_path(self, posix: bool = False): - return MutaPath(super(TestMutaPath, self)._gen_start_path(posix), posix) + return MutaPath(super(TestMutaPath, self)._gen_start_path(posix), posix=posix) @file_test_no_asserts def test_suffix(self, test_file: Path):