Created
September 18, 2026 19:16
-
-
Save andysylvester/f3d490cec5fa64e3a92cf58a41cb030b to your computer and use it in GitHub Desktop.
Fetch Oregon legislature measures for given sessions from the OLIS OData API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """Fetch Oregon legislature measures for given sessions from the OLIS OData API. | |
| Writes one plain-text report per session: | |
| 2025R1 -> measures_2025.txt | |
| 2026R1 -> measures_2026.txt | |
| """ | |
| import sys | |
| import requests | |
| BASE_URL = "https://api.oregonlegislature.gov/odata/odataservice.svc/" | |
| ENDPOINT = "Measures" | |
| # Fields to pull for each measure, in the order they should be reported. | |
| FIELDS = [ | |
| "SessionKey", | |
| "MeasurePrefix", | |
| "MeasureNumber", | |
| "CatchLine", | |
| "MinorityCatchLine", | |
| "MeasureSummary", | |
| ] | |
| # SessionKey -> output file | |
| SESSIONS = { | |
| "2025R1": "measures_2025.txt", | |
| "2026R1": "measures_2026.txt", | |
| } | |
| PAGE_SIZE = 1000 | |
| def fetch_measures(session_key): | |
| """Return all measures for a session, paging through the result set.""" | |
| headers = {"Accept": "application/json"} | |
| measures = [] | |
| skip = 0 | |
| while True: | |
| params = { | |
| "$filter": f"SessionKey eq '{session_key}'", | |
| "$select": ",".join(FIELDS), | |
| "$orderby": "MeasurePrefix,MeasureNumber", | |
| "$top": PAGE_SIZE, | |
| "$skip": skip, | |
| "$format": "json", | |
| } | |
| response = requests.get( | |
| f"{BASE_URL}{ENDPOINT}", headers=headers, params=params, timeout=120 | |
| ) | |
| response.raise_for_status() | |
| page = response.json().get("value", []) | |
| measures.extend(page) | |
| if len(page) < PAGE_SIZE: | |
| break | |
| skip += PAGE_SIZE | |
| return measures | |
| def clean(value): | |
| """Normalize a field value for text output.""" | |
| if value is None: | |
| return "" | |
| return " ".join(str(value).split()) | |
| def write_report(session_key, measures, path): | |
| with open(path, "w", encoding="utf-8") as out: | |
| out.write(f"Oregon Legislature Measures - Session {session_key}\n") | |
| out.write(f"Total measures: {len(measures)}\n") | |
| out.write("=" * 78 + "\n\n") | |
| for measure in measures: | |
| label = ( | |
| f"{clean(measure.get('MeasurePrefix'))} " | |
| f"{clean(measure.get('MeasureNumber'))}" | |
| ).strip() | |
| out.write(f"{label}\n") | |
| for field in FIELDS: | |
| out.write(f" {field}: {clean(measure.get(field))}\n") | |
| out.write("\n") | |
| def main(): | |
| for session_key, path in SESSIONS.items(): | |
| try: | |
| measures = fetch_measures(session_key) | |
| except requests.exceptions.RequestException as e: | |
| print(f"Error accessing OLIS API for {session_key}: {e}") | |
| return 1 | |
| write_report(session_key, measures, path) | |
| print(f"{session_key}: {len(measures)} measures written to {path}") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment