Skip to content

Instantly share code, notes, and snippets.

@andysylvester
Created September 18, 2026 19:16
Show Gist options
  • Select an option

  • Save andysylvester/f3d490cec5fa64e3a92cf58a41cb030b to your computer and use it in GitHub Desktop.

Select an option

Save andysylvester/f3d490cec5fa64e3a92cf58a41cb030b to your computer and use it in GitHub Desktop.
Fetch Oregon legislature measures for given sessions from the OLIS OData API
"""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