Skip to content

Commit

Permalink
Added additional possibility to configure Patcher
Browse files Browse the repository at this point in the history
- added argument that allows adding modules for patching that import file system modules under another name
- fixes #231
  • Loading branch information
mrbean-bremen committed Jun 25, 2017
1 parent b04087a commit d8439c8
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 28 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The release versions are PyPi releases.
## Version 3.3 (as yet unreleased)

#### New Features
* Added possibility to patch modules that import file system modules under another name,
e.g. `import os as '_os` ([#231](../../issues/231)).
* Added support for `dir_fd` argument in several `os` functions ([#206](../../issues/206)).
* Added support for open file descriptor as path argument
in `os.utime`, `os.chmod`, `os.chdir`, `os.chown`, `os.listdir`, `os.stat` and `os.lstat`
Expand Down
20 changes: 20 additions & 0 deletions fake_filesystem_unittest_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import tempfile
import sys

from import_as_example import check_if_exists

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

Expand Down Expand Up @@ -139,6 +141,22 @@ def test_fakepathlib(self):
self.assertTrue(self.fs.Exists('/fake_file.txt'))


class TestImportAsOtherName(fake_filesystem_unittest.TestCase):
def __init__(self, methodName='RunTest'):
special_names = {'import_as_example': {'os': '_os'}}
super(TestImportAsOtherName, self).__init__(methodName,
special_names=special_names)

def setUp(self):
self.setUpPyfakefs()

def testFileExists(self):
file_path = '/foo/bar/baz'
self.fs.CreateFile(file_path)
self.assertTrue(self.fs.Exists(file_path))
self.assertTrue(check_if_exists(file_path))


sys.path.append(os.path.join(os.path.dirname(__file__), 'fixtures'))
import module_with_attributes

Expand All @@ -161,6 +179,8 @@ def testAttributes(self):


import math as path


class TestPatchPathUnittestFailing(TestPyfakefsUnittestBase):
"""Tests the default behavior regarding the argument patch_path:
An own path module (in this case an alias to math) cannot be imported,
Expand Down
21 changes: 21 additions & 0 deletions import_as_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Example module that is used for testing modules that import file system modules
to be patched under another name.
"""
import os as _os


def check_if_exists(filepath):
return _os.path.exists(filepath)
83 changes: 55 additions & 28 deletions pyfakefs/fake_filesystem_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@


def load_doctests(loader, tests, ignore, module,
additional_skip_names=None, patch_path=True): # pylint: disable=unused-argument
additional_skip_names=None,
patch_path=True, special_names=None): # pylint: disable=unused-argument
"""Load the doctest tests for the specified module into unittest.
Args:
loader, tests, ignore : arguments passed in from `load_tests()`
Expand All @@ -74,7 +75,7 @@ def load_doctests(loader, tests, ignore, module,
File `example_test.py` in the pyfakefs release provides a usage example.
"""
_patcher = Patcher(additional_skip_names=additional_skip_names,
patch_path=patch_path)
patch_path=patch_path, special_names=special_names)
globs = _patcher.replaceGlobs(vars(module))
tests.addTests(doctest.DocTestSuite(module,
globs=globs,
Expand All @@ -88,7 +89,8 @@ class TestCase(unittest.TestCase):
modules by fake implementations.
"""

def __init__(self, methodName='runTest', additional_skip_names=None, patch_path=True):
def __init__(self, methodName='runTest', additional_skip_names=None,
patch_path=True, special_names=None):
"""Creates the test class instance and the stubber used to stub out
file system related modules.
Expand All @@ -103,21 +105,34 @@ def __init__(self, methodName='runTest', additional_skip_names=None, patch_path=
from my_module import path
Irrespective of patch_path, module 'os.path' is still correctly faked
if imported the usual way using `import os` or `import os.path`.
special_names: A dictionary with module names as key and a dictionary as
value, where the key is the original name of the module to be patched,
and the value is the name as it is imported.
This allows to patch modules where some of the file system modules are
imported as another name (e.g. `import os as _os`).
If you specify arguments `additional_skip_names` or `patch_path` here
and you have DocTests, consider also specifying the same arguments to
:py:func:`load_doctests`.
Example usage in a derived test class::
Example usage in derived test classes::
class MyTestCase(fake_filesystem_unittest.TestCase):
def __init__(self, methodName='runTest'):
super(MyTestCase, self).__init__(
methodName=methodName, additional_skip_names=['posixpath'])
class MyTestCase(fake_filesystem_unittest.TestCase):
def __init__(self, methodName='runTest'):
super(MyTestCase, self).__init__(
methodName=methodName, additional_skip_names=['posixpath'])
class AnotherTestCase(fake_filesystem_unittest.TestCase):
def __init__(self, methodName='runTest'):
# allow patching a module that imports `os` as `my_os`
special_names = {'amodule': {'os': 'my_os'}}
super(MyTestCase, self).__init__(
methodName=methodName, special_names=special_names)
"""
super(TestCase, self).__init__(methodName)
self._stubber = Patcher(additional_skip_names=additional_skip_names,
patch_path=patch_path)
patch_path=patch_path, special_names=special_names)

@property
def fs(self):
Expand Down Expand Up @@ -210,10 +225,11 @@ class Patcher(object):
if HAS_PATHLIB:
SKIPNAMES.add('pathlib')

def __init__(self, additional_skip_names=None, patch_path=True):
def __init__(self, additional_skip_names=None, patch_path=True, special_names=None):
"""For a description of the arguments, see TestCase.__init__"""

self._skipNames = self.SKIPNAMES.copy()
self._special_names = special_names or {}
if additional_skip_names is not None:
self._skipNames.update(additional_skip_names)
self._patchPath = patch_path
Expand Down Expand Up @@ -282,17 +298,28 @@ def _findModules(self):
# and a test in fake_filesystem_unittest_test.py, class
# TestAttributesWithFakeModuleNames.
if inspect.ismodule(module.__dict__.get('os')):
self._os_modules.add(module)
self._os_modules.add((module, 'os'))
if self._patchPath and inspect.ismodule(module.__dict__.get('path')):
self._path_modules.add(module)
self._path_modules.add((module, 'path'))
if self.HAS_PATHLIB and inspect.ismodule(module.__dict__.get('pathlib')):
self._pathlib_modules.add(module)
self._pathlib_modules.add((module, 'pathlib'))
if inspect.ismodule(module.__dict__.get('shutil')):
self._shutil_modules.add(module)
self._shutil_modules.add((module, 'shutil'))
if inspect.ismodule(module.__dict__.get('tempfile')):
self._tempfile_modules.add(module)
self._tempfile_modules.add((module, 'tempfile'))
if inspect.ismodule(module.__dict__.get('io')):
self._io_modules.add(module)
self._io_modules.add((module, 'io'))
print(module, type(module))
if '__name__' in module.__dict__ and module.__name__ in self._special_names:
module_names = self._special_names[module.__name__]
if 'os' in module_names:
self._os_modules.add((module, module_names['os']))
if self._patchPath and 'path' in module_names:
self._path_modules.add((module, module_names['path']))
if self.HAS_PATHLIB and 'pathlib' in module_names:
self._pathlib_modules.add((module, module_names['pathlib']))
if 'io' in module_names:
self._io_modules.add((module, module_names['io']))

def _refresh(self):
"""Renew the fake file system and set the _isStale flag to `False`."""
Expand Down Expand Up @@ -326,19 +353,19 @@ def setUp(self, doctester=None):
self._stubs.SmartSet(builtins, 'file', self.fake_open)
self._stubs.SmartSet(builtins, 'open', self.fake_open)

for module in self._os_modules:
self._stubs.SmartSet(module, 'os', self.fake_os)
for module in self._path_modules:
self._stubs.SmartSet(module, 'path', self.fake_path)
for module, attr in self._os_modules:
self._stubs.SmartSet(module, attr, self.fake_os)
for module, attr in self._path_modules:
self._stubs.SmartSet(module, attr, self.fake_path)
if self.HAS_PATHLIB:
for module in self._pathlib_modules:
self._stubs.SmartSet(module, 'pathlib', self.fake_pathlib)
for module in self._shutil_modules:
self._stubs.SmartSet(module, 'shutil', self.fake_shutil)
for module in self._tempfile_modules:
self._stubs.SmartSet(module, 'tempfile', self.fake_tempfile_)
for module in self._io_modules:
self._stubs.SmartSet(module, 'io', self.fake_io)
for module, attr in self._pathlib_modules:
self._stubs.SmartSet(module, attr, self.fake_pathlib)
for module, attr in self._shutil_modules:
self._stubs.SmartSet(module, attr, self.fake_shutil)
for module, attr in self._tempfile_modules:
self._stubs.SmartSet(module, attr, self.fake_tempfile_)
for module, attr in self._io_modules:
self._stubs.SmartSet(module, attr, self.fake_io)

def replaceGlobs(self, globs_):
globs = globs_.copy()
Expand Down

0 comments on commit d8439c8

Please sign in to comment.