Skip to main content

Python Quick Start

This guide prepares a generated Python package and a handwritten async application. The application depends on generated APIs but remains outside generated output.

Release status: the Python generator target and runtime package are not yet a public PyPI release. Do not install an unrelated package named teaql or copy an unannounced version from a test archive. The release notes will provide the canonical distribution name, supported Python range, extras, and generator target.

1. Prepare the workspace

teaql-python-quick-start/
├── model/main.xml
├── generated/python-lib/
├── app/main.py
└── tests/test_first_query.py

Create an isolated environment:

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
cargo teaql services
cargo teaql evaluate --input model/main.xml

After publication, install the runtime and async provider using the exact PyPI names and pinned versions from the release notes. Until then, use only an officially supplied generated preview workspace; this page intentionally leaves the public install command open.

2. Create the model

<?xml version="1.0" encoding="UTF-8"?>
<root name="order-review" org="example" data_service="sqlite" version="1.0.0">
<customer_order
order_number="WEB-10001"
_module_key="root" />
</root>

Evaluate before generation and read any Markdown error report. After the public Python target appears in cargo teaql services, generate it into generated/python-lib.

3. Inspect and install the generated package

find generated/python-lib -maxdepth 3 -type f | sort
sed -n '1,220p' generated/python-lib/pyproject.toml
rg 'def purpose|execute_for_list|audit_as|async def save' generated/python-lib
python -m pip install -e generated/python-lib
python -m compileall generated/python-lib

Typical output includes Q.py, E.py, models/, requests/, a runtime package, and pyproject.toml. The emitted project metadata is authoritative for dependencies.

Read Q.py for plural entry points. Never append s or es. Read each Request for predicate names: human entities intentionally use who_are/whose; non-human entities use which_are/with.

4. Initialize UserContext once

The async data service and trusted global state are injected while UserContext is created. Query terminals accept exactly one caller-supplied argument: ctx.

async def create_request_context(authenticated_request):
ctx = UserContext()
# Register generated metadata and an aiosqlite-backed data service.
# Inject trusted tenant, actor, permissions, policy and audit sinks here.
return ctx

Use exact constructors from the released generated package/runtime. There is no valid execute_for_list(ctx, service) form and no compatibility overload.

5. Execute the first query

After inspecting generated method names:

orders = await (
Q.customer_orders()
.comment("Find web orders")
.with_order_number_containing("WEB-")
.order_by_id_ascending()
.limit(20)
.purpose("Display the authorized order list")
.execute_for_list(ctx)
)

comment() may be placed earlier in the builder chain. purpose() transitions to an executable wrapper; execution does not belong on the ordinary Request.

6. Save with an audit reason

order = (
Q.customer_orders()
.comment("Create the first verified order")
.purpose("Persist an authorized order")
.new_entity(ctx)
)
order.update_order_number("WEB-10002")
await order.audit_as("Create the first verified order").save(ctx)

Inspect the generated model before using update_order_number; model-specific update names must not be guessed. Save without audit_as and query without intent must fail closed.

7. Regenerate

Change the model, evaluate, regenerate the complete package, reinstall it, run compileall and tests, and review Q.py, Request, model, expression, and packaging changes. Continue with First Verification and Python Customization.