question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

'Depends' object has no attribute '...' [HELP NEEDED]

See original GitHub issue

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

credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"},
)

def get_user(username: str):
    user = User.get_by_username(username) # CHANGE
    if user:
        return user

async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = TokenData(username=username)
    except JWTError:
        raise credentials_exception
    user = get_user(username=token_data.username) # CHANGE
    if user is None:
        raise credentials_exception
    return user

async def check_role(role: str):
    current_user = await get_current_user()
    print(f"[check_role] current_user: {current_user}")
    roles = [role.name for role in current_user.roles]
    return role in roles

async def check_admin():
    if await check_role('admin'):
        return True
    else:
        raise credentials_exception

Description

I’m trying to use security dependencies throughout my API, in order to make sure that endpoints are only available to the appropriate roles or privileges. Please note that in the above example, I’m defining a wrapper called check_admin because Depends won’t allow me to pass the parameter 'admin' directly to check_role (what a shame!).

I’m using the example from https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ with very small adjustments, such as getting the user from a SQLAlchemy call: User.get_by_username(username). I also pulled the credentials_exception out to the global scope, in order to use it from different places.

I’ve been moving away from Depends, because it’s working in a rather unexpected way: instead of calling whatever dependency and returning its result, it’s returning a Depends object, which I don’t know what to do with.

For instance, I started with:

async def check_role(role: str, current_user: UserSchema = Depends(get_current_user)):
    roles = [role.name for role in current_user.roles]
    return role in roles

but I got:

AttributeError: 'Depends' object has no attribute 'roles'

Every time I convert what used to be a dependency into an explicit call, such as:

async def check_role(role: str):
    current_user = await get_current_user()
    roles = [role.name for role in current_user.roles]
    return role in roles

all I achieve is to propagate the Depends exception to the next function, in this case:

AttributeError: 'Depends' object has no attribute 'rsplit'

because get_current_user got the token Depends(OAuth2PasswordBearer) (instead of an actual token) and then, in the line:

payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])

it raises the above exception.

From the docs — Dependencies - First Steps > Simple and Powerful —, I was under the impression that I could use any level of dependencies, and that these were precisely designed to simplify the code, instead of mixing everything in the ‘man finction’, working a bit like decorators:

Questions

  • am I messing up things with async?
  • should I only use Depends on endpoint functions?
  • should I update any version (FastAPI, Python itself)?

This is blocking my entire API so far. Googling this leads always to the very documentation whose examples I’m unsuccessfully replicating. My only option has been to leave it totally insecure. I work in a highly regulated market. I need help.

Operating System

Windows

Operating System Details

No response

FastAPI Version

0.66.0

Python Version

3.9.0

Additional Context

No response

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:10

github_iconTop GitHub Comments

4reactions
ricardo-reis-1970commented, Aug 18, 2021

@dionisnote

Gosh! Get out of my head! Or don’t.

It’s just that I was precisely considering currying or some other kind of higher order, and you come and show me just that! I feel like I must help someone now… or as soon as I know enough.

I am considering in the end just going with the Security solution and Scopes, but still I’d like to see this all through, out of sheer stubbornness. I kind of suspect that that my whole issue lies in the fact that one probably cannot interrupt the Depends chain. If this is the case, this is yet another pearl missing from the documentation necklace. Your solution actually keeps it.

Yes, but does it work?

Yes… almost!

In fact, when you do Depends(check_role("admin")), you’re not passing it a function, but rather a promise (if a bit of JavaScript speak is allowed here). Since check_role itself is async, it will not return immediately, causing an error. So, the tiny detail is to remove the async from check_role, like this:

def check_role(role: str):
    async def is_users_role(current_user = Depends(get_current_user)):
        print(f"[check_role] current_user: {current_user}")
        roles = [role.name for role in current_user.roles]
        return role in roles
    return is_users_role

Notice how I transferred the async to is_users_role, just for fun and good measure, as it works fine without. The rule here is just not having it in the higher order function, as that one is not part of the mechanism, but rather part of the definition of said mechanism.

I hope this helps you as much as you helped me.

Other two interesting places of my head you seem to be in touch with are the fact that I much favour Functional Programming and the fact that I can actually read your Zdravstvuitie!

Cpacibo bolshoi!

2reactions
TheWindyMancommented, Sep 23, 2021

I’ve been fighting the same issue today, adapting the OAuth2 demo code and some of the fullstack-fast-api-postgres code. It seems to me that the chaining of the Depends statements is what is important. Chaining the demo code, the cookiecutter postgres code and my own code together at first I ran into the same Exception 'Depends' object has no attribute 'rsplit'. In hopes that this is helpful to someone else, the relevant snippets looked like:

# app/services/user_service.py

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/user/token")
.....
async def get_current_user(self, token: str = Depends(oauth2_scheme)) -> UserData:
    try:
        payload = jwt.decode(token=token, key=settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise INVALID_CREDENTIALS
    except JWTError:
        raise INVALID_CREDENTIALS
    user = await self.check_user(user=UserCheck(user_name=username))
    if not user.checked:
        raise INVALID_CREDENTIALS
    current_user = await self.get_user(user=UserCheck(user_name=user.user_name))
    return current_user
-----
# app/api/deps.py

async def current_user(session: AsyncSession = Depends(get_session)) -> UserData:
    user_service = UserService(session=session)
    current_user = await user_service.get_current_user()
    return current_user
-----
# app/api/v1/endpoints/user.py

@router.get("/me", response_model=UserData)
async def current_user(current_user: UserData = Depends(current_user)):
    return current_user

By moving the Depends(oauth2_scheme) from get_current_user() in my app/services/user_service.py to current_user() in my app/api/deps.py and then passing the resulting returned value as passing a normal parameter, it is working.

# app/services/user_service.py

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/user/token")
.....
# pass token directly here
async def get_current_user(self, token: str) -> UserData:
    try:
        payload = jwt.decode(token=token, key=settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise INVALID_CREDENTIALS
    except JWTError:
        raise INVALID_CREDENTIALS
    user = await self.check_user(user=UserCheck(user_name=username))
    if not user.checked:
        raise INVALID_CREDENTIALS
    current_user = await self.get_user(user=UserCheck(user_name=user.user_name))
    return current_user
---
# app/api/deps.py
async def current_user(session: AsyncSession = Depends(get_session), token: str = Depends(oauth2_scheme)) -> UserData:
    user_service = UserService(session=session)
    current_user = await user_service.get_current_user(token=token)
    return current_user
Read more comments on GitHub >

github_iconTop Results From Across the Web

AttributeError: 'Depends' object has no attribute 'query' FastAPI
I'm not sure what scenario are you facing, but I think my example can help. Here is my code: DB Function for dependency...
Read more >
tiangolo/fastapi - Gitter
Hi everyone, I am trying to seperate data logic, with requests, so I am trying to run dependency of db to always close...
Read more >
AttributeError: 'str' object has no attribute 'rsplit' - Trac Hacks
it is code bloat for the normal (python >= 2.4) case. I don't plan on maintaining this patch in the future, so please...
Read more >
[Error][FastAPI] Depends object has no attribute - velog
헬퍼 함수 또는 유틸성 함수에서 Depends 를 사용해서 필요한 의존성을 주입하려고 할 때 발생한 에러이다. 구글링해서 알아본 결과 Depends 자체가 ...
Read more >
Classes as Dependencies - FastAPI
from typing import Union from fastapi import Depends, FastAPI app ... So, if you have an object something (that might not be a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found