Skip to main content

Notebook-native SQL workspace for Pandas DataFrames.

Project description

SnowFrame

SnowFrame is a lightweight SQL workspace for Pandas DataFrames. It lets you register DataFrames as SQL tables, run warehouse-style SQL using DuckDB, and export final outputs back to Pandas.

Pandas DataFrames  →  SnowFrame tables  →  SQL operations  →  Pandas DataFrame

Installation

# Clone or download the repo, then install in editable mode
pip install -e .

# With Jupyter / notebook magic support
pip install -e ".[notebook]"

# With Excel export support
pip install -e ".[excel]"

# Full dev install (includes pytest, openpyxl, ipython)
pip install -e ".[dev]"

Quick start

import pandas as pd
from snowframe import SnowFrame

sales_df = pd.DataFrame({
    "customer_id": [1, 1, 2, 3],
    "amount":      [100, 2500, 700, 1800],
})

customers_df = pd.DataFrame({
    "customer_id": [1, 2, 3],
    "name":        ["Amit", "Riya", "Kabir"],
})

sf = SnowFrame()
sf.load({
    "sales":     sales_df,
    "customers": customers_df,
})

sf.sql("""
    CREATE TABLE final AS
    SELECT
        c.customer_id,
        c.name,
        SUM(s.amount) AS total_amount
    FROM sales s
    JOIN customers c
        ON s.customer_id = c.customer_id
    GROUP BY c.customer_id, c.name
""")

final_df = sf.to_df("final")
print(final_df)

API reference

SnowFrame()

Creates a new session backed by an in-memory DuckDB connection.

sf.load(data)

Register one or more DataFrames.

# Dict → named tables
sf.load({"sales": sales_df, "customers": customers_df})

# Tuple / list → auto-named table1, table2, …
sf.load((df1, df2, df3))

sf.register(name, df)

Register a single DataFrame as a named table.

sf.register("products", products_df)

sf.tables()

Return a Pandas DataFrame listing all registered table names.

sf.tables()
#    table_name
# 0   customers
# 1       sales

sf.sql(query)

Execute any DuckDB SQL statement. Returns self for chaining.

sf.sql("CREATE TABLE big AS SELECT * FROM sales WHERE amount > 1000")
sf.sql("DROP TABLE big")

sf.to_df(table_name)

Read a table back into a Pandas DataFrame.

final_df = sf.to_df("final")

sf.run_file(path)

Execute all SQL statements in a .sql file (split on ;).

sf.run_file("examples/analysis.sql")
final_df = sf.to_df("final")

sf.to_csv(table_name, path) / sf.to_excel(table_name, path)

Export a table to CSV or Excel.

sf.to_csv("final", "output/final.csv")
sf.to_excel("final", "output/final.xlsx")   # requires openpyxl

sf.auto()

Scan the calling scope and auto-register every Pandas DataFrame as a table.

sales     = pd.DataFrame(...)
customers = pd.DataFrame(...)

sf = SnowFrame()
sf.auto()          # registers 'sales' and 'customers' automatically

sf.query_df(sql_text)

Run a SELECT-style query and return a Pandas DataFrame directly.

df = sf.query_df("SELECT * FROM sales WHERE amount > 1000")

sf.show(table_name, limit=10)

Preview the first N rows of a table.

sf.show("sales")           # first 10 rows
sf.show("final", limit=5)  # first 5 rows

sf.describe(table_name)

Show column names and types (DuckDB DESCRIBE).

sf.describe("sales")

sf.close()

Close the underlying DuckDB connection.


SQL file usage

Write SQL in a dedicated file and run it against a live session:

-- examples/analysis.sql
CREATE OR REPLACE TABLE summary AS
SELECT
    c.name,
    COUNT(s.amount)         AS num_orders,
    SUM(s.amount)           AS total_amount,
    ROUND(AVG(s.amount), 2) AS avg_amount
