Skip to main content

An opinionated command-line interface to the OCPF (Massachusetts campaign finance) API

Project description

OCPF Command Line Interface

ocpf is an opinionated command-line interface to the Massachusetts Office of Campaign and Political Finance (OCPF) API (https://api.ocpf.us/). It turns a recurring, multi-step lookup — "who is running in this district and how much have they raised and spent?" — into a single command.

Install

Run it with no install at all using uvx:

uvx ocpf race 37th

Or install the ocpf command onto your PATH:

pipx install ocpf     # isolated, recommended
pip install ocpf      # into the current environment

Then:

ocpf --help

Usage

ocpf race <district> [--year <year>] [--json]

ocpf race produces a year-to-date (YTD) financial summary of the legislative (House or Senate) candidates in a district.

  • <district> may be a name matched case-insensitively against OCPF's district descriptions (& and and are treated alike) or a raw numeric district code. Ambiguous names are never guessed — the tool prints the matching districts with their codes and exits so you can pick one.
  • --year defaults to the current calendar year.
  • --json emits the merged, filtered candidate records (including the underlying *Numeric values) as JSON to stdout. Human status/progress goes to stderr, so JSON output stays pipeable.

Example

$ ocpf race "Suffolk and Middlesex" --year 2026
District:  Senate, Suffolk and Middlesex (code 166)
Election:  primary 9/1/2026, general 11/3/2026
As of:     6/30/2026 (year-to-date, cumulative)

Candidate                 Party  Inc   Raised YTD    Spent YTD  Cash on Hand
------------------------  -----  ---  -----------  -----------  ------------
Brownsberger, William N.  -      *    $265,435.76  $135,490.74   $326,673.49
Lander, Daniel            -           $117,740.53   $32,674.59   $136,386.28
Wood, Brandon             -                $80.00        $3.00        $77.00

* incumbent (holds this seat)

Election dates and the as-of date are timeline context. The money is the single cumulative YTD figure the API provides for each candidate; it is never split into per-primary and per-general amounts.

ocpf filer — one candidate's filing summary

ocpf filer <filer> [--year <year>] [--json]

ocpf filer drills into a single filer: their committee profile, cumulative YTD finances, and most recent reports.

  • <filer> may be a raw numeric cpfId (works for any filer type) or a candidate name matched case-insensitively against the legislative field for the year. cpfIds are shown by ocpf race. As with district names, ambiguous names are never guessed — the tool prints the matching filers with their cpfIds and exits. Name lookup covers legislative filers; for other filer types, pass a cpfId directly.
  • --year defaults to the current calendar year (used for name resolution and YTD context).
  • --json emits the filer, ytdReport, and logReports records (including numeric values) to stdout.
$ ocpf filer "Brownsberger" --year 2026
Filer:      Brownsberger, William N.  (cpfId 14454)
Committee:  Brownsberger Committee
Party:      Democratic    Type: Legislative Candidates
Office:     Senate, Suffolk and Middlesex
Status:     active
Organized:  12/13/2005
Treasurer:  David Merfeld

Year-to-date (as of 6/30/2026):
  Raised YTD:    $265,435.76
  Spent YTD:     $135,490.74
  Cash on Hand:  $326,673.49

Recent reports:
Type            Period   Filed            Receipts  Expenditures
--------------  -------  --------------  ---------  ------------
Deposit Report  7/20/26  Mon, 7/20/2026    $500.00         $0.00
...

Scope

v1 covers legislative races (House and Senate). Other office types (statewide, county, mayoral, ballot question), drill-down into individual reports/donors/expenditures, and free-text candidate-name search are out of scope. See openspec/ for the design and specifications.

Development

The project is managed with uv. From a clone of this repository:

uv sync --extra dev     # runtime deps + pytest/respx
uv run pytest           # run the test suite
uv run ocpf race 37th   # run the CLI from source

Releasing

Notable changes are recorded in CHANGELOG.md.

Releases are published to PyPI automatically by GitHub Actions when a version tag is pushed. Versioning is tag-driven (via hatch-vcs), so the tag is the single source of truth for the package version:

git tag v0.1.0
git push --tags

The release workflow runs the test suite, builds the sdist and wheel, and publishes to PyPI using Trusted Publishing (OIDC) — no API token is stored in the repository.

First release only: before pushing the first tag, register a pending Trusted Publisher on PyPI (Your projects → Publishing) so the initial upload can create the project:

  • PyPI project name: ocpf
  • Owner: bwbensonjr · Repository: ocpf-cli
  • Workflow: release.yml · Environment: pypi

Design Guidelines

  • Use OpenSpec to draft designs and create change proposals.
  • Use clig.dev for command line interface guidelines.
  • Use the github.com/bwbensonjr/ocpf-analysis repository (available locally) for information about the OCPF APIs, especially the /api directory which contains ENDPOINT-STATUS.md and other script and OCPF API test code.
  • Use the github.com/bwbensonjr/ma-election-db repository (available locally) for information on candidates and districts we might want to look up.

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

ocpf-0.2.0.tar.gz (76.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ocpf-0.2.0-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file ocpf-0.2.0.tar.gz.

File metadata

  • Download URL: ocpf-0.2.0.tar.gz
  • Upload date:
  • Size: 76.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ocpf-0.2.0.tar.gz
Algorithm Hash digest
SHA256 4d6fc9bfbb0c5ca973fe21805fffd0d9524fda827be56086ad7aefe62fdf8fdb
MD5 afd7c48998c095f844b1ce9de47cd4a9
BLAKE2b-256 49a646a8ae9b4fd3498251cf4a2f740c278193ae8a506d19a1e26a93edac32ae

See more details on using hashes here.

Provenance

The following attestation bundles were made for ocpf-0.2.0.tar.gz:

Publisher: release.yml on bwbensonjr/ocpf-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ocpf-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: ocpf-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ocpf-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47e60a61573e964c22088f3e7be76812eaa1cb0cf16633b50624de7d87d7fb6a
MD5 115073ff4cb7837747de87f0ce75579c
BLAKE2b-256 d022932f474dc23f999871363e57f074c6e256a35350cc30f596e9637e97a8d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for ocpf-0.2.0-py3-none-any.whl:

Publisher: release.yml on bwbensonjr/ocpf-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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