1212import os
1313import sys
1414import time
15+ import typing as t
1516from datetime import datetime
17+ from typing import TYPE_CHECKING , Any , ClassVar , Optional , Protocol , Type
1618from uuid import uuid4
1719
1820import pytz
21+ from flask .wrappers import Response
1922
2023try :
2124 import cPickle as pickle
2225except ImportError :
2326 import pickle # type: ignore[no-redef]
2427
28+ if TYPE_CHECKING :
29+ from redis import Redis
30+ from flask import Flask
31+ from flask .wrappers import Request
32+
2533from flask .sessions import SessionInterface as FlaskSessionInterface
2634from flask .sessions import SessionMixin
2735from itsdangerous import BadSignature , Signer , want_bytes
@@ -38,11 +46,23 @@ def total_seconds(td):
3846 return td .days * 60 * 60 * 24 + td .seconds
3947
4048
49+ class SessionSerializer (Protocol ):
50+ def dumps (self , session_content : Any ) -> bytes :
51+ """serialize a session object"""
52+ ...
53+
54+ def loads (self , serialized_session : bytes ) -> Any :
55+ """deserialize a session object"""
56+ ...
57+
58+
4159class ServerSideSession (CallbackDict , SessionMixin ):
4260 """Baseclass for server-side based sessions."""
4361
44- def __init__ (self , initial = None , sid = None , permanent = None ):
45- def on_update (self ):
62+ def __init__ (
63+ self , initial = None , sid : Optional [str ] = None , permanent : Optional [bool ] = None
64+ ):
65+ def on_update (self ) -> None :
4666 self .modified = True
4767
4868 CallbackDict .__init__ (self , initial , on_update )
@@ -89,16 +109,25 @@ class DynamoDBSession(ServerSideSession):
89109
90110
91111class PeeweeSession (ServerSideSession ):
92- def __init__ (self , initial = None , sid = None , permanent = None , ip = None ):
112+ def __init__ (
113+ self ,
114+ initial = None ,
115+ sid : Optional [str ] = None ,
116+ permanent : Optional [bool ] = None ,
117+ ip = None ,
118+ ):
93119 super ().__init__ (initial , sid , permanent )
94120 self .ip = ip
95121
96122
97123class SessionInterface (FlaskSessionInterface ):
98- def _generate_sid (self ):
124+ serializer : ClassVar [SessionSerializer ]
125+ session_class : ClassVar [Type [ServerSideSession ]]
126+
127+ def _generate_sid (self ) -> str :
99128 return str (uuid4 ())
100129
101- def _get_signer (self , app ) :
130+ def _get_signer (self , app : Flask ) -> Optional [ Signer ] :
102131 if not app .secret_key :
103132 return None
104133 return Signer (app .secret_key , salt = "flask-session" , key_derivation = "hmac" )
@@ -107,7 +136,7 @@ def _get_signer(self, app):
107136class NullSessionInterface (SessionInterface ):
108137 """Used to open a :class:`flask.sessions.NullSession` instance."""
109138
110- def open_session (self , app , request ) :
139+ def open_session (self , app : Flask , request : Request ) -> None :
111140 return None
112141
113142
@@ -123,10 +152,16 @@ class RedisSessionInterface(SessionInterface):
123152 :param permanent: Whether to use permanent session or not.
124153 """
125154
126- serializer = pickle
127- session_class = RedisSession
155+ serializer : ClassVar [ SessionSerializer ] = t . cast ( SessionSerializer , pickle )
156+ session_class : ClassVar [ Type [ RedisSession ]] = RedisSession
128157
129- def __init__ (self , redis , key_prefix , use_signer = False , permanent = True ):
158+ def __init__ (
159+ self ,
160+ redis : Optional [Redis ],
161+ key_prefix : str ,
162+ use_signer : bool = False ,
163+ permanent : bool = True ,
164+ ):
130165 if redis is None :
131166 from redis import Redis
132167
@@ -137,7 +172,7 @@ def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
137172 self .permanent = permanent
138173 self .has_same_site_capability = hasattr (self , "get_cookie_samesite" )
139174
140- def open_session (self , app , request ) :
175+ def open_session (self , app : Flask , request : Request ) -> Optional [ SessionMixin ] :
141176 sid = request .cookies .get (app .config ["SESSION_COOKIE_NAME" ])
142177 if not sid :
143178 sid = self ._generate_sid ()
@@ -164,7 +199,9 @@ def open_session(self, app, request):
164199 return self .session_class (sid = sid , permanent = self .permanent )
165200 return self .session_class (sid = sid , permanent = self .permanent )
166201
167- def save_session (self , app , session , response ):
202+ def save_session (
203+ self , app : Flask , session : SessionMixin , response : Response
204+ ) -> None :
168205 if not self .should_set_cookie (app , session ):
169206 return
170207 domain = self .get_cookie_domain (app )
@@ -202,7 +239,9 @@ def save_session(self, app, session, response):
202239 )
203240
204241 if self .use_signer :
205- session_id = self ._get_signer (app ).sign (want_bytes (session .sid ))
242+ session_id = t .cast (Signer , self ._get_signer (app )).sign (
243+ want_bytes (session .sid )
244+ )
206245 else :
207246 session_id = session .sid
208247 response .set_cookie (
0 commit comments