From 6bea1feaa00abe149383392df22233ebc3cca14a Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Sat, 31 Aug 2024 14:39:06 +0200 Subject: [PATCH] Use OS-specific delimiters for fake Windows/PosixPath - fixes the behavior of the Path for non-current OS --- pyfakefs/fake_file.py | 3 +- pyfakefs/fake_filesystem.py | 99 ++++++++--- pyfakefs/fake_path.py | 6 +- pyfakefs/fake_pathlib.py | 90 ++++++---- pyfakefs/helpers.py | 38 +++++ .../tests/fake_filesystem_unittest_test.py | 6 +- pyfakefs/tests/fake_pathlib_test.py | 158 +++++++----------- 7 files changed, 247 insertions(+), 153 deletions(-) diff --git a/pyfakefs/fake_file.py b/pyfakefs/fake_file.py index 5be15984..d43eb6d2 100644 --- a/pyfakefs/fake_file.py +++ b/pyfakefs/fake_file.py @@ -419,8 +419,7 @@ def has_permission(self, permission_bits: int) -> bool: class FakeNullFile(FakeFile): def __init__(self, filesystem: "FakeFilesystem") -> None: - devnull = "nul" if filesystem.is_windows_fs else "/dev/null" - super().__init__(devnull, filesystem=filesystem, contents="") + super().__init__(filesystem.devnull, filesystem=filesystem, contents="") @property def byte_contents(self) -> bytes: diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index 56f0e47e..17b25d58 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -81,6 +81,8 @@ True """ +import contextlib +import dataclasses import errno import heapq import os @@ -122,6 +124,9 @@ matching_string, AnyPath, AnyString, + WINDOWS_PROPERTIES, + POSIX_PROPERTIES, + FSType, ) if sys.platform.startswith("linux"): @@ -179,10 +184,6 @@ class FakeFilesystem: """Provides the appearance of a real directory tree for unit testing. Attributes: - path_separator: The path separator, corresponds to `os.path.sep`. - alternative_path_separator: Corresponds to `os.path.altsep`. - is_windows_fs: `True` in a real or faked Windows file system. - is_macos: `True` under MacOS, or if we are faking it. is_case_sensitive: `True` if a case-sensitive file system is assumed. root: The root :py:class:`FakeDirectory` entry of the file system. @@ -217,12 +218,8 @@ def __init__( >>> filesystem = FakeFilesystem(path_separator='/') """ - self.path_separator: str = path_separator - self.alternative_path_separator: Optional[str] = os.path.altsep self.patcher = patcher self.create_temp_dir = create_temp_dir - if path_separator != os.sep: - self.alternative_path_separator = None # is_windows_fs can be used to test the behavior of pyfakefs under # Windows fs on non-Windows systems and vice verse; @@ -235,7 +232,19 @@ def __init__( # is_case_sensitive can be used to test pyfakefs for case-sensitive # file systems on non-case-sensitive systems and vice verse - self.is_case_sensitive: bool = not (self.is_windows_fs or self._is_macos) + self.is_case_sensitive: bool = not (self._is_windows_fs or self._is_macos) + + # by default, we use the configured filesystem + self.fs_type = FSType.DEFAULT + base_properties = ( + WINDOWS_PROPERTIES if self._is_windows_fs else POSIX_PROPERTIES + ) + self.fs_properties = [ + dataclasses.replace(base_properties), + POSIX_PROPERTIES, + WINDOWS_PROPERTIES, + ] + self.path_separator = path_separator self.root: FakeDirectory self._cwd = "" @@ -262,21 +271,30 @@ def __init__( @property def is_linux(self) -> bool: + """Returns `True` in a real or faked Linux file system.""" return not self.is_windows_fs and not self.is_macos @property def is_windows_fs(self) -> bool: - return self._is_windows_fs + """Returns `True` in a real or faked Windows file system.""" + return ( + self.fs_type == FSType.WINDOWS + or self.fs_type == FSType.DEFAULT + and self._is_windows_fs + ) @is_windows_fs.setter def is_windows_fs(self, value: bool) -> None: if self._is_windows_fs != value: self._is_windows_fs = value + if value: + self._is_macos = False self.reset() FakePathModule.reset(self) @property def is_macos(self) -> bool: + """Returns `True` in a real or faked macOS file system.""" return self._is_macos @is_macos.setter @@ -286,6 +304,38 @@ def is_macos(self, value: bool) -> None: self.reset() FakePathModule.reset(self) + @property + def path_separator(self) -> str: + """Returns the path separator, corresponds to `os.path.sep`.""" + return self.fs_properties[self.fs_type.value].sep + + @path_separator.setter + def path_separator(self, value: str) -> None: + self.fs_properties[0].sep = value + if value != os.sep: + self.alternative_path_separator = None + + @property + def alternative_path_separator(self) -> Optional[str]: + """Returns the alternative path separator, corresponds to `os.path.altsep`.""" + return self.fs_properties[self.fs_type.value].altsep + + @alternative_path_separator.setter + def alternative_path_separator(self, value: Optional[str]) -> None: + self.fs_properties[0].altsep = value + + @property + def devnull(self) -> str: + return self.fs_properties[self.fs_type.value].devnull + + @property + def pathsep(self) -> str: + return self.fs_properties[self.fs_type.value].pathsep + + @property + def line_separator(self) -> str: + return self.fs_properties[self.fs_type.value].linesep + @property def cwd(self) -> str: """Return the current working directory of the fake filesystem.""" @@ -334,8 +384,11 @@ def os(self, value: OSType) -> None: self._is_windows_fs = value == OSType.WINDOWS self._is_macos = value == OSType.MACOS self.is_case_sensitive = value == OSType.LINUX - self.path_separator = "\\" if value == OSType.WINDOWS else "/" - self.alternative_path_separator = "/" if value == OSType.WINDOWS else None + self.fs_type = FSType.DEFAULT + base_properties = ( + WINDOWS_PROPERTIES if self._is_windows_fs else POSIX_PROPERTIES + ) + self.fs_properties[0] = base_properties self.reset() FakePathModule.reset(self) @@ -358,6 +411,15 @@ def reset(self, total_size: Optional[int] = None, init_pathlib: bool = True): fake_pathlib.init_module(self) + @contextlib.contextmanager + def use_fs_type(self, fs_type: FSType): + old_fs_type = self.fs_type + try: + self.fs_type = fs_type + yield + finally: + self.fs_type = old_fs_type + def _add_root_mount_point(self, total_size): mount_point = "C:" if self.is_windows_fs else self.path_separator self._cwd = mount_point @@ -403,9 +465,6 @@ def clear_cache(self) -> None: if self.patcher: self.patcher.clear_cache() - def line_separator(self) -> str: - return "\r\n" if self.is_windows_fs else "\n" - def raise_os_error( self, err_no: int, @@ -1144,8 +1203,8 @@ def splitroot(self, path: AnyStr): if isinstance(p, bytes): sep = self.path_separator.encode() altsep = None - if self.alternative_path_separator: - altsep = self.alternative_path_separator.encode() + if self.alternative_path_separator is not None: + altsep = self.alternative_path_separator.encode() # type: ignore[attribute-error] colon = b":" unc_prefix = b"\\\\?\\UNC\\" empty = b"" @@ -1438,7 +1497,7 @@ def exists(self, file_path: AnyPath, check_link: bool = False) -> bool: raise TypeError if not path: return False - if path == self.dev_null.name: + if path == self.devnull: return not self.is_windows_fs or sys.version_info >= (3, 8) try: if self.is_filepath_ending_with_separator(path): @@ -1515,7 +1574,7 @@ def resolve_path(self, file_path: AnyStr, allow_fd: bool = False) -> AnyStr: path = self.replace_windows_root(path) if self._is_root_path(path): return path - if path == matching_string(path, self.dev_null.name): + if path == matching_string(path, self.devnull): return path path_components = self._path_components(path) resolved_components = self._resolve_components(path_components) @@ -1661,7 +1720,7 @@ def get_object_from_normpath( path = make_string_path(file_path) if path == matching_string(path, self.root.name): return self.root - if path == matching_string(path, self.dev_null.name): + if path == matching_string(path, self.devnull): return self.dev_null path = self._original_path(path) diff --git a/pyfakefs/fake_path.py b/pyfakefs/fake_path.py index 013b9e7b..7719ef0b 100644 --- a/pyfakefs/fake_path.py +++ b/pyfakefs/fake_path.py @@ -123,9 +123,9 @@ def __init__(self, filesystem: "FakeFilesystem", os_module: "FakeOsModule"): def reset(cls, filesystem: "FakeFilesystem") -> None: cls.sep = filesystem.path_separator cls.altsep = filesystem.alternative_path_separator - cls.linesep = filesystem.line_separator() - cls.devnull = "nul" if filesystem.is_windows_fs else "/dev/null" - cls.pathsep = ";" if filesystem.is_windows_fs else ":" + cls.linesep = filesystem.line_separator + cls.devnull = filesystem.devnull + cls.pathsep = filesystem.pathsep def exists(self, path: AnyStr) -> bool: """Determine whether the file object exists within the fake filesystem. diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py index 55942b8b..3c4a931e 100644 --- a/pyfakefs/fake_pathlib.py +++ b/pyfakefs/fake_pathlib.py @@ -49,7 +49,8 @@ from pyfakefs.fake_filesystem import FakeFilesystem from pyfakefs.fake_open import fake_open from pyfakefs.fake_os import FakeOsModule, use_original_os -from pyfakefs.helpers import IS_PYPY, is_called_from_skipped_module +from pyfakefs.fake_path import FakePathModule +from pyfakefs.helpers import IS_PYPY, is_called_from_skipped_module, FSType def init_module(filesystem): @@ -67,30 +68,27 @@ def init_module(filesystem): FakePathlibModule.PurePosixPath._flavour = fake_pure_posix_flavour # Pure Windows path separators must be filesystem-independent. - fake_pure_nt_flavour = _FakePosixFlavour(filesystem) + fake_pure_nt_flavour = _FakeWindowsFlavour(filesystem) fake_pure_nt_flavour.sep = "\\" fake_pure_nt_flavour.altsep = "/" FakePathlibModule.PureWindowsPath._flavour = fake_pure_nt_flavour else: # in Python > 3.11, the flavour is no longer a separate class, # but points to the os-specific path module (posixpath/ntpath) - fake_os = FakeOsModule(filesystem) - parser_name = "_flavour" if sys.version_info < (3, 13) else "parser" + fake_os_posix = FakeOsModule(filesystem) + if filesystem.is_windows_fs: + fake_os_posix.path = FakePosixPathModule(filesystem, fake_os_posix) + fake_os_windows = FakeOsModule(filesystem) + if not filesystem.is_windows_fs: + fake_os_windows.path = FakeWindowsPathModule(filesystem, fake_os_windows) - setattr(FakePathlibModule.PosixPath, parser_name, fake_os.path) - setattr(FakePathlibModule.WindowsPath, parser_name, fake_os.path) + parser_name = "_flavour" if sys.version_info < (3, 13) else "parser" - # Pure POSIX path separators must be filesystem independent. - fake_pure_posix_os = FakeOsModule(filesystem) - fake_pure_posix_os.path.sep = "/" - fake_pure_posix_os.path.altsep = None - setattr(FakePathlibModule.PurePosixPath, parser_name, fake_pure_posix_os.path) + # Pure POSIX path properties must be filesystem independent. + setattr(FakePathlibModule.PurePosixPath, parser_name, fake_os_posix.path) - # Pure Windows path separators must be filesystem independent. - fake_pure_nt_os = FakeOsModule(filesystem) - fake_pure_nt_os.path.sep = "\\" - fake_pure_nt_os.path.altsep = "/" - setattr(FakePathlibModule.PureWindowsPath, parser_name, fake_pure_nt_os.path) + # Pure Windows path properties must be filesystem independent. + setattr(FakePathlibModule.PureWindowsPath, parser_name, fake_os_windows.path) def _wrap_strfunc(fake_fct, original_fct): @@ -242,9 +240,6 @@ class _FakeFlavour(flavour): # type: ignore[valid-type, misc] """Fake Flavour implementation used by PurePath and _Flavour""" filesystem = None - sep = "/" - altsep = None - has_drv = False ext_namespace_prefix = "\\\\?\\" @@ -254,9 +249,6 @@ class _FakeFlavour(flavour): # type: ignore[valid-type, misc] def __init__(self, filesystem): self.filesystem = filesystem - self.sep = filesystem.path_separator - self.altsep = filesystem.alternative_path_separator - self.has_drv = filesystem.is_windows_fs super().__init__() @staticmethod @@ -320,9 +312,13 @@ def _splitroot_posix(path, sep): def splitroot(self, path, sep=None): """Split path into drive, root and rest.""" + is_windows = isinstance(self, _FakeWindowsFlavour) if sep is None: - sep = self.filesystem.path_separator - if self.filesystem.is_windows_fs: + if is_windows == self.filesystem.is_windows_fs: + sep = self.filesystem.path_separator + else: + sep = self.sep + if is_windows: return self._splitroot_with_drive(path, sep) return self._splitroot_posix(path, sep) @@ -443,6 +439,9 @@ class _FakeWindowsFlavour(_FakeFlavour): | {"COM%d" % i for i in range(1, 10)} | {"LPT%d" % i for i in range(1, 10)} ) + sep = "\\" + altsep = "/" + has_drv = True pathmod = ntpath def is_reserved(self, parts): @@ -519,6 +518,9 @@ class _FakePosixFlavour(_FakeFlavour): independent of FakeFilesystem properties. """ + sep = "/" + altsep = "" + has_drv = False pathmod = posixpath def is_reserved(self, parts): @@ -551,6 +553,36 @@ def gethomedir(self, username): def compile_pattern(self, pattern): return re.compile(fnmatch.translate(pattern)).fullmatch +else: # Python >= 3.12 + + class FakePosixPathModule(FakePathModule): + def __init__(self, filesystem: "FakeFilesystem", os_module: "FakeOsModule"): + super().__init__(filesystem, os_module) + with self.filesystem.use_fs_type(FSType.POSIX): + self.reset(self.filesystem) + + class FakeWindowsPathModule(FakePathModule): + def __init__(self, filesystem: "FakeFilesystem", os_module: "FakeOsModule"): + super().__init__(filesystem, os_module) + with self.filesystem.use_fs_type(FSType.WINDOWS): + self.reset(self.filesystem) + + def with_fs_type(f: Callable, fs_type: FSType) -> Callable: + """Decorator used for fake_path methods to ensure that + the correct filesystem type is used.""" + + @functools.wraps(f) + def wrapped(self, *args, **kwargs): + with self.filesystem.use_fs_type(fs_type): + return f(self, *args, **kwargs) + + return wrapped + + # decorate all public functions to use the correct fs type + for fct_name in FakePathModule.dir(): + fn = getattr(FakePathModule, fct_name) + setattr(FakeWindowsPathModule, fct_name, with_fs_type(fn, FSType.WINDOWS)) + setattr(FakePosixPathModule, fct_name, with_fs_type(fn, FSType.POSIX)) class FakePath(pathlib.Path): @@ -878,15 +910,11 @@ class PurePosixPath(PurePath): paths""" __slots__ = () - if sys.version_info >= (3, 13): - parser = posixpath class PureWindowsPath(PurePath): """A subclass of PurePath, that represents Windows filesystem paths""" __slots__ = () - if sys.version_info >= (3, 13): - parser = ntpath class WindowsPath(FakePath, PureWindowsPath): """A subclass of Path and PureWindowsPath that represents @@ -1010,9 +1038,9 @@ def wrapped(*args, **kwargs): return wrapped - for name, fn in inspect.getmembers(RealPath, inspect.isfunction): - if not name.startswith("__"): - setattr(RealPath, name, with_original_os(fn)) + for fct_name, fn in inspect.getmembers(RealPath, inspect.isfunction): + if not fct_name.startswith("__"): + setattr(RealPath, fct_name, with_original_os(fn)) class RealPathlibPathModule: diff --git a/pyfakefs/helpers.py b/pyfakefs/helpers.py index 674ce8fa..652969dd 100644 --- a/pyfakefs/helpers.py +++ b/pyfakefs/helpers.py @@ -24,6 +24,8 @@ import traceback from collections import namedtuple from copy import copy +from dataclasses import dataclass +from enum import Enum from stat import S_IFLNK from typing import Union, Optional, Any, AnyStr, overload, cast @@ -205,6 +207,42 @@ def matching_string( # type: ignore[misc] return string # pytype: disable=bad-return-type +@dataclass +class FSProperties: + sep: str + altsep: Optional[str] + pathsep: str + linesep: str + devnull: str + + +# pure POSIX file system properties, for use with PosixPath +POSIX_PROPERTIES = FSProperties( + sep="/", + altsep=None, + pathsep=":", + linesep="\n", + devnull="/dev/null", +) + +# pure Windows file system properties, for use with WindowsPath +WINDOWS_PROPERTIES = FSProperties( + sep="\\", + altsep="/", + pathsep=";", + linesep="\r\n", + devnull="NUL", +) + + +class FSType(Enum): + """Defines which file system properties to use.""" + + DEFAULT = 0 # use current OS file system + modifications in fake file system + POSIX = 1 # pure POSIX properties, for use in PosixPath + WINDOWS = 2 # pure Windows properties, for use in WindowsPath + + class FakeStatResult: """Mimics os.stat_result for use as return type of `stat()` and similar. This is needed as `os.stat_result` has no possibility to set diff --git a/pyfakefs/tests/fake_filesystem_unittest_test.py b/pyfakefs/tests/fake_filesystem_unittest_test.py index 89f6783d..25d8c776 100644 --- a/pyfakefs/tests/fake_filesystem_unittest_test.py +++ b/pyfakefs/tests/fake_filesystem_unittest_test.py @@ -821,6 +821,10 @@ class TestOtherFS(fake_filesystem_unittest.TestCase): def setUp(self): self.setUpPyfakefs() + @unittest.skipIf( + sys.platform != "win32" and sys.version_info < (3, 12), + "Currently not working with these versions", + ) @mock.patch.dict(os.environ, {"HOME": "/home/john"}) def test_real_file_with_home(self): """Regression test for #558""" @@ -850,7 +854,7 @@ def test_windows(self): self.assertEqual("/", os.altsep) self.assertEqual(";", os.pathsep) self.assertEqual("\r\n", os.linesep) - self.assertEqual("nul", os.devnull) + self.assertEqual("NUL", os.devnull) def test_linux(self): self.fs.os = OSType.LINUX diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py index f821febb..afc438aa 100644 --- a/pyfakefs/tests/fake_pathlib_test.py +++ b/pyfakefs/tests/fake_pathlib_test.py @@ -198,7 +198,7 @@ def test_path_parts(self): ) self.assertEqual(path.parents[1], self.path("d:")) - @unittest.skipIf(not is_windows, "Windows-specifc behavior") + @unittest.skipIf(not is_windows, "Windows-specific behavior") def test_is_absolute(self): self.assertTrue(self.path("c:/a/b").is_absolute()) self.assertFalse(self.path("/a/b").is_absolute()) @@ -445,7 +445,7 @@ def test_resolve(self): self.create_dir(self.make_path("antoine", "docs")) self.create_file(self.make_path("antoine", "setup.py")) self.os.chdir(self.make_path("antoine")) - # use real path to handle symlink /var to /private/var in MacOs + # use real path to handle symlink /var to /private/var in macOS self.assert_equal_paths( self.path().resolve(), self.path(self.os.path.realpath(self.make_path("antoine"))), @@ -503,7 +503,7 @@ def test_iterdir_and_glob_without_exe_permission(self): assert len(list(directory.glob("*.txt"))) == 1 assert list(directory.glob("*.txt"))[0] == file_path - # We cannot read files inside of the directory, + # We cannot read files inside the directory, # even if we have read access to the file with self.assertRaises(PermissionError): file_path.stat() @@ -874,10 +874,10 @@ class FakePathlibUsageInOsFunctionsTest(RealPathlibTestCase): def test_join(self): dir1 = "foo" dir2 = "bar" - dir = self.os.path.join(dir1, dir2) - self.assertEqual(dir, self.os.path.join(self.path(dir1), dir2)) - self.assertEqual(dir, self.os.path.join(dir1, self.path(dir2))) - self.assertEqual(dir, self.os.path.join(self.path(dir1), self.path(dir2))) + dir3 = self.os.path.join(dir1, dir2) + self.assertEqual(dir3, self.os.path.join(self.path(dir1), dir2)) + self.assertEqual(dir3, self.os.path.join(dir1, self.path(dir2))) + self.assertEqual(dir3, self.os.path.join(self.path(dir1), self.path(dir2))) def test_normcase(self): dir1 = self.make_path("Foo", "Bar", "Baz") @@ -1236,7 +1236,7 @@ def use_real_fs(self): class FakeFilesystemPathLikeObjectTest(unittest.TestCase): def setUp(self): - self.filesystem = fake_filesystem.FakeFilesystem(path_separator="/") + self.filesystem = fake_filesystem.FakeFilesystem() self.pathlib = fake_pathlib.FakePathlibModule(self.filesystem) self.os = fake_os.FakeOsModule(self.filesystem) @@ -1316,173 +1316,139 @@ class FakePathlibModulePurePathTest(fake_filesystem_unittest.TestCase): def test_windows_pure_path_parsing_backslash(self): path = r"C:\Windows\cmd.exe" pure_result = pathlib.PureWindowsPath(path).stem - self.assertEqual(pure_result, "cmd") + self.assertEqual("cmd", pure_result) self.setUpPyfakefs() self.assertEqual( - fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem, pure_result + pure_result, fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem ) - self.assertEqual(pathlib.PureWindowsPath(path).stem, pure_result) + self.assertEqual(pure_result, pathlib.PureWindowsPath(path).stem) def test_windows_pure_path_parsing_forward_slash(self): path = r"C:/Windows/cmd.exe" pure_result = pathlib.PureWindowsPath(path).stem - self.assertEqual(pure_result, "cmd") + self.assertEqual("cmd", pure_result) self.setUpPyfakefs() self.assertEqual( - fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem, pure_result + pure_result, fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem ) - self.assertEqual(pathlib.PureWindowsPath(path).stem, pure_result) + self.assertEqual(pure_result, pathlib.PureWindowsPath(path).stem) def test_posix_pure_path_parsing(self): path = r"/bin/bash" pure_result = pathlib.PurePosixPath(path).stem - self.assertEqual(pure_result, "bash") + self.assertEqual("bash", pure_result) self.setUpPyfakefs() self.assertEqual( - fake_pathlib.FakePathlibModule.PurePosixPath(path).stem, pure_result + pure_result, fake_pathlib.FakePathlibModule.PurePosixPath(path).stem ) self.assertEqual(pathlib.PurePosixPath(path).stem, pure_result) def test_windows_pure_path_str_backslash(self): path = r"C:\Windows\cmd.exe" pure_result = str(pathlib.PureWindowsPath(path)) - self.assertEqual(pure_result, r"C:\Windows\cmd.exe") + self.assertEqual(r"C:\Windows\cmd.exe", pure_result) self.setUpPyfakefs() self.assertEqual( - str(fake_pathlib.FakePathlibModule.PureWindowsPath(path)), pure_result + pure_result, str(fake_pathlib.FakePathlibModule.PureWindowsPath(path)) ) self.assertEqual(str(pathlib.PureWindowsPath(path)), pure_result) def test_windows_pure_path_str_forward_slash(self): - path = r"C:/Windows/cmd.exe" - pure_result = str(pathlib.PureWindowsPath(path)) - self.assertEqual(pure_result, r"C:\Windows\cmd.exe") + path = "C:/Windows/cmd.exe" + pure_result_win = str(pathlib.PureWindowsPath(path)) + self.assertEqual(r"C:\Windows\cmd.exe", pure_result_win) + pure_result_posix_stem = str(pathlib.PurePosixPath(path).stem) + self.assertEqual("cmd", pure_result_posix_stem) self.setUpPyfakefs() self.assertEqual( - str(fake_pathlib.FakePathlibModule.PureWindowsPath(path)), pure_result + pure_result_win, str(fake_pathlib.FakePathlibModule.PureWindowsPath(path)) ) - self.assertEqual(str(pathlib.PureWindowsPath(path)), pure_result) - self.assertEqual(pathlib.PurePosixPath(path).stem, pure_result) + self.assertEqual(pure_result_win, str(pathlib.PureWindowsPath(path))) + self.assertEqual(pure_result_posix_stem, pathlib.PurePosixPath(path).stem) def test_posix_pure_path_str_backslash(self): path = r"\bin\bash" pure_result = str(pathlib.PurePosixPath(path)) - self.assertEqual(pure_result, r"\bin\bash") + self.assertEqual(r"\bin\bash", pure_result) self.setUpPyfakefs() self.assertEqual( - str(fake_pathlib.FakePathlibModule.PurePosixPath(path)), pure_result + pure_result, str(fake_pathlib.FakePathlibModule.PurePosixPath(path)) ) - self.assertEqual(str(pathlib.PurePosixPath(path)), pure_result) + self.assertEqual(pure_result, str(pathlib.PurePosixPath(path))) def test_posix_pure_path_str_forward_slash(self): - path = r"/bin/bash" + path = "/bin/bash" pure_result = str(pathlib.PurePosixPath(path)) - self.assertEqual(pure_result, r"/bin/bash") + self.assertEqual(r"/bin/bash", pure_result) self.setUpPyfakefs() self.assertEqual( - str(fake_pathlib.FakePathlibModule.PurePosixPath(path)), pure_result + pure_result, str(fake_pathlib.FakePathlibModule.PurePosixPath(path)) ) - self.assertEqual(str(pathlib.PurePosixPath(path)), pure_result) + self.assertEqual(pure_result, str(pathlib.PurePosixPath(path))) - def test_posix_pure_path_is_absolute_1(self): - path = r"/bin/bash" + def check_posix_pure_path_is_absolute(self, path, expected_result): pure_result = pathlib.PurePosixPath(path).is_absolute() - self.assertTrue(pure_result) + self.assertEqual(expected_result, pure_result) self.setUpPyfakefs() self.assertEqual( - fake_pathlib.FakePathlibModule.PurePosixPath(path).is_absolute(), pure_result, - ) - self.assertEqual(pathlib.PurePosixPath(path).is_absolute(), pure_result) - - def test_posix_pure_path_is_absolute_2(self): - path = r"bin/bash" - pure_result = pathlib.PurePosixPath(path).is_absolute() - self.assertFalse(pure_result) - - self.setUpPyfakefs() - self.assertEqual( fake_pathlib.FakePathlibModule.PurePosixPath(path).is_absolute(), - pure_result, ) - self.assertEqual(pathlib.PurePosixPath(path).is_absolute(), pure_result) + self.assertEqual(pure_result, pathlib.PurePosixPath(path).is_absolute()) - def test_posix_pure_path_is_absolute_3(self): - path = r"../bin/bash" - pure_result = pathlib.PurePosixPath(path).is_absolute() - self.assertFalse(pure_result) - - self.setUpPyfakefs() - self.assertEqual( - fake_pathlib.FakePathlibModule.PurePosixPath(path).is_absolute(), - pure_result, - ) - self.assertEqual(pathlib.PurePosixPath(path).is_absolute(), pure_result) + def test_posix_pure_path_is_absolute_for_absolute_path(self): + self.check_posix_pure_path_is_absolute("/bin/bash", expected_result=True) - def test_windows_pure_path_is_absolute_1(self): - path = r"C:/Windows/cmd.exe" - pure_result = pathlib.PureWindowsPath(path).is_absolute() - self.assertTrue(pure_result) + def test_posix_pure_path_is_absolute_for_local_path(self): + self.check_posix_pure_path_is_absolute("bin/bash", expected_result=False) - self.setUpPyfakefs() - self.assertEqual( - fake_pathlib.FakePathlibModule.PureWindowsPath(path).is_absolute(), - pure_result, - ) - self.assertEqual(pathlib.PureWindowsPath(path).is_absolute(), pure_result) + def test_posix_pure_path_is_absolute_for_relative_path(self): + self.check_posix_pure_path_is_absolute("../bin/bash", expected_result=False) - def test_windows_pure_path_is_absolute_2(self): - path = r"./cmd.exe" + def check_windows_pure_path_is_absolute(self, path, expected_result): pure_result = pathlib.PureWindowsPath(path).is_absolute() - self.assertFalse(pure_result) + self.assertEqual(expected_result, pure_result) self.setUpPyfakefs() self.assertEqual( - fake_pathlib.FakePathlibModule.PureWindowsPath(path).is_absolute(), pure_result, + fake_pathlib.FakePathlibModule.PureWindowsPath(path).is_absolute(), ) - self.assertEqual(pathlib.PureWindowsPath(path).is_absolute(), pure_result) + self.assertEqual(pure_result, pathlib.PureWindowsPath(path).is_absolute()) - def test_windows_pure_path_is_absolute_3(self): - path = r"../cmd.exe" - pure_result = pathlib.PureWindowsPath(path).is_absolute() - self.assertFalse(pure_result) + def test_windows_pure_path_is_absolute_for_absolute_path(self): + self.check_windows_pure_path_is_absolute("C:/Windows/cmd.exe", True) - self.setUpPyfakefs() - self.assertEqual( - fake_pathlib.FakePathlibModule.PureWindowsPath(path).is_absolute(), - pure_result, - ) - self.assertEqual(pathlib.PureWindowsPath(path).is_absolute(), pure_result) + def test_windows_pure_path_is_absolute_for_local_path(self): + self.check_windows_pure_path_is_absolute("./cmd.exe", expected_result=False) + + def test_windows_pure_path_is_absolute_for_relative_path(self): + self.check_windows_pure_path_is_absolute("../cmd.exe", expected_result=False) -class PureWindowsPath(FakePathlibModulePurePathTest, fake_filesystem_unittest.TestCase): - def setUpPyfakefs(self): - super().setUpPyfakefs() +class FakePathlibModulePurePathTestWindows(FakePathlibModulePurePathTest): + def setUpPyfakefs(self, **kwargs): + super().setUpPyfakefs(**kwargs) self.fs.os = OSType.WINDOWS -class FakePathlibModulePurePathTestMacos( - FakePathlibModulePurePathTest, fake_filesystem_unittest.TestCase -): - def setUpPyfakefs(self): - super().setUpPyfakefs() +class FakePathlibModulePurePathTestMacos(FakePathlibModulePurePathTest): + def setUpPyfakefs(self, **kwargs): + super().setUpPyfakefs(**kwargs) self.fs.os = OSType.MACOS -class FakePathlibModulePurePathTestLinux( - FakePathlibModulePurePathTest, fake_filesystem_unittest.TestCase -): - def setUpPyfakefs(self): - super().setUpPyfakefs() +class FakePathlibModulePurePathTestLinux(FakePathlibModulePurePathTest): + def setUpPyfakefs(self, **kwargs): + super().setUpPyfakefs(**kwargs) self.fs.os = OSType.LINUX