1

I have a function in my app which look like:

def get_firebase_user(session: Session, firebase_user: FirebaseUser) -> users.User | None:
    if some_condition:
        return user_instance 

And I have an utility module with basic functionality, so I decided to put function which throws an exception if model is None in this module. It's look like:

def throw_none_exception(inst, detail: str) -> None:
    """Throm exception with given detail if instance is None."""
    if inst is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=detail,
        )

And whole problem in my linter. If we declaring models with first function and raising errors with second. In this way of working linter can't detect how models changes so in code like:

user = get_firebase_user(session, firebase_user)
throw_none_exception(user, "Such user doesn't exists")
if user.id == some_random_id:
    return 'You are the luckiest person i\'ve ever seen'

It returns me error

Item "None" of "Optional[User]" has no attribute "id"

Which is pretty annoying:) How can I re declare type of this model? Or how manage to do it with another way so linter won't give an error?

2 Answers 2

2

Here's a way to define throw_none_exception in such a way that it transforms inst to a non-Optional type:

from typing import TypeVar, Optional

_T = TypeVar("_T")

def throw_none_exception(inst: Optional[_T], detail: str) -> _T:
    """Throw exception with given detail if instance is None."""
    if inst is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=detail,
        )
    return inst

Now if you do:

user = throw_none_exception(
    get_firebase_user(session, firebase_user),
    "Such user doesn't exists"
)

user will have a non-Optional type and you should be able to access user.id without typechecking errors.

Sign up to request clarification or add additional context in comments.

Comments

0

The issue here is that the linter can't figure out that throw_none_exception only returns if user isn't None. You just need to drop the linter a hint. assert is the standard way of doing this.

throw_none_exception(user, "Such user doesn't exist")
assert user is not None
if user.id == some_random_id:
    ...

Even if you run Python with the -o flag, all assert statements will be compiled out but your linter will still be satisfied since it's relying upon statically available information.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.