blessingmwiti commited on
Commit
8ad53dd
·
1 Parent(s): ea20131

Auto-run zero-arg Python functions in sandbox

Browse files
Files changed (1) hide show
  1. app.py +48 -1
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import json
2
  import os
3
  import re
 
4
  from pathlib import Path
5
 
6
  import gradio as gr
@@ -266,7 +267,7 @@ async def run_sandbox(language: str, draft_code: str, verdict_json: str) -> str:
266
  if language.lower() != "python":
267
  return "Sandbox execution is currently wired for Python only."
268
 
269
- code = code_from_verdict(draft_code, verdict_json)
270
  if not code.strip():
271
  return "No generated code is available yet."
272
 
@@ -287,6 +288,52 @@ async def run_sandbox(language: str, draft_code: str, verdict_json: str) -> str:
287
  )
288
 
289
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  with gr.Blocks(
291
  title="Split-Brain Co-Pilot",
292
  css=load_static("style.css"),
 
1
  import json
2
  import os
3
  import re
4
+ import ast
5
  from pathlib import Path
6
 
7
  import gradio as gr
 
267
  if language.lower() != "python":
268
  return "Sandbox execution is currently wired for Python only."
269
 
270
+ code = prepare_python_for_sandbox(code_from_verdict(draft_code, verdict_json))
271
  if not code.strip():
272
  return "No generated code is available yet."
273
 
 
288
  )
289
 
290
 
291
+ def prepare_python_for_sandbox(code: str) -> str:
292
+ code = strip_markdown_code_fence(code)
293
+ try:
294
+ tree = ast.parse(code)
295
+ except SyntaxError:
296
+ return code
297
+
298
+ executable_nodes = (
299
+ ast.Assign,
300
+ ast.AugAssign,
301
+ ast.AnnAssign,
302
+ ast.Assert,
303
+ ast.Delete,
304
+ ast.Expr,
305
+ ast.For,
306
+ ast.AsyncFor,
307
+ ast.While,
308
+ ast.If,
309
+ ast.Match,
310
+ ast.Raise,
311
+ ast.Return,
312
+ ast.Try,
313
+ ast.With,
314
+ ast.AsyncWith,
315
+ )
316
+ has_top_level_execution = any(isinstance(node, executable_nodes) for node in tree.body)
317
+ if has_top_level_execution:
318
+ return code
319
+
320
+ for node in tree.body:
321
+ if isinstance(node, ast.FunctionDef) and function_has_no_required_args(node):
322
+ return f'{code}\n\nif __name__ == "__main__":\n {node.name}()\n'
323
+
324
+ return code
325
+
326
+
327
+ def function_has_no_required_args(node: ast.FunctionDef) -> bool:
328
+ args = node.args
329
+ positional = [*args.posonlyargs, *args.args]
330
+ required_positional = len(positional) - len(args.defaults)
331
+ required_kwonly = sum(
332
+ 1 for arg, default in zip(args.kwonlyargs, args.kw_defaults) if default is None
333
+ )
334
+ return required_positional == 0 and required_kwonly == 0
335
+
336
+
337
  with gr.Blocks(
338
  title="Split-Brain Co-Pilot",
339
  css=load_static("style.css"),