From 67b65efa87b6c7f36e3baaab8f584fe192ce307f Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Thu, 15 Oct 2020 17:18:56 +0200 Subject: [PATCH] Allow fake pathlib to be used in other os - adapted fake pathlib.home() to work in other os - fixes #558 --- CHANGES.md | 2 + pyfakefs/fake_filesystem.py | 5 ++- pyfakefs/fake_pathlib.py | 37 +++++++++++-------- .../tests/fake_filesystem_unittest_test.py | 20 ++++++++++ pyfakefs/tests/fake_pathlib_test.py | 26 ++++++++----- 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 508c714c..67d8ab10 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,8 @@ The released versions correspond to PyPi releases. (see [#554](../../issues/554)) #### Fixes + * fix handling of real files in combination with `home` if simulating + Posix under Windows (see [#558](../../issues/558)) * do not call fake `open` if called from skipped module (see [#552](../../issues/552)) * do not call fake `pathlib.Path` if called from skipped module diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index 60286965..a0e5e549 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -1668,7 +1668,10 @@ def _starts_with_drive_letter(self, file_path): the path starts with a drive letter. """ colon = matching_string(file_path, ':') - return (self.is_windows_fs and len(file_path) >= 2 and + # we also allow a drive letter if only the real fs is Windows + # to allow for real path names + return ((self.is_windows_fs or os.name == 'nt') and + len(file_path) >= 2 and file_path[:1].isalpha and (file_path[1:2]) == colon) def _starts_with_root_path(self, file_path): diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py index 1c726dbf..ad4ec9cd 100644 --- a/pyfakefs/fake_pathlib.py +++ b/pyfakefs/fake_pathlib.py @@ -449,7 +449,8 @@ class FakePath(pathlib.Path): def __new__(cls, *args, **kwargs): """Creates the correct subclass based on OS.""" if cls is FakePathlibModule.Path: - cls = (FakePathlibModule.WindowsPath if os.name == 'nt' + cls = (FakePathlibModule.WindowsPath + if cls.filesystem.is_windows_fs else FakePathlibModule.PosixPath) self = cls._from_parts(args, init=True) return self @@ -574,8 +575,15 @@ def home(cls): """Return a new path pointing to the user's home directory (as returned by os.path.expanduser('~')). """ - return cls(cls()._flavour.gethomedir(None). - replace(os.sep, cls.filesystem.path_separator)) + home = os.path.expanduser("~") + if cls.filesystem.is_windows_fs != (os.name == 'nt'): + username = os.path.split(home)[1] + if cls.filesystem.is_windows_fs: + home = os.path.join('C:', 'Users', username) + else: + home = os.path.join('home', username) + cls.filesystem.create_dir(home) + return cls(home.replace(os.sep, cls.filesystem.path_separator)) def samefile(self, other_path): """Return whether other_path is the same or not as this file @@ -660,18 +668,17 @@ class PureWindowsPath(PurePath): """A subclass of PurePath, that represents Windows filesystem paths""" __slots__ = () - if sys.platform == 'win32': - class WindowsPath(FakePath, PureWindowsPath): - """A subclass of Path and PureWindowsPath that represents - concrete Windows filesystem paths. - """ - __slots__ = () - else: - class PosixPath(FakePath, PurePosixPath): - """A subclass of Path and PurePosixPath that represents - concrete non-Windows filesystem paths. - """ - __slots__ = () + class WindowsPath(FakePath, PureWindowsPath): + """A subclass of Path and PureWindowsPath that represents + concrete Windows filesystem paths. + """ + __slots__ = () + + class PosixPath(FakePath, PurePosixPath): + """A subclass of Path and PurePosixPath that represents + concrete non-Windows filesystem paths. + """ + __slots__ = () Path = FakePath diff --git a/pyfakefs/tests/fake_filesystem_unittest_test.py b/pyfakefs/tests/fake_filesystem_unittest_test.py index a7b52a87..a4a92e2f 100644 --- a/pyfakefs/tests/fake_filesystem_unittest_test.py +++ b/pyfakefs/tests/fake_filesystem_unittest_test.py @@ -28,6 +28,7 @@ import unittest import warnings from distutils.dir_util import copy_tree, remove_tree +from pathlib import Path from unittest import TestCase import pyfakefs.tests.import_as_example @@ -743,5 +744,24 @@ def test_run_module(self): load_configs([self.config_module]) +class TestOtherFS(fake_filesystem_unittest.TestCase): + def setUp(self): + self.setUpPyfakefs() + self.fs.is_windows_fs = os.name != 'nt' + + def test_real_file_with_home(self): + """Regression test for #558""" + self.fs.add_real_file(__file__) + with open(__file__) as f: + self.assertTrue(f.read()) + home = Path.home() + if sys.version_info < (3, 6): + # fspath support since Python 3.6 + home = str(home) + os.chdir(home) + with open(__file__) as f: + self.assertTrue(f.read()) + + if __name__ == "__main__": unittest.main() diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py index 705a3b80..0d96ca79 100644 --- a/pyfakefs/tests/fake_pathlib_test.py +++ b/pyfakefs/tests/fake_pathlib_test.py @@ -66,14 +66,21 @@ def test_initialization_type(self): self.assertTrue(isinstance(path, self.pathlib.WindowsPath)) self.assertTrue(isinstance(path, self.pathlib.PureWindowsPath)) self.assertTrue(self.pathlib.PurePosixPath()) - with self.assertRaises(NotImplementedError): - self.pathlib.PosixPath() + # in fake fs, we allow to use the other OS implementation + if self.use_real_fs(): + with self.assertRaises(NotImplementedError): + self.pathlib.PosixPath() + else: + self.assertTrue(self.pathlib.PosixPath()) else: self.assertTrue(isinstance(path, self.pathlib.PosixPath)) self.assertTrue(isinstance(path, self.pathlib.PurePosixPath)) self.assertTrue(self.pathlib.PureWindowsPath()) - with self.assertRaises(NotImplementedError): - self.pathlib.WindowsPath() + if self.use_real_fs(): + with self.assertRaises(NotImplementedError): + self.pathlib.WindowsPath() + else: + self.assertTrue(self.pathlib.WindowsPath()) def test_init_with_segments(self): """Basic initialization tests - taken from pathlib.Path documentation @@ -477,13 +484,12 @@ def test_expanduser(self): def test_home(self): if is_windows: - self.assertEqual(self.path.home(), - self.path( - os.environ['USERPROFILE'].replace('\\', - '/'))) + self.assertEqual(self.path( + os.environ['USERPROFILE'].replace('\\', '/')), + self.path.home()) else: - self.assertEqual(self.path.home(), - self.path(os.environ['HOME'])) + self.assertEqual(self.path(os.environ['HOME']), + self.path.home()) class RealPathlibFileObjectPropertyTest(FakePathlibFileObjectPropertyTest):