DataFolio
A small, self-documenting home for the data behind one analysis.
You already have the objects: a feature table, some labels, an array of embeddings, a fitted model, a parameter dict, a QC plot. DataFolio gives them one directory, one name each, and one sentence each explaining what they are — then hands them back by name months later, from any notebook.
from datafolio import DataFolio
folio = DataFolio("analysis/experiment-12")
folio.add("features", features, description="One row per neuron; normalized morphology")
folio.add("labels", labels, description="Manual labels after the March review")
folio.add("params", {"alpha": 0.1, "seed": 7})
folio.add_model("classifier", clf, inputs=["features", "labels"])
# A different notebook, six months later. One path, no filenames.
folio = DataFolio("analysis/experiment-12")
folio.describe()
features = folio.get("features")
clf = folio.get_model("classifier")
Install
pip install datafolio # core
pip install 'datafolio[polars]' # + lazy scans and Polars frames
Python 3.10+.
Who it's for
One researcher, or a small team sharing mostly read-only work, holding a few to a few dozen understandable objects per analysis. It assumes you are comfortable in pandas, Polars, numpy, and scikit-learn and do not want another framework between you and them.
Good fit when you want to stop writing
pd.read_parquet(BASE / "features_v3_reviewed.parquet") in every notebook,
remember which of five similar files the paper used, keep one analysis's
objects together, or hand a colleague a single path.
What you get
One write path, one read path. add() picks the storage format from the
object's type; get() reads the catalog and returns the matching Python object.
folio.add("table", dataframe) # pandas / Polars / LazyFrame -> Parquet
folio.add("embeddings", array) # numpy -> .npy
folio.add("params", {"alpha": 0.1}) # dict / list / scalar / str -> JSON
folio.add_model("classifier", clf) # -> joblib (or skops)
folio.add_file("plots/qc.png") # -> the file, unchanged
folio.reference_table("raw", "gs://lab-data/raw.parquet") # link, don't copy
Descriptions live next to the data. The most valuable metadata is usually
one sentence saying which of several near-identical files this is. It is stored
in the catalog, shown by describe(), and readable by people who never install
the package.
Ordinary files, not a container format.
experiment-12/
├── items.json # the authoritative catalog (+ metadata + snapshots)
├── CONTENTS.md # derived, human-readable inventory
├── README.md # how to read this directory without datafolio
├── tables/features--r2.parquet
├── models/classifier--r8.joblib
└── artifacts/params--r5.json
Local or cloud, same code. DataFolio("gs://team-analysis/experiment-12").
Lineage, snapshots, and a CLI when you need them:
folio.add("predictions", preds, inputs=["classifier", "holdout"])
folio.create_snapshot("paper-v1", description="Figures 2–4 in the submission")
datafolio describe
datafolio snapshot status
What it is not
Not a database or query engine, not a workflow orchestrator, not data version control, not an experiment tracker, not a multi-writer system, not a backup. Many readers, one writer — treat a cloud folio as single-writer. Comfortable at a few dozen items per folio, not thousands.
DataFolio's rule is to be as lightweight as possible and hand off to better tools as soon as possible: big tables go to Polars as a lazy scan, or to you as a path. See What DataFolio is not for the full list, including the sharp edges worth knowing before you rely on it.
Documentation
Read in this order:
- Your first folio — ten minutes
- Everyday patterns
- Tables: big, external, and lazy
- Models
- Sharing a folio
- Snapshots
- Reading a folio without DataFolio
- What DataFolio is not
Reference: API cheat sheet · CLI · Migrating from 1.x
Development
uv sync
poe test # pytest with coverage
uv run ruff check src/ tests/
poe doc-preview # local docs server
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file datafolio-2.0.0.tar.gz.
File metadata
- Download URL: datafolio-2.0.0.tar.gz
- Upload date:
- Size: 105.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82d43015185e191575e80b50e0ce069556f1c829d16f5b4404be425d7a7cdb7e
|
|
| MD5 |
10c234ba66148c84aa7f57f52ba5979b
|
|
| BLAKE2b-256 |
44d2ee52acb189ac731d75123dafea04e3f5f541ee23ef585dfd8faba1a94b9a
|
File details
Details for the file datafolio-2.0.0-py3-none-any.whl.
File metadata
- Download URL: datafolio-2.0.0-py3-none-any.whl
- Upload date:
- Size: 120.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f7dcb493d6f699621f09a426984972214bf39fa52385c059e1547998156491c
|
|
| MD5 |
9d500075cdabb748c988182e3724cff1
|
|
| BLAKE2b-256 |
db0b7bfe1f9c5ee17f23e608c3243477b74e612e84e883b0a3decf847267da80
|