# HG changeset patch # User Laurent Peuch # Date 1558450033 -7200 # Node ID 8673da7c2f85cac1ef732bdde251c6d9038a31d9 # Parent 3f0e64630d9413ebad9bed530bad8ff4c77e81c9 [cubicweb-ctl] add '--pdb' global option to launch (i)pdb on exception diff -r 3f0e64630d94 -r 8673da7c2f85 cubicweb/cwctl.py --- a/cubicweb/cwctl.py Mon Jul 22 10:54:22 2019 +0200 +++ b/cubicweb/cwctl.py Tue May 21 16:47:13 2019 +0200 @@ -97,6 +97,16 @@ return [drop_prefix(cube) for cube in cwcfg.available_cubes()] +def get_pdb(): + try: + import ipdb + except ImportError: + import pdb + return pdb + else: + return ipdb + + class InstanceCommand(Command): """base class for command taking one instance id as arguments""" arguments = '' @@ -111,6 +121,11 @@ 'help': 'force command without asking confirmation', } ), + ("pdb", + {'action': 'store_true', 'default': False, + 'help': 'launch pdb on exception', + } + ), ) actionverb = None @@ -130,6 +145,7 @@ except Exception as ex: import traceback traceback.print_exc() + sys.stderr.write('instance %s not %s: %s\n' % ( appid, self.actionverb, ex)) status = 8 @@ -138,6 +154,11 @@ sys.stderr.write('%s aborted\n' % self.name) status = 2 # specific error code + if status != 0 and self.config.pdb: + exception_type, exception, traceback_ = sys.exc_info() + pdb = get_pdb() + pdb.post_mortem(traceback_) + sys.exit(status) diff -r 3f0e64630d94 -r 8673da7c2f85 cubicweb/test/unittest_cwctl.py --- a/cubicweb/test/unittest_cwctl.py Mon Jul 22 10:54:22 2019 +0200 +++ b/cubicweb/test/unittest_cwctl.py Tue May 21 16:47:13 2019 +0200 @@ -24,6 +24,7 @@ from logilab.common.clcommands import CommandLine +from cubicweb import cwctl from cubicweb.cwctl import ListCommand, InstanceCommand from cubicweb.devtools.testlib import CubicWebTC from cubicweb.server.migractions import ServerMigrationHelper @@ -89,24 +90,64 @@ pass +class _TestFailCommand(InstanceCommand): + "I need some doc" + name = "test_fail" + + def test_fail_instance(self, appid): + raise Exception() + + class InstanceCommandTest(unittest.TestCase): - def test_getting_called(self): - CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.', - version=cw_version, check_duplicated_command=False) + def setUp(self): + self.CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.', + version=cw_version, check_duplicated_command=False) cwcfg.load_cwctl_plugins() - CWCTL.register(_TestCommand) - - _TestCommand.test_instance = MagicMock(return_value=0) + self.CWCTL.register(_TestCommand) + self.CWCTL.register(_TestFailCommand) # pretend that this instance exists cwcfg.config_for = MagicMock(return_value=object()) + def test_getting_called(self): + _TestCommand.test_instance = MagicMock(return_value=0) + try: - CWCTL.run(["test", "some_instance"]) + self.CWCTL.run(["test", "some_instance"]) except SystemExit as ex: # CWCTL will finish the program after that self.assertEqual(ex.code, 0) _TestCommand.test_instance.assert_called_with("some_instance") + @patch.object(cwctl, 'get_pdb') + def test_pdb_not_called(self, get_pdb): + try: + self.CWCTL.run(["test", "some_instance"]) + except SystemExit as ex: # CWCTL will finish the program after that + self.assertEqual(ex.code, 0) + + get_pdb.assert_not_called() + + @patch.object(cwctl, 'get_pdb') + def test_pdb_called(self, get_pdb): + post_mortem = get_pdb.return_value.post_mortem + try: + self.CWCTL.run(["test_fail", "some_instance", "--pdb"]) + except SystemExit as ex: # CWCTL will finish the program after that + self.assertEqual(ex.code, 8) + + get_pdb.assert_called_once() + post_mortem.assert_called_once() + + @patch.dict(sys.modules, ipdb=MagicMock()) + def test_ipdb_selected_and_called(self): + ipdb = sys.modules['ipdb'] + try: + self.CWCTL.run(["test_fail", "some_instance", "--pdb"]) + except SystemExit as ex: # CWCTL will finish the program after that + self.assertEqual(ex.code, 8) + + ipdb.post_mortem.assert_called_once() + if __name__ == '__main__': unittest.main() diff -r 3f0e64630d94 -r 8673da7c2f85 doc/changes/3.27.rst --- a/doc/changes/3.27.rst Mon Jul 22 10:54:22 2019 +0200 +++ b/doc/changes/3.27.rst Tue May 21 16:47:13 2019 +0200 @@ -17,6 +17,9 @@ exist in the instance directory, the `pyramid.ini` file will be generated with the needed secrets. +* add a --pdb flag to all cubicweb-ctl command to launch (i)pdb if an exception + occurs during a command execution. + Backwards incompatible changes ------------------------------