def main(): args = docopt(__doc__, more_magic=True) _update_argv_from_docopt(args) active_project = None if project.check_for_project(): active_project = project.load() active_project.load_config() print(f"{active_project._name} is the active project.") network.connect(CONFIG.argv["network"]) path, _ = _get_path(args["<filename>"]) path_str = path.absolute().as_posix() try: return_value, frame = run( args["<filename>"], method_name=args["<function>"] or "main", args=args["<arg>"], _include_frame=True, ) exit_code = 0 except Exception as e: print(color.format_tb(e)) frame = next( (i.frame for i in inspect.trace()[::-1] if Path(i.filename).as_posix() == path_str), None, ) if frame is None: # exception was an internal brownie issue - do not open the console sys.exit(1) exit_code = 1 return_value = None try: if args["--interactive"]: # filter internal objects from the namespace prior to opening the console globals_dict = { k: v for k, v in frame.f_globals.items() if not k.startswith("__") } extra_locals = { "_": return_value, **globals_dict, **frame.f_locals } shell = Console(active_project, extra_locals) shell.interact( banner="\nInteractive mode enabled. Use quit() to close.", exitmsg="") finally: # the console terminates from a SystemExit - make sure we still deliver the final gas report if CONFIG.argv["gas"]: print("\n======= Gas profile =======") for line in _build_gas_profile_output(): print(line) sys.exit(exit_code)
def main(): args = docopt(__doc__) _update_argv_from_docopt(args) if project.check_for_project(): active_project = project.load() active_project.load_config() print(f"{active_project._name} is the active project.") else: raise ProjectNotFound network.connect(CONFIG.argv["network"]) path, _ = _get_path(args["<filename>"]) path_str = path.absolute().as_posix() try: run(args["<filename>"], method_name=args["<function>"] or "main") except Exception as e: print(color.format_tb(e)) if args["--interactive"]: frame = next( (i.frame for i in inspect.trace()[::-1] if Path(i.filename).as_posix() == path_str), None, ) if frame is not None: globals_dict = { k: v for k, v in frame.f_globals.items() if not k.startswith("__") } shell = Console(active_project, { **globals_dict, **frame.f_locals }) shell.interact( banner="\nInteractive mode enabled. Use quit() to close.", exitmsg="") sys.exit(1) if CONFIG.argv["gas"]: print("\n======= Gas profile =======") for line in _build_gas_profile_output(): print(line)
def pytest_exception_interact(self, report, call): """ Called when an exception was raised which can potentially be interactively handled. With the `--interactive` flag, outputs the full repr of the failed test and opens an interactive shell using `brownie._cli.console.Console`. Arguments --------- report : _pytest.reports.BaseReport Report object for the failed test. call : _pytest.runner.CallInfo Result/Exception info for the failed test. """ if self.config.getoption("interactive") and report.failed: capman = self.config.pluginmanager.get_plugin("capturemanager") if capman: capman.suspend_global_capture(in_=True) tw = TerminalWriter() report.longrepr.toterminal(tw) locals_dict = call.excinfo.traceback[-1].locals locals_dict = {k: v for k, v in locals_dict.items() if not k.startswith("@")} try: CONFIG.argv["cli"] = "console" shell = Console(self.project, extra_locals={"_callinfo": call, **locals_dict}) shell.interact( banner=f"\nInteractive mode enabled. Use quit() to continue running tests.", exitmsg="", ) except SystemExit: pass finally: CONFIG.argv["cli"] = "test" print("Continuing tests...") if capman: capman.resume_global_capture()
def pytest_exception_interact(self, report, call): """ Called when an exception was raised which can potentially be interactively handled. With the `--interactive` flag, outputs the full repr of the failed test and opens an interactive shell using `brownie._cli.console.Console`. Arguments --------- report : _pytest.reports.BaseReport Report object for the failed test. call : _pytest.runner.CallInfo Result/Exception info for the failed test. """ if self.config.getoption("interactive") and report.failed: location = self._path(report.location[0]) if location not in self.node_map: # if the exception happened prior to collection it is likely a # SyntaxError and we cannot open an interactive debugger return capman = self.config.pluginmanager.get_plugin("capturemanager") if capman: capman.suspend_global_capture(in_=True) tw = TerminalWriter() report.longrepr.toterminal(tw) # find last traceback frame within the active test excinfo = call.excinfo traceback = next( (i for i in excinfo.traceback[::-1] if Path(i.path).as_posix().endswith(location)), excinfo.traceback[-1], ) # get global namespace globals_dict = traceback.frame.f_globals # filter python internals and pytest internals globals_dict = { k: v for k, v in globals_dict.items() if not k.startswith("__") } globals_dict = { k: v for k, v in globals_dict.items() if not k.startswith("@") } # filter test functions and fixtures test_names = self.node_map[location] globals_dict = { k: v for k, v in globals_dict.items() if k not in test_names } globals_dict = { k: v for k, v in globals_dict.items() if not hasattr(v, "_pytestfixturefunction") } # get local namespace locals_dict = traceback.locals locals_dict = { k: v for k, v in locals_dict.items() if not k.startswith("@") } namespace = {"_callinfo": call, **globals_dict, **locals_dict} if "tx" not in namespace and brownie.history: # make it easier to look at the most recent transaction namespace["tx"] = brownie.history[-1] try: CONFIG.argv["cli"] = "console" 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.") 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" print("Continuing tests...") if capman: capman.resume_global_capture()
def pytest_exception_interact(self, report, call): """ Called when an exception was raised which can potentially be interactively handled. With the `--interactive` flag, outputs the full repr of the failed test and opens an interactive shell using `brownie._cli.console.Console`. Arguments --------- report : _pytest.reports.BaseReport Report object for the failed test. call : _pytest.runner.CallInfo Result/Exception info for the failed test. """ if self.config.getoption("interactive") and report.failed: capman = self.config.pluginmanager.get_plugin("capturemanager") if capman: capman.suspend_global_capture(in_=True) tw = TerminalWriter() report.longrepr.toterminal(tw) location = self._path(report.location[0]) # find last traceback frame within the active test traceback = next( (i for i in call.excinfo.traceback[::-1] if i.path.strpath.endswith(location)), call.excinfo.traceback[-1], ) # get global namespace globals_dict = traceback.frame.f_globals # filter python internals and pytest internals globals_dict = { k: v for k, v in globals_dict.items() if not k.startswith("__") } globals_dict = { k: v for k, v in globals_dict.items() if not k.startswith("@") } # filter test functions test_names = self.node_map[location] globals_dict = { k: v for k, v in globals_dict.items() if k not in test_names } # get local namespace locals_dict = traceback.locals locals_dict = { k: v for k, v in locals_dict.items() if not k.startswith("@") } namespace = {"_callinfo": call, **globals_dict, **locals_dict} try: CONFIG.argv["cli"] = "console" shell = Console(self.project, extra_locals=namespace) shell.interact( banner= f"\nInteractive mode enabled. Use quit() to continue running tests.", exitmsg="", ) except SystemExit: pass finally: CONFIG.argv["cli"] = "test" print("Continuing tests...") if capman: capman.resume_global_capture()
def console(ctx): """Interactive shell.""" shell = Console(project=ctx.obj["brownie_project"]) shell.interact(banner="Argobytes environment is ready.", exitmsg="Goodbye!")