# minipy


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

In language model clients it’s often useful to have a ‘code interpreter’
– this is something that runs code, and generally outputs the result of
the last expression (i.e like IPython or Jupyter).

In this section we’ll create the
[`minipy`](https://AnswerDotAI.github.io/toolslm/minipy.html#minipy)
function, which executes a string as Python code, with an optional
timeout. If the last line is an expression, we’ll return that – just
like in IPython or Jupyter, but without needing them installed.

This is an internal function that’s needed for
[`_run`](https://AnswerDotAI.github.io/toolslm/minipy.html#_run) to
ensure that location information is available in the abstract syntax
tree (AST), since otherwise python complains.

This is the internal function used to actually run the code – we pull
off the last AST to see if it’s an expression (i.e something that
returns a value), and if so, we store it to a special `_result` variable
so we can return it.

``` python
_run('import math;math.factorial(12)')
```

    479001600

``` python
_run('print(1+1)')
```

    '2'

We now have the machinery needed to create our
[`minipy`](https://AnswerDotAI.github.io/toolslm/minipy.html#minipy)
function.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/toolslm/blob/main/toolslm/minipy.py#L48"
target="_blank" style="float:right; font-size:smaller">source</a>

### minipy

``` python
def minipy(
    code:str, # Code to execute
    glb:Optional=None, # Globals namespace
    loc:Optional=None, # Locals namespace
    timeout:int=3600, # Maximum run time in seconds
):
```

*Executes python `code` with `timeout` and returning final expression
(similar to IPython).*

There’s no builtin security here – you should generally use this in a
sandbox, or alternatively prompt before running code. It can handle
multiline function definitions, and pretty much any other normal Python
syntax.

``` python
minipy("""def factorial(n):
    if n == 0 or n == 1: return 1
    else: return n * factorial(n-1)
factorial(5)""")
```

    120

If the code takes longer than `timeout` then it returns an error string.

``` python
print(minipy('import time; time.sleep(10)', timeout=1))
```

    Traceback (most recent call last):
      File "<ipython-input-1-15361b58d9a8>", line 14, in minipy
        try: return _run(code, glb, loc)
                    ~~~~^^^^^^^^^^^^^^^^
      File "<ipython-input-1-c68b1c7bc9d7>", line 18, in _run
        try: exec(compiled_code, glb, loc)
             ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
      File "<ast>", line 1, in <module>
      File "<ipython-input-1-15361b58d9a8>", line 9, in handler
        def handler(*args): raise TimeoutError()
                            ^^^^^^^^^^^^^^^^^^^^
    TimeoutError

By default the caller’s global namespace is used.

``` python
minipy("a=1")
a
```

    1

Pass a different `glb` if needed; this requires using `python_ns`.

``` python
glb = {}
minipy("a=3", glb=glb)
a, glb['a']
```

    (1, 3)

[`minipy`](https://AnswerDotAI.github.io/toolslm/minipy.html#minipy) is
designed to be offered as a tool, e.g. via
[`fastcore.funccall.get_schema`](https://fastcore.fast.ai/funccall.html#get_schema):

``` python
from fastcore.funccall import get_schema
```

``` python
get_schema(minipy)
```

    {'name': 'minipy',
     'description': 'Executes python `code` with `timeout` and returning final expression (similar to IPython).',
     'input_schema': {'type': 'object',
      'properties': {'code': {'description': 'Code to execute', 'type': 'string'},
       'glb': {'description': 'Globals namespace',
        'default': None,
        'anyOf': [{'type': 'object'}, {'type': 'null'}]},
       'loc': {'description': 'Locals namespace',
        'default': None,
        'anyOf': [{'type': 'object'}, {'type': 'null'}]},
       'timeout': {'description': 'Maximum run time in seconds',
        'default': 3600,
        'type': 'integer'}},
      'required': ['code']}}
