Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 153021@bnt-lap001 Assistant-Session: 46917be4-6400-4106-b8b7-61953a0caf24 |
||
|---|---|---|
| .forgejo/workflows | ||
| build/lib/web_fetcher | ||
| decisions | ||
| intakes | ||
| registry | ||
| tests | ||
| web_fetcher | ||
| web_fetcher.egg-info | ||
| workplans/archived | ||
| .custodian-brief.md | ||
| .gitignore | ||
| .repo-classification.yaml | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| INTENT.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| SCOPE.md | ||
| WORK-RECORDS.md | ||
web-fetcher
Reusable, provenance-first fetching of web and API data for research.
Every fetch returns Observation records with the value and where it came
from: source, URL, the source's own publication or update time, retrieval
time, and the SHA-256 of the raw payload. Values are never estimated: a spec
yields a sourced value, or an explicit not_found or error record. An
optional content-addressed cache stores the exact bytes each run used, and a
run can be replayed from it offline.
Standard library only. Python 3.10+.
Adapters
| Adapter | Use | Key spec fields |
|---|---|---|
eurostat |
Eurostat dissemination API (JSON-stat 2.0) | dataset, filters, split_by, last |
http_json |
any JSON endpoint | url, source, path (dotted), period_path |
http_csv |
any CSV endpoint (e.g. FRED fredgraph.csv) |
url, source, filter, value_column, period_column |
xlsx_wide |
spreadsheets with one column per period (e.g. Census BTOS) | url, source, sheet, filter, period_regex |
manual |
no machine-readable source; recorded as not_found with a note |
source |
Provenance rules
- Every non-Eurostat spec must name its
source; anokvalue without one is turned into anerror. - "Latest" period (
http_csv,xlsx_wide) follows parsed period order — year, month (2026-09), date, quarter (2026-Q3/2026Q3), semester, week, fixed-width digits (202620). Mixed formats are anerror; pin one withperiod_format, orperiod_format: stringfor plain lexicographic order. The rule applied is written to the observation'snote. - Values must be numeric unless
value_type: string; otherwisenot_found.
Install
pip install "git+https://forgejo.coulomb.social/coulomb/web-fetcher@v0.2.0"
Or put a checkout on PYTHONPATH — there are no dependencies.
Usage
python3 -m web_fetcher fetch specs.json [--cache .cache] [--only ID] > observations.jsonl
python3 -m web_fetcher fetch specs.json --replay .cache > replayed.jsonl # offline, same bytes
from web_fetcher import run_spec
obs = run_spec({"id": "eu_ai", "adapter": "eurostat", "dataset": "isoc_eb_ai",
"filters": {"geo": ["EU27_2020"], "unit": "PC_ENT", "size_emp": "GE10",
"indic_is": "E_AI_TANY"}, "split_by": ["geo"]})
Tests
python3 -B -m unittest discover -s tests
Tests run offline against fixtures in tests/fixtures/. Live smoke test,
one spec per adapter: WEB_FETCHER_LIVE=1 python3 -B -m unittest tests.test_live -v.
See CHANGELOG.md for release notes.
Consumers
assembly-economics: reality checkpoints (checkpoints/sources.json,checkpoints/run_checkpoint.py).