| name | policyengine-python-client |
| description | Using PolicyEngine programmatically via Python client or REST API |
PolicyEngine Python Client
This skill covers programmatic access to PolicyEngine for analysts and researchers.
Installation
# Install the Python client
pip install policyengine
# Or for local development
pip install policyengine-us # Just the US model (offline)
Quick Start: Python Client
from policyengine import Simulation
# Create a household
household = {
"people": {
"you": {
"age": {"2024": 30},
"employment_income": {"2024": 50000}
}
},
"households": {
"your household": {
"members": ["you"],
"state_name": {"2024": "CA"}
}
}
}
# Run simulation
sim = Simulation(situation=household, country_id="us")
income_tax = sim.calculate("income_tax", "2024")
For Users: Why Use Python?
Web app limitations:
- ✅ Great for exploring policies interactively
- ❌ Can't analyze many households at once
- ❌ Can't automate repetitive analyses
- ❌ Limited customization of charts
Python benefits:
- ✅ Analyze thousands of households in batch
- ✅ Automate regular policy analysis
- ✅ Create custom visualizations
- ✅ Integrate with other data sources
- ✅ Reproducible research
For Analysts: Common Workflows
Workflow 1: Calculate Your Own Taxes
from policyengine import Simulation
# Your household (more complex than web app)
household = {
"people": {
"you": {
"age": {"2024": 35},
"employment_income": {"2024": 75000},
"qualified_dividend_income": {"2024": 5000},
"charitable_cash_donations": {"2024": 3000}
},
"spouse": {
"age": {"2024": 33},
"employment_income": {"2024": 60000}
},
"child1": {"age": {"2024": 8}},
"child2": {"age": {"2024": 5}}
},
# ... entities setup (see policyengine-us-skill)
}
sim = Simulation(situation=household, country_id="us")
# Calculate specific values
federal_income_tax = sim.calculate("income_tax", "2024")
state_income_tax = sim.calculate("state_income_tax", "2024")
ctc = sim.calculate("ctc", "2024")
eitc = sim.calculate("eitc", "2024")
print(f"Federal income tax: ${federal_income_tax:,.0f}")
print(f"State income tax: ${state_income_tax:,.0f}")
print(f"Child Tax Credit: ${ctc:,.0f}")
print(f"EITC: ${eitc:,.0f}")
Workflow 2: Analyze a Policy Reform
from policyengine import Simulation
# Define reform (increase CTC to $5,000)
reform = {
"gov.irs.credits.ctc.amount.base_amount": {
"2024-01-01.2100-12-31": 5000
}
}
# Compare baseline vs reform
household = create_household() # Your household definition
sim_baseline = Simulation(situation=household, country_id="us")
sim_reform = Simulation(situation=household, country_id="us", reform=reform)
ctc_baseline = sim_baseline.calculate("ctc", "2024")
ctc_reform = sim_reform.calculate("ctc", "2024")
print(f"CTC baseline: ${ctc_baseline:,.0f}")
print(f"CTC reform: ${ctc_reform:,.0f}")
print(f"Increase: ${ctc_reform - ctc_baseline:,.0f}")
Workflow 3: Batch Analysis
import pandas as pd
from policyengine import Simulation
# Analyze multiple households
households = [
{"income": 30000, "children": 0},
{"income": 50000, "children": 2},
{"income": 100000, "children": 3},
]
results = []
for h in households:
situation = create_household(income=h["income"], num_children=h["children"])
sim = Simulation(situation=situation, country_id="us")
results.append({
"income": h["income"],
"children": h["children"],
"income_tax": sim.calculate("income_tax", "2024"),
"ctc": sim.calculate("ctc", "2024"),
"eitc": sim.calculate("eitc", "2024")
})
df = pd.DataFrame(results)
print(df)
Using the REST API Directly
Authentication
Public access:
- 100 requests per minute (unauthenticated)
- No API key needed for basic use
Authenticated access:
- 1,000 requests per minute
- Contact hello@policyengine.org for API key
Key Endpoints
Calculate household impact:
import requests
url = "https://api.policyengine.org/us/calculate"
payload = {
"household": household_dict,
"policy_id": reform_id # or None for baseline
}
response = requests.post(url, json=payload)
result = response.json()
Get policy details:
# Get policy metadata
response = requests.get("https://api.policyengine.org/us/policy/12345")
policy = response.json()
Get parameter values:
# Get current parameter value
response = requests.get(
"https://api.policyengine.org/us/parameter/gov.irs.credits.ctc.amount.base_amount"
)
parameter = response.json()
For Full API Documentation
OpenAPI spec: https://api.policyengine.org/docs
To explore:
# View all endpoints
curl https://api.policyengine.org/docs
# Test calculate endpoint
curl -X POST https://api.policyengine.org/us/calculate \
-H "Content-Type: application/json" \
-d '{"household": {...}}'
Limitations and Considerations
Rate Limits
Unauthenticated:
- 100 requests/minute
- Good for exploratory analysis
Authenticated:
- 1,000 requests/minute
- Required for production use
Data Privacy
- PolicyEngine does not store household data
- All calculations happen server-side and are not logged
- Reform URLs are public (don't include personal info in reforms)
Performance
API calls:
- Simple household: ~200-500ms
- Population impact: ~5-30 seconds (varies by reform)
- Use caching for repeated calculations
Local simulation (policyengine-us):
- Faster for batch analysis
- No rate limits
- No network dependency
- Limited to one country per package
Choosing Local vs API
Use Local (policyengine-us package)
When:
- Batch analysis of many households
- Need offline capability
- Analyzing parameter sweeps (axes)
- Development/testing
Install:
pip install policyengine-us # US only
pip install policyengine-uk # UK only
Example:
from policyengine_us import Simulation
# Works offline
sim = Simulation(situation=household)
Use API (policyengine or requests)
When:
- Multi-country analysis
- Using latest model version
- Don't want to manage dependencies
- Integration with web services
Example:
import requests
# Requires internet
response = requests.post("https://api.policyengine.org/us/calculate", ...)
For Contributors: Understanding the Client
Repository: PolicyEngine/policyengine.py
To see implementation:
# Clone the client
git clone https://github.com/PolicyEngine/policyengine.py
# See the Simulation class
cat policyengine/simulation.py
# See API integration
cat policyengine/api.py
Architecture:
Simulationclass wraps API callscalculate()method handles caching- Transparent fallback between API and local
Advanced: Direct Country Package Usage
For maximum control and performance, use country packages directly:
from policyengine_us import Simulation
# Full control over situation structure
situation = {
# Complete situation dictionary
# See policyengine-us-skill for patterns
}
sim = Simulation(situation=situation)
result = sim.calculate("variable_name", 2024)
Benefits:
- No API dependency
- Faster (no network)
- Full access to all variables
- Use axes for parameter sweeps
See policyengine-us-skill for detailed patterns.
Examples and Tutorials
PolicyEngine documentation:
Example notebooks:
- Repository: PolicyEngine/analysis-notebooks
- See policyengine-analysis-skill for analysis patterns
Community examples:
- Blog posts: policyengine.org/us/research
- GitHub discussions: github.com/PolicyEngine discussions
Getting Help
For usage questions:
- GitHub Discussions: https://github.com/PolicyEngine/policyengine-us/discussions
For bugs:
- File issues in appropriate repo (policyengine-us, policyengine.py, etc.)
For collaboration:
- Email: hello@policyengine.org