Skip to main content

pypi-winnow-downloads

PyPI version Python versions License CI Coverage pip*/uv/poetry/pdm downloads

Self-hosted PyPI download badge service that winnows CI traffic out of download counts. Produces shields.io-compatible endpoint badges filtered by BigQuery's details.ci flag and an interactive-installer allowlist (pip, uv, poetry, pdm, pipenv, pipx) — more honest than any existing alternative for small or young Python packages.

Eating our own dogfood — the download-count badge in the row above and the breakdown below are produced by this project itself; the reference deployment at pypi-badges.intfar.com refreshes them daily via systemd timer. Both views track the same pypi-winnow-downloads package over a 30-day non-CI window.

By installer (30d, non-CI):

pip downloads pipenv downloads pipx downloads uv downloads poetry downloads pdm downloads

By OS (30d, non-CI):

linux downloads macos downloads windows downloads

What these badges actually count

The hero badge — labelled pip*/uv/poetry/pdm (Nd) (N=30 in the reference deployment, configurable per-package via window_days) — counts downloads that meet all of these conditions over the configured rolling window:

  • details.ci != True (BigQuery's CI-detection flag is not set)
  • details.installer.name is one of the interactive Python packaging tools: pip, uv, poetry, pdm, pipenv, or pipx (the asterisk in pip* covers pip itself plus pipenv and pipx, which delegate to pip and inherit its installer telemetry pattern)

Excluded (the things that inflate other badges):

  • Mirrors: bandersnatch, Nexus, devpi, Artifactory, z3c.pypimirror
  • Browser fetches via the PyPI web UI (installer_name == "Browser")
  • Generic HTTP UAs used by scrapers and scanners (requests, curl, etc.)
  • Unknown installer (installer_name == "None") — uncategorised traffic that in practice is dominated by automated scanners

For context on how much these can dwarf real installs: at v1 deploy time, one of the seed packages had 2,771 "non-CI" downloads in 30 days under a naïve mirror-and-all-installers query, of which 1,325 (48%) was bandersnatch alone and only 14 came from pip + uv + poetry + pdm. The honest signal is the 14.

The filter is fail-closed: a future pypinfo emitting a new mainstream installer will be excluded until the allowlist in src/pypi_winnow_downloads/collector.py is updated explicitly. That's a feature for a project whose pitch is honesty.

Per-installer breakdown. Alongside the hero, the reference deployment also produces one badge per installer in the allowlist (pip, pipenv, pipx, uv, poetry, pdm) plus a pip* aggregate (pip + pipenv + pipx). Each applies the same details.ci != True filter as the hero — so they answer "non-CI downloads broken down by which packaging tool the user was running." Useful for spotting installer-mix shifts (e.g., uv overtaking pip on a young package). See Use this service for your own package below for the per-installer URL pattern.

By OS breakdown. Each per-OS badge applies the same details.ci != True filter as the hero — they answer "non-CI downloads on that OS." Darwin is pypinfo's emission for what users call macOS; the badge filename and label use macos. The per-OS sum can be less than the hero count: rows whose user-agent didn't expose a system_name (or exposed one outside Linux/Darwin/Windows) drop out of the per-OS aggregation but still count toward the hero — same pattern as the per-installer-sum ≤ hero gap.

Install

uv tool install pypi-winnow-downloads

uv tool drops the winnow-collect console-script onto your PATH in an isolated environment without touching your system Python. If you don't have uv installed, plain pip also works:

pip install pypi-winnow-downloads

The collector queries Google's public PyPI BigQuery dataset via pypinfo, so before the first run you'll need a Google Cloud service account JSON key. Pypinfo's installation guide walks the full setup (create a GCP project, enable the BigQuery API, generate the JSON key) and recommends the broad BigQuery User role; the narrower pair BigQuery Job User + BigQuery Data Viewer also works and is what config.example.yaml and the reference deploy document. Then point service.credential_file in your config at the resulting file.

Run with a YAML config — copy config.example.yaml and edit:

winnow-collect --config /path/to/config.yaml

To deploy as a daily systemd timer plus a Caddy HTTPS service serving the output directory, see deploy/README.md.

Use this service for your own package

The reference deployment at pypi-badges.intfar.com produces eight badge JSON files per configured package per window, all under https://pypi-badges.intfar.com/<package>/:

File Label What it counts
downloads-30d-non-ci.json pip*/uv/poetry/pdm (30d) All six allowlisted installers summed (the v1 hero)
installer-pip-30d-non-ci.json pip (30d) pip only
installer-pipenv-30d-non-ci.json pipenv (30d) pipenv only
installer-pipx-30d-non-ci.json pipx (30d) pipx only
installer-uv-30d-non-ci.json uv (30d) uv only
installer-poetry-30d-non-ci.json poetry (30d) poetry only
installer-pdm-30d-non-ci.json pdm (30d) pdm only
installer-pip-family-30d-non-ci.json pip* (30d) pip + pipenv + pipx aggregate
os-linux-30d-non-ci.json linux (30d) Per-OS, Linux
os-macos-30d-non-ci.json macos (30d) Per-OS, macOS (Darwin)
os-windows-30d-non-ci.json windows (30d) Per-OS, Windows

All files exclude CI traffic (BigQuery's details.ci != True). Each is a shields.io endpoint badge JSON.

To embed any of these in your own README, wrap the file URL in shields.io's /endpoint?url= form, URL-encoding the inner URL (/ becomes %2F, : becomes %3A):

[![pip downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2F<your-package>%2Finstaller-pip-30d-non-ci.json)](https://pypi.org/project/<your-package>/)

Replace <your-package> with your PyPI package name. The same template works for any of the eight files — substitute the filename. The window length (30d in the examples) reflects the reference deployment's window_days: 30 setting; if you self-host, your own deployment's window_days substitutes here.

To get your package added to the reference deployment's config.yaml, open an issue or run your own collector — see deploy/README.md.

Status

Beta as of v0.2.0. Self-hosted reference deployment running at pypi-badges.intfar.com since 2026-04-25, producing daily badges for four target packages (the three seed packages in config.example.yaml plus pypi-winnow-downloads itself for the dogfood badge). Test suite holds 100% line coverage on src/. The v1 hero badge JSON shape and filename are stable and won't change before 1.0; new badge files may be added (the v2 installer-mix breakdown landed in v0.2.0 alongside the unchanged hero). Expect occasional breaking changes elsewhere in the 0.x series — the Changed/Removed sections of CHANGELOG.md are where to look on each release.

Acknowledgments

This project rests on three pieces of upstream work:

  • pypinfo by Ofek Lev: the BigQuery query layer for the PyPI download dataset. pypi-winnow-downloads is essentially a filter and badge writer wrapped around pypinfo.
  • shields.io renders the endpoint badges. The collector emits the JSON shape that shields.io's endpoint badge consumes, so badges inherit its caching, theming, and SVG rendering.
  • The bigquery-public-data.pypi.file_downloads dataset, hosted by Google as a public BigQuery dataset and populated by the PyPI Linehaul pipeline, is the underlying data source. Without it, no installer-level breakdown of PyPI downloads would be possible.

Designed and built collaboratively with Claude Code (Anthropic) across planning, implementation, review, and QA. Significant subsystems (the pypinfo XDG_DATA_HOME isolation, the sys.executable-based pypinfo resolver, the installer-allowlist filter, the deploy/ examples) emerged through that planner / Dev / QA loop.

License

Licensed under the Apache License, Version 2.0.

© 2026 Chris Means.

Metadata

Release files for pypi-winnow-downloads 0.3.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 pypi-winnow-downloads 0.3.0
File Size Uploaded
pypi_winnow_downloads-0.3.0.tar.gz 186.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pypi-winnow-downloads 0.3.0
File Interpreter ABI Platform
pypi_winnow_downloads-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 206.2 kB

Release files / pypi_winnow_downloads-0.3.0.tar.gz

Download URL pypi_winnow_downloads-0.3.0.tar.gz
Size 186.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2a5012f5b9b129486a05b07e84741c4a2e25251d6059fa1e95f6ece5d5c5a99f
BLAKE2b-256 checksum
How to use checksums
7e5c57b8352e2275cdd7b9c430506d5da0ed342dc2c25b933cd7a83dbdc88a96
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Apr 30, 2026.

Transparency log

Release files / pypi_winnow_downloads-0.3.0-py3-none-any.whl

Download URL pypi_winnow_downloads-0.3.0-py3-none-any.whl
Size 19.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
13caded7b1b260891cd329bcf39feb3ed7cbd77281c7520eea99020919e07cd0
BLAKE2b-256 checksum
How to use checksums
3d711f74510cb79adc9dbbd1128a9d6878b41a220469dd19e506b2c2e5a9b18d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Apr 30, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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