Commit c8379ac0 authored by Laurent Peuch's avatar Laurent Peuch
Browse files

[cubicweb-ctl/fix] correctly get exception traceback_ for pdb.post_mortem

In python 3 the behavior of sys.exc_info had a very subtle change:

- in python 2 you can call if whenever you want after a try/except statement
  and you'll get information about this last raise
- ipython 3, once you get out of try/except, sys.exc_info is cleaned and you'll
  get (None, None, None)

Hardened the test to avoid this error from happening again.
parent d177d8ab4fd3
......@@ -22,6 +22,7 @@ provide a pluggable commands system.
# possible (for cubicweb-ctl reactivity, necessary for instance for usable bash
# completion). So import locally in command helpers.
import sys
import traceback
from warnings import filterwarnings
from os import listdir
from os.path import exists, join, isdir
......@@ -136,14 +137,22 @@ class InstanceCommand(Command):
appid = args[0]
cmdmeth = getattr(self, '%s_instance' % self.name)
traceback_ = None
try:
status = cmdmeth(appid) or 0
except (ExecutionError, ConfigurationError) as ex:
# we need to do extract this information here for pdb since it is
# now lost in python 3 once we exit the try/catch statement
exception_type, exception, traceback_ = sys.exc_info()
sys.stderr.write('instance %s not %s: %s\n' % (
appid, self.actionverb, ex))
status = 4
except Exception as ex:
import traceback
# idem
exception_type, exception, traceback_ = sys.exc_info()
traceback.print_exc()
sys.stderr.write('instance %s not %s: %s\n' % (
......@@ -151,6 +160,9 @@ class InstanceCommand(Command):
status = 8
except (KeyboardInterrupt, SystemExit) as ex:
# idem
exception_type, exception, traceback_ = sys.exc_info()
sys.stderr.write('%s aborted\n' % self.name)
if isinstance(ex, KeyboardInterrupt):
status = 2 # specific error code
......@@ -158,9 +170,15 @@ class InstanceCommand(Command):
status = ex.code
if status != 0 and self.config.pdb:
exception_type, exception, traceback_ = sys.exc_info()
pdb = get_pdb()
pdb.post_mortem(traceback_)
if traceback_ is not None:
pdb.post_mortem(traceback_)
else:
print("WARNING: Could not access to the traceback because the command return "
"code is different than 0 but the command didn't raised an exception.")
# we can't use "header=" of set_trace because ipdb doesn't supports it
pdb.set_trace()
sys.exit(status)
......
......@@ -139,6 +139,9 @@ class InstanceCommandTest(unittest.TestCase):
get_pdb.assert_called_once()
post_mortem.assert_called_once()
# we want post_mortem to actually receive the traceback
self.assertNotEqual(post_mortem.call_args, ((None,),))
@patch.dict(sys.modules, ipdb=MagicMock())
def test_ipdb_selected_and_called(self):
ipdb = sys.modules['ipdb']
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment