Skip to main content

sourceledger

python license

Build a dataset from public sources where every row says which download it came from.

A project lists its inputs in sources.toml: each source's URL, the publisher's reuse terms, and whether the raw file may be republished. sourceledger runs four stages over that manifest:

  • fetch downloads each source into data/raw/, with a record beside it: the URL, when it was fetched, the SHA-256 and size of the bytes, the vintage the manifest declares, and the server's ETag and Last-Modified. The next fetch sends the ETag back, so an unchanged source is not downloaded again. Each new version of a source is also appended to data/fetches.jsonl.
  • build re-hashes each download against its record, reads it, and writes data/processed/<id>.csv with five provenance columns in front of the source's own: source_id, source_url, retrieved_at, vintage and raw_sha256.
  • validate re-reads the output and reports every problem it finds: output built from an older fetch, a raw file changed since its fetch, a record made for another URL, vintage or pin, a source with no reuse terms, an output with no rows, and output left by a source that is gone or marked unimplemented.
  • revisions OLD_LOG lists the sources whose bytes changed since an earlier copy of the fetch log. A weekly CI run can use it to say when a publisher revised its data.

sourceledger has no dependencies: the standard library does all of it.

Install

uv add sourceledger

Until the first release is on PyPI, install it from GitHub: uv add git+https://github.com/simonvanlierde/sourceledger.

Quick start

Write a sources.toml in the project root:

[[source]]
id = "co2"
status = "implemented"
url = "https://raw.githubusercontent.com/datasets/co2-ppm/main/data/co2-annmean-mlo.csv"
vintage = "main branch, unversioned"
terms = "ODC-PDDL-1.0 (datasets/co2-ppm package; original data from NOAA GML)"
terms_url = "https://opendatacommons.org/licenses/pddl/"
license = "PDDL-1.0"
redistribute = true

Then run the stages from that directory:

sourceledger fetch
sourceledger build
sourceledger validate

sourceledger reads every source as CSV. For other formats, see Your own readers.

What to commit

Commit sources.toml and data/fetches.jsonl. The log holds checksums and URLs, not data, and it is the history of every version of every source you have fetched.

Keep data/raw/ and data/processed/ out of git, so the repository never redistributes a publisher's data. The per-file .fetch.json records live in data/raw/ too. A fresh clone runs fetch before build and validate.

sources.toml

Each [[source]] table takes these keys:

Key Required Meaning
id yes Letters, digits, _ and -. Names the raw file (id plus the URL's extension) and the output.
status yes "implemented", read by every stage, or "unimplemented": a source you know about but don't read yet. validate fails if one of those has output.
url for implemented sources What fetch downloads. Change it and build refuses the old download until you fetch again.
terms, terms_url for implemented sources The publisher's reuse terms in their words, and where they are stated.
license for implemented sources The same terms as an SPDX id, such as "CC-BY-4.0", or "LicenseRef-<name>" for terms with none.
redistribute for implemented sources true if the terms let you republish the raw file, false if not.
vintage no The edition you expect, such as "2024 release" or a TOML date. Recorded with each fetch and stamped on each row. "not stated" when absent. The old key release still works, with a warning.
sha256 no The SHA-256 the download must have. Pin it for a fixed release, and fetch refuses bytes that changed upstream.
max_bytes no The largest download fetch accepts. 200 MiB unless set.
reason no A note for people, such as why a source is unimplemented. sourceledger doesn't read it.

validate reports a missing terms, terms_url, license or redistribute. The other keys are checked when the manifest loads.

How fetch behaves

  • It tries four times, waiting 5, 10 and 20 s between attempts, on 429, 500, 502, 503, 504, network errors and a body cut short. A Retry-After header, in seconds or as a date, raises the wait to at most 120 s. Any other error status fails at once.
  • Each connect and read times out after 30 s, and one source's whole fetch after 300 s.
  • It asks for the file uncompressed, and refuses a compressed reply. The checksum is always of the file as published.
  • It refuses a redirect from a public host to a loopback, private or link-local address. When a redirect is followed, the record keeps the final URL too.
  • Every source is tried. When some fail, the others are still written, and the run exits 1 with one line per failed source.
  • Each file is written to a new temporary file and renamed into place, so a crash never leaves half a file. A fetch log line cut off by a crash is dropped on the next run.

Your own readers

sourceledger reads every source with parse_csv. A project with other formats gives it its own reader, a function from a source's manifest table and raw bytes to columns and rows, and its own command:

# src/my_dataset/pipeline.py
import sourceledger
from sourceledger import Source


def parse(source: Source, payload: bytes) -> tuple[list[str], list[dict[str, str]]]:
    """Every source is CSV here. Branch on source["id"] for one that is not."""
    return sourceledger.parse_csv(source, payload)


def main(argv: list[str] | None = None) -> int:
    return sourceledger.main(argv, parse=parse, prog="my-dataset", user_agent="my-dataset")
# pyproject.toml
[project.scripts]
my-dataset = "my_dataset.pipeline:main"

my-dataset fetch, my-dataset build and my-dataset validate then run with that reader, and publishers see my-dataset as the User-Agent. The project-templates data-pipeline kind sets all of this up, with CI and a weekly run that reports revised sources.

The same stages are functions too: load_manifest, fetch, build, validate and revisions.

Stability

Until 1.0, the public API is what sourceledger exports in __all__, the keys of sources.toml, and the format of fetch records and the fetch log. A breaking change to any of them comes only in a minor version, listed in CHANGELOG.md, with a warning first where that is cheap. Fetch logs written by an earlier version stay readable.

Development

uv sync
uv tool install prek   # once per machine
prek install           # git hooks
just check             # lint, types and tests, as CI runs them

License

MIT. See LICENSE.

Metadata

Release files for sourceledger 0.1.0

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

Source distribution (sdist)

Source distribution for sourceledger 0.1.0
File Size Uploaded Provenance
sourceledger-0.1.0.tar.gz 16.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sourceledger 0.1.0
File Interpreter ABI Platform
sourceledger-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.8 kB

Release files / sourceledger-0.1.0.tar.gz

Download URL sourceledger-0.1.0.tar.gz
Size 16.3 kB
Tags Source
SHA-256 checksum
How to use checksums
bfd39c06b1d34385f8b355eafd7b4f321530ef8b4f92137b86f4d16d84a51c5d
BLAKE2b-256 checksum
How to use checksums
d91d346bff276f08ddc18dd1b604ec8fd28bbad626e62c0c455df617fb33d4cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / sourceledger-0.1.0-py3-none-any.whl

Download URL sourceledger-0.1.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6d81973280ab9dd7359de8062c756cd0268c53c28f6137ed6817c6799c3fd795
BLAKE2b-256 checksum
How to use checksums
b3e437c7fd2bca601bd6117b26be74792de1df3f4d244bfca2f2c9275e1aee14
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for sourceledger 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sourceledger-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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