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.dev2.tar.gz (49.7 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.dev2-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: penwings-0.3.0.dev2.tar.gz
  • Upload date:
  • Size: 49.7 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":"44","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.dev2.tar.gz
Algorithm Hash digest
SHA256 99617f49551ca3fc9950d52d4baa9c82f7086821827858384f49ca9dd7d385ac
MD5 32a85091ee03cba61af311579c8b36ba
BLAKE2b-256 135fd9616bdbc6e09e807d723be50054168c0cbfa73e0a5126f857db8f798ea5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: penwings-0.3.0.dev2-py3-none-any.whl
  • Upload date:
  • Size: 13.5 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":"44","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.dev2-py3-none-any.whl
Algorithm Hash digest
SHA256 8f9c2ac8397e38fbf8f82074a9424e28ee5bf0f204a71a57e05c766f3035f228
MD5 2f0920e07775deab4af2a9418a81ce8f
BLAKE2b-256 bd8b4a01d1c2c27cd4696c5f5766c15ac26b7c2525147e79c456b2a9174da00e

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