Cache per-class field alias info in UniversalBaseModel - #804
Open
rsd-darshan wants to merge 1 commit into
Open
Conversation
Fixes cohere-ai#802 `_coerce_field_names_to_aliases` rebuilt the field name/alias maps on every validation call, which showed up as measurable overhead when parsing many nested models (e.g. v2 `chat_stream` SSE events). Compute the alias map, differing names, and ambiguous keys once per class and cache them by class id, mirroring the existing `_type_adapter_cache`. Also add a fast path that returns the input unchanged when none of its keys need rewriting, and have `parse_obj_as` reuse the same cache instead of re-scanning fields itself.
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.
Fixes #802
_coerce_field_names_to_aliasesis amode="before"validator onUniversalBaseModel, so it runs on every model instantiation, including every nested model parsed out of an SSE event duringchat_stream. It was rebuilding the field name/alias maps from scratch on each call even though they're constant per class.This caches the per-class alias info (name→alias map, the subset of names whose alias differs, and the ambiguous-key set) keyed by class id, mirroring the existing
_type_adapter_cache. Two fast paths are added on top:parse_obj_as's ownhas_pydantic_aliasesscan is also switched to reuse this cache instead of walking the fields a second time.Testing
ruff checkandmypypass on the changed file.pytestrun locally: all failures are pre-existing/unrelated (live API tests requiring a real key, and one unrelated mypy-stub gap inoci_client.py).Note
Low Risk
Refactor of existing alias coercion logic with intended behavioral parity; main risk is a subtle edge case in fast-path or ambiguous-key handling, not security or data integrity.
Overview
Speeds up
UniversalBaseModelvalidation (notably nested models in SSE/chat_stream) by computing field name→alias maps once per class instead of on every instantiation.Introduces
_get_field_alias_infowith a class-id cache (same pattern as_type_adapter_cache) holdingname_to_alias, fields whose alias differs, ambiguous keys, and keys that might need rewriting.parse_obj_asreusesdiffering_namesfrom that cache instead of scanning model fields for real Pydantic aliases._coerce_field_names_to_aliases(Pydantic v1 and v2) now pulls from the cache and adds two early exits: return input unchanged when the class has no alias/name mismatches to care about, or when incoming keys do not intersectrelevant_keys; only then copy the dict and rewrite keys indiffering_names. Ambiguous-key errors are unchanged.Reviewed by Cursor Bugbot for commit bff2128. Bugbot is set up for automated code reviews on this repo. Configure here.