diff --git a/py/test/event.py b/py/test/event.py index 7301e49d9..95ef8771c 100644 --- a/py/test/event.py +++ b/py/test/event.py @@ -45,8 +45,12 @@ class TestrunStart(BaseEvent): self.timestart = time.time() class TestrunFinish(BaseEvent): - def __init__(self, exitstatus=0): + def __init__(self, exitstatus=0, excinfo=None): self.exitstatus = exitstatus + if excinfo is None: + self.excrepr = None + else: + self.excrepr = excinfo.getrepr() self.timeend = time.time() class InternalException(BaseEvent): diff --git a/py/test/report/terminal.py b/py/test/report/terminal.py index d183b6ad2..1f1519ab4 100644 --- a/py/test/report/terminal.py +++ b/py/test/report/terminal.py @@ -132,6 +132,8 @@ class TerminalReporter(BaseReporter): if ev.exitstatus in (0, 1, 2): self.summary_failures() self.summary_skips() + if ev.excrepr is not None: + self.summary_final_exc(ev.excrepr) if ev.exitstatus == 2: self.write_sep("!", "KEYBOARD INTERRUPT") self.summary_deselected() @@ -201,6 +203,13 @@ class TerminalReporter(BaseReporter): for num, fspath, lineno, reason in folded_skips: self._tw.line("%s:%d: [%d] %s" %(fspath, lineno, num, reason)) + def summary_final_exc(self, excrepr): + self.write_sep("!") + if self.config.option.verbose: + excrepr.toterminal(self._tw) + else: + excrepr.reprcrash.toterminal(self._tw) + def out_hostinfo(self): self._tw.line("host 0: %s %s - Python %s" % (py.std.sys.platform, diff --git a/py/test/report/testing/test_terminal.py b/py/test/report/testing/test_terminal.py index 827bae738..0baaccb0a 100644 --- a/py/test/report/testing/test_terminal.py +++ b/py/test/report/testing/test_terminal.py @@ -207,25 +207,41 @@ class TestTerminal(InlineCollection): print s assert s.find("test_show_path_before_running_test.py") != -1 - def test_keyboard_interrupt(self): + def test_keyboard_interrupt(self, verbose=False): modcol = self.getmodulecol(""" def test_foobar(): assert 0 def test_spamegg(): import py; py.test.skip('skip me please!') - """, configargs=("--showskipsummary",), withsession=True) + def test_interrupt_me(): + raise KeyboardInterrupt # simulating the user + """, configargs=("--showskipsummary",) + ("-v",)*verbose, + withsession=True) stringio = py.std.cStringIO.StringIO() rep = TerminalReporter(modcol._config, bus=self.session.bus, file=stringio) rep.processevent(event.TestrunStart()) - for item in self.session.genitems([modcol]): - ev = basic_run_report(item) - rep.processevent(ev) + try: + for item in self.session.genitems([modcol]): + ev = basic_run_report(item) + rep.processevent(ev) + except KeyboardInterrupt: + excinfo = py.code.ExceptionInfo() + else: + py.test.fail("no KeyboardInterrupt??") s = popvalue(stringio) - assert s.find("test_keyboard_interrupt.py Fs") != -1 - rep.processevent(event.TestrunFinish(exitstatus=2)) + if not verbose: + assert s.find("_keyboard_interrupt.py Fs") != -1 + rep.processevent(event.TestrunFinish(exitstatus=2, excinfo=excinfo)) assert_stringio_contains_lines(stringio, [ " def test_foobar():", "> assert 0", "E assert 0", ]) - assert "Skipped: 'skip me please!'" in stringio.getvalue() + text = stringio.getvalue() + assert "Skipped: 'skip me please!'" in text + assert "_keyboard_interrupt.py:6: KeyboardInterrupt" in text + see_details = "raise KeyboardInterrupt # simulating the user" in text + assert see_details == verbose + + def test_verbose_keyboard_interrupt(self): + self.test_keyboard_interrupt(verbose=True) diff --git a/py/test/session.py b/py/test/session.py index 6c6e05287..daafe4f70 100644 --- a/py/test/session.py +++ b/py/test/session.py @@ -103,9 +103,10 @@ class Session(object): if self.config.option.exitfirst: self.shouldstop = True - def sessionfinishes(self, exitstatus=0): + def sessionfinishes(self, exitstatus=0, excinfo=None): """ teardown any resources after a test run. """ - self.bus.notify(event.TestrunFinish(exitstatus=exitstatus)) + self.bus.notify(event.TestrunFinish(exitstatus=exitstatus, + excinfo=excinfo)) self.bus.unsubscribe(self._processfailures) #self.reporter.deactivate() return self._failurelist @@ -123,6 +124,7 @@ class Session(object): self.sessionstarts() self.bus.notify(makehostup()) exitstatus = outcome.EXIT_OK + captured_excinfo = None try: for item in self.collect(colitems): if self.shouldstop: @@ -131,13 +133,14 @@ class Session(object): self.runtest(item) py.test.collect.Item._setupstate.teardown_all() except KeyboardInterrupt: + captured_excinfo = py.code.ExceptionInfo() exitstatus = outcome.EXIT_INTERRUPTED except: self.bus.notify(event.InternalException()) exitstatus = outcome.EXIT_INTERNALERROR if self._failurelist and exitstatus == 0: exitstatus = outcome.EXIT_TESTSFAILED - self.sessionfinishes(exitstatus=exitstatus) + self.sessionfinishes(exitstatus=exitstatus, excinfo=captured_excinfo) return exitstatus def runpdb(self, excinfo):