@@ -96,7 +96,21 @@ def _pydantic_validator(func: Function) -> ExprCall | None:
9696 return None
9797
9898
99- def _process_attribute (attr : Attribute , cls : Class , * , processed : set [str ], show_alias : bool = False ) -> None :
99+ def _literal_or_debug (value : Expr | str | None , / , * , path : str ) -> str | None :
100+ if value is None :
101+ return None
102+ if isinstance (value , str ):
103+ try :
104+ return ast .literal_eval (value )
105+ except ValueError :
106+ return value
107+ elif isinstance (value , (ExprName , Expr )):
108+ _logger .debug (f"Could not resolve expression '{ value } ' as a literal for field { path } " )
109+ return None
110+ return None
111+
112+
113+ def _process_attribute (attr : Attribute , cls : Class , * , processed : set [str ]) -> None :
100114 """Handle Pydantic fields."""
101115 if attr .canonical_path in processed :
102116 return
@@ -191,19 +205,16 @@ def _process_attribute(attr: Attribute, cls: Class, *, processed: set[str], show
191205 attr .value = kwargs .get ("default" )
192206 constraints = {kwarg : value for kwarg , value in kwargs .items () if kwarg not in {"default" , "description" , "alias" }}
193207 attr .extra [common ._self_namespace ]["constraints" ] = constraints
208+ attr .extra [common ._mkdocstrings_namespace ]["template" ] = "pydantic_field.html.jinja"
194209
195- # Store alias if present
196- if show_alias and (alias := kwargs .get ("alias" )):
197- if isinstance (alias , str ):
198- try :
199- attr .extra [common ._self_namespace ]["alias" ] = ast .literal_eval (alias )
200- except ValueError :
201- attr .extra [common ._self_namespace ]["alias" ] = alias
202- # Set the attribute template to the custom template, which will use the alias instead of the attribute name.
203- attr .extra [common ._mkdocstrings_namespace ]["template" ] = "pydantic_attribute_alias.html.jinja"
204- elif isinstance (alias , (ExprName , Expr )):
205- # For now, we can't resolve expressions at static analysis time
206- _logger .debug (f"Could not resolve alias expression for field '{ attr .path } '" )
210+ # Store validation/serialization aliases if defined.
211+ if alias := _literal_or_debug (kwargs .get ("alias" ), path = attr .path ):
212+ attr .extra [common ._self_namespace ]["validation_alias" ] = alias
213+ attr .extra [common ._self_namespace ]["serialization_alias" ] = alias
214+ elif validation_alias := _literal_or_debug (kwargs .get ("validation_alias" ), path = attr .path ):
215+ attr .extra [common ._self_namespace ]["validation_alias" ] = validation_alias
216+ elif serialization_alias := _literal_or_debug (kwargs .get ("serialization_alias" ), path = attr .path ):
217+ attr .extra [common ._self_namespace ]["serialization_alias" ] = serialization_alias
207218
208219 # Populate docstring from the field's `description` argument.
209220 if not attr .docstring and (description_expr := kwargs .get ("description" )):
@@ -228,7 +239,7 @@ def _process_function(func: Function, cls: Class, *, processed: set[str]) -> Non
228239 common ._process_function (func , cls , fields )
229240
230241
231- def _process_class (cls : Class , * , processed : set [str ], schema : bool = False , show_alias : bool = False ) -> None :
242+ def _process_class (cls : Class , * , processed : set [str ], schema : bool = False ) -> None :
232243 """Finalize the Pydantic model data."""
233244 if cls .canonical_path in processed :
234245 return
@@ -263,20 +274,14 @@ def _process_class(cls: Class, *, processed: set[str], schema: bool = False, sho
263274 for member in cls .all_members .values ():
264275 kind = member .kind
265276 if kind is Kind .ATTRIBUTE :
266- _process_attribute (member , cls , processed = processed , show_alias = show_alias ) # ty: ignore[invalid-argument-type]
277+ _process_attribute (member , cls , processed = processed ) # ty: ignore[invalid-argument-type]
267278 elif kind is Kind .FUNCTION :
268279 _process_function (member , cls , processed = processed ) # ty: ignore[invalid-argument-type]
269280 elif kind is Kind .CLASS :
270- _process_class (member , processed = processed , schema = schema , show_alias = show_alias ) # ty: ignore[invalid-argument-type]
281+ _process_class (member , processed = processed , schema = schema ) # ty: ignore[invalid-argument-type]
271282
272283
273- def _process_module (
274- mod : Module ,
275- * ,
276- processed : set [str ],
277- schema : bool = False ,
278- show_alias : bool = False ,
279- ) -> None :
284+ def _process_module (mod : Module , * , processed : set [str ], schema : bool = False ) -> None :
280285 """Handle Pydantic models in a module."""
281286 if mod .canonical_path in processed :
282287 return
@@ -285,9 +290,9 @@ def _process_module(
285290 for cls in mod .classes .values ():
286291 # Don't process aliases, real classes will be processed at some point anyway.
287292 if not cls .is_alias :
288- _process_class (cls , processed = processed , schema = schema , show_alias = show_alias )
293+ _process_class (cls , processed = processed , schema = schema )
289294
290295 for submodule in mod .modules .values ():
291296 # Same for modules, don't process aliased ones.
292297 if not submodule .is_alias :
293- _process_module (submodule , processed = processed , schema = schema , show_alias = show_alias )
298+ _process_module (submodule , processed = processed , schema = schema )
0 commit comments