question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Response model doesn't allow models with allow_arbitrary_types

See original GitHub issue

First 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:open
  • Created 3 years ago
  • Reactions:16
  • Comments:12

github_iconTop GitHub Comments

6reactions
ylassouedcommented, Jun 22, 2021

@Nemesis7, I set the arbitrary_types_allowed option globally as follows, which worked for me. I haven’t tried @pmsoltani’s approach though.

# Assuming this is the module where you declare your data model...
from pydantic import BaseConfig

BaseConfig.arbitrary_types_allowed = True

But eventually, I decided to implement the whole Rest API’s data model using ModelBase. So when I generate the responses, I convert ArbitraryClass instances (returned by the underlying Python core APIs) into SomeModelBaseClass 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.

3reactions
Nemesis7commented, Jun 23, 2021

Setting arbitrary_types_allowed in the BaseConfig works, thanks @ylassoued !

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to include non-pydantic classes in fastapi responses?
Tell pydantic that using arbitrary classes is fine. It will try to jsonify them using vars() , so only straight forward data containers...
Read more >
Extra Models - FastAPI
You can also declare a response using a plain arbitrary dict , declaring just the type of the keys and values, without using...
Read more >
Mapping arbitrary data with DynamoDB using the AWS SDK ...
NET types (see Supported data types), you can use types in your application for which there is no direct mapping to the Amazon...
Read more >
API — Flask-RESTX 1.0.4.dev documentation - Read the Docs
Allow to lazy register the API on a Flask application: ... If default_mediatype is None, a 406 Not Acceptable response will be sent...
Read more >
2 - Requests and responses - Django REST framework
REST framework also introduces a Response object, which is a type of ... behaviour such as returning 405 Method Not Allowed responses when...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found