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

Laurent Peuch cortex at worlddomination.be
Thu Jul 25 12:23:20 CEST 2019


# HG changeset patch
# User Laurent Peuch <cortex at worlddomination.be>
# Date 1564018381 -7200
#      Thu Jul 25 03:33:01 2019 +0200
# Node ID 77505612c086fa21b95632937439bc133beb79a6
# Parent  ae0c09ff6be8469fb9283b89135e4c7c53ac7c6d
[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.

diff --git a/cubicweb/cwctl.py b/cubicweb/cwctl.py
--- a/cubicweb/cwctl.py
+++ b/cubicweb/cwctl.py
@@ -139,10 +139,17 @@ class InstanceCommand(Command):
         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/except 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:
+            # idem
+            exception_type, exception, traceback_ = sys.exc_info()
+
             import traceback
             traceback.print_exc()
 
@@ -151,6 +158,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,7 +168,6 @@ 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_)
 
diff --git a/cubicweb/test/unittest_cwctl.py b/cubicweb/test/unittest_cwctl.py
--- a/cubicweb/test/unittest_cwctl.py
+++ b/cubicweb/test/unittest_cwctl.py
@@ -139,6 +139,9 @@ class InstanceCommandTest(unittest.TestC
         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']



More information about the cubicweb-devel mailing list