@@ -22,13 +22,11 @@ def to_camel_custom(snake: str) -> str:
2222
2323class A2ABaseModel (BaseModel ):
2424 """Base class for shared behavior across A2A data models.
25-
2625 Provides a common configuration (e.g., alias-based population) and
2726 serves as the foundation for future extensions or shared utilities.
2827
29- This implementation overrides __setattr__ and __getattr__ to allow
30- getting and setting fields using their camelCase alias for backward
31- compatibility.
28+ This implementation provides backward compatibility for camelCase aliases
29+ by lazy-loading an alias map upon first use.
3230 """
3331
3432 model_config = ConfigDict (
@@ -40,49 +38,39 @@ class A2ABaseModel(BaseModel):
4038 )
4139
4240 # Cache for the alias -> field_name mapping.
43- # We use a ClassVar so it's created once per class, not per instance .
41+ # It starts as None and is populated on first access .
4442 _alias_to_field_name_map : ClassVar [dict [str , str ] | None ] = None
4543
4644 @classmethod
47- def _initialize_alias_map (cls ) -> None :
48- """Build and cache the alias-to-field-name mapping."""
45+ def _get_alias_map (cls ) -> dict [str , str ]:
46+ """Lazily builds and returns the alias-to-field-name mapping for the class.
47+
48+ The map is cached on the class object to avoid re-computation.
49+ """
4950 if cls ._alias_to_field_name_map is None :
5051 cls ._alias_to_field_name_map = {
5152 field .alias : field_name
5253 for field_name , field in cls .model_fields .items ()
5354 if field .alias is not None
5455 }
56+ return cls ._alias_to_field_name_map
5557
5658 def __setattr__ (self , name : str , value : Any ) -> None :
5759 """Allow setting attributes via their camelCase alias."""
58- self .__class__ ._initialize_alias_map () # noqa: SLF001
59- assert self .__class__ ._alias_to_field_name_map is not None # noqa: SLF001
60-
61- field_name = self .__class__ ._alias_to_field_name_map .get (name ) # noqa: SLF001
62- if field_name :
63- # If the name is an alias, set the actual (snake_case) attribute.
64- super ().__setattr__ (field_name , value )
65- else :
66- # Otherwise, perform a standard attribute assignment.
67- super ().__setattr__ (name , value )
60+ # Get the map and find the corresponding snake_case field name.
61+ field_name = type (self )._get_alias_map ().get (name ) # noqa: SLF001
62+ # If an alias was used, field_name will be set; otherwise, use the original name.
63+ super ().__setattr__ (field_name or name , value )
6864
6965 def __getattr__ (self , name : str ) -> Any :
70- """Allow getting attributes via their camelCase alias.
71-
72- This method is called as a fallback when the attribute 'name' is
73- not found through normal mechanisms.
74- """
75- self .__class__ ._initialize_alias_map () # noqa: SLF001
76- # The map must exist at this point, so we can assert it for type checkers
77- assert self .__class__ ._alias_to_field_name_map is not None # noqa: SLF001
78-
79- field_name = self .__class__ ._alias_to_field_name_map .get (name ) # noqa: SLF001
66+ """Allow getting attributes via their camelCase alias."""
67+ # Get the map and find the corresponding snake_case field name.
68+ field_name = type (self )._get_alias_map ().get (name ) # noqa: SLF001
8069 if field_name :
81- # If the name is an alias, get the actual ( snake_case) attribute.
70+ # If an alias was used, retrieve the actual snake_case attribute.
8271 return getattr (self , field_name )
8372
84- # If the name is not a known alias, it's a genuine missing attribute.
85- # It is crucial to raise AttributeError to maintain normal Python behavior.
73+ # If it's not a known alias, it's a genuine missing attribute.
8674 raise AttributeError (
87- f"'{ self . __class__ .__name__ } ' object has no attribute '{ name } '"
75+ f"'{ type ( self ) .__name__ } ' object has no attribute '{ name } '"
8876 )
0 commit comments