Add support for args to execute_python_file (#3972)

* 🎉 Python scripts can now be executed with arguments through Docker.🎉

* Make args optional

---------

Co-authored-by: k-boikov <64261260+k-boikov@users.noreply.github.com>
Co-authored-by: Reinier van der Leer <reinier.vanderleer@agpt.co>
This commit is contained in:
Mauro Druwel
2023-09-09 03:38:33 +02:00
committed by GitHub
parent 6d7d5ae065
commit 77806700ab
2 changed files with 37 additions and 13 deletions

View File

@@ -79,14 +79,22 @@ def execute_python_code(code: str, agent: Agent) -> str:
"description": "The name of te file to execute",
"required": True,
},
"args": {
"type": "list[str]",
"description": "The (command line) arguments to pass to the script",
"required": False,
},
},
)
@sanitize_path_arg("filename")
def execute_python_file(filename: Path, agent: Agent) -> str:
def execute_python_file(
filename: Path, agent: Agent, args: list[str] | str = []
) -> str:
"""Execute a Python file in a Docker container and return the output
Args:
filename (Path): The name of the file to execute
args (list, optional): The arguments with which to run the python script
Returns:
str: The output of the file
@@ -95,6 +103,9 @@ def execute_python_file(filename: Path, agent: Agent) -> str:
f"Executing python file '{filename}' in working directory '{agent.config.workspace_path}'"
)
if isinstance(args, str):
args = args.split() # Convert space-separated string to a list
if not str(filename).endswith(".py"):
raise InvalidArgumentError("Invalid file type. Only .py files are allowed.")
@@ -110,7 +121,7 @@ def execute_python_file(filename: Path, agent: Agent) -> str:
f"Auto-GPT is running in a Docker container; executing {file_path} directly..."
)
result = subprocess.run(
["python", "-B", str(file_path)],
["python", "-B", str(file_path)] + args,
capture_output=True,
encoding="utf8",
cwd=str(agent.workspace.root),
@@ -152,7 +163,7 @@ def execute_python_file(filename: Path, agent: Agent) -> str:
"python",
"-B",
file_path.relative_to(agent.workspace.root).as_posix(),
],
] + args,
volumes={
str(agent.workspace.root): {
"bind": "/workspace",

View File

@@ -2,6 +2,7 @@ import os
import random
import string
import tempfile
from pathlib import Path
import pytest
@@ -21,12 +22,22 @@ def random_code(random_string) -> str:
@pytest.fixture
def python_test_file(config: Config, random_code: str) -> str:
def python_test_file(config: Config, random_code: str):
temp_file = tempfile.NamedTemporaryFile(dir=config.workspace_path, suffix=".py")
temp_file.write(str.encode(random_code))
temp_file.flush()
yield temp_file.name
yield Path(temp_file.name)
temp_file.close()
@pytest.fixture
def python_test_args_file(config: Config):
temp_file = tempfile.NamedTemporaryFile(dir=config.workspace_path, suffix=".py")
temp_file.write(str.encode("import sys\nprint(sys.argv[1], sys.argv[2])"))
temp_file.flush()
yield Path(temp_file.name)
temp_file.close()
@@ -35,23 +46,25 @@ def random_string():
return "".join(random.choice(string.ascii_lowercase) for _ in range(10))
def test_execute_python_file(python_test_file: str, random_string: str, agent: Agent):
def test_execute_python_file(python_test_file: Path, random_string: str, agent: Agent):
result: str = sut.execute_python_file(python_test_file, agent=agent)
assert result.replace("\r", "") == f"Hello {random_string}!\n"
def test_execute_python_file_args(
python_test_args_file: Path, random_string: str, agent: Agent
):
random_args = [random_string] * 2
random_args_string = " ".join(random_args)
result = sut.execute_python_file(python_test_args_file, agent=agent, random_args)
assert result == f"{random_args_string}\n"
def test_execute_python_code(random_code: str, random_string: str, agent: Agent):
result: str = sut.execute_python_code(random_code, agent=agent)
assert result.replace("\r", "") == f"Hello {random_string}!\n"
def test_execute_python_code_disallows_name_arg_path_traversal(
random_code: str, agent: Agent
):
with pytest.raises(AccessDeniedError, match="path traversal"):
sut.execute_python_code(random_code, agent=agent)
def test_execute_python_code_overwrites_file(random_code: str, agent: Agent):
ai_name = agent.ai_config.ai_name
destination = os.path.join(