Repository navigation
fix: treat KMA Missing sentinels (|v|>=900) as None; add public is_missing() - #31
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
…ecast values getUltraSrtNcst answered a station with no observation with REH/VEC -998, RN1/WSD/UUU/VVV -998.9 and T1H -999; the 단기예보 guide defines +900/-900 and beyond as Missing, but float_or_none passed them straight into typed fields (WeatherSnapshot.humidity == -998). - add public kma.is_missing() / KMA_MISSING_ABS_THRESHOLD (None, blank and finite |v|>=900 are missing; NaN/Inf and non-numeric labels are not) - WeatherSnapshot temperature/humidity/wind_speed/wind_direction/precipitation use the KMA-only kma_value_or_none/kma_int_or_none; shared parsers unchanged - normalize_value returns None for missing, so ForecastItem.value / BeachForecastItem.value / ForecastTimepoint.values are now Optional - ASOS pressure, beach tide level/buoys and grid coordinates keep their values Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
…each sentinels (RED) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
…aN/Inf; document None in ForecastTimepoint.values
- abs(Decimal) applies the context: Overflow on 1e1000000 and rounding
899.999...(33 digits) up to 900. copy_abs() is exact.
- kma_int_or_none("NaN"/"Infinity") raised ValueError from int(); a
non-finite REH/VEC now gives None instead of failing now().
- ForecastTimepoint docstring: a present key with None means present but
missing/blank; an absent key means no row.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj
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.
Summary
The KMA 단기예보 service guide defines values of +900 or more and -900 or less as Missing. In production,
getUltraSrtNcstreturned these sentinels for a station with no observation:REH/VEC -998,RN1/WSD/UUU/VVV -998.9andT1H -999.float_or_nonepassed them through, so typed fields carried them (WeatherSnapshot.humidity == -998,temperature == -999.0).kma.is_missing(value: str | float | Decimal | None) -> boolandkma.KMA_MISSING_ABS_THRESHOLD(Decimal("900")), documented in the README under "Missing 값".TrueforNone,"", whitespace, and finiteabs(v) >= 900. Strings are parsed asDecimal, so"1e400"counts as a sentinel.Falsefor non-numeric labels (강수없음,1.0mm 미만) and for NaN/Infinity. Those are not sentinels, and the caller decides whether they are invalid.WeatherSnapshot.temperature/humidity/wind_speed/wind_direction/precipitationnow go through the KMA-onlykma_value_or_none/kma_int_or_none, or_observed_amountfor RN1. They areNonewhen missing.normalize_valuereturnsNonefor missing or blank values. As a result,ForecastItem.value,BeachForecastItem.valueandForecastTimepoint.valuesbecome... | None. This changes the type contract. The raw string stays inraw.Not changed, on purpose
float_or_none/int_or_noneare unchanged.pa/psis normally above 900 hPa, and ASOS is a different service.tilevelis in cm and can exceed 900, and these come from a different observation network.nx/nyare unchanged.Tests
tests/test_missing_values.pyuses the production payload shape. It went RED on 4ac9a32:now()returned-999.0 -998 -998.9 -998 -998.9, and the forecast values were the sentinels. It is GREEN here.ruff checkandmypy src/kmaare clean. All of this ran on n150.Version stays
0.1.0(unreleased), per the repo convention. The CHANGELOG entry is under0.1.0 - 미배포.Consumer: kor-travel-weather
chore/kma-lib-missing-helperpins this branch head and needs a repin to the merge SHA after this merges.🤖 Generated with Claude Code
https://claude.ai/code/session_01RuoPRjkdpZNYjTZ1RYQoHj