diff --git a/geocode/wikidata.py b/geocode/wikidata.py index e9d4828..6145050 100644 --- a/geocode/wikidata.py +++ b/geocode/wikidata.py @@ -110,13 +110,16 @@ Row = dict[str, dict[str, typing.Any]] Hit = dict[str, str | int | None] -@backoff.on_exception(backoff.expo, QueryError, max_tries=5) +@backoff.on_exception(backoff.expo, (QueryError, RequestException), max_tries=5) def wdqs(query: str) -> list[Row]: """Pass query to the Wikidata Query Service.""" r = requests.post( wikidata_query_api_url, data={"query": query, "format": "json"}, headers=headers ) + if not r.ok: + raise QueryError(query, r) + try: return typing.cast(list[Row], r.json()["results"]["bindings"]) except requests.exceptions.JSONDecodeError: diff --git a/lookup.py b/lookup.py index 0759406..bebe7a3 100755 --- a/lookup.py +++ b/lookup.py @@ -10,6 +10,7 @@ import traceback import typing from time import time +import requests.exceptions import sqlalchemy.exc import werkzeug.debug.tbtools from flask import Flask, jsonify, redirect, render_template, request, url_for @@ -375,7 +376,16 @@ def index() -> str | Response: return jsonify(coords={"lat": lat, "lon": lon}, error=error_msg) needs_commons = request.args.get("needs_commons", "true").lower() != "false" - result = lat_lon_to_wikidata(lat, lon, needs_commons=needs_commons)["result"] + try: + result = lat_lon_to_wikidata(lat, lon, needs_commons=needs_commons)["result"] + except (wikidata.QueryError, wikidata.APIResponseError) as e: + r = e.r if isinstance(e, wikidata.QueryError) else e.response + if r.status_code == 429: + extra = {"Retry-After": r.headers["Retry-After"]} if "Retry-After" in r.headers else {} + return jsonify(error="Rate limited by Wikidata, please try again later"), 429, extra + return jsonify(error=f"Wikidata query failed (HTTP {r.status_code}), please try again later"), 503 + except requests.exceptions.RequestException: + return jsonify(error="Could not connect to Wikidata, please try again later"), 503 result.pop("element", None) result.pop("geojson", None) if logging_enabled: