safely execute python come. built in safety checker. use it as cli, library, server
Project description
Code Cantation
A safe, embeddable code executor for Python—usable both as a library and via a CLI.
Features
- Script execution: Run arbitrary Python scripts with stdout capture.
- Function execution: Define functions in code snippets and invoke them (with or without parameters).
- Safety checks: Static AST-based analysis blocks imports of unsafe modules (e.g.
os,subprocess) and calls to dangerous functions (eval,exec, etc.). - Error reporting: Any runtime errors are captured and returned in the output object.
- Process isolation: Code runs in a separate process with configurable timeout and resource limits.
- Dual usage: Importable as a Python package, or installed as a
cantationCLI tool. Server mode is optional.
Installation
Install from PyPI (library + CLI):
pip install code-cantation
To include FastAPI/uvicorn for server mode (optional extra):
pip install code-cantation[server]
Or install from source in editable mode:
git clone https://github.com/your-repo/code-cantation.git
cd code-cantation
pip install -e .
Usage as a Library
Import and invoke the Executor directly in your code:
from code_cantation import Executor
exe = Executor()
# 1. Run a simple script:
script = """
a = 10
b = 20
print('sum =', a + b)
""" # note: no `return` in script mode
result = exe.execute(code=script)
print("Console:", result.console_log)
# 2. Call a function without parameters:
func_no_args = """
def greet():
print('hello')
return 'hello'
"""
res2 = exe.execute(code=func_no_args, code_type="FUNCTION")
print("Return:", res2.captured_output)
# 3. Call a function with parameters:
func_with_args = """
def add(a, b):
print('adding', a, b)
return a + b
"""
res3 = exe.execute(
code=func_with_args,
code_type="FUNCTION",
input_values=[5, 7]
)
print("Return:", res3.captured_output)
# 4. Restrict file access to a specific folder:
restricted = exe.execute(
code="open('data.txt', 'w').write('ok')",
allowed_root="/sandbox/work" # work_dir defaults to allowed_root
)
print("Error:", restricted.exec_error)
# 5. Check safety violation:
unsafe = "import requests"
res4 = exe.execute(code=unsafe)
print("Safety error:", res4.safety_violation)
The execute(...) method returns a CodeExecutorOutput object with the following attributes:
console_log(str): Captured stdout from the snippet.captured_output(any): Return value of a FUNCTION snippet (orNonefor scripts).exec_error(str): Runtime error message if execution failed.safety_violation(str): Description if safety checks failed.
By default, execution runs in a separate process with a 5s timeout, 5s CPU limit,
and a 256MB memory limit. These can be overridden per call.
If allowed_root is set, file access is restricted to that directory (read/write),
which can also block imports from outside the allowed root.
Usage via CLI
Once installed, the cantation command is available on your PATH. All options mirror the library’s Executor.execute() parameters and always emit a JSON representation of the CodeExecutorOutput.
cantation [--code CODE | --file FILE]
[--no-safety]
[--code-type {SCRIPT,FUNCTION}]
[--input JSON_LIST]
[--unsafe-modules MODULE [MODULE ...]]
[--unsafe-functions FUNC [FUNC ...]]
[--override-default-safety]
[--timeout-sec SECONDS]
[--cpu-time-limit-sec SECONDS]
[--memory-limit-mb MB]
[--allowed-root DIR]
[--work-dir DIR]
Common Examples
-
Run an inline script
cantation \ --code "print('Hello from CLI'); x = 1 + 2; print('x =', x)"
Output
{ "console_log": "Hello from CLI x = 3", "captured_output": null, "exec_error": null, "safety_violation": null }
-
Execute a Python file
cantation --file path/to/script.py
-
Invoke a no-arg function
cantation \ --code "def greet(): print('Hi there'); return 'Hi'" \ --code-type FUNCTION
Output
{ "console_log": "Hi there", "captured_output": "Hi", "exec_error": null, "safety_violation": null }
-
Invoke a function with parameters
cantation \ --code "def add(a, b): return a + b" \ --code-type FUNCTION \ --input '[5, 7]'
Output
{ "console_log": "", "captured_output": 12, "exec_error": null, "safety_violation": null }
-
Disable safety checks
cantation --file my_script.py --no-safety
-
Override unsafe modules/functions
# Disallow use of 'os' and 'eval' cantation --file my_script.py \ --unsafe-modules os \ --unsafe-functions eval
-
Install Libraries Required For Code Execution
cantation \ --install pyfiglet \ --code "import pyfiglet; print(pyfiglet.figlet_format('Hello'))"
-
Set resource limits
cantation \ --code "print('hello')" \ --timeout-sec 3 \ --cpu-time-limit-sec 2 \ --memory-limit-mb 128
Set any of these to
0to disable that limit. -
Restrict file access
cantation \ --code "open('data.txt','w').write('ok')" \ --allowed-root /sandbox/work
Usage As Server
Code Cantation can be run as a server/rest api. The server execute one code at time and therefore has an internal queue for requests.
Server mode requires the optional FastAPI/uvicorn extras:
pip install code-cantation[server]
If you only installed the core package, cantation --server will fail with a message
telling you to install the server extras.
Start server (basic)
cantation --server --install pyfiglet fastapi uvicorn \
--host 127.0.0.1 --port 9000
If you already installed the server extra, you can omit --install fastapi uvicorn.
Start server with allowed root (client-enforced)
The server reads allowed_root and work_dir from each request. Use these in your API payloads
to restrict file access to a specific directory.
Start server securely (no Docker)
Run as a dedicated user with a restricted working directory:
sudo useradd -m cantation
sudo mkdir -p /srv/cantation/work
sudo chown -R cantation:cantation /srv/cantation
sudo -u cantation cantation --server --host 127.0.0.1 --port 9000
Optionally apply OS limits in the same shell:
ulimit -t 5 -v 1048576 -n 128 -u 64
sudo -u cantation cantation --server --host 127.0.0.1 --port 9000
Start server with Docker hardening (recommended)
docker run --rm -it \
--read-only \
--cap-drop=ALL \
--security-opt no-new-privileges \
--user 1000:1000 \
--pids-limit 256 \
--memory 1g \
--cpus 2 \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
-p 9000:9000 \
-v /host/allowed:/sandbox/work:rw \
your-image \
cantation --server --host 0.0.0.0 --port 9000
Call The API
curl -X POST http://127.0.0.1:9000/execute \
-H "Content-Type: application/json" \
-d '{
"code": "import pyfiglet; print(pyfiglet.figlet_format(\"API\"))",
"timeout_sec": 3,
"cpu_time_limit_sec": 2,
"memory_limit_mb": 128,
"allowed_root": "/sandbox/work",
"work_dir": "/sandbox/work"
}'
Use 0 to disable a limit per request.
Recommended: always set allowed_root (and optionally work_dir) in requests to
restrict file access to a specific directory. Combine this with container-level
restrictions for stronger isolation.
Docker Run Recipes
These examples assume your app is installed inside the container and that you want to
restrict file access to a single host directory mounted at /sandbox/work.
Library / CLI (interactive)
docker run --rm -it \
--read-only \
--cap-drop=ALL \
--security-opt no-new-privileges \
--user 1000:1000 \
--pids-limit 128 \
--memory 512m \
--cpus 1 \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
-v /host/allowed:/sandbox/work:rw \
your-image \
cantation \
--code "open('data.txt','w').write('ok')" \
--allowed-root /sandbox/work
FastAPI Server
docker run --rm -it \
--read-only \
--cap-drop=ALL \
--security-opt no-new-privileges \
--user 1000:1000 \
--pids-limit 256 \
--memory 1g \
--cpus 2 \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
-p 9000:9000 \
-v /host/allowed:/sandbox/work:rw \
your-image \
cantation --server --host 0.0.0.0 --port 9000
Note: ensure your image includes the server extra (pip install code-cantation[server]).
Recommended: set allowed_root to /sandbox/work in your requests so file access
is restricted to the mounted directory.
How It Works
If you don't provide the code type, the library will try to figure it out itself.
Executor Code Flow Logic
Testing
A test script (test/test.py) is provided to exercise:
- Script execution
- Function execution (no args)
- Function execution (with args)
- Safety-check failures
- CLI behaviors
Run:
python test/test.py
Contributing
- Fork the repo and create your branch:
git checkout -b feature/YourFeature - Make your changes & add tests
- Run tests:
python sample_test.py - Submit a pull request
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file code_cantation-0.1.1.tar.gz.
File metadata
- Download URL: code_cantation-0.1.1.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad598130a8df3e9aaab3733a9fc55b09a7f8aa5bad916a5fcc99d84e36ac3783
|
|
| MD5 |
f2a5cbf8b971279bd95fdaaea981ec7f
|
|
| BLAKE2b-256 |
601125c9f4cda213a8d2a29196626259e9f5e9b5f4c40eb951be18801fa48b31
|
File details
Details for the file code_cantation-0.1.1-py3-none-any.whl.
File metadata
- Download URL: code_cantation-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4394ed1c33da9c17d886e114bfe9735d11125dd56c81ca711eb713d411457c8c
|
|
| MD5 |
642af9be705dd9120579b4147afd4158
|
|
| BLAKE2b-256 |
9e3e5c68a0b08551eb1e3496902763fdfd1f984ca7badd64f8cff58c22ed62cf
|