diff --git a/brownie/_cli/console.py b/brownie/_cli/console.py index 5a47c2e75..72c9e2440 100644 --- a/brownie/_cli/console.py +++ b/brownie/_cli/console.py @@ -85,7 +85,7 @@ class Console(code.InteractiveConsole): # replaced with `prompt_toolkit.input.defaults.create_pipe_input` prompt_input = None - def __init__(self, project=None, extra_locals=None): + def __init__(self, project=None, extra_locals=None, exit_on_continue=False): """ Launch the Brownie console. @@ -95,6 +95,9 @@ def __init__(self, project=None, extra_locals=None): Active Brownie project to include in the console's local namespace. extra_locals: dict, optional Additional variables to add to the console namespace. + exit_on_continue: bool, optional + If True, the `continue` command causes the console to + raise a SystemExit with error message "continue". """ console_settings = CONFIG.settings["console"] @@ -103,6 +106,11 @@ def __init__(self, project=None, extra_locals=None): _dir=dir, dir=self._dir, exit=_Quitter("exit"), quit=_Quitter("quit"), _console=self ) + self.exit_on_continue = exit_on_continue + if exit_on_continue: + # add continue to the locals so we can quickly reach it via completion hints + locals_dict["continue"] = True + if project: project._update_and_register(locals_dict) @@ -218,6 +226,10 @@ def runsource(self, source, filename="", symbol="single"): mode = self.compile_mode self.compile_mode = "single" + if source == "continue" and self.exit_on_continue: + # used to differentiate exit and continue for pytest interactive debugging + raise SystemExit("continue") + try: code = self.compile(source, filename, mode) except (OverflowError, SyntaxError, ValueError): diff --git a/brownie/test/managers/runner.py b/brownie/test/managers/runner.py index 4e305748d..2be3bfe8f 100644 --- a/brownie/test/managers/runner.py +++ b/brownie/test/managers/runner.py @@ -466,13 +466,15 @@ def pytest_exception_interact(self, report, call): try: CONFIG.argv["cli"] = "console" - shell = Console(self.project, extra_locals=namespace) - shell.interact( - banner="\nInteractive mode enabled. Use quit() to continue running tests.", - exitmsg="", + shell = Console(self.project, extra_locals=namespace, exit_on_continue=True) + banner = ( + "\nInteractive mode enabled. Type `continue` to" + " resume testing or `quit()` to halt execution." ) - except SystemExit: - pass + shell.interact(banner=banner, exitmsg="") + except SystemExit as exc: + if exc.code != "continue": + pytest.exit("Test execution halted due to SystemExit") finally: CONFIG.argv["cli"] = "test"