Rewrite asserts in test-modules loaded very early in the startup

Also now match modules which start with any of the names registered
using register_assert_rewrite as discussed in #1787

Fix #1784
This commit is contained in:
Bruno Oliveira 2016-08-02 19:16:27 -03:00
parent d5be6cba13
commit 6711b1d6ab
3 changed files with 35 additions and 22 deletions

View File

@ -31,10 +31,11 @@ def pytest_namespace():
def register_assert_rewrite(*names): def register_assert_rewrite(*names):
"""Register a module name to be rewritten on import. """Register a module name to be rewritten on import.
This function will make sure that the module will get it's assert This function will make sure that this module or all modules inside
statements rewritten when it is imported. Thus you should make the package will get their assert statements rewritten.
sure to call this before the module is actually imported, usually Thus you should make sure to call this before the module is
in your __init__.py if you are a plugin using a package. actually imported, usually in your __init__.py if you are a plugin
using a package.
""" """
for hook in sys.meta_path: for hook in sys.meta_path:
if isinstance(hook, rewrite.AssertionRewritingHook): if isinstance(hook, rewrite.AssertionRewritingHook):

View File

@ -11,6 +11,7 @@ import re
import struct import struct
import sys import sys
import types import types
from fnmatch import fnmatch
import py import py
from _pytest.assertion import util from _pytest.assertion import util
@ -144,28 +145,29 @@ class AssertionRewritingHook(object):
if fn_pypath.basename == 'conftest.py': if fn_pypath.basename == 'conftest.py':
state.trace("rewriting conftest file: %r" % (fn,)) state.trace("rewriting conftest file: %r" % (fn,))
return True return True
elif self.session is not None:
if self.session is not None:
if self.session.isinitpath(fn): if self.session.isinitpath(fn):
state.trace("matched test file (was specified on cmdline): %r" % state.trace("matched test file (was specified on cmdline): %r" %
(fn,)) (fn,))
return True return True
else:
# modules not passed explicitly on the command line are only # modules not passed explicitly on the command line are only
# rewritten if they match the naming convention for test files # rewritten if they match the naming convention for test files
session = self.session # avoid a cycle here for pat in self.fnpats:
self.session = None # use fnmatch instead of fn_pypath.fnmatch because the
try: # latter might trigger an import to fnmatch.fnmatch
for pat in self.fnpats: # internally, which would cause this method to be
if fn_pypath.fnmatch(pat): # called recursively
state.trace("matched test file %r" % (fn,)) if fnmatch(fn_pypath.basename, pat):
return True state.trace("matched test file %r" % (fn,))
finally: return True
self.session = session
del session for marked in self._must_rewrite:
else: if name.startswith(marked):
for marked in self._must_rewrite: state.trace("matched marked file %r (from %r)" % (name, marked))
if marked.startswith(name): return True
return True
return False return False
def mark_rewrite(self, *names): def mark_rewrite(self, *names):

View File

@ -533,6 +533,16 @@ def test_rewritten():
hook.mark_rewrite('_pytest') hook.mark_rewrite('_pytest')
assert '_pytest' in warnings[0][1] assert '_pytest' in warnings[0][1]
def test_rewrite_module_imported_from_conftest(self, testdir):
testdir.makeconftest('''
import test_rewrite_module_imported
''')
testdir.makepyfile(test_rewrite_module_imported='''
def test_rewritten():
assert "@py_builtins" in globals()
''')
assert testdir.runpytest_subprocess().ret == 0
class TestAssertionRewriteHookDetails(object): class TestAssertionRewriteHookDetails(object):
def test_loader_is_package_false_for_module(self, testdir): def test_loader_is_package_false_for_module(self, testdir):