Skip to main content

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:

  • USAGE on the warehouse the destination loads through
  • USAGE on the database
  • CREATE SCHEMA on the database, or USAGE on every schema the assets write to if you create them yourself
  • CREATE TABLE and CREATE STAGE on those schemas (the load goes through a temporary stage)
  • INSERT, DELETE, SELECT on the tables, and TRUNCATE for 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.

Docker images

The published interloper images do not ship this package. They are built on Alpine, and snowflake-connector-python publishes no musllinux wheels, so installing it there means compiling its C++ extension from source. Run it from a glibc-based image (for example a python:3.12-slim base with pip install interloper-snowflake), or anywhere outside the images.

Metadata

Release files for interloper-snowflake 0.94.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for interloper-snowflake 0.94.2
File Size Uploaded
interloper_snowflake-0.94.2.tar.gz 9.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for interloper-snowflake 0.94.2
File Interpreter ABI Platform
interloper_snowflake-0.94.2-py3-none-any.whl Python 3 none any Details

Total release size: 21.8 kB

Release files / interloper_snowflake-0.94.2.tar.gz

Download URL interloper_snowflake-0.94.2.tar.gz
Size 9.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1ee3aecbd8aca296320b6c98b2c9922958ea53481599dc7e107bc457886e77e2
BLAKE2b-256 checksum
How to use checksums
2aa5e2454531d157c709f7dc3d10cb91e08d21b7bd69a6af43183840392b7805
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.94.2-py3-none-any.whl

Download URL interloper_snowflake-0.94.2-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6f0b9e9633f887ab7f03e93c76b57b32855822f73897821a384b90c7d09fa7f7
BLAKE2b-256 checksum
How to use checksums
953bfb245000a7e7632852cb144be6c06a5518b50b706a64048cf328c42f4528
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 history Release notifications | RSS feed

This release

0.94.2 This release

2 release files

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