diff --git a/fastapi/routing.py b/fastapi/routing.py index d931c19c7..2b83cca28 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -596,29 +596,6 @@ class APIRoute(routing.Route): if not defer_init: self.init_attributes() - def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: - return get_request_handler( - dependant=self.dependant, - body_field=self.body_field, - status_code=self.status_code, - response_class=self.response_class, - response_field=self.secure_cloned_response_field, - response_model_include=self.response_model_include, - response_model_exclude=self.response_model_exclude, - response_model_by_alias=self.response_model_by_alias, - response_model_exclude_unset=self.response_model_exclude_unset, - response_model_exclude_defaults=self.response_model_exclude_defaults, - response_model_exclude_none=self.response_model_exclude_none, - dependency_overrides_provider=self.dependency_overrides_provider, - embed_body_fields=self._embed_body_fields, - ) - - def matches(self, scope: Scope) -> Tuple[Match, Scope]: - match, child_scope = super().matches(scope) - if match != Match.NONE: - child_scope["route"] = self - return match, child_scope - @cached_property def response_field(self) -> Optional[ModelField]: if not self.response_model: @@ -630,16 +607,16 @@ class APIRoute(routing.Route): mode="serialization", ) - # Create a clone of the field, so that a Pydantic submodel is not returned - # as is just because it's an instance of a subclass of a more limited class - # e.g. UserInDB (containing hashed_password) could be a subclass of User - # that doesn't have the hashed_password. But because it's a subclass, it - # would pass the validation and be returned as is. - # By being a new field, no inheritance will be passed as is. A new model - # will always be created. - # TODO: remove when deprecating Pydantic v1 @cached_property def secure_cloned_response_field(self) -> Optional[ModelField]: + # Create a clone of the field, so that a Pydantic submodel is not returned + # as is just because it's an instance of a subclass of a more limited class + # e.g. UserInDB (containing hashed_password) could be a subclass of User + # that doesn't have the hashed_password. But because it's a subclass, it + # would pass the validation and be returned as is. + # By being a new field, no inheritance will be passed as is. A new model + # will always be created. + # TODO: remove when deprecating Pydantic v1 return create_cloned_field(self.response_field) if self.response_field else None @cached_property @@ -652,7 +629,6 @@ class APIRoute(routing.Route): assert is_body_allowed_for_status_code(additional_status_code), ( f"Status code {additional_status_code} must not have a response body" ) - response_name = f"Response_{additional_status_code}_{self.unique_id}" response_field = create_model_field( name=response_name, type_=model, mode="serialization" @@ -691,14 +667,37 @@ class APIRoute(routing.Route): return request_response(self.get_route_handler()) def init_attributes(self) -> None: - self.app = self.app - self.dependant = self.dependant - self.response_field = self.response_field - self.response_fields = self.response_fields - self.secure_cloned_response_field = self.secure_cloned_response_field - self.body_field = self.body_field - self._flat_dependant = self._flat_dependant - self._embed_body_fields = self._embed_body_fields + _ = self.app + _ = self.dependant + _ = self.response_field + _ = self.response_fields + _ = self.secure_cloned_response_field + _ = self.body_field + _ = self._flat_dependant + _ = self._embed_body_fields + + def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: + return get_request_handler( + dependant=self.dependant, + body_field=self.body_field, + status_code=self.status_code, + response_class=self.response_class, + response_field=self.secure_cloned_response_field, + response_model_include=self.response_model_include, + response_model_exclude=self.response_model_exclude, + response_model_by_alias=self.response_model_by_alias, + response_model_exclude_unset=self.response_model_exclude_unset, + response_model_exclude_defaults=self.response_model_exclude_defaults, + response_model_exclude_none=self.response_model_exclude_none, + dependency_overrides_provider=self.dependency_overrides_provider, + embed_body_fields=self._embed_body_fields, + ) + + def matches(self, scope: Scope) -> Tuple[Match, Scope]: + match, child_scope = super().matches(scope) + if match != Match.NONE: + child_scope["route"] = self + return match, child_scope class APIRouter(routing.Router):