opteryx-iceberg
Read-only Apache Iceberg Metastore/FileIO backend for opteryx-catalog, letting an Opteryx workspace query tables from an external Iceberg catalog (REST, SQL, Hive, Glue - whatever pyiceberg's own catalog loader supports) side by side with native Firestore/GCS-backed tables.
This is Tier 1 of Opteryx's Iceberg support: reads only. Writing real Iceberg tables from Opteryx (Tier 2) and serving Opteryx's own catalog as an Iceberg REST endpoint (Tier 3) are separate, later work.
Kept as its own package - not merged into opteryx-catalog or opteryx-core - because it depends on pyiceberg, which pulls in pyarrow/pydantic. Both of those repos are deliberately free of that dependency chain; Iceberg support is optional, the same way opteryx-access is.
Usage
Register a workspace against an external Iceberg catalog using Opteryx's existing connector-registration API:
from opteryx.connectors import register_workspace
from opteryx.connectors.opteryx_connector import OpteryxConnector
from opteryx_iceberg import IcebergMetastore
register_workspace(
"my_iceberg_workspace",
OpteryxConnector,
catalog=IcebergMetastore,
catalog_type="rest", # or "sql", "hive", "glue" - anything pyiceberg's loader supports
uri="https://...",
warehouse="s3://...",
)
Do not pass workspace= yourself — OpteryxConnector injects it automatically (as the registered prefix) when it instantiates IcebergMetastore; passing it explicitly raises a duplicate-keyword-argument error.
Native (Firestore/GCS-backed) workspaces are entirely unaffected - this only applies to workspaces explicitly registered with catalog=IcebergMetastore.
Config passes through to pyiceberg verbatim — nesting included. Every kwarg after catalog= is forwarded untouched to pyiceberg.catalog.load_catalog, so pyiceberg's own config shapes (auth={...}, token=, credential=) are used directly. (Earlier versions required flat auth_type/google_auth_scopes kwargs because opteryx-core's connector cache hashed registration kwargs and a dict value broke it; that cache is now keyed by workspace name in opteryx-core's resolution-first connector layer, the flattening is retired, and passing the old flat kwargs raises a clear ValueError.)
Google auth (BigLake and other Google-fronted REST catalogs)
register_workspace(
"tarchia",
OpteryxConnector,
catalog=IcebergMetastore,
catalog_type="rest",
uri="https://biglake.googleapis.com/iceberg/v1/restcatalog",
warehouse="bl://projects/<project>/catalogs/<catalog>",
auth={"type": "google", "google": {"scopes": ["https://www.googleapis.com/auth/cloud-platform"]}},
**{"header.x-goog-user-project": "<project>"},
)
auth={"type": "google", ...} selects pyiceberg's built-in GoogleAuthManager, which authenticates via Application Default Credentials and refreshes the token on every request — safe for a long-lived server (a manually fetched gcloud auth print-access-token bearer token, by contrast, expires within the hour and is only good for one-off scripts/tests). In production this picks up Cloud Run's attached service account automatically, the same way the rest of the deployment already does — no explicit credentials_path needed. Stored-credential catalogs need no code at all: pass pyiceberg's token= or credential= the same way.
This is wired into worker.opteryx as the tarchia workspace, alongside the native mabel_data registration - reads from it go through the exact same query path as any native table (verified with a real SELECT ... FROM tarchia.interop_ns.people).
Local-dev only for now: worker.opteryx reaches opteryx_iceberg via the same sys.path sibling-checkout convention as opteryx-core/opteryx-catalog/opteryx-access (never pip install -e) - see its pyproject.toml, which does not yet list opteryx-iceberg as a real dependency, since it isn't published anywhere yet. A production Cloud Run deploy of worker.opteryx would need that resolved first (publish opteryx-iceberg somewhere installable, or vendor it) - the tarchia registration works today for local runs only.
What's supported
SELECTqueries against existing Iceberg tables, including predicate pushdown/pruning via standard Iceberg manifest bounds (min_values/max_values/null_counts).- Schema introspection (
DESCRIBE, information_schema).
What's not (yet)
- Any write path:
CREATE/DROP/ALTER/INSERT/renameall raiseNotImplementedError— that's Tier 2. - Iceberg views (Iceberg's view spec has no equivalent here yet).
- Opteryx's own sketch-based pruning stats (
min_k_hashes/histograms) — standard Iceberg manifests don't carry them; queries fall back to standard bounds-based pruning. - Nested Iceberg types (struct/map/list) —
IcebergDataset.schema()raises rather than silently misrepresenting them.
Local development
Sibling opteryx-catalog/opteryx-core checkouts are referenced via sys.path insertion in test files (see tests/), never pip install -e - see those repos' own conventions.
Testing
python -m pytest tests/ -v
Tests run against pyiceberg's own local SqlCatalog (SQLite metadata + local-disk FileIO) — no server, no Docker required.
Real REST-catalog interop check
Snowflake Open Catalog is closed to new signups as of 2026 (Snowflake now points new customers at Horizon Catalog, which needs a full paid-account trial). Instead, real wire-protocol compatibility is verified against Google Lakehouse for Apache Iceberg (BigLake), reusing the existing mabeldev GCP project:
- Catalog:
projects/mabeldev/catalogs/opteryx-iceberg-tier1-test(typebiglake, credential-modeend-user), storing data undergs://tarchia/iceberg-tier1-test. - Verified manually (not in CI - needs a live GCP access token):
dataset_exists,load_dataset,schema()type mapping,scan()including real Iceberg bounds-byte decoding (min_values/max_values/field_ids), andget_relationfor both hit and miss, all throughopteryx_iceberg.IcebergMetastoreagainst a table (interop_ns.people) written independently via plainpyiceberg.catalog.rest.RestCatalog. - Connecting needs
GOOGLE_APPLICATION_CREDENTIALSset in-process (not justgcloud auth activate-service-account) —PyArrowFileIO's GCS backend otherwise hangs trying to reach the GCE metadata server for ADC. Warehouse URI format isbl://projects/<project>/catalogs/<catalog>(not a bareprojects/...path). - This catalog/table is being kept around (not torn down) for reuse in future Tier 1/Tier 2 verification.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opteryx_iceberg-0.1.3.tar.gz.
File metadata
- Download URL: opteryx_iceberg-0.1.3.tar.gz
- Upload date:
- Size: 22.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d6e009c27c5614a6b21554b10ea560604dd03c9529040a34ed8a27d4b9144dd7
|
|
| MD5 |
3993105f7387638ea523874fe284e323
|
|
| BLAKE2b-256 |
aec949ed14c85f74ca281b1f96c9660b6b88a6a22a7128b1834f3a50ec8f42db
|
Provenance
The following attestation bundles were made for opteryx_iceberg-0.1.3.tar.gz:
Publisher:
release.yaml on mabel-dev/opteryx-iceberg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opteryx_iceberg-0.1.3.tar.gz -
Subject digest:
d6e009c27c5614a6b21554b10ea560604dd03c9529040a34ed8a27d4b9144dd7 - Sigstore transparency entry: 2550049594
- Sigstore integration time:
-
Permalink:
mabel-dev/opteryx-iceberg@b3b4caa89ff2ca8e504910d1845fe5b1c9ce3200 -
Branch / Tag:
refs/tags/version-0.1.3 - Owner: https://github.com/mabel-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@b3b4caa89ff2ca8e504910d1845fe5b1c9ce3200 -
Trigger Event:
push
-
Statement type:
File details
Details for the file opteryx_iceberg-0.1.3-py3-none-any.whl.
File metadata
- Download URL: opteryx_iceberg-0.1.3-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cab6c735ca0e3c9dd7769e4b6c8101c24b4b153901b715906ca3e4667b087df3
|
|
| MD5 |
1e3c766d05ceefe00ed227c96190a2e8
|
|
| BLAKE2b-256 |
9789516606b89962677f0333d6e8ccf61a1007f5c95f78b494ce6d2565fe66b4
|
Provenance
The following attestation bundles were made for opteryx_iceberg-0.1.3-py3-none-any.whl:
Publisher:
release.yaml on mabel-dev/opteryx-iceberg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opteryx_iceberg-0.1.3-py3-none-any.whl -
Subject digest:
cab6c735ca0e3c9dd7769e4b6c8101c24b4b153901b715906ca3e4667b087df3 - Sigstore transparency entry: 2550049703
- Sigstore integration time:
-
Permalink:
mabel-dev/opteryx-iceberg@b3b4caa89ff2ca8e504910d1845fe5b1c9ce3200 -
Branch / Tag:
refs/tags/version-0.1.3 - Owner: https://github.com/mabel-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@b3b4caa89ff2ca8e504910d1845fe5b1c9ce3200 -
Trigger Event:
push
-
Statement type: