Python Runtime

PropertyValue
Tag<python>
Output methodprint()
Default binary/usr/bin/python3
Shared scopetrue (default)

Overview

The Python runtime executes code using Python 3. Whatever Python writes to stdout via print() is captured and placed at the tag's position in the output document. Python 2 is not supported.

Output

Use print() to produce output. Each call to print() adds a newline by default. Use end="" to suppress it:

<python>
print("<ul>")
for item in ["Apples", "Oranges", "Bananas"]:
    print(f"  <li>{item}</li>")
print("</ul>")
</python>

For finer control, you can also write directly to sys.stdout:

import sys
sys.stdout.write("no trailing newline")

Shared Scope

With shared scope enabled (the default), all <python> blocks on the same page run in a single Python process. Variables, imports, and function definitions persist across blocks:

<python>
import json

def format_price(cents):
    return f"${cents / 100:.2f}"

products = [
    {"name": "Widget", "price": 1999},
    {"name": "Gadget", "price": 4550},
]
</python>

<h2>Product List</h2>

<python>
for p in products:
    print(f"<div>{p['name']}: {format_price(p['price'])}</div>")
</python>

Both blocks share the same process, so the second block can use products and format_price defined in the first.

Data Processing

Python excels at data manipulation, making it a natural fit for processing data inline:

<python>
import csv
import io

raw = """name,department,salary
Alice,Engineering,95000
Bob,Marketing,72000
Carol,Engineering,102000
Dave,Marketing,68000"""

reader = csv.DictReader(io.StringIO(raw))
rows = list(reader)

by_dept = {}
for row in rows:
    dept = row["department"]
    by_dept.setdefault(dept, []).append(row)

for dept, members in sorted(by_dept.items()):
    total = sum(int(m["salary"]) for m in members)
    avg = total / len(members)
    print(f"<h3>{dept}</h3>")
    print(f"<p>Headcount: {len(members)}, Average salary: ${avg:,.0f}</p>")
    print("<ul>")
    for m in members:
        print(f"  <li>{m['name']} - ${int(m['salary']):,}</li>")
    print("</ul>")
</python>

Cross-Runtime Data Bridge

Python works well as a data source for other runtimes via #set and #get:

<python>
stats = {
    "total_users": 1524,
    "active_today": 342,
    "conversion_rate": 0.067
}
#set("stats", stats)
</python>

<javascript>
const stats = #get("stats");
println(`<p>Conversion: ${(stats.conversion_rate * 100).toFixed(1)}%</p>`);
</javascript>

Salata serializes the Python dictionary to JSON and deserializes it into a JavaScript object transparently.

Configuration

[runtimes.python]
enabled = true
path = "/usr/bin/python3"
shared_scope = true
display_errors = true
FieldTypeDefaultDescription
enabledbooltrueEnable or disable the Python runtime
pathstring/usr/bin/python3Absolute path to the Python 3 binary
shared_scopebooltrueAll blocks share one process per page
display_errorsbool(global fallback)Override the global display_errors setting

Isolated Scope

To run a block in its own process, use the scope attribute:

<python scope="isolated">
# This block has its own Python process.
# Variables from other blocks are not available here.
x = 42
print(x)
</python>

You can also set shared_scope = false in the config to make isolation the default for all Python blocks.

Tips

  • Python 3 is required. Ensure path points to a Python 3 interpreter.
  • Use f-strings for readable output formatting.
  • Heavy imports (like pandas or numpy) are fine but will increase execution time on the first block. With shared scope, the import cost is paid only once per page.
  • The working directory during execution is the directory containing the .slt file being processed.