Merge pull request #4299 from RonnyPfannschmidt/callinfo-sanity
refactor callinfo to simplify ctor magic
This commit is contained in:
commit
e0ba1cbf8d
|
@ -23,7 +23,9 @@ def get_skip_exceptions():
|
|||
def pytest_runtest_makereport(item, call):
|
||||
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
|
||||
# let's substitute the excinfo with a pytest.skip one
|
||||
call2 = call.__class__(lambda: runner.skip(str(call.excinfo.value)), call.when)
|
||||
call2 = runner.CallInfo.from_call(
|
||||
lambda: runner.skip(str(call.excinfo.value)), call.when
|
||||
)
|
||||
call.excinfo = call2.excinfo
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import os
|
|||
import sys
|
||||
from time import time
|
||||
|
||||
import attr
|
||||
import six
|
||||
|
||||
from .reports import CollectErrorRepr
|
||||
|
@ -189,43 +190,57 @@ def check_interactive_exception(call, report):
|
|||
def call_runtest_hook(item, when, **kwds):
|
||||
hookname = "pytest_runtest_" + when
|
||||
ihook = getattr(item.ihook, hookname)
|
||||
return CallInfo(
|
||||
return CallInfo.from_call(
|
||||
lambda: ihook(item=item, **kwds),
|
||||
when=when,
|
||||
treat_keyboard_interrupt_as_exception=item.config.getvalue("usepdb"),
|
||||
reraise=KeyboardInterrupt if not item.config.getvalue("usepdb") else (),
|
||||
)
|
||||
|
||||
|
||||
@attr.s(repr=False)
|
||||
class CallInfo(object):
|
||||
""" Result/Exception info a function invocation. """
|
||||
|
||||
#: None or ExceptionInfo object.
|
||||
excinfo = None
|
||||
_result = attr.ib()
|
||||
# type: Optional[ExceptionInfo]
|
||||
excinfo = attr.ib()
|
||||
start = attr.ib()
|
||||
stop = attr.ib()
|
||||
when = attr.ib()
|
||||
|
||||
def __init__(self, func, when, treat_keyboard_interrupt_as_exception=False):
|
||||
@property
|
||||
def result(self):
|
||||
if self.excinfo is not None:
|
||||
raise AttributeError("{!r} has no valid result".format(self))
|
||||
return self._result
|
||||
|
||||
@classmethod
|
||||
def from_call(cls, func, when, reraise=None):
|
||||
#: context of invocation: one of "setup", "call",
|
||||
#: "teardown", "memocollect"
|
||||
self.when = when
|
||||
self.start = time()
|
||||
start = time()
|
||||
excinfo = None
|
||||
try:
|
||||
self.result = func()
|
||||
except KeyboardInterrupt:
|
||||
if treat_keyboard_interrupt_as_exception:
|
||||
self.excinfo = ExceptionInfo.from_current()
|
||||
else:
|
||||
self.stop = time()
|
||||
raise
|
||||
result = func()
|
||||
except: # noqa
|
||||
self.excinfo = ExceptionInfo.from_current()
|
||||
self.stop = time()
|
||||
excinfo = ExceptionInfo.from_current()
|
||||
if reraise is not None and excinfo.errisinstance(reraise):
|
||||
raise
|
||||
result = None
|
||||
stop = time()
|
||||
return cls(start=start, stop=stop, when=when, result=result, excinfo=excinfo)
|
||||
|
||||
def __repr__(self):
|
||||
if self.excinfo:
|
||||
status = "exception: %s" % str(self.excinfo.value)
|
||||
if self.excinfo is not None:
|
||||
status = "exception"
|
||||
value = self.excinfo.value
|
||||
else:
|
||||
result = getattr(self, "result", "<NOTSET>")
|
||||
status = "result: %r" % (result,)
|
||||
return "<CallInfo when=%r %s>" % (self.when, status)
|
||||
# TODO: investigate unification
|
||||
value = repr(self._result)
|
||||
status = "result"
|
||||
return "<CallInfo when={when!r} {status}: {value}>".format(
|
||||
when=self.when, value=value, status=status
|
||||
)
|
||||
|
||||
|
||||
def pytest_runtest_makereport(item, call):
|
||||
|
@ -269,7 +284,7 @@ def pytest_runtest_makereport(item, call):
|
|||
|
||||
|
||||
def pytest_make_collect_report(collector):
|
||||
call = CallInfo(lambda: list(collector.collect()), "collect")
|
||||
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
|
||||
longrepr = None
|
||||
if not call.excinfo:
|
||||
outcome = "passed"
|
||||
|
|
|
@ -487,13 +487,13 @@ def test_report_extra_parameters(reporttype):
|
|||
|
||||
|
||||
def test_callinfo():
|
||||
ci = runner.CallInfo(lambda: 0, "123")
|
||||
ci = runner.CallInfo.from_call(lambda: 0, "123")
|
||||
assert ci.when == "123"
|
||||
assert ci.result == 0
|
||||
assert "result" in repr(ci)
|
||||
assert repr(ci) == "<CallInfo when='123' result: 0>"
|
||||
|
||||
ci = runner.CallInfo(lambda: 0 / 0, "123")
|
||||
ci = runner.CallInfo.from_call(lambda: 0 / 0, "123")
|
||||
assert ci.when == "123"
|
||||
assert not hasattr(ci, "result")
|
||||
assert repr(ci) == "<CallInfo when='123' exception: division by zero>"
|
||||
|
@ -501,16 +501,6 @@ def test_callinfo():
|
|||
assert "exc" in repr(ci)
|
||||
|
||||
|
||||
def test_callinfo_repr_while_running():
|
||||
def repr_while_running():
|
||||
f = sys._getframe().f_back
|
||||
assert "func" in f.f_locals
|
||||
assert repr(f.f_locals["self"]) == "<CallInfo when='when' result: '<NOTSET>'>"
|
||||
|
||||
ci = runner.CallInfo(repr_while_running, "when")
|
||||
assert repr(ci) == "<CallInfo when='when' result: None>"
|
||||
|
||||
|
||||
# design question: do we want general hooks in python files?
|
||||
# then something like the following functional tests makes sense
|
||||
|
||||
|
|
Loading…
Reference in New Issue