Skip to content

Commit

Permalink
Add checks to avoid patching debugger modules
Browse files Browse the repository at this point in the history
- added Patcher.RUNTIME_SKIPMODULES to allow to skip
  modules whose name starts with specific strings,
  if the related debuuger is loaded
- only done for debugger used in PyCharm and VSCode
  • Loading branch information
mrbean-bremen committed Nov 23, 2024
1 parent 64861d1 commit 95c38ff
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ The released versions correspond to PyPI releases.
### Enhancements
* added some support for loading fake modules in `AUTO` patch mode
using `importlib.import_module` (see [#1079](../../issues/1079))
* added some support to avoid patching debugger related modules
(see [#1083](../../issues/1083))

### Performance
* avoid reloading `tempfile` in Posix systems
Expand Down
19 changes: 18 additions & 1 deletion pyfakefs/fake_filesystem_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,13 @@ class Patcher:
SKIPMODULES.add(posixpath)
SKIPMODULES.add(fcntl)

# a list of test and debug modules detected at run-time
# each tool defines one or more module name prefixes for modules to be skipped
RUNTIME_SKIPMODULES = {
"pydevd": ["_pydevd_", "pydevd", "_pydev_"], # Python debugger (PyCharm/VSCode)
"_jb_runner_tools": ["_jb_"], # JetBrains tools
}

# caches all modules that do not have file system modules or function
# to speed up _find_modules
CACHED_MODULES: Set[ModuleType] = set()
Expand Down Expand Up @@ -1045,10 +1052,20 @@ def patch_functions(self) -> None:
self._stubs.smart_set(module, name, attr)

def patch_modules(self) -> None:
skip_prefix_list = []
for rt_skip_module, prefixes in self.RUNTIME_SKIPMODULES.items():
if rt_skip_module in sys.modules:
skip_prefix_list.extend(prefixes)
skip_prefixes = tuple(skip_prefix_list)

assert self._stubs is not None
for name, modules in self.FS_MODULES.items():
for module, attr in modules:
self._stubs.smart_set(module, name, self.fake_modules[attr])
if not skip_prefixes or not module.__name__.startswith(skip_prefixes):
self._stubs.smart_set(module, name, self.fake_modules[attr])
elif attr in self.unfaked_modules:
self._stubs.smart_set(module, name, self.unfaked_modules[attr])

for name, modules in self.SKIPPED_FS_MODULES.items():
for module, attr in modules:
if attr in self.unfaked_modules:
Expand Down
30 changes: 30 additions & 0 deletions pyfakefs/tests/fake_filesystem_unittest_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,36 @@ def test_path_succeeds(self):
pyfakefs.tests.import_as_example.return_this_file_path()


class RuntimeSkipModuleTest(fake_filesystem_unittest.TestCase):
"""Emulates skipping a module using RUNTIME_SKIPMODULES.
Not all functionality implemented for skip modules will work here."""

def setUp(self):
Patcher.RUNTIME_SKIPMODULES.update(
{"pyfakefs.tests.import_as_example": ["pyfakefs.tests.import_"]}
)
self.setUpPyfakefs()

def tearDown(self):
del self.patcher.RUNTIME_SKIPMODULES["pyfakefs.tests.import_as_example"]

def test_fake_path_does_not_exist1(self):
self.fs.create_file("foo")
self.assertFalse(pyfakefs.tests.import_as_example.check_if_exists1("foo"))

def test_fake_path_does_not_exist2(self):
self.fs.create_file("foo")
self.assertFalse(pyfakefs.tests.import_as_example.check_if_exists2("foo"))

def test_fake_path_does_not_exist3(self):
self.fs.create_file("foo")
self.assertFalse(pyfakefs.tests.import_as_example.check_if_exists3("foo"))

def test_fake_path_does_not_exist4(self):
self.fs.create_file("foo")
self.assertFalse(pyfakefs.tests.import_as_example.check_if_exists4("foo"))


class FakeExampleModule:
"""Used to patch a function that uses system-specific functions that
cannot be patched automatically."""
Expand Down

0 comments on commit 95c38ff

Please sign in to comment.