test_ok2/_pytest/assertion/__init__.py

129 lines
4.4 KiB
Python
Raw Normal View History

"""
2011-05-27 02:15:21 +08:00
support for presenting detailed information in failing assertions.
"""
import py
import imp
import marshal
import struct
import sys
2011-05-27 03:34:27 +08:00
import pytest
from _pytest.monkeypatch import monkeypatch
from _pytest.assertion import reinterpret, util
try:
2011-05-26 05:18:45 +08:00
from _pytest.assertion.rewrite import rewrite_asserts
except ImportError:
rewrite_asserts = None
else:
import ast
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
2011-05-27 12:15:33 +08:00
group.addoption('--assertmode', action="store", dest="assertmode",
choices=("on", "old", "off", "default"), default="default",
metavar="on|old|off",
help="""control assertion debugging tools.
2011-05-27 09:33:12 +08:00
'off' performs no assertion debugging.
'old' reinterprets the expressions in asserts to glean information.
2011-05-27 09:59:43 +08:00
'on' (the default) rewrites the assert statements in test modules to provide
sub-expression results.""")
2011-05-27 12:15:33 +08:00
group.addoption('--no-assert', action="store_true", default=False,
2011-05-27 03:34:27 +08:00
dest="noassert", help="DEPRECATED equivalent to --assertmode=off")
2011-05-27 12:15:33 +08:00
group.addoption('--nomagic', action="store_true", default=False,
dest="nomagic", help="DEPRECATED equivalent to --assertmode=off")
2011-05-27 03:34:27 +08:00
2011-05-27 05:08:25 +08:00
class AssertionState:
"""State for the assertion plugin."""
def __init__(self, config, mode):
self.mode = mode
self.trace = config.trace.root.get("assertion")
def pytest_configure(config):
warn_about_missing_assertion()
2011-05-27 03:34:27 +08:00
mode = config.getvalue("assertmode")
if config.getvalue("noassert") or config.getvalue("nomagic"):
if mode not in ("off", "default"):
raise pytest.UsageError("assertion options conflict")
mode = "off"
elif mode == "default":
mode = "on"
if mode != "off":
def callbinrepr(op, left, right):
hook_result = config.hook.pytest_assertrepr_compare(
config=config, op=op, left=left, right=right)
for new_expl in hook_result:
if new_expl:
return '\n~'.join(new_expl)
2011-05-27 03:34:27 +08:00
m = monkeypatch()
config._cleanup.append(m.undo)
2011-05-26 06:54:02 +08:00
m.setattr(py.builtin.builtins, 'AssertionError',
reinterpret.AssertionError)
m.setattr(util, '_reprcompare', callbinrepr)
if mode == "on" and rewrite_asserts is None:
mode = "old"
2011-05-27 05:18:18 +08:00
config._assertstate = AssertionState(config, mode)
config._assertstate.trace("configured with mode set to %r" % (mode,))
def _write_pyc(co, source_path):
if hasattr(imp, "cache_from_source"):
# Handle PEP 3147 pycs.
pyc = py.path(imp.cache_from_source(source_math))
pyc.dirname.ensure(dir=True)
else:
pyc = source_path + "c"
mtime = int(source_path.mtime())
fp = pyc.open("wb")
try:
fp.write(imp.get_magic())
fp.write(struct.pack("<l", mtime))
marshal.dump(co, fp)
finally:
fp.close()
return pyc
def before_module_import(mod):
if mod.config._assertstate.mode != "on":
return
# Some deep magic: load the source, rewrite the asserts, and write a
2011-05-27 02:15:03 +08:00
# fake pyc, so that it'll be loaded when the module is imported.
source = mod.fspath.read()
try:
tree = ast.parse(source)
except SyntaxError:
# Let this pop up again in the real import.
2011-05-27 05:08:25 +08:00
mod.config._assertstate.trace("failed to parse: %r" % (mod.fspath,))
return
rewrite_asserts(tree)
try:
co = compile(tree, str(mod.fspath), "exec")
except SyntaxError:
# It's possible that this error is from some bug in the assertion
# rewriting, but I don't know of a fast way to tell.
2011-05-27 05:08:25 +08:00
mod.config._assertstate.trace("failed to compile: %r" % (mod.fspath,))
return
mod._pyc = _write_pyc(co, mod.fspath)
mod.config._assertstate.trace("wrote pyc: %r" % (mod._pyc,))
def after_module_import(mod):
if not hasattr(mod, "_pyc"):
return
state = mod.config._assertstate
try:
mod._pyc.remove()
except py.error.ENOENT:
state.trace("couldn't find pyc: %r" % (mod._pyc,))
else:
state.trace("removed pyc: %r" % (mod._pyc,))
def warn_about_missing_assertion():
try:
assert False
except AssertionError:
pass
else:
sys.stderr.write("WARNING: failing tests may report as passing because "
"assertions are turned off! (are you using python -O?)\n")
pytest_assertrepr_compare = util.assertrepr_compare