Open mattmess1221 opened 1 year ago
I would look into it soon
I've explored this and really didn't encounter any errors, have you updated Fastapi to the latest version available? can you share a gist?
It's kinda weird, sometimes it works just fine, but other times it really hates it.
Given this little database manager wrapper class:
class DBManager:
engine: sqlalchemy.ext.asyncio.AsyncEngine
sessionmaker: sqlalchemy.ext.asyncio.async_sessionmaker[sqlalchemy.ext.asyncio.AsyncSession]
@classmethod
def db_init(cls, create_async_engine=sqlalchemy.ext.asyncio.create_async_engine,
async_sessionmaker=sqlalchemy.ext.asyncio.async_sessionmaker):
""" Initialize the manager with it's singleton properties
"""
settings = get_settings() # just returns a Pydantic settings object
cls.engine = create_async_engine(
settings.database_url,
pool_pre_ping=True,
echo=settings.debug,
)
cls.sessionmaker = async_sessionmaker(
bind=cls.engine,
autoflush=False,
future=True,
expire_on_commit=False,
)
@classmethod
def get_sessionmaker(cls) -> sqlalchemy.ext.asyncio.async_sessionmaker[sqlalchemy.ext.asyncio.AsyncSession]:
return cls.sessionmaker
This seems fine:
router = InferringRouter(prefix="/thing", tags=["thing"])
@cbv(router)
class ThingService:
sessionmaker: async_sessionmaker[AsyncSession] = Depends(DBManager.get_sessionmaker)
but this does not:
router = InferringRouter(prefix="/thing", tags=["thing"])
Sessionmaker = Annotated[async_sessionmaker[AsyncSession], Depends(DBManager.get_sessionmaker)]
@cbv(router)
class ThingService:
sessionmaker: Sessionmaker
Just to make sure it works with base FastAPI, I tried this and it works fine:
router = APIRouter(prefix="/thing")
Sessionmaker = Annotated[async_sessionmaker[AsyncSession], Depends(DBManager.get_sessionmaker)]
@wallet_router.get("/{thing_id}")
async def test_route(sessionmaker: Sessionmaker, thing_id: int) -> str:
return f"test: {thing_id}"
The traceback I get when trying the middle one that breaks is:
Traceback (most recent call last):
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/main.py", line 404, in main
run(
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/main.py", line 569, in run
server.run()
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/server.py", line 60, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/server.py", line 67, in serve
config.load()
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/config.py", line 477, in load
self.loaded_app = import_from_string(self.app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/Users/jpg/repos/test-proj/service.py", line 82, in <module>
@cbv(wallet_router)
^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi_restful/cbv.py", line 30, in decorator
return _cbv(router, cls, *urls)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi_restful/cbv.py", line 41, in _cbv
_register_endpoints(router, cls, *urls)
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi_restful/cbv.py", line 117, in _register_endpoints
router.include_router(cbv_router)
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/routing.py", line 806, in include_router
self.add_api_route(
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/routing.py", line 608, in add_api_route
route = route_class(
^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/routing.py", line 454, in __init__
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 310, in get_dependant
sub_dependant = get_param_sub_dependant(
^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 123, in get_param_sub_dependant
return get_sub_dependant(
^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 159, in get_sub_dependant
sub_dependant = get_dependant(
^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 303, in get_dependant
type_annotation, depends, param_field = analyze_param(
^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 462, in analyze_param
field = create_response_field(
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpg/Library/Caches/pypoetry/virtualenvs/test-proj-RbGL24dd-py3.11/lib/python3.11/site-packages/fastapi/utils.py", line 92, in create_response_field
return ModelField(
^^^^^^^^^^^
File "pydantic/fields.py", line 436, in pydantic.fields.ModelField.__init__
File "pydantic/fields.py", line 552, in pydantic.fields.ModelField.prepare
File "pydantic/fields.py", line 755, in pydantic.fields.ModelField._type_analysis
TypeError: Fields of type "<class 'sqlalchemy.ext.asyncio.session.async_sessionmaker'>" are not supported.
This doesn't work either, but it doesn't cause a traceback:
class GlobalSettings(BaseSettings):
debug: bool
def get_settings() -> BaseSettings:
return GlobalSettings()
Settings = Annotated[GlobalSettings, Depends(get_settings)]
router = InferringRouter(prefix="/thing", tags=["thing"])
@cbv(router)
class ThingService:
settings: Settings
Instead it weirdly changes all of the methods registered in ThingService to expect a GlobalSettings instance as it's input parameter. The generated OpenAPI documentation is very weird suddenly.
At first I thought it worked fine but it does not.
I'm facing this, trying to simplify some type signatures using Annotated
.
Any news?
The new way to declare a dependency in FastAPI 0.95 is to use
arg: Annotated[type, Depends(func)] = default
. Using this on a cbv decorated class attribute does not behave as expected. The cbv seems to treat the attribute as if it wasn't annotated at all.Example: