Repository navigation
A Custom Location in Kosovo builds, and the name "Kosovo" no longer means Serbia - #77
Merged
Merged
Conversation
…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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 tasks done
The October changelog and its README line keep main's entries and add this PR's. #74's entry no longer says Kosovo can't be looked up, and Kosovo's 2040 figure is the one main gives now (38,768 t; 38,771 when this branch was cut). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HughRunyan
added a commit
that referenced
this pull request
Oct 17, 2026
#77, which this branch was stacked on, is now squashed onto main. Where the two touch the same lines (_iso3_for, the prefill tests) this branch's version is kept; everything else is main's. The changelog keeps main's entries, including #77's correct links, which this branch had replaced with placeholders, and adds this PR's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 of 8 tasks
HughRunyan
added a commit
that referenced
this pull request
Oct 17, 2026
* Bump the python-minor-and-patch group with 2 updates Bumps the python-minor-and-patch group with 2 updates: [fastapi](https://github.com/fastapi/fastapi) and [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy). Updates `fastapi` from 0.141.1 to 0.142.2 - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](fastapi/fastapi@0.141.1...0.142.2) Updates `sqlalchemy` from 2.1.1 to 2.1.3 - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.142.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-minor-and-patch - dependency-name: sqlalchemy dependency-version: 2.1.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Indonesia sizes its waste from its own IPCC row msw_per_capita_country is IPCC 2019 Refinement Vol. 5 Ch. 2 Table 2A.1 (Updated), 2010 column. All 167 of its rows match the IPCC's, but Indonesia's (0.19 t/person/yr) was never typed in, so Indonesia fell back to the South-Eastern Asia default, 0.46: 2.4x its own row. Adds the row and cites the source tables in comments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: Indonesia's per-capita waste row (#76) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * SWEET can name its next release, with tests for the counting scripts/next_release.py turns a list of git tags into the next free sweet/YYYY.MM.N for a month (N from 0, one past the highest used), checks a hand-typed release name, and picks the newest release in a list. Tags that are not release names -- other projects' wastemap/ and submission/ tags, a stray sweet/test -- are ignored. Standard library only, tags on stdin, so the release workflow can run it before installing anything and the tests need no git or network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A one-click workflow cuts a dated SWEET release from main .github/workflows/release.yml (Actions > Release > Run workflow) tags a commit on main as sweet/YYYY.MM.N -- by default the tip of main and the next free number for the current UTC month -- and publishes a GitHub Release whose notes list the pull requests merged since the previous release, with a link to the month's changelog file. The job summary records the tag, the commit and the links. Before anything is tagged it refuses: a commit main does not contain; a name that already exists, or one that would sort before the newest release; a commit that is already a release; a commit that does not contain the newest release; and a commit whose own test suite fails (the same install and pytest command as tests.yml, run against that commit). The tag is annotated and pushed without force, so a release can never be moved. Only main's copy of the workflow may run, and one release runs at a time so two cannot take the same number. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * setup.py and the package docstring say releases are sweet/ tags Both said SWEET has no releases. They now say a release is a git tag sweet/YYYY.MM.N cut by the Release workflow, that setup.py's "0.1" is still decoration and never bumped, and that __version__ stays the commit: a release names one commit, the commit is all an installed copy can report without a repository, and it is the only name a branch install has. No code changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The README says how to cut, name and pin a SWEET release The README's release section described a shared vYYYY.MM.DD tag that was renamed to wastemap/YYYY.MM.DD in September and is not SWEET's own release anyway. It now explains sweet/YYYY.MM.N: what the name means, that a release is never moved or reused, how to cut one from the Actions tab, what the workflow refuses, and how an app pins one (a release name, or a SWEET branch only on a feature branch). Its Usage section pointed at sweet_tools_obj.py, model.py and load_from_database, none of which exist any more; it is now a short map of the modules and entry points the two apps actually call. changelog/README.md no longer says the project publishes no tags. It says releases are cut from main with generated notes listing the PRs since the last release, and that the monthly files keep the human-written entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The recovery command writes the same notes the Release step would have If the tag is pushed but the Release fails, the command in the job summary now includes the changelog link (and the first release's note), quoted for bash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A copy built from git knows its commit, without the app having to say setup.py writes the commit of a clean checkout into the built package as SWEET_python/_build_sha.py, which is how pip builds a git install, and __version__ reads it first (source "build"), then SWEET_GIT_SHA, then .git. The stamp goes only into the build directory, never the source tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The README says how an installed copy knows its commit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * SWEET's docs say its population table is the only copy Climate TRACE's pipeline and its offline country-data build now read SWEET_python/pops_yearly.csv (RMI_Climate_TRACE_Waste_Methane#208), so the "two copies, nothing keeps them in step" text in constants.py and population.py is out of date. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A site with no recorded type is typed by one rule, the same one Climate TRACE uses SWEET guessed a missing site type in seven places, from one of two region lists (one with Eastern Europe, one with Australia and New Zealand instead). Climate TRACE's pipeline used a fuller rule: income, region and named countries. So a Kazakh site with no type was a sanitary landfill in Climate TRACE and an open dump in WasteMAP's site tool. The rule now lives in SWEET_python/site_type_defaults.py, moved unchanged from Climate TRACE's landfill_table_ops.fill_landfill_types. A site is a sanitary landfill where its country is high income, or its region is one of landfill_default_regions plus Western Asia and Central Asia, or it is China, Russia, Mexico, Brazil or Costa Rica. Otherwise, and always for Mongolia and Yemen, it is an open dump. Income comes from SWEET_python/country_income.py, copied from the World Bank table Climate TRACE reads (What a Waste 2.0's country file, 217 countries). Every guess in city_params now calls it: the city split's last fallback (three branches), site_only_estimate, both trace paths, and the site tool's prefill by location and for a listed site with no type. dst_baseline_blank's fallback is left to #74, which rewrites it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: a site with no recorded type is guessed the same way everywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Gas capture and oxidation follow a site's reports year by year when its rows carry their year The Climate TRACE pipeline's consolidated input gives a site one row per year and marks each with `row_year`. On those rows a reported gas collection efficiency or oxidation belongs to its year: one value is used in every model year, and several are carried back and forward -- the first back to the start, each forward to the next report, the latest to the end. Two consequences. A modelled site, which has no reported-emissions year, keeps its measured efficiency instead of falling to the site-type default. And if upstream starts resolving these two per year, the series follows the reports with no change here. Rows without `row_year` -- the legacy input and every other caller -- keep the old rule (site mean, overwritten in reported years). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The carried series reads nullable year and value columns Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: gas capture and oxidation follow a site's yearly reports when its rows carry their year Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Rows that carry their year never fall back to the emissions-year rule If every row_year on a site's rows was blank, both builders fell through to the legacy rule, which places a value by its reported-emissions year. For gas capture that brought back the fault this branch fixes: a modelled site, with no such year, lost its measured efficiency to the site-type default. Now an undated value on these rows is the site's value in every year, and a site with no value at all gets the gated default as before. Raised in review of #84. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The places SWEET applies a Climate TRACE modelling decision carry a comment naming it Seven decisions from RMI_Climate_TRACE_Waste_Methane's docs/MODEL_DECISIONS.md are tagged where SWEET applies them: MCF, site type, waste composition, gas capture, oxidation, flaring and population growth. That repo's test checks the comments once a SWEET release containing them is pinned. Comments only; no number moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bump the python-minor-and-patch group with 5 updates Bumps the python-minor-and-patch group with 5 updates: | Package | From | To | | --- | --- | --- | | [asyncpg](https://github.com/MagicStack/asyncpg) | `0.31.0` | `0.32.0` | | [fastapi](https://github.com/fastapi/fastapi) | `0.142.2` | `0.143.0` | | [numpy](https://github.com/numpy/numpy) | `2.5.3` | `2.5.4` | | [pydantic](https://github.com/pydantic/pydantic) | `2.13.5` | `2.14.0` | | [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) | `2.1.3` | `2.1.4` | Updates `asyncpg` from 0.31.0 to 0.32.0 - [Release notes](https://github.com/MagicStack/asyncpg/releases) - [Commits](MagicStack/asyncpg@v0.31.0...v0.32.0) Updates `fastapi` from 0.142.2 to 0.143.0 - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](fastapi/fastapi@0.142.2...0.143.0) Updates `numpy` from 2.5.3 to 2.5.4 - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](numpy/numpy@v2.5.3...v2.5.4) Updates `pydantic` from 2.13.5 to 2.14.0 - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md) - [Commits](pydantic/pydantic@v2.13.5...v2.14.0) Updates `sqlalchemy` from 2.1.3 to 2.1.4 - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: asyncpg dependency-version: 0.32.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-minor-and-patch - dependency-name: fastapi dependency-version: 0.143.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-minor-and-patch - dependency-name: numpy dependency-version: 2.5.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-minor-and-patch - dependency-name: pydantic dependency-version: 2.14.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-minor-and-patch - dependency-name: sqlalchemy dependency-version: 2.1.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com> * The README explains decision comments, and a pull-request template asks about them A "Decision comments" section says what a `# decision:` comment marks, that the list lives in the Climate TRACE pipeline repo, which four tagged decisions WasteMAP shares, and that changing a tagged line needs a paired Climate TRACE pull request updating its entry. A new pull-request template asks whether a change touches a tagged line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Seven more Climate TRACE modelling decisions are marked where SWEET applies them Comments naming entries in RMI_Climate_TRACE_Waste_Methane's docs/MODEL_DECISIONS.md: waste-before-1970-is-zero, intake-ends-before-close-year, intake-follows-population, decay-rate-from-climate, methane-potential-by-waste-type, monthly-from-decay-model and particulate-factors. Comments only; no number moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: seven decisions, not nine Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * City DST scenarios run for São Paulo and Brasília: load_csv_new normalizes a city's composition (#73) * load_csv_new normalizes a city's composition, so the city DST runs for São Paulo and Brasília WasteMAP's cities table publishes Brazil's precomputed rows with their source composition as it is: São Paulo's ten Waste Components sum to 99%, Brasília's to 87%, and Brazil's national default to 100.1%. load_csv_new was the one loader that took a composition as published. implement_dst_changes_simple_v1_5 therefore rejected São Paulo and Brasília outright with "Invalid waste fractions" (São Paulo by float rounding alone: 1 - 0.99 = 0.010000000000000009). Every other Brazilian city's typed masses missed or exceeded its waste, and its no-change scenario drifted from the baseline. Normalize proportionally, as load_andre_params and dst_baseline_blank do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: load_csv_new normalizes a city's composition Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * A Custom Location buries or dumps its waste in every country (#74) * A Custom Location buries or dumps its waste in every country City.dst_baseline_blank looked a country's disposal split up with .get(iso3, .get(region, 0)). Southern Asia, South-Eastern Asia and Southern Africa have no row in fraction_open_dumped / fraction_landfilled (no label mismatch: the other regional tables carry them as 0.0 # np.nan), and Canada's, Germany's and Switzerland's country rows are all zeros, so 31 countries got a (0, 0, 0) split. Every landfill took 0% of the waste and the city modelled no landfill methane; the except-KeyError fallback never ran because .get never raises. defaults_2019.disposal_split_for gives the split load_andre_params gives a cities-table row with no landfill data: the country's row if it sends waste anywhere, else the region's, else all landfill in landfill_default_regions and all dumpsite elsewhere. load_andre_params is unchanged, so the cities table doesn't move; the other 218 countries' Custom Location output is bit-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The changelog links the WasteMAP half Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A Custom Location's fallback split follows Climate TRACE's site-type rule main's #83 moved load_andre_params's no-data fallback to site_type_defaults.landfill_is_default. disposal_split_for still used landfill_default_regions, so the parity test failed for Brunei (high income): the cities table landfills it, a Custom Location dumped it. Calling the shared rule makes the two agree for all 249 countries; only Brunei moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Moving waste to a city's existing gas capture changes its emissions (#75) * Moving waste to a city's existing gas capture changes its emissions The City DST's "move waste to existing gas capture" lever (move_gas and existing_gas_pct in implement_dst_changes_simple_v1_5) rewrote split_fractions in the generic branch but never passed the split to the landfills, whose waste comes from their own fraction_of_waste. Only the new-landfill-with-capture block did that, and WasteMAP switches that lever off for every city it offers this one to. So the slider returned the no-change scenario at every setting for all 7 cities in the June 2026 table where it is live. The arithmetic was wrong too: it multiplied the shares without capture by existing / original, scaling them up (Lahore's landfill without capture came out at 171% of its waste) and zeroing them for a city with no capture. _move_to_existing_gas_capture gives capture existing_gas_pct and the landfill and dumpsite without capture the rest, in their original proportions, and the scenario applies that split to the landfills. A request the lever can't carry out raises INVALID_PARAMETERS. The new-landfill sum check now builds CustomError with both arguments; it raised TypeError, a 500 at the API. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Link the changelog to the PRs it ships in Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Drop the add_gas oxidation known limitation: #78 fixes it "Add gas capture" losing the oxidation it sets is fixed in #78 (with RMI/WasteMAP#856), so this changelog no longer lists it as a known limitation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * The City DST's "add gas capture" applies the oxidation it sets (#78) * The City DST's "add gas capture" applies the oxidation it sets In the generic branch of implement_dst_changes_simple_v1_5, add_gas gives the landfill without capture an oxidation factor of 0.22 after the implementation year and the dumpsite it converts to a controlled dumpsite 0.1, and sets skip_ox = True to keep them. The emissions loop at the end replaced that with skip_ox = scenario_parameters.sites_method, which is false on this branch, so Landfill.estimate_emissions reset both from gas_capture (still False) to 0.1 and 0: the gas capture applied, the oxidation never did. Each branch now sets skip_ox itself and the loop uses it; the real-sites branch keeps True. Every add_gas result falls another 10.0-13.3% after the implementation year; a city that landfills everything goes from -60.0% to -65.3% against no change in 2040. Across WasteMAP's June 2026 table and a Custom Location in every country, the no-change scenario, the other levers and every year up to the implementation year are bit-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Link the changelog to the PRs it ships in Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * A Custom Location in Kosovo builds, and the name "Kosovo" no longer means Serbia (#77) * A Custom Location in Kosovo builds: SWEET's own country table before 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> * Changelog links the paired WasteMAP PR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * A blank or junk country is not found, and the site tool's prefill finds every country the geocoder names (#80) * A Custom Location in Kosovo builds: SWEET's own country table before 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> * A blank or junk country is not found; the prefill finds every country the geocoder names _iso3_for ended with pycountry's fuzzy search, which scores every country for an empty name and scores a country for any of its subdivisions that match. So "" and " " were the United Kingdom (the most subdivisions), "None" Italy (Frosinone), "nan" Thailand (Nan province), and None raised AttributeError rather than LookupError. _iso3_for now raises LookupError for anything that isn't a non-blank string, strips the name, and takes the fuzzy answer only when the name is whole words of that country's own name or its initials ("UK", "UAE"). The site tool's prefill (sdst_prepopulate) crashed with AttributeError for a point Nominatim can't place or gives no country, and failed for 11 English names Nominatim uses that neither SWEET nor pycountry spell its way (Turkey, Ivory Coast, Cape Verde, ...). _iso3_at tries the geocoder's name, then its ISO 3166-1 code, and the prefill says "No country at <lat>, <lon>." where there is none. Over 306 reverse-geocoded points (222 country names): 210 resolve as before, the 11 now resolve, Sint Maarten moves from NLD to SXM. Every code and name in SWEET's own table resolves as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Changelog: cite #80 and RMI/WasteMAP#859 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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(incity_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:LookupError, soCity.dst_baseline_blankandCity.cityparams_obj_for_blank_siteraisedValueError("Country 'XKX' not found.").defaults_2019.region_lookup_iso3["XKX"]is "Southern Europe", so SWEET had the defaults; only the lookup failed.search_fuzzy("Kosovo")returns Serbia, whose province Kosovo-Metohija matches.sdst_prepopulatenames 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=25Expected: 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)raisesValueError: Country 'XKX' not found.Fix
_iso3_fortries 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_blankfor every code WasteMAP's/v1/dst_countriesoffers, before and after:ValueErrorKosovo 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_siteandsdst_prepopulatecall_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_prepopulatefor a point in Pristina returnsXKX, notSRB. The geocoder and database are faked, so it runs offline.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
XKXcan't be looked up, before or after", and counts 249 countries. If this merges first, those lines need updating when A Custom Location buries or dumps its waste in every country #74 is rebased; with both, Kosovo takes Southern Europe's regional disposal split.changelog/2026-10.mddoesn't exist on main. City DST scenarios run for São Paulo and Brasília: load_csv_new normalizes a city's composition #73, A Custom Location buries or dumps its waste in every country #74, Moving waste to a city's existing gas capture changes its emissions #75 and this PR each create it, so whichever merges second resolves a simple conflict.""→ GBR,"None"→ ITA). None of WasteMAP's frontends send those, so I've left it for a separate change.Acceptance criteria
City("*").dst_baseline_blank("XKX", 2_000_000, 500.0, 25.0)builds a city._iso3_forresolves every code and name in SWEET's own table to SWEET's code, Kosovo included.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