Module trase.tools.r2
R2 (Cloudflare object storage) connection helpers for Trase Python scripts.
See :mod:trase.tools.r2.connection for usage — storage_options() for
pandas/polars, attach_duckdb_secret() for DuckDB, wrangler_env() for
shelling out to the wrangler CLI (preferred for one-off object get/put),
cloudflare_client() for bucket-level admin via the official SDK, and
client() (boto3) for anything else — all backed by Secrets
Manager-vaulted R2 tokens rather than locally-held credentials.
Sub-modules
trase.tools.r2.connection-
Access the Cloudflare R2 bucket (
trase-r2) via Secrets Manager-vaulted tokens …
Functions
def api_token(role: Role = 'ro') ‑> str-
The Cloudflare API token (
cfut_…) forrole.Same secret, same bucket restriction as the S3 Access Key/Secret pair from :func:
client()/:func:storage_options()— but not usable for object get/put via this route: Cloudflare's REST API (whatwranglerand the officialcloudflarePython package speak) 403s on object writes for anything less than an Admin-tier token, and ours are deliberately bucket-scoped "Object Read & Write" (https://github.com/cloudflare/workers-sdk/issues/9235). Only useful if you separately hold/create an Admin-tier token — see :func:cloudflare_client(). def attach_duckdb_secret(con, role: Role = 'ro', name: str = 'trase_r2') ‑> str-
Create a
TYPE r2DuckDB secret namednameoncon. Returnsname.Lets callers then address objects as
r2://<bucket>/<key>directly — DuckDB derives the endpoint fromACCOUNT_IDitself. def bucket() ‑> strdef client(role: Role = 'ro')-
A boto3 S3 client configured against the R2 endpoint with the resolved role's credentials.
The way to actually read/write objects — pandas/polars (:func:
storage_options()) and this function both go through the S3-compatible API, which is the only one our bucket-scoped tokens work against for object operations (see :func:api_token()). def cloudflare_client(role: Role = 'ro')-
The official
cloudflarePython SDK client, authenticated forrole.Only useful for R2 bucket-level administration (CORS, lifecycle rules, custom domains, bucket create/delete) — Cloudflare's REST API has no object-level get/put/list at all (those stay on :func:
client()/ :func:storage_options(), S3-compatible), and even bucket admin needs an Admin-tier token: our tokens are bucket-scoped "Object Read & Write" and will 403 here (https://github.com/cloudflare/workers-sdk/issues/9235). def endpoint_url() ‑> strdef storage_options(role: Role = 'ro') ‑> dict-
storage_options()for pandas/polars (via s3fs) reads/writes against R2. def uri(key: str, scheme: "Literal['s3', 'r2']" = 's3') ‑> str-
Build an
s3://(boto3/pandas/polars) orr2://(native DuckDB) URI forkey. def wrangler_env(role: Role = 'ro') ‑> dict[str, str]-
Env vars for shelling out to the
wranglerCLI.Merge into a subprocess call, e.g.::
subprocess.run( ["npx", "wrangler", "r2", "bucket", "cors", "set", bucket(), "--rules", path], env={**os.environ, **wrangler_env("rw")}, check=True, )Not for object get/put —
wrangler r2 object …needs an Admin-tier token and 403s with ours (bucket-scoped "Object Read & Write"); use :func:storage_options()/:func:attach_duckdb_secret()/ :func:client()(S3-compatible API) for that instead. This is only useful forwrangler r2 bucket() …bucket-admin subcommands, and only if the resolved token happens to be Admin-tier.