Merge pull request #4980 from blueyed/fixup_namespace_packages

monkeypatch.syspath_prepend: call fixup_namespace_packages
This commit is contained in:
Daniel Hahler 2019-03-25 23:10:00 +01:00 committed by GitHub
commit 51f64c2920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 46 additions and 15 deletions

View File

@ -0,0 +1 @@
Namespace packages are handled better with ``monkeypatch.syspath_prepend`` and ``testdir.syspathinsert`` (via ``pkg_resources.fixup_namespace_packages``).

View File

@ -262,10 +262,15 @@ class MonkeyPatch(object):
def syspath_prepend(self, path): def syspath_prepend(self, path):
""" Prepend ``path`` to ``sys.path`` list of import locations. """ """ Prepend ``path`` to ``sys.path`` list of import locations. """
from pkg_resources import fixup_namespace_packages
if self._savesyspath is None: if self._savesyspath is None:
self._savesyspath = sys.path[:] self._savesyspath = sys.path[:]
sys.path.insert(0, str(path)) sys.path.insert(0, str(path))
# https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171
fixup_namespace_packages(str(path))
def chdir(self, path): def chdir(self, path):
""" Change the current working directory to the specified path. """ Change the current working directory to the specified path.
Path can be a string or a py.path.local object. Path can be a string or a py.path.local object.

View File

@ -593,11 +593,16 @@ class Testdir(object):
This is undone automatically when this object dies at the end of each This is undone automatically when this object dies at the end of each
test. test.
""" """
from pkg_resources import fixup_namespace_packages
if path is None: if path is None:
path = self.tmpdir path = self.tmpdir
sys.path.insert(0, str(path))
dirname = str(path)
sys.path.insert(0, dirname)
fixup_namespace_packages(dirname)
# a call to syspathinsert() usually means that the caller wants to # a call to syspathinsert() usually means that the caller wants to
# import some dynamically created files, thus with python3 we # import some dynamically created files, thus with python3 we
# invalidate its import caches # invalidate its import caches
@ -606,12 +611,10 @@ class Testdir(object):
def _possibly_invalidate_import_caches(self): def _possibly_invalidate_import_caches(self):
# invalidate caches if we can (py33 and above) # invalidate caches if we can (py33 and above)
try: try:
import importlib from importlib import invalidate_caches
except ImportError: except ImportError:
pass return
else: invalidate_caches()
if hasattr(importlib, "invalidate_caches"):
importlib.invalidate_caches()
def mkdir(self, name): def mkdir(self, name):
"""Create a new (sub)directory.""" """Create a new (sub)directory."""

View File

@ -34,8 +34,6 @@ class TestModule(object):
) )
def test_import_prepend_append(self, testdir, monkeypatch): def test_import_prepend_append(self, testdir, monkeypatch):
syspath = list(sys.path)
monkeypatch.setattr(sys, "path", syspath)
root1 = testdir.mkdir("root1") root1 = testdir.mkdir("root1")
root2 = testdir.mkdir("root2") root2 = testdir.mkdir("root2")
root1.ensure("x456.py") root1.ensure("x456.py")

View File

@ -1335,7 +1335,7 @@ class TestEarlyRewriteBailout(object):
# Setup conditions for py's fspath trying to import pathlib on py34 # Setup conditions for py's fspath trying to import pathlib on py34
# always (previously triggered via xdist only). # always (previously triggered via xdist only).
# Ref: https://github.com/pytest-dev/py/pull/207 # Ref: https://github.com/pytest-dev/py/pull/207
monkeypatch.setattr(sys, "path", [""] + sys.path) monkeypatch.syspath_prepend("")
monkeypatch.delitem(sys.modules, "pathlib", raising=False) monkeypatch.delitem(sys.modules, "pathlib", raising=False)
testdir.makepyfile( testdir.makepyfile(

View File

@ -437,3 +437,28 @@ def test_context():
m.setattr(functools, "partial", 3) m.setattr(functools, "partial", 3)
assert not inspect.isclass(functools.partial) assert not inspect.isclass(functools.partial)
assert inspect.isclass(functools.partial) assert inspect.isclass(functools.partial)
def test_syspath_prepend_with_namespace_packages(testdir, monkeypatch):
for dirname in "hello", "world":
d = testdir.mkdir(dirname)
ns = d.mkdir("ns_pkg")
ns.join("__init__.py").write(
"__import__('pkg_resources').declare_namespace(__name__)"
)
lib = ns.mkdir(dirname)
lib.join("__init__.py").write("def check(): return %r" % dirname)
monkeypatch.syspath_prepend("hello")
import ns_pkg.hello
assert ns_pkg.hello.check() == "hello"
with pytest.raises(ImportError):
import ns_pkg.world
# Prepending should call fixup_namespace_packages.
monkeypatch.syspath_prepend("world")
import ns_pkg.world
assert ns_pkg.world.check() == "world"

View File

@ -4,7 +4,6 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
import os import os
import re
import sys import sys
import types import types
@ -165,10 +164,10 @@ def test_importplugin_error_message(testdir, pytestpm):
with pytest.raises(ImportError) as excinfo: with pytest.raises(ImportError) as excinfo:
pytestpm.import_plugin("qwe") pytestpm.import_plugin("qwe")
expected_message = '.*Error importing plugin "qwe": Not possible to import: .' assert str(excinfo.value).endswith(
expected_traceback = ".*in test_traceback" 'Error importing plugin "qwe": Not possible to import: ☺'
assert re.match(expected_message, str(excinfo.value)) )
assert re.match(expected_traceback, str(excinfo.traceback[-1])) assert "in test_traceback" in str(excinfo.traceback[-1])
class TestPytestPluginManager(object): class TestPytestPluginManager(object):