Lancetnik / FastDepends

FastDepends - FastAPI Dependency Injection system extracted from FastAPI and cleared of all HTTP logic. Async and sync modes are both supported.
https://lancetnik.github.io/FastDepends/
MIT License
294 stars 11 forks source link

ForwardRef annotations and non-global context breaks models resolution #26

Closed Nnonexistent closed 10 months ago

Nnonexistent commented 10 months ago

If both of the following conditions are met, the PydanticUserError exception is raised during function call:

  1. ForwardRef annotations for arguments (e.g. with from __future__ import annotations or, even, just with string annotations)
  2. Usage of non-global context. For example in attempt to dynamically create inject in wrapped function.

My particular case was from usage of faststream, where I needed dynamically attach broker to different handlers. It all works well, but I have to be careful not to switch forward refs by accident.

Reproduction:

from __future__ import annotations  # all is working if you comment this line

import asyncio
from pydantic import BaseModel

from fast_depends import inject

def container_function():
    class Model(BaseModel):
        num: int

    @inject
    async def main(a: Model):
        pass

    return main

main = container_function()
asyncio.run(main({"num": 1}))

PS. Nice libraries, keep up great work!

Lancetnik commented 10 months ago

@Nnonexistent great job! I found not only FastDepends, but FastAPI bug too 😃 I'll take a look, what I can do with it

FastAPI in this case hase the same error

from __future__ import annotations

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel

def main():
    app = FastAPI()

    class M(BaseModel):
        m: str

    @app.post("/")
    async def handler(m: M):
        print(m)

    with TestClient(app) as client:
        r = client.post("/", json={"m": "Hi!"})
        print(r.json())

main()
pydantic.errors.PydanticUndefinedAnnotation: name 'M' is not defined