Commit 170562ff authored by Laurent Peuch's avatar Laurent Peuch
Browse files

[cubicweb-ctl] add '--pdb' global option to launch (i)pdb on exception

parent 3f0e64630d94
......@@ -97,6 +97,16 @@ def available_cube_names(cwcfg):
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 = '<instance>'
......@@ -111,6 +121,11 @@ class InstanceCommand(Command):
'help': 'force command without asking confirmation',
}
),
("pdb",
{'action': 'store_true', 'default': False,
'help': 'launch pdb on exception',
}
),
)
actionverb = None
......@@ -130,6 +145,7 @@ class InstanceCommand(Command):
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 @@ class InstanceCommand(Command):
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)
......
......@@ -24,6 +24,7 @@ from unittest.mock import patch, MagicMock
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 @@ class _TestCommand(InstanceCommand):
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()
......@@ -17,6 +17,9 @@ New features
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
------------------------------
......
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