Compare commits

..

No commits in common. "b430411b7edc4d56bc07fcf1b6eeec9ee21282f3" and "76437d524048507f86857a3dacb59565e4dfcd1f" have entirely different histories.

44 changed files with 0 additions and 118081 deletions

View file

@ -151,13 +151,6 @@ def lat_lon_to_wikidata(
if not nearby_result.get("missing"):
return {"elements": elements, "result": nearby_result}
# For points in the sea near any coast (e.g. England), try nearest polygon
nearest = model.Polygon.nearest(lat, lon)
if nearest:
nearby_result = do_lookup([nearest], lat, lon)
if not nearby_result.get("missing"):
return {"elements": elements, "result": nearby_result}
if not needs_commons:
# Direct lookup: find Wikidata items whose P402 (OSM relation ID) matches
# one of the OSM polygons that contain this point.

View file

@ -1,101 +0,0 @@
#!/usr/bin/env python3
"""
Download and save fixture data for the sample locations.
Run from the project root directory:
python tests/capture_fixtures.py
This makes real HTTP requests to WDQS and the Wikidata API and uses the
local PostGIS database. The output is saved to tests/fixtures/ and is
used by test_examples.py so those tests run without any network access.
Re-run this script whenever the expected results change (e.g. after an OSM
or Wikidata edit that affects a sample location).
"""
import json
import sys
from pathlib import Path
from unittest.mock import patch
sys.path.insert(0, str(Path(__file__).parent.parent))
import geocode.wikidata as wikidata_module
from geocode import samples
from lookup import app, lat_lon_to_wikidata
FIXTURES_DIR = Path(__file__).parent / "fixtures"
def capture_sample(i: int, lat: float, lon: float, name: str) -> None:
"""Capture and save fixture data for one sample location."""
wdqs_calls: dict[str, list] = {}
api_calls: dict[str, dict] = {}
# Hold references to the real functions before patching.
real_wdqs = wikidata_module.wdqs
real_api_call = wikidata_module.api_call
def recording_wdqs(query: str) -> list:
result = real_wdqs(query)
wdqs_calls[query] = result
return result
def recording_api_call(params: dict) -> dict:
key = json.dumps(params, sort_keys=True)
result = real_api_call(params)
api_calls[key] = result
return result
with patch("geocode.wikidata.wdqs", side_effect=recording_wdqs), patch(
"geocode.wikidata.api_call", side_effect=recording_api_call
):
reply = lat_lon_to_wikidata(lat, lon)
result = reply["result"]
commons_cat = result.get("commons_cat")
fixture: dict = {
"lat": lat,
"lon": lon,
"name": name,
"wdqs": wdqs_calls,
"api": api_calls,
"expected_wikidata": result.get("wikidata"),
"expected_commons_cat": commons_cat["title"]
if isinstance(commons_cat, dict)
else None,
}
fixture_path = FIXTURES_DIR / f"sample_{i:02d}.json"
fixture_path.write_text(json.dumps(fixture, indent=2, ensure_ascii=False))
qid = fixture["expected_wikidata"] or "none"
cat = fixture["expected_commons_cat"] or "no commons cat"
print(f" [{i:02d}] {name}: {qid} / {cat}")
def main() -> None:
"""Capture fixtures for all samples."""
FIXTURES_DIR.mkdir(exist_ok=True)
indices = None
if len(sys.argv) > 1:
# Allow passing specific indices on the command line, e.g.:
# python tests/capture_fixtures.py 0 5 12
indices = {int(a) for a in sys.argv[1:]}
print(f"Capturing fixtures for {len(samples)} samples...")
with app.app_context():
for i, (lat, lon, name) in enumerate(samples):
if indices and i not in indices:
continue
print(f"[{i:02d}/{len(samples) - 1}] {name} ({lat}, {lon})")
capture_sample(i, lat, lon, name)
print(f"\nDone. Fixtures saved to {FIXTURES_DIR}/")
if __name__ == "__main__":
main()

View file

@ -1,17 +0,0 @@
"""Shared pytest fixtures."""
import pytest
@pytest.fixture(scope="session")
def flask_app():
"""Return the Flask application."""
from lookup import app
return app
@pytest.fixture(scope="session")
def app_ctx(flask_app):
"""Push a Flask application context for the whole test session."""
with flask_app.app_context():
yield

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
{
"lat": 53.351,
"lon": -2.701,
"name": "Halton",
"wdqs": {
"SELECT DISTINCT ?item ?itemLabel ?commonsSiteLink ?commonsCat WHERE {\n { ?item rdfs:label 'Runcorn'@en } UNION { ?item skos:altLabel 'Runcorn'@en }\n FILTER NOT EXISTS { ?item wdt:P31 wd:Q17362920 } .# ignore Wikimedia duplicated page\n OPTIONAL { ?commonsSiteLink schema:about ?item ;\n schema:isPartOf <https://commons.wikimedia.org/> }\n OPTIONAL { ?item wdt:P373 ?commonsCat }\n ?item wdt:P625 ?coords .\n\n FILTER(geof:distance(?coords, \"Point(-2.701 53.351)\"^^geo:wktLiteral) < 10)\n FILTER(?commonsCat || ?commonsSiteLink)\n\n SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\". }\n}\n": [
{
"item": {
"type": "uri",
"value": "http://www.wikidata.org/entity/Q1009316"
},
"commonsCat": {
"type": "literal",
"value": "Runcorn"
},
"itemLabel": {
"xml:lang": "en",
"type": "literal",
"value": "Runcorn"
}
}
]
},
"api": {},
"expected_wikidata": "Q1009316",
"expected_commons_cat": "Runcorn"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,682 +0,0 @@
{
"lat": 53.392,
"lon": -0.022,
"name": "Brackenborough with Little Grimsby",
"wdqs": {},
"api": {
"{\"action\": \"wbgetentities\", \"ids\": \"Q4953658\"}": {
"entities": {
"Q4953658": {
"pageid": 4734351,
"ns": 0,
"title": "Q4953658",
"lastrevid": 2445683664,
"modified": "2025-12-22T21:20:25Z",
"type": "item",
"id": "Q4953658",
"labels": {
"en": {
"language": "en",
"value": "Brackenborough with Little Grimsby"
},
"sv": {
"language": "sv",
"value": "Brackenborough with Little Grimsby"
},
"ceb": {
"language": "ceb",
"value": "Brackenborough with Little Grimsby"
},
"tr": {
"language": "tr",
"value": "Brackenborough with Little Grimsby"
},
"ga": {
"language": "ga",
"value": "Brackenborough le Little Grimsby"
},
"fr": {
"language": "fr",
"value": "Brackenborough with Little Grimsby"
},
"mul": {
"language": "mul",
"value": "Brackenborough with Little Grimsby"
}
},
"descriptions": {
"de": {
"language": "de",
"value": "Gemeinde in der englischen Grafschaft Lincolnshire"
},
"fr": {
"language": "fr",
"value": "localité britannique du comté anglais de Lincolnshire"
},
"en": {
"language": "en",
"value": "civil parish in Lincolnshire, UK"
},
"ar": {
"language": "ar",
"value": "أبرشية مدنية في المملكة المتحدة"
}
},
"aliases": {
"en": [
{
"language": "en",
"value": "Brackenborough with Little Grimsby (civil parish), Lincolnshire"
},
{
"language": "en",
"value": "Brackenborough with Little Grimsby, Lincolnshire"
}
]
},
"claims": {
"P625": [
{
"mainsnak": {
"snaktype": "value",
"property": "P625",
"hash": "d56de4b68b43b43fe97aee6a61dccc5000554e9e",
"datavalue": {
"value": {
"latitude": 53.4,
"longitude": 0,
"altitude": null,
"precision": 0.1,
"globe": "http://www.wikidata.org/entity/Q2"
},
"type": "globecoordinate"
},
"datatype": "globe-coordinate"
},
"type": "statement",
"id": "Q4953658$9718EB71-20AB-4466-9282-340CC6984F56",
"rank": "normal",
"references": [
{
"hash": "fa278ebfc458360e5aed63d5058cca83c46134f1",
"snaks": {
"P143": [
{
"snaktype": "value",
"property": "P143",
"hash": "e4f6d9441d0600513c4533c672b5ab472dc73694",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 328,
"id": "Q328"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
]
},
"snaks-order": [
"P143"
]
}
]
}
],
"P17": [
{
"mainsnak": {
"snaktype": "value",
"property": "P17",
"hash": "a44880420787fb348836dc51d3babc5227c4ef7e",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 145,
"id": "Q145"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
},
"type": "statement",
"id": "Q4953658$A761C40C-581F-4A8C-BB10-7B167EC4C5EC",
"rank": "normal",
"references": [
{
"hash": "fa278ebfc458360e5aed63d5058cca83c46134f1",
"snaks": {
"P143": [
{
"snaktype": "value",
"property": "P143",
"hash": "e4f6d9441d0600513c4533c672b5ab472dc73694",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 328,
"id": "Q328"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
]
},
"snaks-order": [
"P143"
]
}
]
}
],
"P31": [
{
"mainsnak": {
"snaktype": "value",
"property": "P31",
"hash": "b55cf11b6c802451b5ce3c81756cd063d3c7b7fb",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 1115575,
"id": "Q1115575"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
},
"type": "statement",
"id": "Q4953658$4FB2A362-5DD1-4C3B-B11B-2FFBBAB2C784",
"rank": "normal"
}
],
"P1566": [
{
"mainsnak": {
"snaktype": "value",
"property": "P1566",
"hash": "46d8fff6acdd96c5878adadb277c78cdf5a2b26d",
"datavalue": {
"value": "7301566",
"type": "string"
},
"datatype": "external-id"
},
"type": "statement",
"id": "Q4953658$8CA40F0B-2DFB-4425-9476-AC43081E77AA",
"rank": "normal",
"references": [
{
"hash": "88694a0f4d1486770c269f7db16a1982f74da69d",
"snaks": {
"P248": [
{
"snaktype": "value",
"property": "P248",
"hash": "1b3ef912a2bd61e18dd43abd184337eb010b2e96",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 830106,
"id": "Q830106"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
]
},
"snaks-order": [
"P248"
]
}
]
}
],
"P373": [
{
"mainsnak": {
"snaktype": "value",
"property": "P373",
"hash": "c7bffdf55152b4948146dd62dce67865247d4ce9",
"datavalue": {
"value": "Brackenborough with Little Grimsby",
"type": "string"
},
"datatype": "string"
},
"type": "statement",
"id": "Q4953658$112752D4-ECDA-4269-A9B7-4B601A7E574B",
"rank": "normal"
}
],
"P836": [
{
"mainsnak": {
"snaktype": "value",
"property": "P836",
"hash": "4766718e26a4faf7dcde33195620c24100a0140f",
"datavalue": {
"value": "E04005605",
"type": "string"
},
"datatype": "external-id"
},
"type": "statement",
"id": "Q4953658$896CDCC6-E620-41D9-8B04-173F1B50D707",
"rank": "normal",
"references": [
{
"hash": "4881a6edaba7b0f179d612969aefc94ed4768626",
"snaks": {
"P813": [
{
"snaktype": "value",
"property": "P813",
"hash": "310c4d7f7d53b6a5c57ec198e61d481cbfccb045",
"datavalue": {
"value": {
"time": "+2017-03-14T00:00:00Z",
"timezone": 0,
"before": 0,
"after": 0,
"precision": 11,
"calendarmodel": "http://www.wikidata.org/entity/Q1985727"
},
"type": "time"
},
"datatype": "time"
}
]
},
"snaks-order": [
"P813"
]
}
]
}
],
"P131": [
{
"mainsnak": {
"snaktype": "value",
"property": "P131",
"hash": "a45427cde8301216e2ab3586ad98b4df63c800f2",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 82181,
"id": "Q82181"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
},
"type": "statement",
"id": "Q4953658$D9512857-C801-44BE-AEA6-8787D89F0277",
"rank": "normal",
"references": [
{
"hash": "a0dde1d73f9a85c67c4a2cbeddbcecf7198f07f9",
"snaks": {
"P143": [
{
"snaktype": "value",
"property": "P143",
"hash": "141583182d86fb45cf7098a86a993bc44e404092",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 2242955,
"id": "Q2242955"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
]
},
"snaks-order": [
"P143"
]
}
]
}
],
"P3120": [
{
"mainsnak": {
"snaktype": "value",
"property": "P3120",
"hash": "3ef13dfc0e9c62c2218248c5945be0496061bf08",
"datavalue": {
"value": "7000000000005371",
"type": "string"
},
"datatype": "external-id"
},
"type": "statement",
"qualifiers": {
"P2868": [
{
"snaktype": "value",
"property": "P2868",
"hash": "a92e88154c4cc68adfb7a6c25dcb0dcbe2904dea",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 1115575,
"id": "Q1115575"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
]
},
"qualifiers-order": [
"P2868"
],
"id": "Q4953658$CE73E131-69FB-4EDA-A5B2-DDECDD7ABBEE",
"rank": "normal"
}
],
"P402": [
{
"mainsnak": {
"snaktype": "value",
"property": "P402",
"hash": "8be7d707321f55f9b15e9817305bd7b2c244c996",
"datavalue": {
"value": "1318169",
"type": "string"
},
"datatype": "external-id"
},
"type": "statement",
"id": "Q4953658$8c291528-a8b5-4ea2-a530-ab5eed62a2f5",
"rank": "normal"
}
],
"P646": [
{
"mainsnak": {
"snaktype": "value",
"property": "P646",
"hash": "e5c4757c4fc5cc3cd91be680cac5bf11b6c5a9c9",
"datavalue": {
"value": "/m/095lbx",
"type": "string"
},
"datatype": "external-id"
},
"type": "statement",
"id": "Q4953658$CAE845CD-2739-4F5B-A1C8-07BF19CA476E",
"rank": "normal"
}
],
"P1082": [
{
"mainsnak": {
"snaktype": "value",
"property": "P1082",
"hash": "82b127e7d94aea3e97df48c239ba95a8636a7f15",
"datavalue": {
"value": {
"amount": "+83",
"unit": "1"
},
"type": "quantity"
},
"datatype": "quantity"
},
"type": "statement",
"qualifiers": {
"P1539": [
{
"snaktype": "value",
"property": "P1539",
"hash": "d7a33aa3284a7d6d72a972b23ee46451239a975e",
"datavalue": {
"value": {
"amount": "+38",
"unit": "1"
},
"type": "quantity"
},
"datatype": "quantity"
}
],
"P1540": [
{
"snaktype": "value",
"property": "P1540",
"hash": "bca52a91b62b1e768f81afdba8b515b8125aad85",
"datavalue": {
"value": {
"amount": "+45",
"unit": "1"
},
"type": "quantity"
},
"datatype": "quantity"
}
],
"P1538": [
{
"snaktype": "value",
"property": "P1538",
"hash": "9210a01fc4dfd89134e386c82fddf587299ad72d",
"datavalue": {
"value": {
"amount": "+35",
"unit": "1"
},
"type": "quantity"
},
"datatype": "quantity"
}
],
"P459": [
{
"snaktype": "value",
"property": "P459",
"hash": "f34609d440cf44ebaa8a3e704c9369413240618c",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 39825,
"id": "Q39825"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
],
"P585": [
{
"snaktype": "value",
"property": "P585",
"hash": "4a6fe7f861358928efef462e361b21704446d129",
"datavalue": {
"value": {
"time": "+2021-00-00T00:00:00Z",
"timezone": 0,
"before": 0,
"after": 0,
"precision": 9,
"calendarmodel": "http://www.wikidata.org/entity/Q1985727"
},
"type": "time"
},
"datatype": "time"
}
]
},
"qualifiers-order": [
"P1539",
"P1540",
"P1538",
"P459",
"P585"
],
"id": "Q4953658$DBF8ABC1-17EA-40A2-B292-A47CCA907133",
"rank": "normal",
"references": [
{
"hash": "1777794f031f3bb865bc1ba87bbd53bc9876131c",
"snaks": {
"P854": [
{
"snaktype": "value",
"property": "P854",
"hash": "4c66907bd33eaecbde827c8cd51e360e09c96a39",
"datavalue": {
"value": "https://www.nomisweb.co.uk/sources/census_2021_pp",
"type": "string"
},
"datatype": "url"
}
],
"P1476": [
{
"snaktype": "value",
"property": "P1476",
"hash": "aa1dc2edff48c56602cb3ea15bb643db64bca4ca",
"datavalue": {
"value": {
"text": "Parish Profiles",
"language": "en-gb"
},
"type": "monolingualtext"
},
"datatype": "monolingualtext"
}
],
"P1433": [
{
"snaktype": "value",
"property": "P1433",
"hash": "cd20b2aec2e4baf705095049375a6af4c4bd8fb6",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 16970190,
"id": "Q16970190"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
],
"P123": [
{
"snaktype": "value",
"property": "P123",
"hash": "dd874c88654df8083801b38f5c0607e1755b0234",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 1334971,
"id": "Q1334971"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
}
],
"P813": [
{
"snaktype": "value",
"property": "P813",
"hash": "997eb33b0d995db84c7ff54ea10dea029e3b9829",
"datavalue": {
"value": {
"time": "+2024-08-05T00:00:00Z",
"timezone": 0,
"before": 0,
"after": 0,
"precision": 11,
"calendarmodel": "http://www.wikidata.org/entity/Q1985727"
},
"type": "time"
},
"datatype": "time"
}
]
},
"snaks-order": [
"P854",
"P1476",
"P1433",
"P123",
"P813"
]
}
]
}
],
"P7959": [
{
"mainsnak": {
"snaktype": "value",
"property": "P7959",
"hash": "3b8c6dafefe7046353b50e3fbf6371f4cda7c5e7",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 67533486,
"id": "Q67533486"
},
"type": "wikibase-entityid"
},
"datatype": "wikibase-item"
},
"type": "statement",
"id": "Q4953658$388032D0-22B6-4585-87FA-8DB11ABEF47E",
"rank": "normal"
}
]
},
"sitelinks": {
"cebwiki": {
"site": "cebwiki",
"title": "Brackenborough with Little Grimsby",
"badges": []
},
"commonswiki": {
"site": "commonswiki",
"title": "Category:Brackenborough with Little Grimsby",
"badges": []
},
"enwiki": {
"site": "enwiki",
"title": "Brackenborough with Little Grimsby",
"badges": []
},
"frwiki": {
"site": "frwiki",
"title": "Brackenborough with Little Grimsby",
"badges": []
},
"svwiki": {
"site": "svwiki",
"title": "Brackenborough with Little Grimsby",
"badges": []
},
"trwiki": {
"site": "trwiki",
"title": "Brackenborough with Little Grimsby",
"badges": []
}
}
}
},
"success": 1
}
},
"expected_wikidata": "Q4953658",
"expected_commons_cat": "Brackenborough with Little Grimsby"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,31 +0,0 @@
{
"lat": 55.7644,
"lon": -4.177,
"name": "East Kilbride",
"wdqs": {
"SELECT ?item ?itemLabel ?commonsSiteLink ?commonsCat WHERE {\n ?item wdt:P528 \"277\" .\n ?item wdt:P31 wd:Q5124673 .\n OPTIONAL { ?commonsSiteLink schema:about ?item ;\n schema:isPartOf <https://commons.wikimedia.org/> }\n OPTIONAL { ?item wdt:P373 ?commonsCat }\n SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\". }\n}": [
{
"item": {
"type": "uri",
"value": "http://www.wikidata.org/entity/Q68826060"
},
"commonsSiteLink": {
"type": "uri",
"value": "https://commons.wikimedia.org/wiki/Category:East_Kilbride_(civil_parish)"
},
"commonsCat": {
"type": "literal",
"value": "East Kilbride (civil parish)"
},
"itemLabel": {
"xml:lang": "en",
"type": "literal",
"value": "East Kilbride"
}
}
]
},
"api": {},
"expected_wikidata": "Q68826060",
"expected_commons_cat": "East Kilbride (civil parish)"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
"""
Tests for the sample locations listed in geocode.samples.
Fixtures are pre-recorded snapshots of WDQS and Wikidata API responses.
Generate or refresh them (requires network + DB) with:
python tests/capture_fixtures.py
The tests themselves only need the local PostGIS database.
"""
import json
from pathlib import Path
import pytest
from geocode import samples
from lookup import lat_lon_to_wikidata
FIXTURES_DIR = Path(__file__).parent / "fixtures"
def _load_fixture(i: int) -> dict:
path = FIXTURES_DIR / f"sample_{i:02d}.json"
if not path.exists():
pytest.skip(f"No fixture file — run: python tests/capture_fixtures.py {i}")
return json.loads(path.read_text())
def _make_mock_wdqs(fixture: dict, name: str):
"""Return a mock for geocode.wikidata.wdqs that replays saved responses."""
saved = fixture["wdqs"]
def mock_wdqs(query: str) -> list:
if query not in saved:
short = query[:120].replace("\n", " ")
raise AssertionError(
f"[{name}] Unexpected WDQS query (not in fixture):\n {short}"
)
return saved[query]
return mock_wdqs
def _make_mock_api_call(fixture: dict, name: str):
"""Return a mock for geocode.wikidata.api_call that replays saved responses."""
saved = fixture["api"]
def mock_api_call(params: dict) -> dict:
key = json.dumps(params, sort_keys=True)
if key not in saved:
raise AssertionError(
f"[{name}] Unexpected api_call (not in fixture): {key}"
)
return saved[key]
return mock_api_call
@pytest.mark.parametrize(
"i,lat,lon,name",
[(i, lat, lon, name) for i, (lat, lon, name) in enumerate(samples)],
ids=[name for _, _, name in samples],
)
def test_example(app_ctx, mocker, i: int, lat: float, lon: float, name: str) -> None:
"""Each sample location resolves to the expected Wikidata item and Commons category."""
fixture = _load_fixture(i)
mocker.patch("geocode.wikidata.wdqs", side_effect=_make_mock_wdqs(fixture, name))
mocker.patch(
"geocode.wikidata.api_call", side_effect=_make_mock_api_call(fixture, name)
)
reply = lat_lon_to_wikidata(lat, lon)
result = reply["result"]
expected_qid = fixture["expected_wikidata"]
assert result.get("wikidata") == expected_qid, (
f"{name}: wikidata mismatch — expected {expected_qid!r}, "
f"got {result.get('wikidata')!r}"
)
expected_cat = fixture["expected_commons_cat"]
if expected_cat:
commons = result.get("commons_cat")
assert isinstance(commons, dict), (
f"{name}: expected commons_cat={expected_cat!r} but result has none"
)
assert commons["title"] == expected_cat, (
f"{name}: commons_cat mismatch — expected {expected_cat!r}, "
f"got {commons['title']!r}"
)
else:
assert not result.get("commons_cat"), (
f"{name}: expected no commons_cat but got {result.get('commons_cat')!r}"
)