110 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			110 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
support for presenting detailed information in failing assertions.
 | 
						|
"""
 | 
						|
import py
 | 
						|
import sys
 | 
						|
import pytest
 | 
						|
from _pytest.monkeypatch import monkeypatch
 | 
						|
from _pytest.assertion import util
 | 
						|
 | 
						|
REWRITING_AVAILABLE = "_ast" in sys.builtin_module_names
 | 
						|
 | 
						|
def pytest_addoption(parser):
 | 
						|
    group = parser.getgroup("debugconfig")
 | 
						|
    group.addoption('--assertmode', action="store", dest="assertmode",
 | 
						|
                    choices=("rewrite", "reinterp", "off", "default"),
 | 
						|
                    default="default", metavar="off|reinterp|rewrite",
 | 
						|
                    help="""control assertion debugging tools.
 | 
						|
'off' performs no assertion debugging.
 | 
						|
'reinterp' reinterprets the expressions in asserts to glean information.
 | 
						|
'rewrite' (the default) rewrites the assert statements in test modules on import
 | 
						|
to provide sub-expression results.""")
 | 
						|
    group.addoption('--no-assert', action="store_true", default=False,
 | 
						|
        dest="noassert", help="DEPRECATED equivalent to --assertmode=off")
 | 
						|
    group.addoption('--nomagic', action="store_true", default=False,
 | 
						|
        dest="nomagic", help="DEPRECATED equivalent to --assertmode=off")
 | 
						|
 | 
						|
class AssertionState:
 | 
						|
    """State for the assertion plugin."""
 | 
						|
 | 
						|
    def __init__(self, config, mode):
 | 
						|
        self.mode = mode
 | 
						|
        self.trace = config.trace.root.get("assertion")
 | 
						|
        self.pycs = []
 | 
						|
 | 
						|
def pytest_configure(config):
 | 
						|
    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 = "rewrite"
 | 
						|
    if mode == "on" and not REWRITING_AVAILABLE:
 | 
						|
        mode = "reinterp"
 | 
						|
    if mode != "off":
 | 
						|
        _load_modules(mode)
 | 
						|
        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)
 | 
						|
        m = monkeypatch()
 | 
						|
        config._cleanup.append(m.undo)
 | 
						|
        m.setattr(py.builtin.builtins, 'AssertionError',
 | 
						|
                  reinterpret.AssertionError)
 | 
						|
        m.setattr(util, '_reprcompare', callbinrepr)
 | 
						|
    hook = None
 | 
						|
    if mode == "rewrite":
 | 
						|
        hook = rewrite.AssertionRewritingHook()
 | 
						|
        sys.meta_path.append(hook)
 | 
						|
    warn_about_missing_assertion(mode)
 | 
						|
    config._assertstate = AssertionState(config, mode)
 | 
						|
    config._assertstate.hook = hook
 | 
						|
    config._assertstate.trace("configured with mode set to %r" % (mode,))
 | 
						|
 | 
						|
def pytest_unconfigure(config):
 | 
						|
    if config._assertstate.mode == "rewrite":
 | 
						|
        rewrite._drain_pycs(config._assertstate)
 | 
						|
    hook = config._assertstate.hook
 | 
						|
    if hook is not None:
 | 
						|
        sys.meta_path.remove(hook)
 | 
						|
 | 
						|
def pytest_sessionstart(session):
 | 
						|
    hook = session.config._assertstate.hook
 | 
						|
    if hook is not None:
 | 
						|
        hook.set_session(session)
 | 
						|
 | 
						|
def pytest_sessionfinish(session):
 | 
						|
    if session.config._assertstate.mode == "rewrite":
 | 
						|
        rewrite._drain_pycs(session.config._assertstate)
 | 
						|
    hook = session.config._assertstate.hook
 | 
						|
    if hook is not None:
 | 
						|
        hook.session = None
 | 
						|
 | 
						|
def _load_modules(mode):
 | 
						|
    """Lazily import assertion related code."""
 | 
						|
    global rewrite, reinterpret
 | 
						|
    from _pytest.assertion import reinterpret
 | 
						|
    if mode == "rewrite":
 | 
						|
        from _pytest.assertion import rewrite
 | 
						|
 | 
						|
def warn_about_missing_assertion(mode):
 | 
						|
    try:
 | 
						|
        assert False
 | 
						|
    except AssertionError:
 | 
						|
        pass
 | 
						|
    else:
 | 
						|
        if mode == "rewrite":
 | 
						|
            specifically = ("assertions which are not in test modules "
 | 
						|
                            "will be ignored")
 | 
						|
        else:
 | 
						|
            specifically = "failing tests may report as passing"
 | 
						|
 | 
						|
        sys.stderr.write("WARNING: " + specifically +
 | 
						|
                        " because assertions are turned off "
 | 
						|
                        "(are you using python -O?)\n")
 | 
						|
 | 
						|
pytest_assertrepr_compare = util.assertrepr_compare
 |