Skip to content

Commit 70f7222

Browse files
committed
Merge pull request pytest-dev#1291 from ulope/master
Make monkeypatch differentiate ImportError sources
2 parents c5631b6 + 2e02579 commit 70f7222

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
``--pdb`` with standard I/O capture enabled.
1010
Thanks Erik M. Bray for the PR.
1111

12+
- fix #900: Better error message in case the target of a ``monkeypatch`` call
13+
raises an ``ImportError``.
14+
15+
1216
2.8.5
1317
-----
1418

_pytest/monkeypatch.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
""" monkeypatching and mocking functionality. """
22

33
import os, sys
4+
import re
5+
46
from py.builtin import _basestring
57

8+
9+
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
10+
11+
612
def pytest_funcarg__monkeypatch(request):
713
"""The returned ``monkeypatch`` funcarg provides these
814
helper methods to modify objects, dictionaries or os.environ::
@@ -34,14 +40,28 @@ def derive_importpath(import_path, raising):
3440
(import_path,))
3541
rest = []
3642
target = import_path
43+
target_parts = set(target.split("."))
3744
while target:
3845
try:
3946
obj = __import__(target, None, None, "__doc__")
40-
except ImportError:
47+
except ImportError as ex:
48+
if hasattr(ex, 'name'):
49+
# Python >= 3.3
50+
failed_name = ex.name
51+
else:
52+
match = RE_IMPORT_ERROR_NAME.match(ex.args[0])
53+
assert match
54+
failed_name = match.group(1)
55+
4156
if "." not in target:
4257
__tracebackhide__ = True
4358
pytest.fail("could not import any sub part: %s" %
4459
import_path)
60+
elif failed_name != target \
61+
and not any(p == failed_name for p in target_parts):
62+
# target is importable but causes ImportError itself
63+
__tracebackhide__ = True
64+
pytest.fail("import error in %s: %s" % (target, ex.args[0]))
4565
target, name = target.rsplit(".", 1)
4666
rest.append(name)
4767
else:

testing/test_monkeypatch.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import os, sys
2+
import textwrap
3+
24
import pytest
35
from _pytest.monkeypatch import monkeypatch as MonkeyPatch
46

@@ -245,6 +247,21 @@ def f():
245247
*1 passed*
246248
""")
247249

250+
def test_importerror(testdir):
251+
p = testdir.mkpydir("package")
252+
p.join("a.py").write(textwrap.dedent("""\
253+
import doesnotexist
254+
255+
x = 1
256+
"""))
257+
testdir.tmpdir.join("test_importerror.py").write(textwrap.dedent("""\
258+
def test_importerror(monkeypatch):
259+
monkeypatch.setattr('package.a.x', 2)
260+
"""))
261+
result = testdir.runpytest()
262+
result.stdout.fnmatch_lines("""
263+
*import error in package.a.x: No module named {0}doesnotexist{0}*
264+
""".format("'" if sys.version_info > (3, 0) else ""))
248265

249266

250267
class SampleNew(object):

0 commit comments

Comments
 (0)