Skip to content

Commit 9f38b89

Browse files
committed
Fix handling of pausing fs during reporting
- use hookwrapper to disable patching during reporting - disable patching between tests for non function-scope fixtures
1 parent 4ddc306 commit 9f38b89

File tree

5 files changed

+36
-17
lines changed

5 files changed

+36
-17
lines changed

CHANGES.md

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

1616
## Unreleased
1717

18+
### Fixes
19+
* fixed an interaction problem of `fs` with other pytest fixtures (see [#1200](../../issues/1200))
20+
1821
### Infrastructure
1922
* fixed some warnings in tests (see [#1190](../../issues/1190))
2023

docs/usage.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ you can define a longer name in your ``conftest.py`` and use that in your tests:
4343
"""
4444
yield fs
4545
46+
.. note:: Filesystem patching is paused in the pytest logreport phases to ensure that
47+
logs are correctly written to the real filesystem.
48+
4649
Class-, module- and session-scoped fixtures
4750
...........................................
4851
For convenience, class-, module- and session-scoped fixtures with the same
@@ -55,6 +58,9 @@ respectively.
5558
done in the fake filesystem inside a test will remain there until the respective scope
5659
ends (see also :ref:`nested_patcher_invocation`).
5760

61+
.. note:: To avoid unwanted side-effects, the patching is paused between the tests,
62+
even if the fixture is still active.
63+
5864
.. _unittest_usage:
5965

6066
Patch using fake_filesystem_unittest

pyfakefs/fake_filesystem_unittest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ def fake_path_module(fs: FakeFilesystem):
789789
"io": fake_io.FakeIoModule,
790790
"pathlib": fake_pathlib_module,
791791
}
792-
if sys.version_info >= (3, 13):
792+
if sys.version_info[:2] == (3, 13):
793793
# for Python 3.13, we need both pathlib (path with __init__.py) and
794794
# pathlib._local (has the actual implementation);
795795
# depending on how pathlib is imported, either may be used
@@ -806,10 +806,10 @@ def fake_path_module(fs: FakeFilesystem):
806806
# be contained in - this allows for alternative modules like
807807
# `pathlib` and `pathlib2`
808808
self._class_modules["Path"] = ["pathlib"]
809-
if sys.version_info >= (3, 13):
809+
if sys.version_info[:2] == (3, 13):
810810
self._class_modules["Path"].append("pathlib._local")
811811
self._unfaked_module_classes["pathlib"] = fake_pathlib.RealPathlibModule
812-
if sys.version_info >= (3, 13):
812+
if sys.version_info[:2] == (3, 13):
813813
self._unfaked_module_classes["pathlib._local"] = (
814814
fake_pathlib.RealPathlibModule
815815
)

pyfakefs/pytest_plugin.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ def my_fakefs_test(fs):
99
assert os.path.exists('/var/data/xx1.txt')
1010
"""
1111

12+
import contextlib
13+
1214
import py
1315
import pytest
1416
from _pytest import capture
1517

16-
from pyfakefs.fake_filesystem_unittest import Patcher
18+
from pyfakefs.fake_filesystem_unittest import Patcher, Pause
1719

1820
try:
1921
from _pytest import pathlib
@@ -85,22 +87,18 @@ def pytest_sessionfinish(session, exitstatus):
8587
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
8688
def pytest_runtest_logreport(report):
8789
"""Make sure that patching is not active during reporting."""
88-
pause = Patcher.PATCHER is not None and report.when == "call"
89-
if pause:
90+
pause = Patcher.PATCHER is not None and Patcher.PATCHER.is_patching
91+
context_mgr = Pause(Patcher.PATCHER) if pause else contextlib.nullcontext()
92+
with context_mgr:
93+
yield
94+
if pause and report.when == "teardown":
95+
# if we get here, we are not in a function scope fixture
96+
# in this case, we still want to pause patching between the tests
9097
Patcher.PATCHER.pause()
91-
yield
9298

9399

94-
@pytest.hookimpl(hookwrapper=True, trylast=True)
100+
@pytest.hookimpl(tryfirst=True)
95101
def pytest_runtest_setup(item):
102+
# resume patcher if not in a function scope
96103
if Patcher.PATCHER is not None:
97104
Patcher.PATCHER.resume()
98-
yield
99-
100-
101-
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
102-
def pytest_runtest_teardown(item, nextitem):
103-
"""Make sure that patching is not active during reporting."""
104-
if Patcher.PATCHER is not None:
105-
Patcher.PATCHER.pause()
106-
yield
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from pyfakefs.fake_filesystem import FakeFileOpen
2+
3+
4+
def test_monkeypatch_with_fs(fs, monkeypatch):
5+
"""Regression test for issue 1200"""
6+
fake_open = FakeFileOpen(fs)
7+
monkeypatch.setattr("builtins.open", fake_open, raising=False)
8+
9+
10+
def test_open():
11+
"""Tests if open is poisoned by the above test"""
12+
assert "built-in" in str(open)

0 commit comments

Comments
 (0)