[cubicweb-ctl] respect sys.exit status code when aborting a command
authorLaurent Peuch <cortex@worlddomination.be>
Mon, 22 Jul 2019 11:21:10 +0200
changeset 12696 eb83daa69495
parent 12695 38dfd90c335a
child 12709 280c9db41038
[cubicweb-ctl] respect sys.exit status code when aborting a command When exploring the stack of all calls to a cubicweb-ctl command, it has been discovered than on a KeyboardInterrupt and on a SystemExit exception the base class InstanceCommand (for commands that works on one instance) will always set the return code of cubicweb-ctl to 8: this mean that if another command do a `sys.exit(some_code)` the exit code will be ignored and overwritten by '8'. This behavior is not intuitive, apparently not documented and doesn't seems to have any justification. It also prevent commands from exciting with different return codes which could be a desired behavior in the situation of scripting.
cubicweb/cwctl.py
cubicweb/test/unittest_cwctl.py
--- a/cubicweb/cwctl.py	Mon Jul 22 11:32:12 2019 +0200
+++ b/cubicweb/cwctl.py	Mon Jul 22 11:21:10 2019 +0200
@@ -150,9 +150,12 @@
                 appid, self.actionverb, ex))
             status = 8
 
-        except (KeyboardInterrupt, SystemExit):
+        except (KeyboardInterrupt, SystemExit) as ex:
             sys.stderr.write('%s aborted\n' % self.name)
-            status = 2  # specific error code
+            if isinstance(ex, KeyboardInterrupt):
+                status = 2  # specific error code
+            else:
+                status = ex.code
 
         if status != 0 and self.config.pdb:
             exception_type, exception, traceback_ = sys.exc_info()
--- a/cubicweb/test/unittest_cwctl.py	Mon Jul 22 11:32:12 2019 +0200
+++ b/cubicweb/test/unittest_cwctl.py	Mon Jul 22 11:21:10 2019 +0200
@@ -148,6 +148,22 @@
 
         ipdb.post_mortem.assert_called_once()
 
+    @patch.object(_TestFailCommand, 'test_fail_instance', side_effect=SystemExit(42))
+    def test_respect_return_error_code(self, test_fail_instance):
+        with self.assertRaises(SystemExit) as cm:
+            self.CWCTL.run(["test_fail", "some_instance"])
+        self.assertEqual(cm.exception.code, 42)
+
+        test_fail_instance.assert_called_once()
+
+    @patch.object(_TestFailCommand, 'test_fail_instance', side_effect=KeyboardInterrupt)
+    def test_error_code_keyboardinterupt_2(self, test_fail_instance):
+        with self.assertRaises(SystemExit) as cm:
+            self.CWCTL.run(["test_fail", "some_instance"])
+        self.assertEqual(cm.exception.code, 2)
+
+        test_fail_instance.assert_called_once()
+
 
 if __name__ == '__main__':
     unittest.main()