From 86fc12dd15a3d96a05385aefe16bb2c9640c19f6 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 28 Oct 2009 19:51:20 +0100 Subject: [PATCH] resolves issue #59 resolves issue #48 Have the path.pyimport() helper raise an EnvironmentError if an import of a given file returns a module that does not appear to be coming from the actual path. E.g. for a directory layout like this: a / test_whatever.py b / test_whatever.py calling py.path.local("b/test_whatever.py").pyimport() will fail if the other globally scoped test_whatever module was loaded already. --HG-- branch : trunk --- _py/path/local.py | 11 ++++++++++- _py/test/plugin/pytest_pytester.py | 6 ++++++ doc/changelog.txt | 5 +++++ testing/path/test_local.py | 21 +++++++++++++++++++++ testing/pytest/test_pycollect.py | 12 ++++++++++++ 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/_py/path/local.py b/_py/path/local.py index 12df59f69..1e87120c0 100644 --- a/_py/path/local.py +++ b/_py/path/local.py @@ -516,7 +516,16 @@ class LocalPath(FSBase): self._prependsyspath(self.dirpath()) modname = self.purebasename mod = __import__(modname, None, None, ['__doc__']) - #self._module = mod + modfile = mod.__file__ + if modfile[-4:] in ('.pyc', '.pyo'): + modfile = modfile[:-1] + elif modfile.endswith('$py.class'): + modfile = modfile[:-9] + '.py' + if not self.samefile(modfile): + raise EnvironmentError("mismatch:\n" + "imported module %r\n" + "does not stem from %r\n" + "maybe __init__.py files are missing?" % (mod, str(self))) return mod else: try: diff --git a/_py/test/plugin/pytest_pytester.py b/_py/test/plugin/pytest_pytester.py index 99ac5377d..901eecac4 100644 --- a/_py/test/plugin/pytest_pytester.py +++ b/_py/test/plugin/pytest_pytester.py @@ -70,6 +70,12 @@ class TmpTestdir: py.std.sys.path.remove(p) if hasattr(self, '_olddir'): self._olddir.chdir() + # delete modules that have been loaded from tmpdir + for name, mod in list(sys.modules.items()): + if mod: + fn = getattr(mod, '__file__', None) + if fn and fn.startswith(str(self.tmpdir)): + del sys.modules[name] def getreportrecorder(self, obj): if isinstance(obj, py._com.Registry): diff --git a/doc/changelog.txt b/doc/changelog.txt index 00a573189..2b00c382b 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,11 @@ Changes between 1.0.2 and '1.1.0b1' ===================================== +* fix issue48 and issue59: raise an Error if the module + from an imported test file does not seem to come from + the filepath - avoids "same-name" confusion that has + been reported repeatedly + * merged Ronny's nose-compatibility hacks: now nose-style setup_module() and setup() functions are supported diff --git a/testing/path/test_local.py b/testing/path/test_local.py index 773fdf3d2..333025fba 100644 --- a/testing/path/test_local.py +++ b/testing/path/test_local.py @@ -336,6 +336,27 @@ class TestImport: from xxxpackage import module1 assert module1 is mod1 + def test_pyimport_check_filepath_consistency(self, monkeypatch, tmpdir): + name = 'pointsback123' + ModuleType = type(py.std.sys) + p = tmpdir.ensure(name + '.py') + for ending in ('.pyc', '$py.class', '.pyo'): + mod = ModuleType(name) + pseudopath = tmpdir.ensure(name+ending) + mod.__file__ = str(pseudopath) + monkeypatch.setitem(sys.modules, name, mod) + newmod = p.pyimport() + assert mod == newmod + monkeypatch.undo() + mod = ModuleType(name) + pseudopath = tmpdir.ensure(name+"123.py") + mod.__file__ = str(pseudopath) + monkeypatch.setitem(sys.modules, name, mod) + excinfo = py.test.raises(EnvironmentError, "p.pyimport()") + s = str(excinfo.value) + assert "mismatch" in s + assert name+"123" in s + def test_pypkgdir(tmpdir): pkg = tmpdir.ensure('pkg1', dir=1) pkg.ensure("__init__.py") diff --git a/testing/pytest/test_pycollect.py b/testing/pytest/test_pycollect.py index 2ef6de35a..ad1ac1a77 100644 --- a/testing/pytest/test_pycollect.py +++ b/testing/pytest/test_pycollect.py @@ -16,6 +16,18 @@ class TestModule: py.test.raises(ImportError, modcol.collect) py.test.raises(ImportError, modcol.run) + def test_import_duplicate(self, testdir): + a = testdir.mkdir("a") + b = testdir.mkdir("b") + p = a.ensure("test_whatever.py") + p.pyimport() + del py.std.sys.modules['test_whatever'] + b.ensure("test_whatever.py") + result = testdir.runpytest() + s = result.stdout.str() + assert 'mismatch' in s + assert 'test_whatever' in s + def test_syntax_error_in_module(self, testdir): modcol = testdir.getmodulecol("this is a syntax error") py.test.raises(SyntaxError, modcol.collect)