diff --git a/CHANGES.md b/CHANGES.md index 81f80905..9c96a849 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,10 @@ The release versions are PyPi releases. ## Version 3.5 (As yet unreleased) #### New Features - + * added support for path-like objects as arguments in `create_file()`, + `create_dir()`, `create_symlink()`, `add_real_file()` and + `add_real_directory()` (Python >= 3.6, see [#409](../../issues/409)) + #### Infrastructure * moved tests into package * use README.md in pypi ([#358](../../issues/358)) diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index 8a6cfa48..8839d074 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -2176,6 +2176,12 @@ def remove_object(self, file_path): except AttributeError: self.raise_io_error(errno.ENOTDIR, file_path) + def make_string_path(self, path): + path = make_string_path(path) + os_sep = self._matching_string(path, os.sep) + fake_sep = self._matching_string(path, self.path_separator) + return path.replace(os_sep, fake_sep) + def create_dir(self, directory_path, perm_bits=PERM_DEF): """Create `directory_path`, and all the parent directories. @@ -2191,6 +2197,7 @@ def create_dir(self, directory_path, perm_bits=PERM_DEF): Raises: OSError: if the directory already exists. """ + directory_path = self.make_string_path(directory_path) directory_path = self.absnormpath(directory_path) self._auto_mount_drive_if_needed(directory_path) if self.exists(directory_path, check_link=True): @@ -2279,6 +2286,8 @@ def add_real_file(self, source_path, read_only=True, target_path=None): that `pyfakefs` must not modify the real file system. """ target_path = target_path or source_path + source_path = make_string_path(source_path) + target_path = self.make_string_path(target_path) real_stat = os.stat(source_path) fake_file = self.create_file_internally(target_path, read_from_real_fs=True) @@ -2398,6 +2407,7 @@ def create_file_internally(self, file_path, raw_io: `True` if called from low-level API (`os.open`) """ error_class = OSError if raw_io else IOError + file_path = self.make_string_path(file_path) file_path = self.absnormpath(file_path) if not is_int_type(st_mode): raise TypeError( @@ -2464,6 +2474,8 @@ def create_symlink(self, file_path, link_target, create_missing_dirs=True): "on Windows before Python 3.2") # the link path cannot end with a path separator + file_path = self.make_string_path(file_path) + link_target = self.make_string_path(link_target) file_path = self.normcase(file_path) if self.ends_with_path_separator(file_path): if self.exists(file_path): diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py index 97a98839..19439066 100644 --- a/pyfakefs/tests/fake_pathlib_test.py +++ b/pyfakefs/tests/fake_pathlib_test.py @@ -27,7 +27,7 @@ import sys import unittest -from pyfakefs import fake_pathlib +from pyfakefs import fake_pathlib, fake_filesystem from pyfakefs.tests.test_utils import RealFsTestCase is_windows = sys.platform == 'win32' @@ -910,5 +910,61 @@ def use_real_fs(self): return True +@unittest.skipIf(sys.version_info < (3, 6), + 'Path-like objects new in Python 3.6') +class FakeFilesystemPathLikeObjectTest(unittest.TestCase): + + def setUp(self): + self.filesystem = fake_filesystem.FakeFilesystem(path_separator='/') + self.pathlib = fake_pathlib.FakePathlibModule(self.filesystem) + self.os = fake_filesystem.FakeOsModule(self.filesystem) + + def test_create_dir_with_pathlib_path(self): + dir_path_string = 'foo/bar/baz' + dir_path = self.pathlib.Path(dir_path_string) + self.filesystem.create_dir(dir_path) + self.assertTrue(self.os.path.exists(dir_path_string)) + self.assertEqual(stat.S_IFDIR, + self.os.stat(dir_path_string).st_mode & stat.S_IFDIR) + + def test_create_file_with_pathlib_path(self): + file_path_string = 'foo/bar/baz' + file_path = self.pathlib.Path(file_path_string) + self.filesystem.create_file(file_path) + self.assertTrue(self.os.path.exists(file_path_string)) + self.assertEqual(stat.S_IFREG, + self.os.stat(file_path_string).st_mode & stat.S_IFREG) + + def test_create_symlink_with_pathlib_path(self): + file_path = self.pathlib.Path('foo/bar/baz') + link_path_string = 'foo/link' + link_path = self.pathlib.Path(link_path_string) + self.filesystem.create_symlink(link_path, file_path) + self.assertTrue(self.os.path.lexists(link_path_string)) + self.assertEqual(stat.S_IFLNK, + self.os.lstat(link_path_string).st_mode & + stat.S_IFLNK) + + def test_add_existing_real_file_with_pathlib_path(self): + real_file_path_string = os.path.abspath(__file__) + real_file_path = self.pathlib.Path(real_file_path_string) + self.filesystem.add_real_file(real_file_path) + fake_filepath_string = real_file_path_string.replace( + os.sep, self.os.sep) + self.assertTrue(self.os.path.exists(fake_filepath_string)) + self.assertEqual(stat.S_IFREG, self.os.stat( + fake_filepath_string).st_mode & stat.S_IFREG) + + def test_add_existing_real_directory_with_pathlib_path(self): + real_dirpath_string = os.path.dirname(os.path.abspath(__file__)) + real_dir_path = self.pathlib.Path(real_dirpath_string) + self.filesystem.add_real_directory(real_dir_path) + fake_dirpath_string = real_dirpath_string.replace( + os.sep, self.os.sep) + self.assertTrue(self.os.path.exists(fake_dirpath_string)) + self.assertEqual(stat.S_IFDIR, self.os.stat( + fake_dirpath_string).st_mode & stat.S_IFDIR) + + if __name__ == '__main__': unittest.main()