1+ from typing import Any , ClassVar
2+
13from pydantic import BaseModel , ConfigDict
24from pydantic .alias_generators import to_camel
35
@@ -23,6 +25,9 @@ class A2ABaseModel(BaseModel):
2325
2426 Provides a common configuration (e.g., alias-based population) and
2527 serves as the foundation for future extensions or shared utilities.
28+
29+ This implementation overrides __setattr__ to allow setting fields
30+ using their camelCase alias for backward compatibility.
2631 """
2732
2833 model_config = ConfigDict (
@@ -32,3 +37,34 @@ class A2ABaseModel(BaseModel):
3237 serialize_by_alias = True ,
3338 alias_generator = to_camel_custom ,
3439 )
40+
41+ # Cache for the alias -> field_name mapping.
42+ # We use a ClassVar so it's created once per class, not per instance.
43+ # The type hint is now corrected to be `ClassVar[<optional_type>]`.
44+ _alias_to_field_name_map : ClassVar [dict [str , str ] | None ] = None
45+
46+ def __setattr__ (self , name : str , value : Any ):
47+ """Allow setting attributes via their camelCase alias.
48+
49+ This is overridden to provide backward compatibility for code that
50+ sets model fields using aliases after initialization.
51+ """
52+ # Build the alias-to-name mapping on first use and cache it.
53+ if self .__class__ ._alias_to_field_name_map is None :
54+ # Using a lock or other mechanism could make this more thread-safe
55+ # for highly concurrent applications, but this is fine for most cases.
56+ self .__class__ ._alias_to_field_name_map = {
57+ field .alias : field_name
58+ for field_name , field in self .model_fields .items ()
59+ if field .alias is not None
60+ }
61+
62+ # If the attribute name is a known alias, redirect the assignment
63+ # to the actual (snake_case) field name.
64+ field_name = self .__class__ ._alias_to_field_name_map .get (name )
65+ if field_name :
66+ # Use the actual field name for the assignment
67+ super ().__setattr__ (field_name , value )
68+ else :
69+ # Otherwise, perform a standard attribute assignment
70+ super ().__setattr__ (name , value )
0 commit comments