FROM sales s
JOIN customers c ON s.customer_id = c.customer_id
GROUP BY c.name
ORDER BY total_amount DESC;

CREATE OR REPLACE TABLE high_value AS
SELECT * FROM summary WHERE total_amount > 1000;
sf = SnowFrame()
sf.load({"sales": sales_df, "customers": customers_df})
sf.run_file("examples/analysis.sql")

summary_df    = sf.to_df("summary")
high_value_df = sf.to_df("high_value")

Notebook / Databricks-style usage

Install

pip install -e ".[notebook]"
jupyter lab

Setup cell

%load_ext snowframe

import pandas as pd
from snowframe import SnowFrame, set_active_session

sales = pd.DataFrame({
    "customer_id": [1, 1, 2, 3, 3],
    "amount":      [100, 2500, 700, 1800, 300],
})
customers = pd.DataFrame({
    "customer_id": [1, 2, 3],
    "name":        ["Amit", "Riya", "Kabir"],
})

sf = SnowFrame()
sf.auto()              # auto-registers 'sales' and 'customers' from this scope
set_active_session(sf)
sf.tables()

DDL cell — creates a table, prints success + table list

%%sf

CREATE OR REPLACE TABLE final AS
SELECT
    c.name,
    SUM(s.amount) AS total_amount
FROM sales s
JOIN customers c
    ON s.customer_id = c.customer_id
GROUP BY c.name
ORDER BY total_amount DESC;

SELECT cell — displays result DataFrame inline

%%sf
SELECT * FROM final;

SHOW TABLES cell

%%sf
SHOW TABLES;

Back in Python

final_df = sf.to_df("final")

sf.show("final")          # first 10 rows
sf.describe("final")      # column names and types

Databricks users: The same pattern works in Databricks notebooks. Replace %%sf with a Python cell calling sf.query_df("SELECT …") or sf.sql("CREATE …") if cell magics are unavailable.


CLI

# Execute a SQL file (no pre-loaded DataFrames; useful for DuckDB file-based tables)
snowframe run examples/analysis.sql

Running the examples

pip install -e .
python examples/basic_usage.py

Running tests

pip install -e ".[dev]"
pytest tests/ -v

Limitations

  • In-memory only — all tables live in DuckDB's in-memory database. Nothing is persisted to disk unless you call to_csv / to_excel.
  • Single connection — each SnowFrame() instance has its own isolated DuckDB connection; tables are not shared between sessions.
  • SQL file parsingrun_file splits on ;. SQL comments that contain semicolons (-- note; ignore) may cause incorrect splits. Use -- comments without semicolons inside SQL files.
  • Table name safetyto_df(name) interpolates the table name directly into SQL. Use only valid SQL identifiers as table names.
  • Excel export — requires openpyxl: pip install openpyxl or pip install -e ".[excel]".
  • CLI — the snowframe run command has no mechanism to load Python DataFrames. It is useful for SQL that reads from DuckDB-native sources (e.g. READ_CSV, READ_PARQUET).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

snowframe-0.1.0.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

snowframe-0.1.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file snowframe-0.1.0.tar.gz.

File metadata

  • Download URL: snowframe-0.1.0.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for snowframe-0.1.0.tar.gz
Algorithm Hash digest
SHA256 43b2e8810fc1de34d75496f2b7a79f8e575d4f76523b9d6192e3f2804fc641a6
MD5 51bbbf522e236fba072692c0959189ba
BLAKE2b-256 de96168f8d10290d9244f5e41d7cf79f0716545117ed861ae0362c81ad967e78

See more details on using hashes here.

File details

Details for the file snowframe-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: snowframe-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for snowframe-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 95e65de38c8c4d9cbb1ca746248f4acd278ec1bfb0ca269350221fe8f1d659af
MD5 ba581ff22a4f76914c527e9a9e1e778b
BLAKE2b-256 006723b25a15cd1bb10cf80606cf4567ac0bf1bce1c6c2a3da437399f187cd95

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page