refactor CallInfo constructor magic into named constructor
This commit is contained in:
		
							parent
							
								
									b531f7d585
								
							
						
					
					
						commit
						847eacea19
					
				|  | @ -23,7 +23,9 @@ def get_skip_exceptions(): | ||||||
| def pytest_runtest_makereport(item, call): | def pytest_runtest_makereport(item, call): | ||||||
|     if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()): |     if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()): | ||||||
|         # let's substitute the excinfo with a pytest.skip one |         # 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 |         call.excinfo = call2.excinfo | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import os | ||||||
| import sys | import sys | ||||||
| from time import time | from time import time | ||||||
| 
 | 
 | ||||||
|  | import attr | ||||||
| import six | import six | ||||||
| 
 | 
 | ||||||
| from .reports import CollectErrorRepr | from .reports import CollectErrorRepr | ||||||
|  | @ -189,43 +190,57 @@ def check_interactive_exception(call, report): | ||||||
| def call_runtest_hook(item, when, **kwds): | def call_runtest_hook(item, when, **kwds): | ||||||
|     hookname = "pytest_runtest_" + when |     hookname = "pytest_runtest_" + when | ||||||
|     ihook = getattr(item.ihook, hookname) |     ihook = getattr(item.ihook, hookname) | ||||||
|     return CallInfo( |     return CallInfo.from_call( | ||||||
|         lambda: ihook(item=item, **kwds), |         lambda: ihook(item=item, **kwds), | ||||||
|         when=when, |         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): | class CallInfo(object): | ||||||
|     """ Result/Exception info a function invocation. """ |     """ Result/Exception info a function invocation. """ | ||||||
| 
 | 
 | ||||||
|     #: None or ExceptionInfo object. |     _result = attr.ib() | ||||||
|     excinfo = None |     # 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", |         #: context of invocation: one of "setup", "call", | ||||||
|         #: "teardown", "memocollect" |         #: "teardown", "memocollect" | ||||||
|         self.when = when |         start = time() | ||||||
|         self.start = time() |         excinfo = None | ||||||
|         try: |         try: | ||||||
|             self.result = func() |             result = func() | ||||||
|         except KeyboardInterrupt: |  | ||||||
|             if treat_keyboard_interrupt_as_exception: |  | ||||||
|                 self.excinfo = ExceptionInfo.from_current() |  | ||||||
|             else: |  | ||||||
|                 self.stop = time() |  | ||||||
|                 raise |  | ||||||
|         except:  # noqa |         except:  # noqa | ||||||
|             self.excinfo = ExceptionInfo.from_current() |             excinfo = ExceptionInfo.from_current() | ||||||
|         self.stop = time() |             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): |     def __repr__(self): | ||||||
|         if self.excinfo: |         if self.excinfo is not None: | ||||||
|             status = "exception: %s" % str(self.excinfo.value) |             status = "exception" | ||||||
|  |             value = self.excinfo.value | ||||||
|         else: |         else: | ||||||
|             result = getattr(self, "result", "<NOTSET>") |             # TODO: investigate unification | ||||||
|             status = "result: %r" % (result,) |             value = repr(self._result) | ||||||
|         return "<CallInfo when=%r %s>" % (self.when, status) |             status = "result" | ||||||
|  |         return "<CallInfo when={when!r} {status}: {value}>".format( | ||||||
|  |             when=self.when, value=value, status=status | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def pytest_runtest_makereport(item, call): | def pytest_runtest_makereport(item, call): | ||||||
|  | @ -269,7 +284,7 @@ def pytest_runtest_makereport(item, call): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def pytest_make_collect_report(collector): | def pytest_make_collect_report(collector): | ||||||
|     call = CallInfo(lambda: list(collector.collect()), "collect") |     call = CallInfo.from_call(lambda: list(collector.collect()), "collect") | ||||||
|     longrepr = None |     longrepr = None | ||||||
|     if not call.excinfo: |     if not call.excinfo: | ||||||
|         outcome = "passed" |         outcome = "passed" | ||||||
|  |  | ||||||
|  | @ -487,13 +487,13 @@ def test_report_extra_parameters(reporttype): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_callinfo(): | def test_callinfo(): | ||||||
|     ci = runner.CallInfo(lambda: 0, "123") |     ci = runner.CallInfo.from_call(lambda: 0, "123") | ||||||
|     assert ci.when == "123" |     assert ci.when == "123" | ||||||
|     assert ci.result == 0 |     assert ci.result == 0 | ||||||
|     assert "result" in repr(ci) |     assert "result" in repr(ci) | ||||||
|     assert repr(ci) == "<CallInfo when='123' result: 0>" |     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 ci.when == "123" | ||||||
|     assert not hasattr(ci, "result") |     assert not hasattr(ci, "result") | ||||||
|     assert repr(ci) == "<CallInfo when='123' exception: division by zero>" |     assert repr(ci) == "<CallInfo when='123' exception: division by zero>" | ||||||
|  | @ -501,16 +501,6 @@ def test_callinfo(): | ||||||
|     assert "exc" in repr(ci) |     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? | # design question: do we want general hooks in python files? | ||||||
| # then something like the following functional tests makes sense | # then something like the following functional tests makes sense | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue