Allow to pass any object as lifespan state
This is a breaking change.
This is here first for discussion.
It breaks probably one of the most popular patterns: request.state.DEPNAME
For example, a database session middleware may set current session like that
class DbMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
scope["state"]['dbsession'] = "database_connection"
await self.app(scope, receive, send)
and request it in an endpoint like
async def view(request: Request[LifespanState]):
return JSONResponse(
{
"request_state": request.state.dbsession,
}
)
Now it throws AttributeError: 'State' object has no attribute 'dbsession'.
IMO, this breaks too many third-party integrations.
What if we bind LifespanStateT to State to require all child states to inherit from State? This way we can maintain b/w compatibility and users can provide types?
_LifespanStateT = TypeVar("_LifespanStateT", default=State, bind=State)
class MyState(State):
key: str
dbsession: Any
class DbMiddleware:
async def __call__(self, scope, receive, send):
scope["state"]['dbsession'] = "database_connection"
await self.app(scope, receive, send)
async def lifespan_state():
yield MyState(key='value')
async def view(request: Request[MyState]):
print(request.state.dbsession) # works
print(request.state.key) # also works
@alex-oleshkevich Would there be a way to move away from the State class? But yeah, I agree that what you are proposing is better for the ecosystem.
@alex-oleshkevich Would there be a way to move away from the
Stateclass? But yeah, I agree that what you are proposing is better for the ecosystem.
State can be a protocol, but this is not very convenient. In short, we only need a common interface to set/get values from the state.
I've applied your comment, but this doesn't provide the DX that I'm aiming. State is initialized with a dict, which is not type safe.
Due to the limitations of Python's type system, I don't think there will be an elegant way to implement this feature. For now, using TypedDict/dataclass is a good compromise design.
I agree @abersheeran , let me try implementing it focusing on TypedDict.