Spaces:
Runtime error
Runtime error
Download tool.py from piotrekgrl/smolagents-local-python-debugger-tool: direct link, hf CLI and curl.
- Browser
- Download file 4.78 kB
-
https://huggingface.co/spaces/piotrekgrl/smolagents-local-python-debugger-tool/resolve/main/tool.py
- Command line
-
hf download hf://spaces/piotrekgrl/smolagents-local-python-debugger-tool/tool.py
-
curl -L -o tool.py https://huggingface.co/spaces/piotrekgrl/smolagents-local-python-debugger-tool/resolve/main/tool.py
4.78 kB
| from smolagents.tools import Tool | |
| import pdb | |
| import smolagents | |
| import io | |
| import sys | |
| class LocalPythonDebuggerTool(Tool): | |
| name = "local-python-debugger" | |
| description = """ | |
| The Local Python Debugger Tool is designed to assist in debugging InterpreterErrors—specifically, errors related to "Code execution failed at line". | |
| It is not intended for other types of InterpreterErrors, such as: | |
| - "Reached the max number of operations" | |
| - "Code parsing failed on line" | |
| The tool debugs code executed in the following manner: | |
| ```python | |
| expression = ast.parse(code) | |
| for node in expression.body: | |
| result = evaluate_ast(node, ...) | |
| ``` | |
| where evaluate_ast processes the Abstract Syntax Tree (AST) by evaluating AST functions like: ast.Assign, ast.AugAssign, ast.Call, ast.Constant, ast.Name, ast.BinOp, etc. | |
| As a result, the debugger output reflects the evaluate_ast execution context rather than a direct Python runtime environment. | |
| Possible debugger commands: | |
| - bt - Shows the full stack trace, helping to understand where the error occurred in the call stack. | |
| - args - Shows the arguments passed to the function. | |
| - l - Lists the source code of the current file. | |
| - p {variable} - Prints the value of the variable. NOTE: variable names are different than in the code. They should be inspected first with `l` command. | |
| """ | |
| inputs = {'code': {'type': 'string', 'description': 'code to debug'}, 'command': {'type': 'string', 'description': 'pdb command to execute'}} | |
| output_type = "string" | |
| def setup(self): | |
| from smolagents import LocalPythonInterpreter | |
| from smolagents.default_tools import FinalAnswerTool | |
| import io | |
| import pdb | |
| self.python_executor = LocalPythonInterpreter( | |
| [], | |
| {"final_answer": FinalAnswerTool()}, | |
| max_print_outputs_length=None, | |
| ) | |
| self.output_capture = io.StringIO() | |
| self.pdb_instance = pdb.Pdb(stdout=self.output_capture) | |
| def wrap_code_with_trycatch(self, code: str) -> str: | |
| from smolagents.utils import parse_code_blobs | |
| try: | |
| code = parse_code_blobs(code) | |
| except Exception as e: | |
| pass | |
| code_lines = code.split("\n") | |
| for i, line in enumerate(code_lines): | |
| code_lines[i] = f"\t{line}" | |
| code = "\n".join(code_lines) | |
| # add extra indentation | |
| code = ( | |
| f"try:\n{code}\n" + "except Exception as e:" + "\n\t" + "out=sys.exc_info()" | |
| ) | |
| code = "out=None" + "\n" + code + "\n" + "out" # provide results in output | |
| return code | |
| def execute_code(self, code: str, state: dict): | |
| from smolagents.utils import parse_code_blobs | |
| code = parse_code_blobs(code) | |
| # Silencing the tool_validation error: execute_code: Name '' is undefined. | |
| py_executor_output = None | |
| py_executor_logs = None | |
| py_executor_is_final_answer = None | |
| py_executor_output, py_executor_logs, py_executor_is_final_answer = ( | |
| self.python_executor(code, state) | |
| ) | |
| return py_executor_output, py_executor_logs, py_executor_is_final_answer | |
| def execude_pdb_command( | |
| self, command: str, traceback | |
| ): | |
| output = None | |
| try: | |
| # Set up the pdb instance with the current frame and traceback | |
| frame = traceback.tb_frame | |
| while frame.f_back: | |
| frame = frame.f_back | |
| self.pdb_instance.reset() | |
| self.pdb_instance.setup(frame, traceback) | |
| # Execute the pdb command | |
| self.pdb_instance.onecmd(command) | |
| # Retrieve the output | |
| output = self.output_capture.getvalue() | |
| finally: | |
| # Clear the output capture for future use | |
| self.output_capture.truncate(0) | |
| self.output_capture.seek(0) | |
| return output | |
| def forward(self, code: str, command: str): | |
| import sys | |
| code = self.wrap_code_with_trycatch(code) | |
| state = {"sys": sys} | |
| # Silencing the tool_validation error: execute_code: Name '' is undefined. | |
| py_executor_output = None | |
| tb = None | |
| py_executor_output, py_executor_logs, py_executor_is_final_answer = ( | |
| self.execute_code(code, state) | |
| ) | |
| if py_executor_output is not None: | |
| try: | |
| exc_type, exc_value, tb = py_executor_output | |
| except Exception as e: | |
| return "No traceback found" | |
| pdb_result = self.execude_pdb_command(command, tb) | |
| return pdb_result | |
| return "No traceback found" | |
| def __init__(self, *args, **kwargs): | |
| self.is_initialized = False | |