Skip to content

Commit d8439c8

Browse files
committed
Added additional possibility to configure Patcher
- added argument that allows adding modules for patching that import file system modules under another name - fixes #231
1 parent b04087a commit d8439c8

File tree

4 files changed

+98
-28
lines changed

4 files changed

+98
-28
lines changed

CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The release versions are PyPi releases.
44
## Version 3.3 (as yet unreleased)
55

66
#### New Features
7+
* Added possibility to patch modules that import file system modules under another name,
8+
e.g. `import os as '_os` ([#231](../../issues/231)).
79
* Added support for `dir_fd` argument in several `os` functions ([#206](../../issues/206)).
810
* Added support for open file descriptor as path argument
911
in `os.utime`, `os.chmod`, `os.chdir`, `os.chown`, `os.listdir`, `os.stat` and `os.lstat`

fake_filesystem_unittest_test.py

+20
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import tempfile
2727
import sys
2828

29+
from import_as_example import check_if_exists
30+
2931
if sys.version_info >= (3, 4):
3032
import pathlib
3133

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

141143

144+
class TestImportAsOtherName(fake_filesystem_unittest.TestCase):
145+
def __init__(self, methodName='RunTest'):
146+
special_names = {'import_as_example': {'os': '_os'}}
147+
super(TestImportAsOtherName, self).__init__(methodName,
148+
special_names=special_names)
149+
150+
def setUp(self):
151+
self.setUpPyfakefs()
152+
153+
def testFileExists(self):
154+
file_path = '/foo/bar/baz'
155+
self.fs.CreateFile(file_path)
156+
self.assertTrue(self.fs.Exists(file_path))
157+
self.assertTrue(check_if_exists(file_path))
158+
159+
142160
sys.path.append(os.path.join(os.path.dirname(__file__), 'fixtures'))
143161
import module_with_attributes
144162

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

162180

163181
import math as path
182+
183+
164184
class TestPatchPathUnittestFailing(TestPyfakefsUnittestBase):
165185
"""Tests the default behavior regarding the argument patch_path:
166186
An own path module (in this case an alias to math) cannot be imported,

import_as_example.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
"""
14+
Example module that is used for testing modules that import file system modules
15+
to be patched under another name.
16+
"""
17+
import os as _os
18+
19+
20+
def check_if_exists(filepath):
21+
return _os.path.exists(filepath)

pyfakefs/fake_filesystem_unittest.py

+55-28
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363

6464

6565
def load_doctests(loader, tests, ignore, module,
66-
additional_skip_names=None, patch_path=True): # pylint: disable=unused-argument
66+
additional_skip_names=None,
67+
patch_path=True, special_names=None): # pylint: disable=unused-argument
6768
"""Load the doctest tests for the specified module into unittest.
6869
Args:
6970
loader, tests, ignore : arguments passed in from `load_tests()`
@@ -74,7 +75,7 @@ def load_doctests(loader, tests, ignore, module,
7475
File `example_test.py` in the pyfakefs release provides a usage example.
7576
"""
7677
_patcher = Patcher(additional_skip_names=additional_skip_names,
77-
patch_path=patch_path)
78+
patch_path=patch_path, special_names=special_names)
7879
globs = _patcher.replaceGlobs(vars(module))
7980
tests.addTests(doctest.DocTestSuite(module,
8081
globs=globs,
@@ -88,7 +89,8 @@ class TestCase(unittest.TestCase):
8889
modules by fake implementations.
8990
"""
9091

91-
def __init__(self, methodName='runTest', additional_skip_names=None, patch_path=True):
92+
def __init__(self, methodName='runTest', additional_skip_names=None,
93+
patch_path=True, special_names=None):
9294
"""Creates the test class instance and the stubber used to stub out
9395
file system related modules.
9496
@@ -103,21 +105,34 @@ def __init__(self, methodName='runTest', additional_skip_names=None, patch_path=
103105
from my_module import path
104106
Irrespective of patch_path, module 'os.path' is still correctly faked
105107
if imported the usual way using `import os` or `import os.path`.
108+
special_names: A dictionary with module names as key and a dictionary as
109+
value, where the key is the original name of the module to be patched,
110+
and the value is the name as it is imported.
111+
This allows to patch modules where some of the file system modules are
112+
imported as another name (e.g. `import os as _os`).
106113
107114
If you specify arguments `additional_skip_names` or `patch_path` here
108115
and you have DocTests, consider also specifying the same arguments to
109116
:py:func:`load_doctests`.
110117
111-
Example usage in a derived test class::
118+
Example usage in derived test classes::
112119
113-
class MyTestCase(fake_filesystem_unittest.TestCase):
114-
def __init__(self, methodName='runTest'):
115-
super(MyTestCase, self).__init__(
116-
methodName=methodName, additional_skip_names=['posixpath'])
120+
class MyTestCase(fake_filesystem_unittest.TestCase):
121+
def __init__(self, methodName='runTest'):
122+
super(MyTestCase, self).__init__(
123+
methodName=methodName, additional_skip_names=['posixpath'])
124+
125+
126+
class AnotherTestCase(fake_filesystem_unittest.TestCase):
127+
def __init__(self, methodName='runTest'):
128+
# allow patching a module that imports `os` as `my_os`
129+
special_names = {'amodule': {'os': 'my_os'}}
130+
super(MyTestCase, self).__init__(
131+
methodName=methodName, special_names=special_names)
117132
"""
118133
super(TestCase, self).__init__(methodName)
119134
self._stubber = Patcher(additional_skip_names=additional_skip_names,
120-
patch_path=patch_path)
135+
patch_path=patch_path, special_names=special_names)
121136

122137
@property
123138
def fs(self):
@@ -210,10 +225,11 @@ class Patcher(object):
210225
if HAS_PATHLIB:
211226
SKIPNAMES.add('pathlib')
212227

213-
def __init__(self, additional_skip_names=None, patch_path=True):
228+
def __init__(self, additional_skip_names=None, patch_path=True, special_names=None):
214229
"""For a description of the arguments, see TestCase.__init__"""
215230

216231
self._skipNames = self.SKIPNAMES.copy()
232+
self._special_names = special_names or {}
217233
if additional_skip_names is not None:
218234
self._skipNames.update(additional_skip_names)
219235
self._patchPath = patch_path
@@ -282,17 +298,28 @@ def _findModules(self):
282298
# and a test in fake_filesystem_unittest_test.py, class
283299
# TestAttributesWithFakeModuleNames.
284300
if inspect.ismodule(module.__dict__.get('os')):
285-
self._os_modules.add(module)
301+
self._os_modules.add((module, 'os'))
286302
if self._patchPath and inspect.ismodule(module.__dict__.get('path')):
287-
self._path_modules.add(module)
303+
self._path_modules.add((module, 'path'))
288304
if self.HAS_PATHLIB and inspect.ismodule(module.__dict__.get('pathlib')):
289-
self._pathlib_modules.add(module)
305+
self._pathlib_modules.add((module, 'pathlib'))
290306
if inspect.ismodule(module.__dict__.get('shutil')):
291-
self._shutil_modules.add(module)
307+
self._shutil_modules.add((module, 'shutil'))
292308
if inspect.ismodule(module.__dict__.get('tempfile')):
293-
self._tempfile_modules.add(module)
309+
self._tempfile_modules.add((module, 'tempfile'))
294310
if inspect.ismodule(module.__dict__.get('io')):
295-
self._io_modules.add(module)
311+
self._io_modules.add((module, 'io'))
312+
print(module, type(module))
313+
if '__name__' in module.__dict__ and module.__name__ in self._special_names:
314+
module_names = self._special_names[module.__name__]
315+
if 'os' in module_names:
316+
self._os_modules.add((module, module_names['os']))
317+
if self._patchPath and 'path' in module_names:
318+
self._path_modules.add((module, module_names['path']))
319+
if self.HAS_PATHLIB and 'pathlib' in module_names:
320+
self._pathlib_modules.add((module, module_names['pathlib']))
321+
if 'io' in module_names:
322+
self._io_modules.add((module, module_names['io']))
296323

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

329-
for module in self._os_modules:
330-
self._stubs.SmartSet(module, 'os', self.fake_os)
331-
for module in self._path_modules:
332-
self._stubs.SmartSet(module, 'path', self.fake_path)
356+
for module, attr in self._os_modules:
357+
self._stubs.SmartSet(module, attr, self.fake_os)
358+
for module, attr in self._path_modules:
359+
self._stubs.SmartSet(module, attr, self.fake_path)
333360
if self.HAS_PATHLIB:
334-
for module in self._pathlib_modules:
335-
self._stubs.SmartSet(module, 'pathlib', self.fake_pathlib)
336-
for module in self._shutil_modules:
337-
self._stubs.SmartSet(module, 'shutil', self.fake_shutil)
338-
for module in self._tempfile_modules:
339-
self._stubs.SmartSet(module, 'tempfile', self.fake_tempfile_)
340-
for module in self._io_modules:
341-
self._stubs.SmartSet(module, 'io', self.fake_io)
361+
for module, attr in self._pathlib_modules:
362+
self._stubs.SmartSet(module, attr, self.fake_pathlib)
363+
for module, attr in self._shutil_modules:
364+
self._stubs.SmartSet(module, attr, self.fake_shutil)
365+
for module, attr in self._tempfile_modules:
366+
self._stubs.SmartSet(module, attr, self.fake_tempfile_)
367+
for module, attr in self._io_modules:
368+
self._stubs.SmartSet(module, attr, self.fake_io)
342369

343370
def replaceGlobs(self, globs_):
344371
globs = globs_.copy()

0 commit comments

Comments
 (0)