Skip to content

Commit b87dc6e

Browse files
authored
fix: Subprocess interpreter don't have output (camel-ai#1590)
1 parent 2ed9c02 commit b87dc6e

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

camel/interpreters/subprocess_interpreter.py

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,70 @@ def run_file(
9898
if not file.is_file():
9999
raise RuntimeError(f"{file} is not a file.")
100100
code_type = self._check_code_type(code_type)
101-
cmd = shlex.split(
102-
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
103-
file_name=str(file)
101+
if code_type == "python":
102+
# For Python code, use ast to analyze and modify the code
103+
import ast
104+
105+
import astor
106+
107+
with open(file, 'r') as f:
108+
source = f.read()
109+
110+
# Parse the source code
111+
try:
112+
tree = ast.parse(source)
113+
# Get the last node
114+
if tree.body:
115+
last_node = tree.body[-1]
116+
# If it's an expression, wrap it in a print
117+
if isinstance(last_node, ast.Expr):
118+
tree.body[-1] = ast.Expr(
119+
value=ast.Call(
120+
func=ast.Name(id='print', ctx=ast.Load()),
121+
args=[
122+
ast.Call(
123+
func=ast.Name(
124+
id='repr', ctx=ast.Load()
125+
),
126+
args=[last_node.value],
127+
keywords=[],
128+
)
129+
],
130+
keywords=[],
131+
)
132+
)
133+
# Fix missing source locations
134+
ast.fix_missing_locations(tree)
135+
# Convert back to source
136+
modified_source = astor.to_source(tree)
137+
# Create a temporary file with the modified source
138+
temp_file = self._create_temp_file(modified_source, "py")
139+
cmd = shlex.split(f"python {temp_file!s}")
140+
except SyntaxError:
141+
# If parsing fails, run the original file
142+
cmd = shlex.split(
143+
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
144+
file_name=str(file)
145+
)
146+
)
147+
else:
148+
# For non-Python code, use standard execution
149+
cmd = shlex.split(
150+
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
151+
file_name=str(file)
152+
)
104153
)
105-
)
154+
106155
proc = subprocess.Popen(
107156
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
108157
)
109158
stdout, stderr = proc.communicate()
159+
return_code = proc.returncode
160+
161+
# Clean up temporary file if it was created
162+
if code_type == "python" and 'temp_file' in locals():
163+
temp_file.unlink()
164+
110165
if self.print_stdout and stdout:
111166
print("======stdout======")
112167
print(Fore.GREEN + stdout + Fore.RESET)
@@ -115,8 +170,19 @@ def run_file(
115170
print("======stderr======")
116171
print(Fore.RED + stderr + Fore.RESET)
117172
print("==================")
118-
exec_result = f"{stdout}"
119-
exec_result += f"(stderr: {stderr})" if stderr else ""
173+
174+
# Build the execution result
175+
exec_result = ""
176+
if stdout:
177+
exec_result += stdout
178+
if stderr:
179+
exec_result += f"(stderr: {stderr})"
180+
if return_code != 0:
181+
error_msg = f"(Execution failed with return code {return_code})"
182+
if not stderr:
183+
exec_result += error_msg
184+
elif error_msg not in stderr:
185+
exec_result += error_msg
120186
return exec_result
121187

122188
def run(

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,5 +538,6 @@ module = [
538538
"pandasai",
539539
"sklearn.metrics.pairwise",
540540
"sympy",
541+
"astor",
541542
]
542543
ignore_missing_imports = true

test/prompts/test_prompt_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def test_code_prompt_execute(monkeypatch):
140140
"a = 1\nprint('Hello, World!')", code_type="python"
141141
)
142142
result = code_prompt.execute()
143-
assert result == "Hello, World!\n"
143+
assert result == "Hello, World!\nNone\n"
144144

145145

146146
def test_code_prompt_execute_error(monkeypatch):

0 commit comments

Comments
 (0)