I have a decorator which adds a user onto the flask global context g:
class User:
    def __init__(self, user_data) -> None:
        self.username: str = user_data["username"]
        self.email: str = user_data["email"]
def login_required(f):
    @wraps(f)
    def wrap(*args, **kwargs):
        user_data = get_user_data()
        user = User(user_data)
        g.user = User(user_data)
        return f(*args, **kwargs)
    return wrap
I want the type (User) of g.user to be known when I access g.user in the controllers. How can I achieve this? (I am using pyright)
I had a similar issue described in Typechecking dynamically added attributes. One solution is to add the custom type hints using typing.TYPE_CHECKING:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from flask.ctx import _AppCtxGlobals
    class MyGlobals(_AppCtxGlobals):
        user: 'User'
    g = MyGlobals()
else:
    from flask import g
Now e.g.
reveal_type(g.user)
will emit
note: Revealed type is 'myapp.User'
If the custom types should be reused in multiple modules, you can introduce a partial stub for flask. The location of the stubs is dependent on the type checker, e.g. mypy reads custom stubs from the MYPY_PATH environment variable, pyright looks for a typings directory in the project root dir etc. Example of a partial stub:
# _typeshed/flask/__init__.pyi
from typing import Any
from flask.ctx import _AppCtxGlobals
from models import User
def __getattr__(name: str) -> Any: ...  # incomplete
class MyGlobals(_AppCtxGlobals):
    user: User
    def __getattr__(self, name: str) -> Any: ...  # incomplete
g: MyGlobals
                        You could proxy the g object. Consider the following implementation:
import flask
class User:
    ...
class _g:
    user: User
    # Add type hints for other attributes
    # ...
    def __getattr__(self, key):
        return getattr(flask.g, key)
g = _g()
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With