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.0a6

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.0a6
File Size Uploaded
rowstile-0.1.0a6.tar.gz 315.3 kB Details

Built distribution (wheel)

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

Total release size: 657.9 kB

Release files / rowstile-0.1.0a6.tar.gz

Download URL rowstile-0.1.0a6.tar.gz
Size 315.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1f185e9cb1416b5d9ac720e462177798ed26fb86f0d4a91597737e5f202ae172
BLAKE2b-256 checksum
How to use checksums
ed75fea6a7399e6fec81c41f85194ca509a864a137a3fbf04d19f7c12d93d991
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 7, 2026.

Transparency log

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

Download URL rowstile-0.1.0a6-py3-none-any.whl
Size 342.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16b1a54b6ee1ac693b5c30ae0d898786d5c2cc79d35bfaafab5fcfd678756660
BLAKE2b-256 checksum
How to use checksums
8d65ba5ff403d8213d73449b96ecd98441ff42cf83d8fd4ac963333fc7a66dd8
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 7, 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