1

I am using a synchronous (SQLite) session in a FastAPI Dependency as shown in the SQLModel Tutorial:

def get_session():
    with Session(engine) as session:
        yield session

However, when a route "depends" on a Dependency and a Security that use get_session, the session is created twice resulting in errors such as:

sqlalchemy.exc.InvalidRequestError: Object '<User at 0x7f218cbf6a00>' is already attached to session '1' (this is '2')

Here is a reduced example (full working example):

from fastapi import Depends, Security
from fastapi.security import SecurityScopes
from sqlmodel import Session, create_engine, select


def get_session():
    with Session(engine) as session:
        yield session


async def get_current_user(
    security_scopes: SecurityScopes,
    token: str = Depends(oauth2_scheme),
    session: Session = Depends(get_session)
):
    # Token read omitted 
    user = session.get(User, token_data.user_uuid)
    if user is None:
        raise credentials_exception
    return user


async def get_current_app_user(
    current_user: User = Security(get_current_user, scopes=["app"])
):
    return current_user


@app.patch("/me", response_model=UserRead)
def update_current_user(
    user: UserUpdate,
    current_user: User = Depends(get_current_app_user).
    session: Session = Depends(get_session),
):
    user_data = user.dict(exclude_unset=True)
    for key, value in user_data.items():
        setattr(current_user, key, value)
    # Session and session from current_user are different ⚠️
    session.add(current_user) 
    session.commit()
    session.refresh(current_user)
    return current_user

How can this be prevented? I would expect a Security to reuse Dependencies as long as use_cache=True.

Edit: This issue appears only if scopes of Security is a non empty list. This is because scopes are part of the cache_key:

self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
DurandA
  • 1,095
  • 1
  • 17
  • 35

0 Answers0