( code: string )
| 6 | * Execute Python code and capture outputs |
| 7 | */ |
| 8 | export async function executePythonCode( |
| 9 | code: string |
| 10 | ): Promise<PythonExecutionResult> { |
| 11 | const pyodide = getPyodide(); |
| 12 | if (!pyodide) { |
| 13 | throw new Error('Pyodide not initialized'); |
| 14 | } |
| 15 | |
| 16 | const startTime = performance.now(); |
| 17 | const outputs: CellOutput[] = []; |
| 18 | let error: string | undefined; |
| 19 | |
| 20 | try { |
| 21 | // Setup output capture |
| 22 | await pyodide.runPython(` |
| 23 | import sys |
| 24 | import io |
| 25 | from contextlib import redirect_stdout, redirect_stderr |
| 26 | |
| 27 | # Create string buffers for capturing output |
| 28 | _stdout_buffer = io.StringIO() |
| 29 | _stderr_buffer = io.StringIO() |
| 30 | _output_captured = [] |
| 31 | |
| 32 | # Custom print function to capture output |
| 33 | _original_print = print |
| 34 | def _capture_print(*args, **kwargs): |
| 35 | # Capture in buffer |
| 36 | _original_print(*args, file=_stdout_buffer, **kwargs) |
| 37 | # Also print normally for console |
| 38 | _original_print(*args, **kwargs) |
| 39 | |
| 40 | print = _capture_print |
| 41 | `); |
| 42 | |
| 43 | // Execute the user code |
| 44 | let result; |
| 45 | try { |
| 46 | // Check if code needs async handling |
| 47 | const needsAsync = |
| 48 | code.includes('sql(') || |
| 49 | code.includes('query(') || |
| 50 | code.includes('sql_bridge.') || |
| 51 | code.includes('await ') || |
| 52 | code.includes('micropip.install'); |
| 53 | |
| 54 | if (needsAsync) { |
| 55 | // Use runPythonAsync for code that might call async functions |
| 56 | result = await pyodide.runPythonAsync(code); |
| 57 | } else { |
| 58 | // Use regular runPython for synchronous code |
| 59 | result = pyodide.runPython(code); |
| 60 | } |
| 61 | } catch (pythonError: any) { |
| 62 | error = `${pythonError.name}: ${pythonError.message}`; |
| 63 | |
| 64 | outputs.push({ |
| 65 | id: crypto.randomUUID(), |
no test coverage detected