Split up code into functions to ease comprehension
This commit is contained in:
		
							parent
							
								
									a6286cb05f
								
							
						
					
					
						commit
						50c222d66a
					
				
							
								
								
									
										123
									
								
								lookup.py
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								lookup.py
									
									
									
									
									
								
							| 
						 | 
					@ -15,6 +15,9 @@ app = Flask(__name__)
 | 
				
			||||||
app.config.from_object("config.default")
 | 
					app.config.from_object("config.default")
 | 
				
			||||||
database.init_app(app)
 | 
					database.init_app(app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tags = typing.Mapping[str, str]
 | 
				
			||||||
 | 
					Elements = sqlalchemy.orm.query.Query[model.Polygon]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_random_lat_lon() -> tuple[float, float]:
 | 
					def get_random_lat_lon() -> tuple[float, float]:
 | 
				
			||||||
    """Select random lat/lon within the UK."""
 | 
					    """Select random lat/lon within the UK."""
 | 
				
			||||||
| 
						 | 
					@ -28,12 +31,10 @@ def get_random_lat_lon() -> tuple[float, float]:
 | 
				
			||||||
    return lat, lon
 | 
					    return lat, lon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Elements = sqlalchemy.orm.query.Query
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def do_lookup(
 | 
					def do_lookup(
 | 
				
			||||||
    elements: Elements, lat: str | float, lon: str | float
 | 
					    elements: Elements, lat: str | float, lon: str | float
 | 
				
			||||||
) -> wikidata.WikidataDict:
 | 
					) -> wikidata.WikidataDict:
 | 
				
			||||||
 | 
					    """Do lookup."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        hit = osm_lookup(elements, lat, lon)
 | 
					        hit = osm_lookup(elements, lat, lon)
 | 
				
			||||||
    except wikidata.QueryError as e:
 | 
					    except wikidata.QueryError as e:
 | 
				
			||||||
| 
						 | 
					@ -47,6 +48,7 @@ def do_lookup(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def lat_lon_to_wikidata(lat: str | float, lon: str | float) -> dict[str, typing.Any]:
 | 
					def lat_lon_to_wikidata(lat: str | float, lon: str | float) -> dict[str, typing.Any]:
 | 
				
			||||||
 | 
					    """Lookup lat/lon and find most appropriate Wikidata item."""
 | 
				
			||||||
    scotland_code = scotland.get_scotland_code(lat, lon)
 | 
					    scotland_code = scotland.get_scotland_code(lat, lon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    elements: typing.Any
 | 
					    elements: typing.Any
 | 
				
			||||||
| 
						 | 
					@ -66,8 +68,11 @@ def lat_lon_to_wikidata(lat: str | float, lon: str | float) -> dict[str, typing.
 | 
				
			||||||
        return {"elements": elements, "result": result}
 | 
					        return {"elements": elements, "result": result}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    admin_level = result.get("admin_level")
 | 
					    admin_level = result.get("admin_level")
 | 
				
			||||||
 | 
					    if not admin_level:
 | 
				
			||||||
 | 
					        return {"elements": elements, "result": result}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not admin_level or admin_level >= 7:
 | 
					    assert isinstance(admin_level, int)
 | 
				
			||||||
 | 
					    if admin_level >= 7:
 | 
				
			||||||
        return {"elements": elements, "result": result}
 | 
					        return {"elements": elements, "result": result}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    row = wikidata.geosearch(lat, lon)
 | 
					    row = wikidata.geosearch(lat, lon)
 | 
				
			||||||
| 
						 | 
					@ -79,71 +84,83 @@ def lat_lon_to_wikidata(lat: str | float, lon: str | float) -> dict[str, typing.
 | 
				
			||||||
    return {"elements": elements, "result": result}
 | 
					    return {"elements": elements, "result": result}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_admin_level(tags: Tags) -> int | None:
 | 
				
			||||||
 | 
					    """Read admin_level from tags."""
 | 
				
			||||||
 | 
					    admin_level_tag = tags.get("admin_level")
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        int(admin_level_tag) if admin_level_tag and admin_level_tag.isdigit() else None
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def hit_from_wikidata_tag(tags: Tags) -> wikidata.Hit | None:
 | 
				
			||||||
 | 
					    """Check element for a wikidata tag."""
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "wikidata": qid,
 | 
				
			||||||
 | 
					            "commons_cat": commons,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if "wikidata" in tags
 | 
				
			||||||
 | 
					        and (commons := wikidata.qid_to_commons_category(qid := tags["wikidata"]))
 | 
				
			||||||
 | 
					        else None
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def hit_from_ref_gss_tag(tags: Tags) -> wikidata.Hit | None:
 | 
				
			||||||
 | 
					    """Check element for rss:gss tag."""
 | 
				
			||||||
 | 
					    gss = tags.get("ref:gss")
 | 
				
			||||||
 | 
					    return wikidata.get_commons_cat_from_gss(gss) if gss else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def hit_from_name(
 | 
				
			||||||
 | 
					    tags: Tags, lat: str | float, lon: str | float
 | 
				
			||||||
 | 
					) -> wikidata.Hit | None:
 | 
				
			||||||
 | 
					    """Use name to look for hit."""
 | 
				
			||||||
 | 
					    if not (name := tags.get("name")):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    if name.endswith(" CP"):  # civil parish
 | 
				
			||||||
 | 
					        name = name[:-3]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rows = wikidata.lookup_wikidata_by_name(name, lat, lon)
 | 
				
			||||||
 | 
					    return wikidata.commons_from_rows(rows) if len(rows) == 1 else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def osm_lookup(
 | 
					def osm_lookup(
 | 
				
			||||||
    elements: Elements, lat: str | float, lon: str | float  # type:ignore
 | 
					    elements: Elements, lat: str | float, lon: str | float
 | 
				
			||||||
) -> wikidata.Hit | None:
 | 
					) -> wikidata.Hit | None:
 | 
				
			||||||
    """OSM lookup."""
 | 
					    """OSM lookup."""
 | 
				
			||||||
    ret: wikidata.Hit | None
 | 
					    ret: wikidata.Hit | None
 | 
				
			||||||
    for e in elements:
 | 
					    for e in elements:
 | 
				
			||||||
        assert isinstance(e, model.Polygon)
 | 
					        assert isinstance(e, model.Polygon)
 | 
				
			||||||
        assert e.tags
 | 
					        assert e.tags
 | 
				
			||||||
        tags: typing.Mapping[str, typing.Any] = e.tags
 | 
					        tags: typing.Mapping[str, str] = e.tags
 | 
				
			||||||
        admin_level_tag = tags.get("admin_level")
 | 
					        admin_level: int | None = get_admin_level(tags)
 | 
				
			||||||
        admin_level: int | None = (
 | 
					 | 
				
			||||||
            int(admin_level_tag)
 | 
					 | 
				
			||||||
            if admin_level_tag and admin_level_tag.isdigit()
 | 
					 | 
				
			||||||
            else None
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if not admin_level and tags.get("boundary") != "political":
 | 
					        if not admin_level and tags.get("boundary") != "political":
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        if "wikidata" in tags:
 | 
					        if not (
 | 
				
			||||||
            qid = tags["wikidata"]
 | 
					            (hit := hit_from_wikidata_tag(tags))
 | 
				
			||||||
            commons = wikidata.qid_to_commons_category(qid)
 | 
					            or (hit := hit_from_ref_gss_tag(tags))
 | 
				
			||||||
            if commons:
 | 
					            or (hit := hit_from_name(tags, lat, lon))
 | 
				
			||||||
                return {
 | 
					        ):
 | 
				
			||||||
                    "wikidata": qid,
 | 
					 | 
				
			||||||
                    "commons_cat": commons,
 | 
					 | 
				
			||||||
                    "admin_level": admin_level,
 | 
					 | 
				
			||||||
                    "element": e.osm_id,
 | 
					 | 
				
			||||||
                    "geojson": typing.cast(str, e.geojson_str),
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
        gss = tags.get("ref:gss")
 | 
					 | 
				
			||||||
        if gss:
 | 
					 | 
				
			||||||
            ret = wikidata.get_commons_cat_from_gss(gss)
 | 
					 | 
				
			||||||
            if ret:
 | 
					 | 
				
			||||||
                ret["admin_level"] = admin_level
 | 
					 | 
				
			||||||
                ret["element"] = e.osm_id
 | 
					 | 
				
			||||||
                ret["geojson"] = typing.cast(str, e.geojson_str)
 | 
					 | 
				
			||||||
                return ret
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        name = tags.get("name")
 | 
					 | 
				
			||||||
        if not name:
 | 
					 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        if name.endswith(" CP"):
 | 
					        hit["admin_level"] = admin_level
 | 
				
			||||||
            name = name[:-3]
 | 
					        hit["element"] = e.osm_id
 | 
				
			||||||
        rows = wikidata.lookup_wikidata_by_name(name, lat, lon)
 | 
					        hit["geojson"] = typing.cast(str, e.geojson_str)
 | 
				
			||||||
 | 
					        return hit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if len(rows) == 1:
 | 
					    has_wikidata_tag = [e for e in elements if e.tags.get("wikidata")]
 | 
				
			||||||
            ret = wikidata.commons_from_rows(rows)
 | 
					 | 
				
			||||||
            if ret:
 | 
					 | 
				
			||||||
                ret["admin_level"] = admin_level
 | 
					 | 
				
			||||||
                ret["element"] = e.osm_id
 | 
					 | 
				
			||||||
                return ret
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    has_wikidata_tag = [e.tags for e in elements if e.tags.get("wikidata")]
 | 
					 | 
				
			||||||
    if len(has_wikidata_tag) != 1:
 | 
					    if len(has_wikidata_tag) != 1:
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert has_wikidata_tag[0]
 | 
					    e = has_wikidata_tag[0]
 | 
				
			||||||
    qid = has_wikidata_tag[0]["wikidata"]
 | 
					    assert e.tags
 | 
				
			||||||
    return typing.cast(
 | 
					    qid = e.tags["wikidata"]
 | 
				
			||||||
        wikidata.Hit,
 | 
					    return {
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        "wikidata": qid,
 | 
					        "wikidata": qid,
 | 
				
			||||||
 | 
					        "element": e.osm_id,
 | 
				
			||||||
 | 
					        "geojson": typing.cast(str, e.geojson_str),
 | 
				
			||||||
        "commons_cat": wikidata.qid_to_commons_category(qid),
 | 
					        "commons_cat": wikidata.qid_to_commons_category(qid),
 | 
				
			||||||
        "admin_level": admin_level,
 | 
					        "admin_level": admin_level,
 | 
				
			||||||
        },
 | 
					    }
 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def redirect_to_detail(q: str) -> Response:
 | 
					def redirect_to_detail(q: str) -> Response:
 | 
				
			||||||
| 
						 | 
					@ -231,7 +248,7 @@ def detail_page() -> Response | str:
 | 
				
			||||||
        str=str,
 | 
					        str=str,
 | 
				
			||||||
        element_id=element,
 | 
					        element_id=element,
 | 
				
			||||||
        geojson=geojson,
 | 
					        geojson=geojson,
 | 
				
			||||||
        **reply
 | 
					        **reply,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue