Skip to content
Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **Per-installer badge files (v2 installer-mix feature).** The collector now emits seven additional shields.io endpoint badge JSON files per package per window, alongside the existing v1 hero (`downloads-<N>d-non-ci.json`, unchanged). New files: `installer-pip-<N>d-non-ci.json`, `installer-pipenv-<N>d-non-ci.json`, `installer-pipx-<N>d-non-ci.json`, `installer-uv-<N>d-non-ci.json`, `installer-poetry-<N>d-non-ci.json`, `installer-pdm-<N>d-non-ci.json`, and `installer-pip-family-<N>d-non-ci.json` (the pip-family aggregate = pip + pipenv + pipx). All seven apply the same `details.ci != True` filter as v1, with each file's `installer_name` allowlisting handled by the existing `_INSTALLER_ALLOWLIST`. The badge label format follows v1's parameterized `(Nd)` style — e.g., `pip (30d)`, `pip* (30d)`. Color logic (`blue` if count ≥ 10 else `lightgrey`) and the count-formatting helper (`format_count`) are unchanged. `run_pypinfo`'s return type changes from `int` to `dict[str, int]` mapping `installer_name` → count; the v1 hero count is now `sum(per_installer.values())`. `_health.json` per-package successful entries gain a `counts` field carrying the seven-keyed dict; the existing top-level `count` field is preserved verbatim for backwards compatibility with any monitoring or scripting that reads it. README expanded to dogfood all six individual installer counts in the badge row and gains a new "Use this service for your own package" section documenting the URL pattern for third-party packages. No new config fields — the collector always emits all eight files; maintainer's README picks which to display via shields.io endpoint URLs. Backwards-compat guarantees: `downloads-<N>d-non-ci.json` filename, schema, and value unchanged for any given pypinfo response; `_health.json` top-level fields unchanged. Spec: `docs/superpowers/specs/2026-04-28-installer-mix-badge-design.md`.

## [0.1.3] - 2026-04-28

### Added
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
[![CI](https://img.shields.io/github/actions/workflow/status/cmeans/pypi-winnow-downloads/ci.yml?label=CI)](https://github.com/cmeans/pypi-winnow-downloads/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/cmeans/pypi-winnow-downloads/graph/badge.svg)](https://codecov.io/gh/cmeans/pypi-winnow-downloads)
[![pip*/uv/poetry/pdm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Fdownloads-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![pip downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-pip-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![pipenv downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-pipenv-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![pipx downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-pipx-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![uv downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-uv-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![poetry downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-poetry-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![pdm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-pdm-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)

Self-hosted PyPI download badge service that winnows CI traffic out of download
counts. Produces [shields.io](https://shields.io/badges/endpoint-badge)-compatible endpoint
Expand Down Expand Up @@ -76,6 +82,45 @@ To deploy as a daily systemd timer plus a Caddy HTTPS service serving the
output directory, see
[`deploy/README.md`](https://github.com/cmeans/pypi-winnow-downloads/blob/main/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 |

All files exclude CI traffic (BigQuery's `details.ci != True`). Each is a
[shields.io endpoint badge](https://shields.io/badges/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`):

```markdown
[![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](https://github.com/cmeans/pypi-winnow-downloads/issues/new)
or run your own collector — see
[`deploy/README.md`](https://github.com/cmeans/pypi-winnow-downloads/blob/main/deploy/README.md).

## Status

Alpha. Self-hosted reference deployment running at
Expand Down
Loading