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

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.1.0.tar.gz (72.1 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.1.0-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for ocpf-0.1.0.tar.gz
Algorithm Hash digest
SHA256 505311408792ceaa7e5276312e9938607e295f6f7533db177d1eef8713ed76d3
MD5 ba94744f34e07dfde4b084c81eaf4665
BLAKE2b-256 6bf60cfee3d0ee7d97eafc671dc74b503b0b3ba461c463f86fd9d37a6102b601

See more details on using hashes here.

Provenance

The following attestation bundles were made for ocpf-0.1.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.1.0-py3-none-any.whl.

File metadata

  • Download URL: ocpf-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.2 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 417a92119afe3eb2ed977c2ed135f38ca8b24dfd8f9a43942dcce7d13099b6e7
MD5 1c771038f3227e93f704a5da358ce415
BLAKE2b-256 3f1335b5986372def55a89c8d460ac27dcc599dca9988a740d468f66508ce43c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ocpf-0.1.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