Add BLS client library, example scripts, and usage docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1
bls_client/queries/__init__.py
Normal file
1
bls_client/queries/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from . import employment, prices, wages, productivity
|
||||
133
bls_client/queries/employment.py
Normal file
133
bls_client/queries/employment.py
Normal file
@ -0,0 +1,133 @@
|
||||
"""
|
||||
Pre-built employment series IDs — ready to pass to BLSClient.fetch().
|
||||
|
||||
All functions return a single series ID string or a dict of {label: series_id}.
|
||||
"""
|
||||
|
||||
from ..series import laus_state, laus_msa, ces_national, ces_state, jolts
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# National employment
|
||||
# ---------------------------------------------------------------------------
|
||||
def nonfarm_payrolls(seasonal: bool = True) -> str:
|
||||
"""Total nonfarm payroll employment (CES). The headline monthly jobs number."""
|
||||
return ces_national("total_nonfarm", "employees", seasonal)
|
||||
|
||||
|
||||
def private_payrolls(seasonal: bool = True) -> str:
|
||||
"""Total private sector payroll employment."""
|
||||
return ces_national("total_private", "employees", seasonal)
|
||||
|
||||
|
||||
def government_employment(seasonal: bool = True) -> str:
|
||||
"""Total government employment (federal + state + local)."""
|
||||
return ces_national("government", "employees", seasonal)
|
||||
|
||||
|
||||
def manufacturing_employment(seasonal: bool = True) -> str:
|
||||
return ces_national("manufacturing", "employees", seasonal)
|
||||
|
||||
|
||||
def national_unemployment_rate(seasonal: bool = True) -> str:
|
||||
"""National unemployment rate from the CPS (U-3 rate)."""
|
||||
return "LNS14000000" if seasonal else "LNU04000000"
|
||||
|
||||
|
||||
def national_labor_force_participation(seasonal: bool = True) -> str:
|
||||
"""National labor force participation rate."""
|
||||
return "LNS11300000" if seasonal else "LNU01300000"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# LAUS — state unemployment
|
||||
# ---------------------------------------------------------------------------
|
||||
def dc_unemployment_rate(seasonal: bool = False) -> str:
|
||||
return laus_state(11, "rate", seasonal)
|
||||
|
||||
|
||||
def md_unemployment_rate(seasonal: bool = False) -> str:
|
||||
return laus_state(24, "rate", seasonal)
|
||||
|
||||
|
||||
def va_unemployment_rate(seasonal: bool = False) -> str:
|
||||
return laus_state(51, "rate", seasonal)
|
||||
|
||||
|
||||
def state_unemployment(state_fips: int, seasonal: bool = False) -> dict:
|
||||
"""All four LAUS measures for a state."""
|
||||
return {
|
||||
"rate": laus_state(state_fips, "rate", seasonal),
|
||||
"unemployed": laus_state(state_fips, "unemployed", seasonal),
|
||||
"employed": laus_state(state_fips, "employed", seasonal),
|
||||
"laborforce": laus_state(state_fips, "laborforce", seasonal),
|
||||
}
|
||||
|
||||
|
||||
def dc_region_unemployment() -> dict:
|
||||
"""Unemployment rates for DC, MD, VA states + DC Metro, Baltimore, Richmond MSAs."""
|
||||
return {
|
||||
"DC State": laus_state(11, "rate"),
|
||||
"Maryland": laus_state(24, "rate"),
|
||||
"Virginia": laus_state(51, "rate"),
|
||||
"DC Metro MSA": laus_msa(11, 47900, "rate"),
|
||||
"Baltimore MSA":laus_msa(24, 12580, "rate"),
|
||||
"Richmond MSA": laus_msa(51, 40060, "rate"),
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# JOLTS
|
||||
# ---------------------------------------------------------------------------
|
||||
def job_openings_level(seasonal: bool = True) -> str:
|
||||
return jolts("job_openings", "L", seasonal=seasonal)
|
||||
|
||||
|
||||
def job_openings_rate(seasonal: bool = True) -> str:
|
||||
return jolts("job_openings", "R", seasonal=seasonal)
|
||||
|
||||
|
||||
def quits_level(seasonal: bool = True) -> str:
|
||||
return jolts("quits", "L", seasonal=seasonal)
|
||||
|
||||
|
||||
def hires_level(seasonal: bool = True) -> str:
|
||||
return jolts("hires", "L", seasonal=seasonal)
|
||||
|
||||
|
||||
def layoffs_level(seasonal: bool = True) -> str:
|
||||
return jolts("layoffs", "L", seasonal=seasonal)
|
||||
|
||||
|
||||
def jolts_dashboard() -> dict:
|
||||
"""All five JOLTS measures (levels, SA) as a labeled dict."""
|
||||
return {
|
||||
"Job Openings": job_openings_level(),
|
||||
"Hires": hires_level(),
|
||||
"Quits": quits_level(),
|
||||
"Layoffs": layoffs_level(),
|
||||
"Total Separations": jolts("total_separations", "L"),
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# QCEW
|
||||
# ---------------------------------------------------------------------------
|
||||
def qcew_national_private() -> str:
|
||||
"""QCEW — national, private sector, all industries, quarterly."""
|
||||
return "ENU0000010510000"
|
||||
|
||||
|
||||
def qcew_dc_private() -> str:
|
||||
"""QCEW — DC, private sector, all industries."""
|
||||
return "ENU1100010510000"
|
||||
|
||||
|
||||
def qcew_state(state_fips: int, ownership: str = "5") -> str:
|
||||
"""
|
||||
QCEW state-level series.
|
||||
|
||||
Args:
|
||||
state_fips: 2-digit FIPS
|
||||
ownership: "0"=all, "5"=private, "1"=federal, "2"=state, "3"=local
|
||||
"""
|
||||
return f"ENU{state_fips:02d}0001{ownership}10000"
|
||||
124
bls_client/queries/prices.py
Normal file
124
bls_client/queries/prices.py
Normal file
@ -0,0 +1,124 @@
|
||||
"""
|
||||
Pre-built price series IDs — CPI, PPI, Import/Export, Average Prices.
|
||||
"""
|
||||
|
||||
from ..series import cpi, ppi_commodity
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CPI-U
|
||||
# ---------------------------------------------------------------------------
|
||||
def cpi_all_items(seasonal: bool = False) -> str:
|
||||
"""CPI-U all items, US city average."""
|
||||
return cpi("all_items", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_core(seasonal: bool = True) -> str:
|
||||
"""CPI-U all items less food and energy (core inflation)."""
|
||||
return cpi("core", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_food(seasonal: bool = False) -> str:
|
||||
return cpi("food", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_energy(seasonal: bool = False) -> str:
|
||||
return cpi("energy", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_shelter(seasonal: bool = False) -> str:
|
||||
return cpi("shelter", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_gasoline(seasonal: bool = True) -> str:
|
||||
return cpi("gasoline", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_medical(seasonal: bool = False) -> str:
|
||||
return cpi("medical", seasonal=seasonal)
|
||||
|
||||
|
||||
def cpi_dashboard(seasonal: bool = False) -> dict:
|
||||
"""Key CPI components as a labeled dict."""
|
||||
return {
|
||||
"All Items": cpi_all_items(seasonal),
|
||||
"Core (ex food/NRG)": cpi_core(True),
|
||||
"Food": cpi_food(seasonal),
|
||||
"Energy": cpi_energy(seasonal),
|
||||
"Shelter": cpi_shelter(seasonal),
|
||||
"Medical Care": cpi_medical(seasonal),
|
||||
"Gasoline": cpi_gasoline(True),
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CPI-W
|
||||
# ---------------------------------------------------------------------------
|
||||
def cpi_w_all_items(seasonal: bool = False) -> str:
|
||||
"""CPI-W all items (used for Social Security COLA)."""
|
||||
return cpi("all_items", seasonal=seasonal, series="W")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PPI
|
||||
# ---------------------------------------------------------------------------
|
||||
def ppi_all_commodities() -> str:
|
||||
"""PPI — all commodities index."""
|
||||
return ppi_commodity("00000000")
|
||||
|
||||
|
||||
def ppi_finished_goods() -> str:
|
||||
"""PPI — finished goods."""
|
||||
return ppi_commodity("3")
|
||||
|
||||
|
||||
def ppi_energy() -> str:
|
||||
return ppi_commodity("05")
|
||||
|
||||
|
||||
def ppi_food() -> str:
|
||||
return ppi_commodity("02")
|
||||
|
||||
|
||||
def ppi_dashboard() -> dict:
|
||||
return {
|
||||
"All Commodities": ppi_all_commodities(),
|
||||
"Finished Goods": ppi_finished_goods(),
|
||||
"Food": ppi_food(),
|
||||
"Energy": ppi_energy(),
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Average Prices (AP)
|
||||
# ---------------------------------------------------------------------------
|
||||
def avg_price_electricity() -> str:
|
||||
"""Average retail price of electricity per KWh."""
|
||||
return "APU000072610"
|
||||
|
||||
|
||||
def avg_price_gasoline_regular() -> str:
|
||||
"""Average retail price of regular unleaded gasoline per gallon."""
|
||||
return "APU00007471A"
|
||||
|
||||
|
||||
def avg_price_eggs() -> str:
|
||||
"""Average retail price of eggs per dozen."""
|
||||
return "APU0000708111"
|
||||
|
||||
|
||||
def avg_price_ground_beef() -> str:
|
||||
"""Average retail price of ground beef per pound."""
|
||||
return "APU0000703112"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Import/Export Price Indexes (EI)
|
||||
# ---------------------------------------------------------------------------
|
||||
def import_price_index() -> str:
|
||||
"""Import price index — all imports."""
|
||||
return "EIUIR"
|
||||
|
||||
|
||||
def export_price_index() -> str:
|
||||
"""Export price index — all exports."""
|
||||
return "EIUIQ"
|
||||
36
bls_client/queries/productivity.py
Normal file
36
bls_client/queries/productivity.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""
|
||||
Pre-built productivity series IDs — Major Sector Productivity & Costs.
|
||||
"""
|
||||
|
||||
from ..series import productivity
|
||||
|
||||
def business_output_per_hour(seasonal: bool = True) -> str:
|
||||
"""Business sector output per hour worked (quarterly)."""
|
||||
return productivity("business", "output_per_hour", seasonal)
|
||||
|
||||
|
||||
def business_unit_labor_cost(seasonal: bool = True) -> str:
|
||||
"""Business sector unit labor costs (quarterly)."""
|
||||
return productivity("business", "unit_labor_cost", seasonal)
|
||||
|
||||
|
||||
def business_real_comp_per_hour(seasonal: bool = True) -> str:
|
||||
"""Business sector real compensation per hour."""
|
||||
return productivity("business", "real_comp_per_hr", seasonal)
|
||||
|
||||
|
||||
def nonfarm_output_per_hour(seasonal: bool = True) -> str:
|
||||
return productivity("nonfarm_business", "output_per_hour", seasonal)
|
||||
|
||||
|
||||
def manufacturing_output_per_hour(seasonal: bool = True) -> str:
|
||||
return productivity("manufacturing", "output_per_hour", seasonal)
|
||||
|
||||
|
||||
def productivity_dashboard() -> dict:
|
||||
return {
|
||||
"Business Output/Hr": business_output_per_hour(),
|
||||
"Business Unit Labor Cost": business_unit_labor_cost(),
|
||||
"Nonfarm Output/Hr": nonfarm_output_per_hour(),
|
||||
"Manufacturing Output/Hr": manufacturing_output_per_hour(),
|
||||
}
|
||||
120
bls_client/queries/wages.py
Normal file
120
bls_client/queries/wages.py
Normal file
@ -0,0 +1,120 @@
|
||||
"""
|
||||
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. "151132" 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": "151132",
|
||||
"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 = True) -> str:
|
||||
"""ECI — civilian workers, all industries, total compensation."""
|
||||
return eci("10", "10", component="A", seasonal=seasonal)
|
||||
|
||||
|
||||
def eci_wages(seasonal: bool = True) -> str:
|
||||
"""ECI — civilian workers, wages and salaries only."""
|
||||
return eci("10", "10", component="W", seasonal=seasonal)
|
||||
|
||||
|
||||
def eci_benefits(seasonal: bool = True) -> str:
|
||||
"""ECI — civilian workers, benefit costs only."""
|
||||
return eci("10", "10", component="B", seasonal=seasonal)
|
||||
|
||||
|
||||
def eci_private(seasonal: bool = True) -> str:
|
||||
"""ECI — private sector, total compensation."""
|
||||
return eci("20", "10", component="A", seasonal=seasonal)
|
||||
|
||||
|
||||
def eci_state_local(seasonal: bool = True) -> str:
|
||||
"""ECI — state and local government, total compensation."""
|
||||
return eci("30", "10", component="A", 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."""
|
||||
return "CMU1010000000000D"
|
||||
|
||||
|
||||
def ecec_health_insurance() -> str:
|
||||
"""ECEC — health insurance cost per hour worked."""
|
||||
return "CMU1010000000000H"
|
||||
|
||||
|
||||
def ecec_retirement() -> str:
|
||||
"""ECEC — retirement & savings cost per hour worked."""
|
||||
return "CMU1010000000000R"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 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"
|
||||
Reference in New Issue
Block a user