Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for path-like objects in Python 3.6 #3

Closed
wants to merge 10 commits into from
410 changes: 410 additions & 0 deletions .pylintrc

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ python:
- "3.3"
- "3.4"
- "3.5"
- "3.6-dev"

install:
- if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]]; then pip install importlib unittest2; fi
Expand Down
70 changes: 70 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Release Notes
The release versions are PyPi releases.

## Unreleased

#### New Features
* support for `pathlib` (Python >= 3.4)
* support for `os.replace` (Python >= 3.3)
* `os.access`, `os.chmod`, `os.chown`, `os.stat`, `os.utime`:
support for `follow_symlinks` argument (Python >= 3.3)
* support for `os.scandir` (Python >= 3.5)
* option to not fake modules named `path`
* `glob.glob`, `glob.iglob`: support for `recursive` argument (Python >= 3.5)
* support for `glob.iglob`

## Version 2.9

#### New Features
* `io.open`, `os.open`: support for `encoding` argument
* `os.makedirs`: support for `exist_ok` argument (Python >= 3.2)
* support for fake `io.open()`
* support for mount points
* support for hard links
* support for float times (mtime, ctime)
* Windows support:
* support for alternative path separator (Windows)
* support for case-insensitive filesystems
* support for drive letters and UNC paths
* support for filesystem size
* `shutil.rmtree`: support for `ignore_errors` and `onerror` arguments
* support for `os.fsync()` and `os.fdatasync()`
* `os.walk`: Support for `followlinks` argument

