Files
bls-data/README.md
Dave Boyd 5c8e0f11f3 Add README Quickstart with prerequisites; update author email
- README: add a 5-minute Quickstart with a Python 3.9+ prerequisites
  block (OS-specific python3/pip notes + venv step for PEP-668 systems)
- pyproject: set author email to david.boyd1@dc.gov

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 14:54:39 -04:00

235 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BLS Data Library
A small, dependency-light Python library for pulling U.S. Bureau of Labor Statistics
(BLS) time series — unemployment, payrolls, inflation, wages, job openings, and
productivity — with pre-built series-ID helpers so you never have to hand-encode a
series ID.
---
## ⚡ Quickstart (5 minutes)
**Prerequisites:** Python **3.9 or newer** — get it at
[python.org/downloads](https://www.python.org/downloads/) if needed, then verify with
`python3 --version`. On macOS/Linux use `python3` / `pip3`; on Windows use `python` /
`pip`. On recent Ubuntu/Debian, create a virtual environment first so `pip` will run:
`python3 -m venv .venv && . .venv/bin/activate`.
```bash
# 1. Register a FREE BLS API key (instant, emailed in seconds):
# https://data.bls.gov/registrationEngine/
# 2. Set up config (config.example.py ships a template):
cp config.example.py config.py
export BLS_API_KEY="your-key-here" # config.py reads this env var
# 3. Install the one dependency:
pip install -r requirements.txt
# 4. Generate the DC/MD/VA unemployment report:
python3 generate_report.py # → dc_md_va_unemployment_report.html
```
**Want to see the output first?** Open the included `dc_md_va_unemployment_report.html`
in any browser — it's a finished sample, fully self-contained, no internet required.
**Where to go next:** `docs/BLS_Library_Overview.md` for the full tour · `USAGE.md` for
the API · `series_id_formats.md` for building your own series IDs.
> **Note:** You must use **your own** free BLS key. No key is included in this package.
---
```python
from bls_client import BLSClient
from bls_client.queries import employment, prices
client = BLSClient(API_KEY)
# Latest national nonfarm payrolls
client.fetch_latest(employment.nonfarm_payrolls(), years=1)
# A labeled CPI dashboard in one call
client.fetch_named(prices.cpi_dashboard(), 2024, 2025)
```
All 82 zero-argument query helpers are verified against the live API.
---
## Install
```bash
pip install -r requirements.txt # just `requests`
# or install the package itself (editable):
pip install -e .
```
## Configure your API key
Register for a free key (instant, no approval): https://data.bls.gov/registrationEngine/
The free v2 key allows 500 queries/day, 50 series/query, 20 years/query.
```bash
cp config.example.py config.py
export BLS_API_KEY="your-key" # preferred — config.py reads this env var
```
`config.py` is gitignored; the env var takes precedence over anything written in the file.
You can also pass the key directly: `BLSClient("your-key")`.
## Quick start
```bash
python3 examples/basic_pull.py # payrolls, CPI dashboard, DC-region unemployment
python3 examples/custom_series.py # building custom series IDs
```
## Tests
```bash
pip install -e ".[dev]" # pytest
pytest # offline: 95 tests locking the series-ID encodings
pytest -m live # also hit the live API (needs network + BLS_API_KEY)
```
---
## What's in the box
```
bls_client/
├── client.py BLSClient — batching, caching, named fetches, catalog metadata, row flattening
├── series.py low-level series-ID builders (LAUS, CES, CPI, PPI, OES, JOLTS, ECI, ECEC, QCEW, productivity)
├── qcew.py QCEW Open Data CSV client (county/industry detail; no key, no quota)
├── cache.py on-disk response cache (FileCache)
├── retry.py exponential-backoff retry for transient network errors
├── errors.py BLSError / BLSQuotaError / BLSRequestError
└── queries/
├── employment.py payrolls, unemployment (LAUS), JOLTS, QCEW totals
├── prices.py CPI, PPI, average prices, import/export prices
├── wages.py OES occupational wages, ECI, ECEC breakdown
└── productivity.py major-sector productivity & costs
```
`BLSClient` highlights:
- `fetch(ids, start, end)` — auto-batches >50 series, returns `{series_id: {data, catalog}}`
- `fetch_latest(ids, years=N)` — most recent N years
- `fetch_named({label: id})` — returns results keyed by your labels
- `latest_obs(series)` / `to_rows(results)` — convenience for the most recent value / CSV-ready rows
See **[USAGE.md](USAGE.md)** for the full API and **[series_id_formats.md](series_id_formats.md)**
for the series-ID decode tables.
---
## Coverage
| Survey | Helpers | Notes |
|---|---|---|
| LAUS — local area unemployment | state / metro / county rates, DC-region dashboard | ✅ |
| CES — payroll employment | national by supersector; state/metro | ✅ |
| CPS — household survey | national unemployment rate, participation | ✅ |
| JOLTS — job openings & turnover | openings/hires/quits/layoffs, dashboard | ✅ |
| CPI — consumer prices | all-items, core, food, energy, gasoline, …; dashboard | ✅ |
| PPI — producer prices | all commodities, final demand, food, energy | ✅ |
| OES — occupational wages | employment + wage percentiles by SOC; 15 common occupations | ✅ |
| ECI — employment cost index | total comp / wages / benefits × civilian/private/gov | ✅ |
| ECEC — employer cost levels | full breakdown: comp, wages, benefits, paid leave, supplemental, health insurance, retirement, legally-required | ✅ |
| Productivity & costs | output/hr, ULC, comp, hours × business/nonfarm/manufacturing | ✅ |
| QCEW — quarterly census | national/state totals (timeseries) **plus** full county/industry detail via the CSV module (`bls_client.qcew`) | ✅ |
## Caching & quota handling
```python
client = BLSClient(API_KEY, cache=True) # on-disk cache at ~/.cache/bls (1-day TTL)
client.fetch(...) # repeated identical requests don't re-spend quota
client.queries_used # network calls made this session (cache hits excluded)
```
A blown daily quota raises `BLSQuotaError` (vs `BLSRequestError` for a bad request), so
"am I throttled or is my series ID wrong?" is no longer ambiguous.
Transient network failures (timeouts, dropped connections, `429`/`5xx`) are retried with
exponential backoff — `BLSClient(API_KEY, retries=2, backoff=0.5)` (set `retries=0` to
disable). A server `Retry-After` header is honored. The QCEW CSV client retries too. Note
that retries deliberately exclude `BLSQuotaError` and 4xx — those won't fix themselves.
## QCEW county/industry detail
The timeseries helpers give QCEW national/state totals; the `qcew` module reaches the full
county- and industry-level detail via BLS's separate CSV service (no key, no quota):
```python
from bls_client import qcew
rows = qcew.area("11000", 2024, "a") # everything for DC, annual
dc_private = qcew.filter_rows(rows, own_code="private", industry_code="10", agglvl_code="51")
hospitals = qcew.industry("622", 2024, "a") # one NAICS across all areas
```
## Known limitations
- **Coverage is the headline cut** of each survey, not an exhaustive mirror — e.g. CES is
national supersectors + a couple of states; CPI is the common items; OES ships 15 named
occupations (any SOC works via `occupation_*`). Broaden the helper dicts as needed.
---
## Appendix: BLS API reference
Reference material for working directly with the API (the library wraps all of this).
### API versions
| Feature | v1 (no key) | v2 (registered) |
|---------------------------|-------------|-----------------|
| Daily query limit | 25 | 500 |
| Series per query | 25 | 50 |
| Years of history | 10 | 20 |
| Net/percent changes | No | Yes |
| Series descriptions | No | Yes |
| Calculations | No | Yes |
### Endpoints
```
GET /v2/surveys # all survey codes and names (see surveys.json)
GET /v2/surveys/{abbr} # one survey
GET /v2/timeseries/popular?survey={abbr} # 25 most-requested series IDs for a survey
POST /v2/timeseries/data/ # the time-series data endpoint
```
Base URL: `https://api.bls.gov/publicAPI/v2`
**POST body (registered, all v2 features):**
```json
{
"seriesid": ["LAUST110000000000003", "CES0000000001"],
"startyear": "2020", "endyear": "2025",
"registrationkey": "YOUR_KEY",
"catalog": true, "calculations": true, "annualaverage": true
}
```
**Period codes:** monthly `M01``M12` (`M13` = annual avg); quarterly `Q01``Q04` (`Q05` = annual avg); annual `A01`.
**Status codes:** `REQUEST_SUCCEEDED`, `REQUEST_FAILED`, `REQUEST_NOT_PROCESSED` (often = daily quota hit).
**Footnote codes:** `R` revised, `P` preliminary, `X`/`N` unavailable.
A full real response is saved in `api_response_example.json`.
### Bulk flat files
Base: `https://download.bls.gov/pub/time.series/` — each survey folder has
`{prefix}.series` (master list), `{prefix}.data.*` (observations), and `{prefix}.{dimension}`
decode tables (area, industry, measure). Tab-delimited; handy for bulk PostgreSQL ingest.
Key prefixes: `la/` LAUS, `ce/` CES, `sm/` state-metro, `en/` QCEW, `oe/` OES, `jt/` JOLTS,
`cu/` CPI-U, `wp/` PPI.
### Other files in this repo
- `series_id_formats.md` — series-ID decode tables for each survey
- `qcew_field_schema.md` — QCEW quarterly/annual CSV field layouts
- `surveys.json` — complete survey list from the API
- `bls_dataset_explorer.py` / `.html` — browsable survey catalog
- `dc_md_va_unemployment.py` / `generate_report.py` — example report generators