Coverage for src/fastoai/dependencies.py: 62%

1 from functools import lru_cache

2 from typing import Annotated

3

4 from fastapi import Depends, HTTPException, status

5 from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

6 from openai import AsyncOpenAI

7 from sqlalchemy.ext.asyncio import create_async_engine

8 from sqlmodel import SQLModel

9 from sqlmodel.ext.asyncio.session import AsyncSession

10

11 from .models import APIKey, User

12 from .settings import Settings, get_settings

13

14 SettingsDependency = Annotated[Settings, Depends(get_settings)]

15

16

17 async def get_session(settings: SettingsDependency):

18 """Get session."""

19 engine = create_async_engine(settings.database_url)

20 async with engine.begin() as conn:

21 await conn.run_sync(SQLModel.metadata.create_all)

22 async with AsyncSession(engine) as session:

23 yield session

24

25

26 SessionDependency = Annotated[AsyncSession, Depends(get_session)]

27

28

29@lru_cache

30 def get_openai(settings: SettingsDependency):

31 """Get OpenAI client."""

32 return AsyncOpenAI(**settings.openai.model_dump())

33

34

35 OpenAIDependency = Annotated[AsyncOpenAI, Depends(get_openai)]

36

37 security = HTTPBearer()

38

39

40 async def get_user(

41 *,

42 credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)],

43 session: SessionDependency,

44) -> User:

45 """Get the current user."""

46 api_key = await session.get(APIKey, credentials.credentials)

47 if api_key is None:

48 raise HTTPException(

49 status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key"

50 )

51 await session.refresh(api_key, ["user"])

52 if not api_key.user.is_active:

53 raise HTTPException(

54 status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user"

55 )

56 return api_key.user

57

58

59 UserDependency = Annotated[User, Depends(get_user)]