Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

rowstile for Python

pip install --pre rowstile (--pre while only an alpha is published) installs the rowstile command (rowstile init, dev, migrate, review; also python -m rowstile) and the SDK for Python apps. Extras bring the integrations' dependencies: rowstile[fastapi], [sqlalchemy], [psycopg], [asyncpg]. Python 3.11 or newer.

The SDK for Python apps on a rowstile policy: every transaction signs in as whoever the request or the job acts for, refused writes become a 403 with the database's reason, rows the user can't see a 404, and the app refuses to start on a connection that skips row-level security. It holds no rowstile logic: it calls the authz.* functions the policy made, and translates their answers.

from fastapi import FastAPI
from sqlalchemy.ext.asyncio import create_async_engine
from rowstile.fastapi import Rowstile

engine = create_async_engine("postgresql+asyncpg://app@db/app")
app = FastAPI()
Rowstile(app, engine, user=current_user)     # current_user(request): its user's id, or None; before adding routes
module what
rowstile acting_as(who), @job(who), Principal, Refused, NotFound, refusal(exc), error_code(exc) (rowstile's code for any database error: AZ709), act_as_sql()
rowstile.fastapi Rowstile(app, engine, user=...): the request's principal, 403/404 problem bodies, the start-up check
rowstile.sqlalchemy install(engine) (sync or async; SQLModel too), ids(type, perm) for where, perms_of() for a list's buttons, can() (Queries[ObjectType, Permission]() has the three taking only the generated client's names, so a misspelled one doesn't type-check), expect() for Core updates and deletes, why_stale() for the ORM's StaleDataError
rowstile.psycopg transaction(conn, who), atransaction(aconn, who), expect(), aexpect()
rowstile.asyncpg transaction(conn, who), expect()
rowstile.alembic include_name, include_object: autogenerate leaves rowstile's objects alone
rowstile.testing pytest fixtures: as_user, assert_refused, assert_not_found (awaited, with an async function), authz_owner_url, authz_app_url; database_per_worker(url): a copy of the migrated test database for each pytest-xdist worker

Who a transaction acts for: 42 or "42" (a user), ("service", 3) (another principal type of the policy), or None (nobody: only what anyone may see; None given to a call is nobody too, whoever the code around it acts for). A plain id is always a user's, whatever it holds: "service:3" is the user with that id, so an id from outside (a username, an identity provider's subject) can't name a service. Principal.parse("service:3") reads back what str() wrote, for text your own code wrote. Every transaction signs in, even when nobody is signed in, and nothing uses a session-level SET, so pools and poolers in transaction mode are safe; behind one that keeps no prepared statements, turn the driver's off (Behind a pooler).

With FastAPI: user(request) runs in a middleware that Rowstile(...) adds, so give it the session or the token to read from the request itself. What a middleware of yours puts on request.state is there only if that middleware was added after Rowstile(...) (Starlette runs the one added last first); added before, it hasn't run yet. user may raise an HTTPException. The start-up check runs whether or not the app has a lifespan. WebSockets are not signed in: use rowstile.acting_as() in the endpoint. An engine in AUTOCOMMIT can't be signed in (the sign-in lasts a transaction): its queries fail with NotSignedIn.

Policy changes ship as migrations for your tool (rowstile migrate, with tool = "alembic" in rowstile.toml). The types and permissions of your policy are generated names (rowstile client py), so a misspelled permission doesn't type-check.

integrations/fastapi/ is the conformance suite: a small FastAPI app on SQLAlchemy (async, asyncpg) and Alembic, and the checks every supported stack passes (integrations/fastapi/test.sh).

Metadata

Release files for rowstile 0.1.0a3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rowstile 0.1.0a3
File Size Uploaded
rowstile-0.1.0a3.tar.gz 303.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rowstile 0.1.0a3
File Interpreter ABI Platform
rowstile-0.1.0a3-py3-none-any.whl Python 3 none any Details

Total release size: 635.0 kB

Release files / rowstile-0.1.0a3.tar.gz

Download URL rowstile-0.1.0a3.tar.gz
Size 303.7 kB
Tags Source
SHA-256 checksum
How to use checksums
fc32060e06870a58c530b25cf1ab778e84fb947295c4ac837fc4be9778f4c142
BLAKE2b-256 checksum
How to use checksums
1850a1bca2abefdfdf0f6435af513a8ae4f2bd710ba3d41ff66517e5d12a7256
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / rowstile-0.1.0a3-py3-none-any.whl

Download URL rowstile-0.1.0a3-py3-none-any.whl
Size 331.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d207f518b4df890da16573c560b7cb46445048b05aacab0fa8d872804f5f08f
BLAKE2b-256 checksum
How to use checksums
91af0711eb02a0fc1acf2786ab877f736beec46ac15a79d57beb49116d3f7e49
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page