diff --git a/sceptre/cli/helpers.py b/sceptre/cli/helpers.py index b5749c529..fd82a2c16 100644 --- a/sceptre/cli/helpers.py +++ b/sceptre/cli/helpers.py @@ -27,16 +27,23 @@ def catch_exceptions(func): simplified. :returns: The decorated function. """ + def logging_level(): + logger = logging.getLogger(__name__) + return logger.getEffectiveLevel() + @wraps(func) def decorated(*args, **kwargs): """ Invokes ``func``, catches expected errors, prints the error message and - exits sceptre with a non-zero exit code. + exits sceptre with a non-zero exit code. In debug mode, the original + exception is re-raised to assist debugging. """ try: return func(*args, **kwargs) except (SceptreException, BotoCoreError, ClientError, Boto3Error, TemplateError) as error: + if logging_level() == logging.DEBUG: + raise write(error) sys.exit(1) diff --git a/tests/test_cli.py b/tests/test_cli.py index 1fe02ac21..e90aac5fe 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -56,7 +56,7 @@ def teardown_method(self, test_method): self.patcher_StackActions.stop() @patch("sys.exit") - def test_catch_excecptions(self, mock_exit): + def test_catch_exceptions(self, mock_exit): @catch_exceptions def raises_exception(): raise SceptreException() @@ -64,6 +64,17 @@ def raises_exception(): raises_exception() mock_exit.assert_called_once_with(1) + def test_catch_exceptions_debug_mode(self): + @catch_exceptions + def raises_exception(): + raise SceptreException() + + logger = logging.getLogger("sceptre") + logger.setLevel(logging.DEBUG) + + with pytest.raises(SceptreException): + raises_exception() + @pytest.mark.parametrize("command,files,output", [ # one --var option (