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

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

Built distribution (wheel)

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

Total release size: 644.8 kB

Release files / rowstile-0.1.0a4.tar.gz

Download URL rowstile-0.1.0a4.tar.gz
Size 308.6 kB
Tags Source
SHA-256 checksum
How to use checksums
cb1c63a9ed931343f03525282af7f88adabde743ccb8ddc2be7d975626641120
BLAKE2b-256 checksum
How to use checksums
a5d29c87de7e04f6714abd708dee113d8a9aff54df4f8ecc7239a9b52dcc15ba
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 6, 2026.

Transparency log

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

Download URL rowstile-0.1.0a4-py3-none-any.whl
Size 336.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
103618f35f84d2087064a8d8850306e8b1228f00f57e63024710078a4247655d
BLAKE2b-256 checksum
How to use checksums
83c948c0bbf919154e474c781dec3e4f4ab04087e3d6f46a1c6e686b49ec0408
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 6, 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