@@ -548,6 +548,28 @@ def _format_collection(
548548 return f'{ brackets [0 ]} \n ' + ',\n ' .join (elements ) + f',\n { indent } { brackets [1 ]} '
549549
550550
551+ def _camel_to_snake (camel_case_string : str ) -> str :
552+ """Converts a camelCase string to snake_case."""
553+ snake_case_string = re .sub (r'(?<!^)([A-Z])' , r'_\1' , camel_case_string )
554+ return snake_case_string .lower ()
555+
556+
557+ def _camel_key_to_snake (message : Any ):
558+ """Converts all camelCase keys to snake_case in a dict or list."""
559+ if isinstance (message , dict ):
560+ return {
561+ # Several xxxMetadata fields have already released with camelCase
562+ # values, we need to keep them as is.
563+ _camel_to_snake (key ) if 'Metadata' not in key else key :
564+ _camel_key_to_snake (value ) if 'Metadata' not in key else value
565+ for key , value in message .items ()
566+ }
567+ elif isinstance (message , list ):
568+ return [_camel_key_to_snake (value ) for value in message ]
569+ else :
570+ return message
571+
572+
551573class BaseModel (pydantic .BaseModel ):
552574
553575 model_config = pydantic .ConfigDict (
@@ -576,6 +598,9 @@ def _from_response(
576598 response : dict [str , object ],
577599 kwargs : dict [str , object ],
578600 ) -> T :
601+ # Convert all camelCase keys to snake_case before loading the response.
602+ response = _camel_key_to_snake (response )
603+
579604 # To maintain forward compatibility, we need to remove extra fields from
580605 # the response.
581606 # We will provide another mechanism to allow users to access these fields.
0 commit comments