mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-08-26 14:53:31 +02:00
fix(stargazer-map): resolve countries via ISO code instead of English name (Russia/Turkey/Ivory Coast were dropped) (#2956)
* fix(stargazer-map): resolve countries via ISO code, not English name username_to_country() matched Nominatim's English display_name against pycountry, but the two vocabularies disagree: pycountry.countries.lookup() raises LookupError for "Russia", "Turkey" and "Ivory Coast" (its ISO names are "Russian Federation", "Türkiye", "Côte d'Ivoire"). Those users were silently recorded as unknown -- the committed cache has 963 users with a country and zero Russia, so Russia rendered grey on the map. Request addressdetails from Nominatim and read address.country_code instead. No new dependency, same one request per user, and it drops the reversed-component loop that could false-positive on a city or region named like a country. The return value is unchanged: still a pycountry .name string, so the CSV cache and the ISO-3 rendering lookup are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(stargazer-map): drop non-answer locations before geocoding Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
50
.github/generate_map.py
vendored
50
.github/generate_map.py
vendored
@@ -61,6 +61,35 @@ HEADERS = {
|
||||
}
|
||||
GEOL = Nominatim(user_agent="gh-stargazer-map")
|
||||
|
||||
# Non-answers that Nominatim happily resolves to a real place: "Earth" is a
|
||||
# town in Texas, "Remote" is a settlement in Oregon. Matched on the whole
|
||||
# stripped, lowercased string only -- "Earth, TX" is someone's actual address
|
||||
# and must still geocode.
|
||||
JUNK_LOCATIONS = {
|
||||
"127.0.0.1",
|
||||
"/dev/null",
|
||||
"anywhere",
|
||||
"earth",
|
||||
"everywhere",
|
||||
"here",
|
||||
"home",
|
||||
"internet",
|
||||
"localhost",
|
||||
"mars",
|
||||
"moon",
|
||||
"n/a",
|
||||
"none",
|
||||
"nowhere",
|
||||
"null",
|
||||
"planet earth",
|
||||
"remote",
|
||||
"space",
|
||||
"the internet",
|
||||
"unknown",
|
||||
"world",
|
||||
"worldwide",
|
||||
}
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -105,21 +134,18 @@ def username_to_country(login):
|
||||
loc = (resp.json() or {}).get("location") or ""
|
||||
if not loc.strip():
|
||||
return ""
|
||||
if loc.strip().strip(".!").lower() in JUNK_LOCATIONS:
|
||||
return ""
|
||||
try:
|
||||
g = GEOL.geocode(loc, language="en", timeout=10)
|
||||
g = GEOL.geocode(loc, language="en", addressdetails=True, timeout=10)
|
||||
except Exception:
|
||||
return ""
|
||||
if not g or "display_name" not in g.raw:
|
||||
return ""
|
||||
# take the last comma-separated component that matches a country
|
||||
for part in reversed(g.raw["display_name"].split(",")):
|
||||
part = part.strip()
|
||||
try:
|
||||
country = pycountry.countries.lookup(part).name
|
||||
return country
|
||||
except LookupError:
|
||||
pass
|
||||
return ""
|
||||
# Use the ISO code from the structured address: Nominatim's English display
|
||||
# names ("Russia", "Turkey", "Ivory Coast") do not all match pycountry's ISO
|
||||
# names ("Russian Federation", "Türkiye", "Côte d'Ivoire").
|
||||
code = ((g.raw.get("address") or {}).get("country_code") or "") if g else ""
|
||||
country = pycountry.countries.get(alpha_2=code.upper()) if code else None
|
||||
return country.name if country else ""
|
||||
|
||||
|
||||
def count_by_country(cache):
|
||||
|
||||
Reference in New Issue
Block a user