interloper-snowflake
Snowflake integration for interloper: a SnowflakeDestination that stores
assets as Snowflake tables, and the SnowflakeConnection that holds the
credentials.
The destination is a DatabaseDestination: it writes the Snowflake dialect
and nothing else. Partition replacement, windows and reads by partition come
from core, exactly as for BigQuery.
Setup
The connection needs an account identifier, a user and a password, and optionally a role (the user's default role otherwise).
The account identifier is the part of your Snowflake URL before
.snowflakecomputing.com, in either format:
myorg-myaccount: organisation and account name (preferred)xy12345.eu-central-1: the legacy account locator with its region, and its cloud where your URL carries one (e.g.xy12345.us-east-2.aws)
The role the connection runs as needs:
USAGEon the warehouse the destination loads throughUSAGEon the databaseCREATE SCHEMAon the database, orUSAGEon every schema the assets write to if you create them yourselfCREATE TABLEandCREATE STAGEon those schemas (the load goes through a temporary stage)INSERT,DELETE,SELECTon the tables, andTRUNCATEfor unpartitioned assets (the table owner has all of them)
A sketch for a dedicated loading role:
CREATE ROLE interloper;
GRANT USAGE ON WAREHOUSE load_wh TO ROLE interloper;
GRANT USAGE, CREATE SCHEMA ON DATABASE analytics TO ROLE interloper;
GRANT ROLE interloper TO USER interloper_loader;
Schemas and tables the role creates are owned by it, so the remaining grants follow.
Usage
import interloper as il
from interloper_snowflake import SnowflakeConnection, SnowflakeDestination
destination = SnowflakeDestination(
connection=SnowflakeConnection(account="myorg-myaccount", user="LOADER", password="..."),
database="ANALYTICS",
warehouse="LOAD_WH",
default_dataset="raw",
)
The credentials also load from the environment (SNOWFLAKE_ACCOUNT,
SNOWFLAKE_USER, SNOWFLAKE_PASSWORD, SNOWFLAKE_ROLE), so
SnowflakeConnection() works with no arguments.
In a deployed instance you configure this through the UI instead: add a Snowflake connection, then a Snowflake destination, picking the database and warehouse from the lists the connection can see.
Datasets are schemas
An asset's dataset is the Snowflake schema its table lives in, inside the
destination's database. An asset without a dataset falls back to
default_dataset; with neither, the write fails with a ConfigError. A
missing schema is created on the first write, and a missing table is created
typed from the asset's schema (or one inferred from the data):
| Field type | Snowflake type |
|---|---|
bool |
BOOLEAN |
int |
NUMBER(38,0) |
float |
FLOAT |
Decimal |
NUMBER(38,9) |
datetime |
TIMESTAMP_NTZ |
date |
DATE |
bytes |
BINARY |
str, Any |
VARCHAR |
| nested models, lists, dicts | VARIANT |
An existing table is never altered: a column the data carries but the table does not is dropped with a warning.
Quoted identifiers
Every database, schema, table and column name is double-quoted, so Snowflake keeps it exactly as the asset spells it. Snowflake folds unquoted identifiers to upper case, so a lower-case asset must be queried with quotes:
SELECT "cost" FROM "ANALYTICS"."marts"."ads_stats";
-- SELECT cost FROM analytics.marts.ads_stats looks for "COST" in "ADS_STATS" and fails
Partitions
A partitioned write replaces the partition's rows: it deletes them, then loads
the data, inside one BEGIN ... COMMIT, rolled back on failure. A time
partition deletes by half-open bounds ("day" >= %s AND "day" < %s), so a
monthly partition whose rows hold daily dates is replaced whole; any other
partition deletes by equality on its id. A window deletes each partition it
covers and loads the whole batch once. An unpartitioned asset truncates its
table and reloads it.
Each write first does everything that is DDL or file transfer: it creates the
schema and table if missing, creates a temporary stage in the schema (once per
session), and uploads the data as one Parquet file with PUT, under a prefix of
its own. Only then does it open the transaction, which holds nothing but the
DELETE (or TRUNCATE) and a COPY INTO projecting the file's columns by name
($1:"cost"). Snowflake commits an open transaction whenever it runs DDL, so
keeping DDL out of the block is what makes a replace atomic: a failed load
rolls back the delete and the partition keeps its old rows. Reads go through
fetch_pandas_all, so both directions stay columnar.
Notes
Each destination opens its own session through the connection, on its own warehouse and database, so destinations sharing a connection never switch each other's warehouse. That session is shared by every asset the destination writes, and a Snowflake transaction belongs to the session rather than to a cursor, so the destination serialises its writes.
Metadata
Release files for interloper-snowflake 0.95.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| interloper_snowflake-0.95.0.tar.gz | 9.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| interloper_snowflake-0.95.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.4 kB
Release files / interloper_snowflake-0.95.0.tar.gz
| Download URL | interloper_snowflake-0.95.0.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c95e0bfcc4840662bb9a3e1b47ebc311bbb4352844301193e8650022f90192dd
|
|
BLAKE2b-256 checksum How to use checksums |
a143db8ce76f3b1aacb195fa7f1676ad4e21c7f57a9ec809325aaadcaeae10ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / interloper_snowflake-0.95.0-py3-none-any.whl
| Download URL | interloper_snowflake-0.95.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a07dace75f7f8fb282f43ba6e1ec19de7cce0f7a2f1cfb182bab44dd28694a99
|
|
BLAKE2b-256 checksum How to use checksums |
393d0006a9a41e6d17b64f95f25d1a32ff7f0d39348b5c80cc6080cfa482a841
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|