-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Description
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.
Commit to Help
- I commit to help with one of those options 👆
Example Code
# This needs to be in two files because the nature of the bug involves different globalns
# entries for a decorated function versus the module of the original function.
# If you put the code here into two files (func.py and main.py) in a directory, then the
# bug can be reproduced by running:
# PYTHONPATH=.:$PYTHONPATH python ./main.py
# This should cause an exception `NameError: name 'MyModel' is not defined`
# func.py
from pydantic import BaseModel
def foo(obj: "MyModel") -> "MyModel":
return obj
class MyModel(BaseModel):
x: int
# main.py
import functools, typing
from fastapi import FastAPI
from pydantic import BaseModel
from func import foo
app = FastAPI()
def deco(func):
@functools.wraps(func)
def passthrough(*args, **kwargs):
return func(*args, **kwargs)
return passthrough
decorated = deco(foo)
assert issubclass(typing.get_type_hints(decorated)["obj"], BaseModel)
assert decorated.__annotations__ == foo.__annotations__
assert isinstance(decorated.__annotations__["obj"], str)
method = app.post('/endpoint')(decorated)Description
Using a decorator employing functools.wraps or a similar causes a NameError in fastapi/dependencies/utils.py in get_typed_annotation. The implementation there differs from the implementation in typing, which dereferences the __wrapped__ attribute to find the namespace the original function was defined in. This allows forward references to be handled correctly:
https://github.com/python/cpython/blob/576dd901170af30fc50b0a7f07a388b38fd724a9/Lib/typing.py#L2314-L2315
In the "Example Code" section, my example includes assertions showing that typing.get_type_hints handles this situation correctly. I believe this can be fixed either by using the same implementation as typing uses, or by calling typing.get_type_hints, and only doing special FastAPI-specific logic if that fails.
Operating System
macOS
Operating System Details
I first saw this on Ubuntu Linux with python 3.8, then later reproduced it on my Macbook in python 3.9. The example code was tested on the Mac.
I do not believe the bug is related to operating systems. I think it's a bug in how pure python code handles type annotations.
FastAPI Version
0.78.0
Python Version
Python 3.9.1
Additional Context
This bug is unlikely to come up in most ordinary code, but is likely to come up when using metaprogramming or decorators (especially in programmatically adding endpoints). The context I found it in was in a in-house workflow framework we are building at my job. The framework uses some decorators to alter the type signature of methods, and passes them to FastAPI to expose task endpoints. This leads to the above error.
I definitely understand that such an odd use case is probably not high priority for the maintainers, but I hope you'll be willing to review a PR from me fixing the bug.
Thank you for all your work on FastAPI! It is an amazingly well-made piece of software.