Skip to content

Commit 4623168

Browse files
committed
Clear fs cache on session finish
- avoids problems with cached modules during session shutdown - see #866
1 parent 841face commit 4623168

File tree

6 files changed

+58
-12
lines changed

6 files changed

+58
-12
lines changed

.github/workflows/testsuite.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ jobs:
112112
run: |
113113
pip install -r requirements.txt
114114
pip install -U pytest==${{ matrix.pytest-version }}
115+
pip install opentimelineio
115116
if [[ '${{ matrix.pytest-version }}' == '4.0.2' ]]; then
116117
pip install -U attrs==19.1.0
117118
fi

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ The released versions correspond to PyPI releases.
33

44
## Unreleased
55

6+
### Fixes
7+
* Clear the patched module cache on session shutdown (pytest only)
8+
(see [#866](../../issues/866)). Added a class method `Patcher.cler_fs_cache`
9+
for clearing the patched module cache.
610

711
## [Version 5.2.3](https://pypi.python.org/pypi/pyfakefs/5.2.3) (2023-07-10)
812
Adds compatibility with PyPy 3.10 and Python 3.12.

docs/usage.rst

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,7 @@ use_cache
625625
.........
626626
If True (the default), patched and non-patched modules are cached between tests
627627
to avoid the performance hit of the file system function lookup (the
628-
patching itself is reverted after each test). As this is a new
629-
feature, this argument allows to turn it off in case it causes any problems:
628+
patching itself is reverted after each test). This argument allows to turn it off in case it causes any problems:
630629

631630
.. code:: python
632631
@@ -635,9 +634,22 @@ feature, this argument allows to turn it off in case it causes any problems:
635634
fake_fs.create_file("foo", contents="test")
636635
...
637636
638-
Please write an issue if you encounter any problem that can be fixed by using
639-
this parameter. Note that this argument may be removed in a later version, if
640-
no problems come up.
637+
If using ``pytest``, the cache is always cleared before the final test shutdown, as there has been a problem
638+
happening on shutdown related to removing the cached modules.
639+
This does not happen for other test methods so far.
640+
641+
If you think you have encountered a similar problem with ``unittest``, you may try to clear the cache
642+
during module shutdown using the class method for clearing the cache:
643+
644+
.. code:: python
645+
646+
from pyfakefs.fake_filesystem_unittest import Patcher
647+
648+
649+
def tearDownModule():
650+
Patcher.clear_fs_cache()
651+
652+
Please write an issue if you encounter any problem that can be fixed by using this parameter.
641653

642654
If you want to clear the cache just for a specific test instead, you can call
643655
``clear_cache`` on the ``Patcher`` or the ``fake_filesystem`` instance:

pyfakefs/fake_filesystem_unittest.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -629,13 +629,19 @@ def __init__(
629629
self._dyn_patcher: Optional[DynamicPatcher] = None
630630
self._patching = False
631631

632-
def clear_cache(self) -> None:
632+
@classmethod
633+
def clear_fs_cache(cls) -> None:
633634
"""Clear the module cache."""
634-
self.__class__.CACHED_MODULES = set()
635-
self.__class__.FS_MODULES = {}
636-
self.__class__.FS_FUNCTIONS = {}
637-
self.__class__.FS_DEFARGS = []
638-
self.__class__.SKIPPED_FS_MODULES = {}
635+
print("Clearing the cache")
636+
cls.CACHED_MODULES = set()
637+
cls.FS_MODULES = {}
638+
cls.FS_FUNCTIONS = {}
639+
cls.FS_DEFARGS = []
640+
cls.SKIPPED_FS_MODULES = {}
641+
642+
def clear_cache(self) -> None:
643+
"""Clear the module cache (convenience instance method)."""
644+
self.__class__.clear_fs_cache()
639645

640646
def _init_fake_module_classes(self) -> None:
641647
# IMPORTANT TESTING NOTE: Whenever you add a new module below, test

pyfakefs/pytest_plugin.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ def my_fakefs_test(fs):
88
fs.create_file('/var/data/xx1.txt')
99
assert os.path.exists('/var/data/xx1.txt')
1010
"""
11+
1112
import py
1213
import pytest
1314
from _pytest import capture
@@ -17,7 +18,7 @@ def my_fakefs_test(fs):
1718
try:
1819
from _pytest import pathlib
1920
except ImportError:
20-
pathlib = None
21+
pathlib = None # type:ignore[assignment]
2122

2223
Patcher.SKIPMODULES.add(py)
2324
Patcher.SKIPMODULES.add(pytest)
@@ -73,3 +74,9 @@ def fs_session(request):
7374
patcher.setUp()
7475
yield patcher.fs
7576
patcher.tearDown()
77+
78+
79+
@pytest.hookimpl(tryfirst=True)
80+
def pytest_sessionfinish(session, exitstatus):
81+
"""Make sure that the cache is cleared before the final test shutdown."""
82+
Patcher.clear_fs_cache()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
This is a regression test for #866 that shall ensure that
3+
shutting down the test session after this specific call does not result
4+
in a segmentation fault.
5+
"""
6+
import opentimelineio as otio
7+
8+
9+
def test_empty_fs(fs):
10+
pass
11+
12+
13+
def test_create_clip(fs):
14+
"""If the fs cache is not cleared during session shutdown, a segmentation fault
15+
will happen during garbage collection of the cached modules."""
16+
otio.core.SerializableObjectWithMetadata(metadata={})

0 commit comments

Comments
 (0)