@@ -232,6 +232,12 @@ def _is_dunder(attr_name: str):
232232
233233
234234def _wrap_pydantic_model (model : type [_T_PYDANTIC_MODEL ]) -> "_PydanticModelWrapper[_T_PYDANTIC_MODEL]" :
235+ # In case we have a forwardref within one of the fields
236+ # For example, when "from __future__ import annotations" is used in the file with the schema
237+ if model is not BaseModel :
238+ model .model_rebuild (raise_errors = False )
239+ model = cast (type [_T_PYDANTIC_MODEL ], model )
240+
235241 decorators = _get_model_decorators (model )
236242 validators = {}
237243 for decorator_wrapper in decorators :
@@ -240,8 +246,20 @@ def _wrap_pydantic_model(model: type[_T_PYDANTIC_MODEL]) -> "_PydanticModelWrapp
240246
241247 wrapped_validator = _wrap_validator (decorator_wrapper .func , decorator_wrapper .shim , decorator_wrapper .info )
242248 validators [decorator_wrapper .cls_var_name ] = wrapped_validator
249+
250+ annotations = {
251+ name : value
252+ if not isinstance (value , str )
253+ else model .model_fields [name ].annotation or model .__annotations__ [name ]
254+ for name , value in model .__annotations__ .items ()
255+ }
256+
243257 fields = {
244- field_name : PydanticFieldWrapper (model .model_fields [field_name ], model .__annotations__ [field_name ], field_name )
258+ field_name : PydanticFieldWrapper (
259+ model .model_fields [field_name ],
260+ annotations [field_name ],
261+ field_name ,
262+ )
245263 for field_name in model .__annotations__
246264 }
247265
@@ -264,7 +282,7 @@ def _wrap_pydantic_model(model: type[_T_PYDANTIC_MODEL]) -> "_PydanticModelWrapp
264282 fields = fields ,
265283 other_attributes = other_attributes ,
266284 validators = validators ,
267- annotations = model . __annotations__ . copy () ,
285+ annotations = annotations ,
268286 )
269287
270288
@@ -356,6 +374,7 @@ def generate_model_copy(self, generator: "SchemaGenerator") -> type[_T_PYDANTIC_
356374 if not validator .is_deleted and type (validator ) == _ValidatorWrapper # noqa: E721
357375 }
358376 fields = {name : field .generate_field_copy (generator ) for name , field in self .fields .items ()}
377+
359378 model_copy = type (self .cls )(
360379 self .name ,
361380 tuple (generator [cast (type [BaseModel ], base )] for base in self .cls .__bases__ ),
@@ -494,7 +513,6 @@ def _change_version_of_a_non_container_annotation(self, annotation: Any) -> Any:
494513 ) or isinstance (annotation , fastapi .security .base .SecurityBase ):
495514 return annotation
496515
497- # If we do not use modifier, we will get an unhashable module error
498516 def modifier (annotation : Any ):
499517 return self .change_version_of_annotation (annotation )
500518
@@ -637,8 +655,6 @@ def __getitem__(self, model: type[_T_ANY_MODEL], /) -> type[_T_ANY_MODEL]:
637655
638656 if model in self .concrete_models :
639657 return self .concrete_models [model ]
640- else :
641- wrapper = self ._get_wrapper_for_model (model )
642658
643659 wrapper = self ._get_wrapper_for_model (model )
644660 model_copy = wrapper .generate_model_copy (self )
@@ -661,6 +677,8 @@ def _get_wrapper_for_model(
661677 return self .model_bundle .enums [model ]
662678
663679 if lenient_issubclass (model , BaseModel ):
680+ # TODO: My god, what if one of its fields is in our concrete schemas and we don't use it? :O
681+ # TODO: Add an argument with our concrete schemas for _wrap_pydantic_model
664682 wrapper = _wrap_pydantic_model (model )
665683 self .model_bundle .schemas [model ] = wrapper
666684 elif lenient_issubclass (model , Enum ):
@@ -989,5 +1007,5 @@ def _try_eval_type(value: Any, globals: dict[str, Any]) -> Any:
9891007 new_value , success = pydantic_try_eval_type (value , globals )
9901008 if success :
9911009 return new_value
992- else :
1010+ else : # pragma: no cover # Can't imagine when this would happen
9931011 return value
0 commit comments