'Depends' object has no attribute '...' [HELP NEEDED]
See original GitHub issueFirst 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:
- Created 2 years ago
- Comments:10
Top GitHub Comments
@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 theDepends
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). Sincecheck_role
itself isasync
, it will not return immediately, causing an error. So, the tiny detail is to remove theasync
fromcheck_role
, like this:Notice how I transferred the
async
tois_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!
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 theDepends
statements is what is important. Chaining the demo code, the cookiecutter postgres code and my own code together at first I ran into the sameException 'Depends' object has no attribute 'rsplit'
. In hopes that this is helpful to someone else, the relevant snippets looked like:By moving the
Depends(oauth2_scheme)
fromget_current_user()
in myapp/services/user_service.py
tocurrent_user()
in myapp/api/deps.py
and then passing the resulting returned value as passing a normal parameter, it is working.