Repair every dead series-ID encoding (library now 82/82 query helpers
return live data, verified against the BLS API):
- JOLTS: 21-char format (was 18) — add state/area/sizeclass fields
- OES: national area code 0000000 (was invalid 0000400)
- ECI: correct owner/component/estimate encoding, default unadjusted (CIU)
- Productivity: 4-digit sector + 4-digit measure codes (was 2+3)
- QCEW: 13-char timeseries-API form (ENUUS00010510 / ENU{fips}00010{own}10)
- PPI: repoint finished-goods -> final demand (WPUFD4); keep alias
- ECEC: drop fabricated health-insurance/retirement helpers; add total benefits
- wages SOC: software developers 151132 -> 151252 (2018 SOC)
Tooling/docs:
- config reads BLS_API_KEY env var (takes precedence; config.py gitignored)
- add requirements.txt
- rewrite README as project front door + coverage table + limitations
- correct JOLTS/OES tables in series_id_formats.md, USAGE.md, dataset explorer
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
121 lines
4.5 KiB
Python
121 lines
4.5 KiB
Python
"""
|
|
Pre-built wage and compensation series IDs — OES, ECI, ECEC, CPS earnings.
|
|
"""
|
|
|
|
from ..series import oes_national, eci
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# OES — Occupational Employment & Wage Statistics
|
|
# ---------------------------------------------------------------------------
|
|
def all_occupations_employment() -> str:
|
|
"""National employment across all occupations, all industries."""
|
|
return oes_national("000000", "000000", "employment")
|
|
|
|
|
|
def occupation_annual_median_wage(soc_code: str) -> str:
|
|
"""
|
|
Annual median wage for a specific occupation (national, all industries).
|
|
|
|
Args:
|
|
soc_code: 6-digit SOC code (e.g. "151252" for software developers,
|
|
"291141" for registered nurses, "119021" for construction mgrs)
|
|
"""
|
|
return oes_national(soc_code, "000000", "annual_median")
|
|
|
|
|
|
def occupation_employment(soc_code: str) -> str:
|
|
"""Employment level for a specific occupation (national)."""
|
|
return oes_national(soc_code, "000000", "employment")
|
|
|
|
|
|
# Common occupation codes
|
|
SOC_CODES = {
|
|
"software_developers": "151252",
|
|
"registered_nurses": "291141",
|
|
"teachers_elementary": "252021",
|
|
"accountants": "132011",
|
|
"construction_managers": "119021",
|
|
"truck_drivers": "533032",
|
|
"janitors": "372011",
|
|
"retail_salespersons": "412031",
|
|
"first_line_supervisors_mfg":"511011",
|
|
"lawyers": "231011",
|
|
"physicians": "291229",
|
|
"police_officers": "333051",
|
|
"social_workers": "211029",
|
|
"financial_analysts": "132051",
|
|
"data_scientists": "152051",
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ECI — Employment Cost Index
|
|
# ---------------------------------------------------------------------------
|
|
def eci_total_compensation(seasonal: bool = False) -> str:
|
|
"""ECI — civilian workers, all industries, total compensation (12-mo % change)."""
|
|
return eci(owner="10", component="10", seasonal=seasonal)
|
|
|
|
|
|
def eci_wages(seasonal: bool = False) -> str:
|
|
"""ECI — civilian workers, wages and salaries only (12-mo % change)."""
|
|
return eci(owner="10", component="20", seasonal=seasonal)
|
|
|
|
|
|
def eci_benefits(seasonal: bool = False) -> str:
|
|
"""ECI — civilian workers, benefit costs only (12-mo % change)."""
|
|
return eci(owner="10", component="30", seasonal=seasonal)
|
|
|
|
|
|
def eci_private(seasonal: bool = False) -> str:
|
|
"""ECI — private sector, total compensation (12-mo % change)."""
|
|
return eci(owner="20", component="10", seasonal=seasonal)
|
|
|
|
|
|
def eci_state_local(seasonal: bool = False) -> str:
|
|
"""ECI — state and local government, total compensation (12-mo % change)."""
|
|
return eci(owner="30", component="10", seasonal=seasonal)
|
|
|
|
|
|
def eci_dashboard() -> dict:
|
|
return {
|
|
"Total Compensation (Civilian)": eci_total_compensation(),
|
|
"Wages & Salaries (Civilian)": eci_wages(),
|
|
"Benefits (Civilian)": eci_benefits(),
|
|
"Total Comp (Private)": eci_private(),
|
|
"Total Comp (State/Local Gov)": eci_state_local(),
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ECEC — Employer Costs for Employee Compensation
|
|
# ---------------------------------------------------------------------------
|
|
def ecec_total_compensation() -> str:
|
|
"""ECEC — civilian workers, total compensation cost per hour worked."""
|
|
return "CMU1010000000000D"
|
|
|
|
|
|
def ecec_total_benefits() -> str:
|
|
"""ECEC — civilian workers, total benefits cost per hour worked."""
|
|
return "CMU1036000000000D"
|
|
|
|
# Note: ECEC benefit subcomponents (health insurance, retirement & savings, etc.)
|
|
# are encoded as specific benefit-subcell codes in the series ID (suffix stays "D").
|
|
# Look them up against the ECEC component list before adding helpers — do not
|
|
# fabricate them with a letter suffix (the old "...H"/"...R" forms were invalid).
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CPS Earnings (LE)
|
|
# ---------------------------------------------------------------------------
|
|
def median_weekly_earnings(seasonal: bool = True) -> str:
|
|
"""Median usual weekly earnings — full-time wage and salary workers."""
|
|
return "LEU0252881600" if seasonal else "LEU0252881500"
|
|
|
|
|
|
def median_weekly_earnings_men() -> str:
|
|
return "LEU0252882800"
|
|
|
|
|
|
def median_weekly_earnings_women() -> str:
|
|
return "LEU0252882900"
|