Skip to main content

Lightweight library to handle data and reproduce workflows

Project description

Penwings

Penwings is a lightweight Python library for building reproducible data workflows.

It provides simple, composable tools to:

  • manage project structure
  • standardize data access
  • cache SQL queries efficiently

The goal is to reduce boilerplate and make data pipelines faster, cleaner, and reproducible by default.


✨ Features

🗂️ Project Structure Management

  • Standardized folder setup for data science projects
  • Automatic project root detection
  • Flexible, extensible path system

🧠 SQL → Parquet Caching

  • Execute SQL queries via SQLAlchemy
  • Automatically cache results as Parquet
  • Reuse cached data to avoid unnecessary database hits
  • Configurable refresh logic

⚡ Lightweight & Modular

  • Minimal core dependencies (pandas, numpy)
  • Optional SQL support
  • Designed to scale into larger workflows

📦 Installation

pip install penwings

Optional SQL support

pip install penwings[sql]

Requires Python 3.11+


🚀 Quick Start

1. Project structure

from penwings import ProjectPaths

paths = ProjectPaths()

print(paths.data)
print(paths.models)

Creates a standardized structure like:

configs/
data/
  raw/
  processed/
  external/
features/
logs/
models/
notebooks/
reports/
  figures/
  tables/
sql/

2. SQL caching

from sqlalchemy import create_engine
from penwings import SQLParquetCache

engine = create_engine("sqlite:///example.db")

cache = SQLParquetCache(
    sql_dir="sql",
    parquet_dir="cache",
    conn=engine,
    refresh_days=1
)

📊 Usage

Using SQL files

df = cache.get("sales.sql")
  • Loads from Parquet if cached
  • Otherwise executes SQL and caches result

Using raw SQL

query = "SELECT * FROM sales WHERE month = '2026-02'"

df = cache.get(
    sql=query,
    parquet_name="sales_feb"
)

Cache behavior

df = cache.get("sales.sql", force=True)
  • force=True → always re-run SQL

  • refresh_days=N → cache expires after N days

  • returns:

    • DataFrame

🧩 ProjectPaths

Create only specific parts of a project:

paths = ProjectPaths(folders=["data", "ml"])

Custom directories:

paths = ProjectPaths(
    custom_dirs={
        "modules": "src/modules",
        "views": "src/views"
    }
)

Access paths:

paths.data
paths["models"]
paths.as_dict()

🧠 Design Philosophy

Penwings is built around a few core ideas:

  • Reproducibility first → deterministic data access via caching
  • Convention over configuration → sensible defaults for structure
  • Composable building blocks → small tools that work well together
  • Lightweight core → no heavy framework overhead

🛣️ Roadmap

  • Pipeline abstraction (data workflows as steps)
  • Improved SQL utilities and query management
  • Integration with feature engineering workflows
  • Better caching strategies and metadata tracking

🔢 Versioning

Penwings follows semantic versioning:

  • MAJOR → breaking changes
  • MINOR → new features
  • PATCH → bug fixes

🤝 Contributing

Contributions are welcome!

  1. Fork the repository
  2. Create a branch (feature/my-feature)
  3. Commit your changes
  4. Open a pull request

📄 License

MIT License — see LICENSE


💡 Example Workflow

from sqlalchemy import create_engine
from penwings import ProjectPaths, SQLParquetCache

# Setup project structure
paths = ProjectPaths()

# Setup SQL cache
engine = create_engine("sqlite:///example.db")

cache = SQLParquetCache(
    sql_dir=paths.sql,
    parquet_dir=paths.data,
    conn=engine
)

# Load data
df_sales = cache.get("sales.sql")

⭐ Why Penwings?

Penwings sits between:

  • ad-hoc scripts ❌
  • heavy frameworks ❌

It gives you just enough structure to:

  • stay organized
  • move fast
  • keep workflows reproducible

without getting in your way.

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

penwings-0.3.0.dev1.tar.gz (49.8 kB view details)

Uploaded Source

Built Distribution

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

penwings-0.3.0.dev1-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file penwings-0.3.0.dev1.tar.gz.

File metadata

  • Download URL: penwings-0.3.0.dev1.tar.gz
  • Upload date:
  • Size: 49.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for penwings-0.3.0.dev1.tar.gz
Algorithm Hash digest
SHA256 9ff09c7fe52ef4b6e1972b870f8b1055bfff049825da1aa4cc8e339b9bbab6a5
MD5 9e90676b10f0b1729fe67f71318fcdab
BLAKE2b-256 829098ea337be6836fdeb2c5e1966a22d00c233b7bf4daba17b0b82ea1016ac0

See more details on using hashes here.

File details

Details for the file penwings-0.3.0.dev1-py3-none-any.whl.

File metadata

  • Download URL: penwings-0.3.0.dev1-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for penwings-0.3.0.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 46907784c94176f7953775eb341d9e7eec15eedac32dd7fa5aa3bfc4b13b1b5a
MD5 eceb8e81d7580c900b7955f059e6597e
BLAKE2b-256 3c5eec16f00a4e62b63dbdccb7166ac6f56a0c633155afc3c9b065a4b8bf4c91

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