Response model doesn't allow models with allow_arbitrary_types
See original GitHub issueFirst check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google “How to X in FastAPI” and didn’t find any information.
- I already read and followed all the tutorial in the docs and didn’t find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
Example - not specifying response_model
Creating a Pydantic
model that has a field with an arbitrary class will raise RuntimeError
stating that there is no validator for class ArbitraryClass
:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ArbitraryClass:
def __init__(self, attr: str) -> None:
self.attr = attr
class SomeModel(BaseModel):
name: str = 'SomeModel'
arbitrary_field: ArbitraryClass
class Config:
arbitrary_types_allowed = True
@app.get('/')
async def return_model_with_arbitrary_type():
model = SomeModel(arbitrary_field=ArbitraryClass('attr_value'))
return model
Results of running example without response_model
specified
This works fine, since Pydantic
allows creation of models where fields have arbitrary types when we use arbitrary_types_allowed
in Config
. The returned JSON is also nicely formatted, asattribute: value
pair:
{
"name": "SomeModel",
"arbitrary_field": {
"attr": "attr_value"
}
}
Example - specifying response_model
When we try to specify that the response model for this endpoint is SomeModel
:
@app.get('/', response_model=SomeModel)
async def return_model_with_arbitrary_type():
model = SomeModel(arbitrary_field=ArbitraryClass('attr_value'))
return model
We get an error:
Traceback (most recent call last):
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 65, in create_response_field
return response_field(field_info=field_info)
File "pydantic/fields.py", line 284, in pydantic.fields.ModelField.__init__
File "pydantic/fields.py", line 362, in pydantic.fields.ModelField.prepare
File "pydantic/fields.py", line 538, in pydantic.fields.ModelField.populate_validators
File "pydantic/validators.py", line 629, in find_validators
RuntimeError: no validator found for <class 'backend.main.ArbitraryClass'>, see `arbitrary_types_allowed` in Config
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 193, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/Users/fisheye36/Projects/fastapi-issue/src/backend/__main__.py", line 1, in <module>
from backend.main import run_server
File "/Users/fisheye36/Projects/fastapi-issue/src/backend/main.py", line 37, in <module>
async def return_model_with_arbitrary_type():
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 494, in decorator
self.add_api_route(
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 439, in add_api_route
route = route_class(
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/routing.py", line 315, in __init__
] = create_cloned_field(self.response_field)
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 91, in create_cloned_field
use_type.__fields__[f.name] = create_cloned_field(
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 94, in create_cloned_field
new_field = create_response_field(name=field.name, type_=use_type)
File "/Users/fisheye36/Projects/fastapi-issue/.env/lib/python3.8/site-packages/fastapi/utils.py", line 67, in create_response_field
raise fastapi.exceptions.FastAPIError(
fastapi.exceptions.FastAPIError: Invalid args for response field! Hint: check that <class 'backend.main.ArbitraryClass'> is a valid pydantic field type
Question
Pydantic
allows models like that. FastAPI
also allows returning models like that and handles them well. The only problem here is something wrong happens when that kind of model is specified as a response model.
I know I could create validators for ArbitraryClass
, but what if the class is coming from some other library and I can’t edit its source?
Environment
- OS: macOS Catalina 10.15.7
- FastAPI Version: 0.61.2
- Python version: 3.8.2
Issue Analytics
- State:
- Created 3 years ago
- Reactions:16
- Comments:12
@Nemesis7, I set the
arbitrary_types_allowed
option globally as follows, which worked for me. I haven’t tried @pmsoltani’s approach though.But eventually, I decided to implement the whole Rest API’s data model using
ModelBase
. So when I generate the responses, I convertArbitraryClass
instances (returned by the underlying Python core APIs) intoSomeModelBaseClass
instances supported by pydantic. I believe this is cleanest approach: separate the core data model from the Rest data model, and convert from one to another.Setting
arbitrary_types_allowed
in theBaseConfig
works, thanks @ylassoued !