From 8fd5a658eb7d36e6816d65ee8f81ebef79c1af14 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 12 Apr 2019 17:27:36 +0200 Subject: [PATCH] monkeypatch.syspath_prepend: invalidate import cache This was done with testdir only, and uses the fixed monkeypatch method there now. --- changelog/5098.bugfix.rst | 1 + src/_pytest/monkeypatch.py | 12 ++++++++++++ src/_pytest/pytester.py | 19 +------------------ testing/test_monkeypatch.py | 7 +++++++ 4 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 changelog/5098.bugfix.rst diff --git a/changelog/5098.bugfix.rst b/changelog/5098.bugfix.rst new file mode 100644 index 000000000..f0104b24e --- /dev/null +++ b/changelog/5098.bugfix.rst @@ -0,0 +1 @@ +Invalidate import caches with ``monkeypatch.syspath_prepend``, which is required with namespace packages being used. diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index f6c134664..3e221d3d9 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -271,6 +271,18 @@ class MonkeyPatch(object): # https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171 fixup_namespace_packages(str(path)) + # A call to syspathinsert() usually means that the caller wants to + # import some dynamically created files, thus with python3 we + # invalidate its import caches. + # This is especially important when any namespace package is in used, + # since then the mtime based FileFinder cache (that gets created in + # this case already) gets not invalidated when writing the new files + # quickly afterwards. + if sys.version_info >= (3, 3): + from importlib import invalidate_caches + + invalidate_caches() + def chdir(self, path): """ Change the current working directory to the specified path. Path can be a string or a py.path.local object. diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 131876910..d90ef1ce7 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -616,27 +616,10 @@ class Testdir(object): This is undone automatically when this object dies at the end of each test. """ - from pkg_resources import fixup_namespace_packages - if path is None: path = self.tmpdir - dirname = str(path) - sys.path.insert(0, dirname) - fixup_namespace_packages(dirname) - - # a call to syspathinsert() usually means that the caller wants to - # import some dynamically created files, thus with python3 we - # invalidate its import caches - self._possibly_invalidate_import_caches() - - def _possibly_invalidate_import_caches(self): - # invalidate caches if we can (py33 and above) - try: - from importlib import invalidate_caches - except ImportError: - return - invalidate_caches() + self.monkeypatch.syspath_prepend(str(path)) def mkdir(self, name): """Create a new (sub)directory.""" diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index d43fb6bab..9e45e05c8 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -462,3 +462,10 @@ def test_syspath_prepend_with_namespace_packages(testdir, monkeypatch): import ns_pkg.world assert ns_pkg.world.check() == "world" + + # Should invalidate caches via importlib.invalidate_caches. + tmpdir = testdir.tmpdir + modules_tmpdir = tmpdir.mkdir("modules_tmpdir") + monkeypatch.syspath_prepend(str(modules_tmpdir)) + modules_tmpdir.join("main_app.py").write("app = True") + from main_app import app # noqa: F401