fix: migrate 3 cross-field validators to Pydantic V2 - #310
Open
dulcetberg wants to merge 1 commit into
Open
Conversation
Converts the remaining `@validator` usages in src/validation/models.py that read other fields via V1's `values` parameter: - RawDataCurrentParams.check_bind_option (bind_zip) - StatsRequestParams.set_geometry_or_iso3 (geometry) - DynamicCategoriesModel.set_geometry_or_iso3 (geometry, plus its extra HDX dataset/category cross-checks) `@validator(field, allow_reuse=True)` -> `@field_validator(field)` + `@classmethod`; `values.get(...)` -> `info.data.get(...)`. The two `set_geometry_or_iso3` validators additionally used `pre=True, always=True` in V1, which has no direct V2 validator-level equivalent. Converting to `mode="before"` alone is not sufficient: it does not run when the field is omitted and falls back to its default. The correct V2 replacement is `validate_default=True` on the field's own `Field(...)` declaration, which was added to both `geometry` fields here. Verified behaviorally (all 4 cases: geometry-only, iso3-only, both supplied, neither supplied) that this reproduces the original V1 semantics exactly. Part of the pydantic v1->v2 migration tracked in hotosm#256. Continues the incremental approach from hotosm#307/hotosm#308/hotosm#309; this covers the 3 validators that were deliberately deferred out of hotosm#309 for needing this more involved treatment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Brian Bergstrom <dulcetberg@gmail.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.
Summary
Converts the 3 remaining
@validatorusages insrc/validation/models.pythat read other fields via V1'svaluesparameter (deliberately deferred out of #309 since they need themode="before"+info.datatreatment rather than a plain decorator swap):RawDataCurrentParams.check_bind_option(bind_zip)StatsRequestParams.set_geometry_or_iso3(geometry)DynamicCategoriesModel.set_geometry_or_iso3(geometry— this one also has extra HDX dataset/category cross-checks beyond the base geometry/iso3 logic)@validator(field, allow_reuse=True)→@field_validator(field)+@classmethod;values.get(...)→info.data.get(...).The
always=TruegotchaThe two
set_geometry_or_iso3validators usedpre=True, always=Truein V1, so they run even whengeometryis omitted (this is how the "either geometry or iso3, not neither" check works). V2'sfield_validatorhas noalwaysequivalent —mode="before"alone does not run when the field is omitted and its default is used. Verified this with an isolated test before relying on it.The correct V2 replacement is
validate_default=Trueon the field's ownField(...)declaration, added here to bothgeometryfields. Re-verified behaviorally across all 4 cases (geometry-only, iso3-only, both supplied, neither supplied) that this reproduces the original V1 semantics exactly.Part of the
pydanticv1→v2 migration tracked in #256. Continues the incremental approach from #307/#308/#309.Test plan
pytest tests/test_app.pypasses (5 passed)StatsRequestParams: neither/both/geometry-only/iso3-only all raise/pass exactly as beforeRawDataCurrentParams.check_bind_option: disallowed output_type + bind_zip=False raises, allowed output_type + bind_zip=False passes, default bind_zip passes regardless of output_typeDynamicCategoriesModel.set_geometry_or_iso3's extra HDX dataset-required-when-hdx_upload logic🤖 Generated with Claude Code