Skip to content

Commit

Permalink
More performance improvements
Browse files Browse the repository at this point in the history
- do not import pytest if not needed - moved SKIPMODULE setting
  back to pytest plugin
- move warning supression out of loop
- slight improvement of temp path creation performance
  • Loading branch information
mrbean-bremen committed Nov 18, 2020
1 parent 802aef8 commit 9e6317b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 41 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ The released versions correspond to PyPi releases.

## Version 4.3.0 (as yet unreleased)


### Changes
* The `patchfs` decorator now expects a positional argument instead of the
keyword arguments `fs`. This avoids confusion with the pytest `fs`
Expand All @@ -14,6 +13,7 @@ The released versions correspond to PyPi releases.
default to avoid a large performance impact. An additional parameter
`patch_default_args` has been added that switches this behavior on
(see [#567](../../issues/567)).
* Some setup performance improvements have been added

## [Version 4.2.1](https://pypi.python.org/pypi/pyfakefs/4.2.1) (2020-11-02)

Expand Down
27 changes: 20 additions & 7 deletions pyfakefs/fake_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,17 @@ def _starts_with_sep(self, path):
return (path.startswith(sep) or altsep is not None and
path.startswith(altsep))

def _add_c_drive(self):
"""Optimized version for the default Windows C drive.
For internal use only.
"""
if self.is_windows_fs:
self.last_dev += 1
self.mount_points['C:'] = {
'idev': self.last_dev, 'total_size': None, 'used_size': 0
}
self.root.get_entry('C:') .st_dev = self.last_dev

def add_mount_point(self, path, total_size=None):
"""Add a new mount point for a filesystem device.
The mount point gets a new unique device number.
Expand Down Expand Up @@ -2306,14 +2317,15 @@ def make_string_path(self, path):
fake_sep = matching_string(path, self.path_separator)
return path.replace(os_sep, fake_sep)

def create_dir(self, directory_path, perm_bits=PERM_DEF):
def create_dir(self, directory_path, perm_bits=PERM_DEF, check=True):
"""Create `directory_path`, and all the parent directories.
Helper method to set up your test faster.
Args:
directory_path: The full directory path to create.
perm_bits: The permission bits as set by `chmod`.
check: For internal use only.
Returns:
The newly created FakeDirectory object.
Expand All @@ -2322,10 +2334,11 @@ def create_dir(self, directory_path, perm_bits=PERM_DEF):
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):
self.raise_os_error(errno.EEXIST, directory_path)
if check:
directory_path = self.absnormpath(directory_path)
self._auto_mount_drive_if_needed(directory_path)
if self.exists(directory_path, check_link=True):
self.raise_os_error(errno.EEXIST, directory_path)
path_components = self._path_components(directory_path)
current_dir = self.root

Expand All @@ -2338,10 +2351,10 @@ def create_dir(self, directory_path, perm_bits=PERM_DEF):
current_dir.add_entry(new_dir)
current_dir = new_dir
else:
if S_ISLNK(directory.st_mode):
if check and S_ISLNK(directory.st_mode):
directory = self.resolve(directory.contents)
current_dir = directory
if directory.st_mode & S_IFDIR != S_IFDIR:
if check and directory.st_mode & S_IFDIR != S_IFDIR:
self.raise_os_error(errno.ENOTDIR, current_dir.path)

# set the permission after creating the directories
Expand Down
59 changes: 26 additions & 33 deletions pyfakefs/fake_filesystem_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,6 @@ class Patcher:
None, fake_filesystem, fake_filesystem_shutil,
sys, linecache, tokenize
}
try:
import py
import pytest
SKIPMODULES.add(py)
SKIPMODULES.add(pytest)
except ImportError:
pass

assert None in SKIPMODULES, ("sys.modules contains 'None' values;"
" must skip them.")
Expand Down Expand Up @@ -606,7 +599,6 @@ def _find_modules(self):
Later, `setUp()` will stub these with the fake file system
modules.
"""

module_names = list(self._fake_module_classes.keys()) + [PATH_MODULE]
for name, module in list(sys.modules.items()):
try:
Expand All @@ -622,33 +614,27 @@ def _find_modules(self):
for sn in self._skip_names]))
module_items = module.__dict__.copy().items()

with warnings.catch_warnings():
# ignore deprecation warnings, see #542
warnings.filterwarnings(
'ignore',
category=DeprecationWarning
)
modules = {name: mod for name, mod in module_items
if self._is_fs_module(mod, name, module_names)}

if skipped:
for name, mod in modules.items():
self._skipped_modules.setdefault(name, set()).add(
(module, mod.__name__))
continue
modules = {name: mod for name, mod in module_items
if self._is_fs_module(mod, name, module_names)}

if skipped:
for name, mod in modules.items():
self._modules.setdefault(name, set()).add(
self._skipped_modules.setdefault(name, set()).add(
(module, mod.__name__))
functions = {name: fct for name, fct in
module_items
if self._is_fs_function(fct)}
continue

for name, mod in modules.items():
self._modules.setdefault(name, set()).add(
(module, mod.__name__))
functions = {name: fct for name, fct in
module_items
if self._is_fs_function(fct)}

# find default arguments that are file system functions
if self.patch_default_args:
for _, fct in module_items:
for f, i, d in self._def_values(fct):
self._def_functions.append((f, i, d))
# find default arguments that are file system functions
if self.patch_default_args:
for _, fct in module_items:
for f, i, d in self._def_values(fct):
self._def_functions.append((f, i, d))

for name, fct in functions.items():
self._fct_modules.setdefault(
Expand Down Expand Up @@ -684,7 +670,13 @@ def setUp(self, doctester=None):
shutil._HAS_FCOPYFILE = False

temp_dir = tempfile.gettempdir()
self._find_modules()
with warnings.catch_warnings():
# ignore deprecation warnings, see #542
warnings.filterwarnings(
'ignore',
category=DeprecationWarning
)
self._find_modules()
self._refresh()

if doctester is not None:
Expand All @@ -696,7 +688,8 @@ def setUp(self, doctester=None):

# the temp directory is assumed to exist at least in `tempfile1`,
# so we create it here for convenience
self.fs.create_dir(temp_dir)
self.fs.create_dir(temp_dir, check=False)
self.fs._add_c_drive()

def start_patching(self):
if not self._patching:
Expand Down
4 changes: 4 additions & 0 deletions pyfakefs/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ def my_fakefs_test(fs):
assert os.path.exists('/var/data/xx1.txt')
"""

import py
import pytest

from pyfakefs.fake_filesystem_unittest import Patcher

Patcher.SKIPMODULES.add(py)
Patcher.SKIPMODULES.add(pytest)


@pytest.fixture
def fs(request):
Expand Down

0 comments on commit 9e6317b

Please sign in to comment.