From d8751513c6ff4e4e6d723329cff0f8b89e181c24 Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Mon, 6 May 2024 12:48:17 -0500 Subject: [PATCH] Fix pure windows path behavior (#1011) * Hard-code path separators in `Pure*Path` classes * Fixes #1006 --- CHANGES.md | 3 +++ pyfakefs/fake_pathlib.py | 33 ++++++++++++++++++++++++----- pyfakefs/tests/fake_pathlib_test.py | 26 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fa7c9e99..34aefc34 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,9 @@ The released versions correspond to PyPI releases. * The usage of the `pathlib2` and `scandir` modules in pyfakefs is now deprecated. They will now cause deprecation warnings if still used. Support for patching these modules will be removed in pyfakefs 6.0. +* `PureWindowsPath` and `PurePosixPath` now use filesystem-independent path separators, + and their path-parsing behaviors are now consistent regardless of runtime platform + and/or faked filesystem customization (see [#1006](../../issues/1006)). ## [Version 5.4.1](https://pypi.python.org/pypi/pyfakefs/5.4.0) (2024-04-11) Fixes a regression. diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py index 5a3f46d3..dc474c80 100644 --- a/pyfakefs/fake_pathlib.py +++ b/pyfakefs/fake_pathlib.py @@ -55,15 +55,38 @@ def init_module(filesystem): # pylint: disable=protected-access FakePath.filesystem = filesystem if sys.version_info < (3, 12): - FakePathlibModule.PureWindowsPath._flavour = _FakeWindowsFlavour(filesystem) - FakePathlibModule.PurePosixPath._flavour = _FakePosixFlavour(filesystem) + FakePathlibModule.WindowsPath._flavour = _FakeWindowsFlavour(filesystem) + FakePathlibModule.PosixPath._flavour = _FakePosixFlavour(filesystem) + + # Pure POSIX path separators must be filesystem-independent. + fake_pure_posix_flavour = _FakePosixFlavour(filesystem) + fake_pure_posix_flavour.sep = "/" + fake_pure_posix_flavour.altsep = None + 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.sep = "\\" + fake_pure_nt_flavour.altsep = "/" + FakePathlibModule.PureWindowsPath._flavour = fake_pure_nt_flavour else: # in Python 3.12, the flavour is no longer an own class, # but points to the os-specific path module (posixpath/ntpath) fake_os = FakeOsModule(filesystem) - fake_path = fake_os.path - FakePathlibModule.PureWindowsPath._flavour = fake_path - FakePathlibModule.PurePosixPath._flavour = fake_path + FakePathlibModule.PosixPath._flavour = fake_os.path + FakePathlibModule.WindowsPath._flavour = fake_os.path + + # 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 + FakePathlibModule.PurePosixPath._flavour = fake_pure_posix_os.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 = "/" + FakePathlibModule.PureWindowsPath._flavour = fake_pure_nt_os.path def _wrap_strfunc(strfunc): diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py index 145b0cdd..f142361a 100644 --- a/pyfakefs/tests/fake_pathlib_test.py +++ b/pyfakefs/tests/fake_pathlib_test.py @@ -1286,5 +1286,31 @@ def test_is_file_for_unreadable_dir_windows(self): path.is_file() +class FakePathlibModulePurePathTest(unittest.TestCase): + def test_windows_pure_path_parsing(self): + """Verify faked pure Windows paths use filesystem-independent separators.""" + + path = r"C:\Windows\cmd.exe" + self.assertEqual( + fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem, + pathlib.PureWindowsPath(path).stem, + ) + + path = r"C:/Windows/cmd.exe" + self.assertEqual( + fake_pathlib.FakePathlibModule.PureWindowsPath(path).stem, + pathlib.PureWindowsPath(path).stem, + ) + + def test_posix_pure_path_parsing(self): + """Verify faked pure POSIX paths use filesystem-independent separators.""" + + path = r"/bin/bash" + self.assertEqual( + fake_pathlib.FakePathlibModule.PurePosixPath(path).stem, + pathlib.PurePosixPath(path).stem, + ) + + if __name__ == "__main__": unittest.main(verbosity=2)