Example #1
0
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)
Example #2
0
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)
Example #3
0
def console(testproject, monkeypatch):
    monkeypatch.setattr("brownie._cli.console.Console.showtraceback", _exception)
    monkeypatch.setattr("brownie._cli.console.Console.showsyntaxerror", _exception)
    argv = sys.argv
    sys.argv = ["brownie", "console"]
    c = Console(testproject, create_pipe_input())
    yield c
    sys.argv = argv
Example #4
0
    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()
Example #5
0
    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()
Example #6
0
    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!")
Example #8
0
def console(testproject):
    argv = sys.argv
    sys.argv = ["brownie", "console"]
    c = Console(testproject)
    yield c
    sys.argv = argv