shell source

Exported source
import ast, time, signal, traceback
from fastcore.utils import *

get_shell is like python, except it also maintains a stateful interpreter, rather than just running a single line of code. This is implemented using IPython, so that must be installed.

Exported source
from IPython.terminal.interactiveshell import TerminalInteractiveShell
from IPython.utils.capture import capture_output
def exception2str(ex:Exception)->str:
    "Convert exception `ex` into a string"
    return ''.join(traceback.format_exception(type(ex), ex, ex.__traceback__))
try: print(1/0)
except Exception as e: print(exception2str(e))
Traceback (most recent call last):
  File "/var/folders/ss/34z569j921v58v8n1n_8z7h40000gn/T/ipykernel_37260/4058275565.py", line 1, in <module>
    try: print(1/0)
               ~^~
ZeroDivisionError: division by zero

source

TerminalInteractiveShell.run_cell

 TerminalInteractiveShell.run_cell (cell, timeout=None)

Wrapper for original run_cell which adds timeout and output capture

Exported source
TerminalInteractiveShell.orig_run = TerminalInteractiveShell.run_cell
Exported source
@patch
def run_cell(self:TerminalInteractiveShell, cell, timeout=None):
    "Wrapper for original `run_cell` which adds timeout and output capture"
    if timeout:
        def handler(*args): raise TimeoutError()
        signal.signal(signal.SIGALRM, handler)
        signal.alarm(timeout)
    try:
        with capture_output() as io: result = self.orig_run(cell)
        result.stdout = io.stdout
        return result
    except TimeoutException as e:
        result = self.ExecutionResult(error_before_exec=None, error_in_exec=e)
    finally:
        if timeout: signal.alarm(0)

source

get_shell

 get_shell ()

Get a TerminalInteractiveShell with minimal functionality

Exported source
def get_shell()->TerminalInteractiveShell:
    "Get a `TerminalInteractiveShell` with minimal functionality"
    sh = TerminalInteractiveShell()
    sh.logger.log_output = sh.history_manager.enabled = False
    dh = sh.displayhook
    dh.finish_displayhook = dh.write_output_prompt = dh.start_displayhook = lambda: None
    dh.write_format_data = lambda format_dict, md_dict=None: None
    sh.logstart = sh.automagic = sh.autoindent = False
    sh.autocall = 0
    sh.system = lambda cmd: None
    return sh
shell = get_shell()
r = shell.run_cell('print(3); 1+1')
r.result,r.stdout
(2, '3\n')
r = shell.run_cell('raise Exception("blah")')
print(exception2str(r.error_in_exec))
Traceback (most recent call last):
  File "/Users/jhoward/miniconda3/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3577, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-1-338156281413>", line 1, in <module>
    raise Exception("blah")
Exception: blah
r = shell.run_cell('import time; time.sleep(10)', timeout=1)
r.error_in_exec
TimeoutError()