Skip to content

A Custom Location in Kosovo builds, and the name "Kosovo" no longer means Serbia - #77

Open
HughRunyan wants to merge 2 commits into
mainfrom
custom-location-runs-for-kosovo
Open

HughRunyan wants to merge 2 commits into
mainfrom
custom-location-runs-for-kosovo

Conversation

@HughRunyan

@HughRunyan HughRunyan commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Bug

A city DST Custom Location in Kosovo answers HTTP 500 on wastemap.earth, and the site tool's prefill for a point in Kosovo returns Serbia.

_iso3_for (in city_params.py) turns the caller's country into the ISO3 code SWEET's defaults are keyed by. It asked pycountry first, and pycountry has no Kosovo:

  • By code it raised. XKX, the code SWEET's own tables and WasteMAP's country list use, gave LookupError, so City.dst_baseline_blank and City.cityparams_obj_for_blank_site raised ValueError("Country 'XKX' not found."). defaults_2019.region_lookup_iso3["XKX"] is "Southern Europe", so SWEET had the defaults; only the lookup failed.
  • By name it was Serbia. search_fuzzy("Kosovo") returns Serbia, whose province Kosovo-Metohija matches. sdst_prepopulate names the country with the geocoder's English name, so a point in Kosovo was prefilled, and then modelled, as Serbia. The same search resolves "Curacao" to the Netherlands, and finds nothing for Macau, Pitcairn Islands, Svalbard and Jan Mayen Islands, US Minor Islands, or French Southern and Antarctic Lands.

Environment: prod API (api.wastemap.earth), SWEET_python main d5c592e, pycountry 26.2.16.

Reproduction (read-only GET):

curl -sG https://api.wastemap.earth/v1/city_emissions/city_baseline_parameters_v1_5 --data-urlencode "city_name=*" --data-urlencode country=XKX --data-urlencode population=2000000 --data-urlencode precipitation=500 --data-urlencode temperature=25

Expected: a baseline, as for country=PAK.
Actual: Internal Server Error (HTTP 500). Locally: City("*").dst_baseline_blank("XKX", 2_000_000, 500.0, 25.0) raises ValueError: Country 'XKX' not found.

Fix

_iso3_for tries SWEET's own table first: by code (defaults_2019.region_lookup_iso3), then by name (defaults_2019.country_to_iso3), ignoring case as pycountry does. Anything else goes to pycountry as before, so the exact-before-fuzzy order that fixed "MUS" (#71) stands.

Effect (model-output change for a country given by name)

Checked by running dst_baseline_blank for every code WasteMAP's /v1/dst_countries offers, before and after:

before after
XKX (Kosovo), 2040, 2M people, 500 mm, 25 °C ValueError 38,771 t CH4
"Kosovo" by name Serbia: 26,818 t 38,771 t
other 249 codes — bit-identical (each already resolved to itself)
site-tool prefill, point in Kosovo SRB; food 44.3%, k 0.143, growth −0.76%/yr XKX; Southern Europe's composition (food 35.7%), k 0.333, Kosovo's growth −0.08%/yr

Kosovo has no country rows in SWEET's defaults, so it takes Southern Europe's regional ones. It does have its own UN population series, which it now grows with. Climate TRACE's pipeline is unaffected: only dst_baseline_blank, cityparams_obj_for_blank_site and sdst_prepopulate call _iso3_for, and all three are WasteMAP paths.

Tests

tests/test_country_lookup.py (14 of its 17 fail on main):

  • dst_baseline_blank("XKX", 2_000_000, 500.0, 25.0) builds a city that grows with Kosovo's population.
  • cityparams_obj_for_blank_site(country="XKX", …) builds.
  • sdst_prepopulate for a point in Pristina returns XKX, not SRB. The geocoder and database are faked, so it runs offline.
  • Every code and every name in SWEET's own table resolves to SWEET's code; a country that doesn't exist still raises.

Full suite: 289 passed (Python 3.13 locally; CI runs 3.12).

Paired PR

RMI/WasteMAP#857, on the same branch name, so WasteMAP CI installs this branch. It makes both city DST endpoints answer 400 rather than 500 for a country SWEET can't find, and its fast tests run a Custom Location for every country the DST offers. Merge this one first.

Notes for review

Acceptance criteria

  • City("*").dst_baseline_blank("XKX", 2_000_000, 500.0, 25.0) builds a city.
  • _iso3_for resolves every code and name in SWEET's own table to SWEET's code, Kosovo included.
  • The site tool's prefill for a point in Kosovo returns XKX.
  • Every other code WasteMAP offers gives bit-identical output.
  • Changelog updated (changelog/2026-10.md, changelog/README.md).

Definition of Done

Acceptance criteria met · tests & checks pass · docs (changelog) updated · reviewed & merged.

🤖 Generated with Claude Code

…pycountry

pycountry has no Kosovo. _iso3_for asked it first, so XKX, the code SWEET's
defaults and WasteMAP's country list use, raised LookupError, and
dst_baseline_blank and cityparams_obj_for_blank_site raised "Country 'XKX' not
found." (WasteMAP's city tool answered 500). By name, the fuzzy search resolved
"Kosovo" to Serbia, so sdst_prepopulate prefilled a point in Kosovo as Serbia.

_iso3_for now tries region_lookup_iso3 by code, then country_to_iso3 by name,
both ignoring case, before pycountry. The other 249 codes WasteMAP offers
resolve as before, so their output is bit-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HughRunyan HughRunyan added bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs test Adds or modifies tests labels Oct 9, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working model-output-change Changes model OUTPUT values (expected progress, not breaking); results differ from prior runs test Adds or modifies tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant