Merge pull request #1787 from nicoddemus/fix-rewrite-conftest

Rewrite asserts in test-modules loaded very early in the startup
This commit is contained in:
Bruno Oliveira 2016-08-03 16:10:55 -03:00 committed by GitHub
commit 6e3105dc8f
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):