#### Fixes
* `shutil` functions like `make_archive` do not work with pyfakefs (#104)
* file permissions on deletion not correctly handled (#27)
* `shutil.copy` error with bytes contents (#105)
* mtime and ctime not updated on content changes
* Reading from fake block devices doesn't work (#24)

## Version 2.7

#### Infrastructure
* moved repository from GoogleCode to GitHub, merging 3 projects
* added continous integration testing with Travis CI
* added usage documentation in project wiki
* better support for pypi releases

#### New Features
* added direct unit test support in `fake_filesystem_unittest`
(transparently patches all calls to faked implementations)
* added support for doctests
* added support for cygwin
* better support for Python 3

#### Fixes
* `chown` incorrectly accepts non-integer uid/gid arguments
* incorrect behavior of `relpath`, `abspath` and `normpath` on Windows.
* Python 3 `open` in binary mode not working (#32)
* `mkstemp` returns no valid file descriptor (#19)
* `open` methods lack `IOError` for prohibited operations (#18)
* incorrectly resolved relative path (#3)
* `FakeFileOpen` keyword args do not match the `__builtin__` equivalents (#5)
* relative paths not supported (#16, #17)

## Older Versions
As there have been three different projects that have been merged together
for release 2.7, no older release notes are given.
The following versions are still avaliable in PyPi:
* 1.1, 1.2, 2.0, 2.1, 2.2, 2.3 and 2.4
10 changes: 8 additions & 2 deletions all_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""A test suite that runs all tests for pyfakefs at once."""

import unittest
import sys

import fake_filesystem_glob_test
import fake_filesystem_shutil_test
Expand All @@ -26,6 +27,9 @@
import fake_filesystem_unittest_test
import example_test

if sys.version_info >= (3, 4):
import fake_pathlib_test


class AllTests(unittest.TestSuite):
"""A test suite that runs all tests for pyfakefs at once."""
Expand All @@ -41,11 +45,13 @@ def suite(self): # pylint: disable-msg=C6409
loader.loadTestsFromModule(fake_filesystem_unittest_test),
loader.loadTestsFromModule(example_test),
])
if sys.version_info >= (3, 4):
self.addTests([
loader.loadTestsFromModule(fake_pathlib_test)
])
return self


if __name__ == '__main__':
import sys

result = unittest.TextTestRunner(verbosity=2).run(AllTests().suite())
sys.exit(int(not result.wasSuccessful()))
153 changes: 153 additions & 0 deletions fake_filesystem_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,21 @@ def testStat(self):
self.assertTrue(stat.S_IFREG & self.os.stat(file_path).st_mode)
self.assertEqual(5, self.os.stat(file_path)[stat.ST_SIZE])

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testStatNoFollowSymlinks(self):
"""Test that stat with follow_symlinks=False behaves like lstat."""
directory = 'xyzzy'
base_name = 'plugh'
file_contents = 'frobozz'
# Just make sure we didn't accidentally make our test data meaningless.
self.assertNotEqual(len(base_name), len(file_contents))
file_path = '%s/%s' % (directory, base_name)
link_path = '%s/link' % directory
self.filesystem.CreateFile(file_path, contents=file_contents)
self.filesystem.CreateLink(link_path, base_name)
self.assertEqual(len(file_contents), self.os.stat(file_path, follow_symlinks=False)[stat.ST_SIZE])
self.assertEqual(len(base_name), self.os.stat(link_path, follow_symlinks=False)[stat.ST_SIZE])

@unittest.skipIf(TestCase.is_windows and sys.version_info < (3, 3),
'Links are not supported under Windows before Python 3.3')
def testLstat(self):
Expand Down Expand Up @@ -1083,6 +1098,23 @@ def testRenameToExistentFile(self):
self.assertEqual('test contents 1',
self.filesystem.GetObject(new_file_path).contents)

@unittest.skipIf(sys.version_info < (3, 3), 'replace is new in Python 3.3')
def testReplaceToExistentFile(self):
"""Replaces an existing file (does not work with `rename()` under Windows).
"""
directory = 'xyzzy'
old_file_path = '%s/plugh_old' % directory
new_file_path = '%s/plugh_new' % directory
self.filesystem.CreateFile(old_file_path, contents='test contents 1')
self.filesystem.CreateFile(new_file_path, contents='test contents 2')
self.assertTrue(self.filesystem.Exists(old_file_path))
self.assertTrue(self.filesystem.Exists(new_file_path))
self.os.replace(old_file_path, new_file_path)
self.assertFalse(self.filesystem.Exists(old_file_path))
self.assertTrue(self.filesystem.Exists(new_file_path))
self.assertEqual('test contents 1',
self.filesystem.GetObject(new_file_path).contents)

def testRenameToNonexistentDir(self):
"""Can rename a file to a name in a nonexistent dir."""
directory = 'xyzzy'
Expand Down Expand Up @@ -1488,6 +1520,30 @@ def testAccess400(self):
self.assertFalse(self.os.access(path, self.rwx))
self.assertFalse(self.os.access(path, self.rw))

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testAccessSymlink(self):
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)
self.os.chmod(link_path, 0o400)

# test file
self.assertTrue(self.os.access(link_path, self.os.F_OK))
self.assertTrue(self.os.access(link_path, self.os.R_OK))
self.assertFalse(self.os.access(link_path, self.os.W_OK))
self.assertFalse(self.os.access(link_path, self.os.X_OK))
self.assertFalse(self.os.access(link_path, self.rwx))
self.assertFalse(self.os.access(link_path, self.rw))

# test link itself
self.assertTrue(self.os.access(link_path, self.os.F_OK, follow_symlinks=False))
self.assertTrue(self.os.access(link_path, self.os.R_OK, follow_symlinks=False))
self.assertTrue(self.os.access(link_path, self.os.W_OK, follow_symlinks=False))
self.assertTrue(self.os.access(link_path, self.os.X_OK, follow_symlinks=False))
self.assertTrue(self.os.access(link_path, self.rwx, follow_symlinks=False))
self.assertTrue(self.os.access(link_path, self.rw, follow_symlinks=False))

def testAccessNonExistentFile(self):
# set up
path = '/non/existent/file'
Expand All @@ -1511,6 +1567,46 @@ def testChmod(self):
self.assertTrue(st.st_mode & stat.S_IFREG)
self.assertFalse(st.st_mode & stat.S_IFDIR)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testChmodFollowSymlink(self):
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)
self.os.chmod(link_path, 0o6543)

st = self.os.stat(link_path)
self.assertModeEqual(0o6543, st.st_mode)
st = self.os.stat(link_path, follow_symlinks=False)
self.assertModeEqual(0o777, st.st_mode)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testChmodNoFollowSymlink(self):
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)
self.os.chmod(link_path, 0o6543, follow_symlinks=False)

st = self.os.stat(link_path)
self.assertModeEqual(0o666, st.st_mode)
st = self.os.stat(link_path, follow_symlinks=False)
self.assertModeEqual(0o6543, st.st_mode)

@unittest.skipIf(TestCase.is_windows, 'lchmod not supported in Windows')
def testLchmod(self):
"""lchmod shall behave like chmod with follow_symlinks=True since Python 3.3"""
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)
self.os.lchmod(link_path, 0o6543)

st = self.os.stat(link_path)
self.assertModeEqual(0o666, st.st_mode)
st = self.os.lstat(link_path)
self.assertModeEqual(0o6543, st.st_mode)

def testChmodDir(self):
# set up
path = '/some_dir'
Expand Down Expand Up @@ -1642,6 +1738,33 @@ def testUtimeDir(self):
self.assertEqual(1.0, st.st_atime)
self.assertEqual(2.0, st.st_mtime)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testUtimeFollowSymlinks(self):
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)

self.os.utime(link_path, (1, 2))
st = self.os.stat(link_path)
self.assertEqual(1, st.st_atime)
self.assertEqual(2, st.st_mtime)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testUtimeNoFollowSymlinks(self):
path = '/some_file'
self._CreateTestFile(path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, path)

self.os.utime(link_path, (1, 2), follow_symlinks=False)
st = self.os.stat(link_path)
self.assertNotEqual(1, st.st_atime)
self.assertNotEqual(2, st.st_mtime)
st = self.os.stat(link_path, follow_symlinks=False)
self.assertEqual(1, st.st_atime)
self.assertEqual(2, st.st_mtime)

def testUtimeNonExistent(self):
# set up
path = '/non/existent/file'
Expand Down Expand Up @@ -1693,6 +1816,36 @@ def testChownExistingFile(self):
self.assertEqual(st[stat.ST_UID], 200)
self.assertEqual(st[stat.ST_GID], 201)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testChownFollowSymlink(self):
file_path = 'some_file'
self.filesystem.CreateFile(file_path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, file_path)

self.os.chown(link_path, 100, 101)
st = self.os.stat(link_path)
self.assertEqual(st[stat.ST_UID], 100)
self.assertEqual(st[stat.ST_GID], 101)
st = self.os.stat(link_path, follow_symlinks=False)
self.assertNotEqual(st[stat.ST_UID], 100)
self.assertNotEqual(st[stat.ST_GID], 101)

@unittest.skipIf(sys.version_info < (3, 3), 'follow_symlinks new in Python 3.3')
def testChownNoFollowSymlink(self):
file_path = 'some_file'
self.filesystem.CreateFile(file_path)
link_path = '/link_to_some_file'
self.filesystem.CreateLink(link_path, file_path)

self.os.chown(link_path, 100, 101, follow_symlinks=False)
st = self.os.stat(link_path)
self.assertNotEqual(st[stat.ST_UID], 100)
self.assertNotEqual(st[stat.ST_GID], 101)
st = self.os.stat(link_path, follow_symlinks=False)
self.assertEqual(st[stat.ST_UID], 100)
self.assertEqual(st[stat.ST_GID], 101)

def testChownBadArguments(self):
"""os.chown() with bad args (Issue #30)"""
file_path = 'some_file'
Expand Down
13 changes: 13 additions & 0 deletions fake_filesystem_unittest_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import tempfile
import sys

if sys.version_info >= (3, 4):
import pathlib

if sys.version_info < (2, 7):
import unittest2 as unittest
else:
Expand Down Expand Up @@ -127,6 +130,16 @@ def test_tempdirectory(self):
with open('%s/fake_file.txt' % td, 'w') as f:
self.assertTrue(self.fs.Exists(td))

@unittest.skipIf(sys.version_info < (3, 4), "pathlib new in Python 3.4")
def test_fakepathlib(self):
with pathlib.Path('/fake_file.txt') as p:
with p.open('w') as f:
f.write('text')
is_windows = sys.platform.startswith('win')
if is_windows:
self.assertTrue(self.fs.Exists(r'\fake_file.txt'))
else:
self.assertTrue(self.fs.Exists('/fake_file.txt'))

import math as path

Expand Down
Loading