Skip to content

Commit b23680e

Browse files
committed
Avoid reloading glob in Python 3.13
- patch glob instead - avoids performance hit on tests
1 parent 20a0c34 commit b23680e

File tree

4 files changed

+13
-16
lines changed

4 files changed

+13
-16
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ The released versions correspond to PyPI releases.
1818
* the `additional_skip_names` parameter now works with more modules (see [#1023](../../issues/1023))
1919
* added support for `os.fchmod`, allow file descriptor argument for `os.chmod` only for POSIX
2020
for Python < 3.13
21+
* avoid reloading `glob` in Python 3.13 (did affect test performance)
2122

2223
### Fixes
2324
* removing files while iterating over `scandir` results is now possible (see [#1051](../../issues/1051))
2425
* fake `pathlib.PosixPath` and `pathlib.WindowsPath` now behave more like in the real filesystem
25-
(see [#1055](../../issues/1055))
26+
(see [#1053](../../issues/1053))
2627

2728
## [Version 5.6.0](https://pypi.python.org/pypi/pyfakefs/5.6.0) (2024-07-12)
2829
Adds preliminary Python 3.13 support.

pyfakefs/fake_filesystem_unittest.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -593,9 +593,6 @@ def __init__(
593593
self.modules_to_reload: List[ModuleType] = (
594594
[] if sys.platform == "win32" else [tempfile]
595595
)
596-
if sys.version_info >= (3, 13):
597-
# need to reload glob which holds references to os functions
598-
self.modules_to_reload.append(glob)
599596
if modules_to_reload is not None:
600597
self.modules_to_reload.extend(modules_to_reload)
601598
self.patch_default_args = patch_default_args
@@ -983,6 +980,7 @@ def start_patching(self) -> None:
983980
self.patch_modules()
984981
self.patch_functions()
985982
self.patch_defaults()
983+
self._set_glob_os_functions()
986984

987985
self._dyn_patcher = DynamicPatcher(self)
988986
sys.meta_path.insert(0, self._dyn_patcher)
@@ -993,6 +991,13 @@ def start_patching(self) -> None:
993991
self._dyn_patcher.cleanup()
994992
sys.meta_path.pop(0)
995993

994+
def _set_glob_os_functions(self):
995+
# make sure the os functions cached in glob are patched
996+
if sys.version_info >= (3, 13):
997+
globber = glob._StringGlobber # type: ignore[module-attr]
998+
globber.lstat = staticmethod(os.lstat)
999+
globber.scandir = staticmethod(os.scandir)
1000+
9961001
def patch_functions(self) -> None:
9971002
assert self._stubs is not None
9981003
for (name, ft_name, ft_mod), modules in self.FS_FUNCTIONS.items():
@@ -1073,6 +1078,7 @@ def stop_patching(self, temporary=False) -> None:
10731078
if self.linecache_updatecache is not None:
10741079
linecache.updatecache = self.linecache_updatecache
10751080
linecache.checkcache = self.linecache_checkcache
1081+
self._set_glob_os_functions()
10761082

10771083
@property
10781084
def is_patching(self):

pyfakefs/fake_pathlib.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import errno
3333
import fnmatch
3434
import functools
35-
import glob
3635
import inspect
3736
import ntpath
3837
import os
@@ -640,15 +639,6 @@ def _init(self, template=None):
640639
# only needed until Python 3.8
641640
self._closed = False
642641

643-
if sys.version_info >= (3, 13):
644-
645-
def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
646-
# make sure we get the patched version of the globber
647-
self._globber = glob._StringGlobber # type: ignore[module-attr]
648-
return super()._glob_selector( # type: ignore[attribute-error]
649-
parts, case_sensitive, recurse_symlinks
650-
)
651-
652642
def _path(self):
653643
"""Returns the underlying path string as used by the fake
654644
filesystem.

pyfakefs/tests/fake_pathlib_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,11 +822,11 @@ def test_glob(self):
822822
self.create_file(self.make_path("foo", "setup.pyc"))
823823
path = self.path(self.make_path("foo"))
824824
self.assertEqual(
825-
sorted(path.glob("*.py")),
826825
[
827826
self.path(self.make_path("foo", "all_tests.py")),
828827
self.path(self.make_path("foo", "setup.py")),
829828
],
829+
sorted(path.glob("*.py")),
830830
)
831831

832832
@unittest.skipIf(not is_windows, "Windows specific test")
@@ -837,12 +837,12 @@ def test_glob_case_windows(self):
837837
self.create_file(self.make_path("foo", "example.Py"))
838838
path = self.path(self.make_path("foo"))
839839
self.assertEqual(
840-
sorted(path.glob("*.py")),
841840
[
842841
self.path(self.make_path("foo", "all_tests.PY")),
843842
self.path(self.make_path("foo", "example.Py")),
844843
self.path(self.make_path("foo", "setup.py")),
845844
],
845+
sorted(path.glob("*.py")),
846846
)
847847

848848
@unittest.skipIf(is_windows, "Posix specific test")

0 commit comments

Comments
 (0)