1
1
from functools import wraps
2
2
from http import HTTPStatus
3
3
from json import dumps as json_encode
4
+ from typing import Any , Callable
4
5
5
6
from django .core .exceptions import ImproperlyConfigured
6
7
from django .http import HttpRequest , HttpResponse
7
8
from django .template .loader import render_to_string
8
9
9
- from .helpers import deep_transform_callables , validate_type
10
+ from .helpers import deep_transform_callables
10
11
from .prop_classes import DeferredProp , IgnoreOnFirstLoadProp , MergeableProp
11
12
from .settings import settings
12
13
15
16
# a mock module
16
17
import requests
17
18
except ImportError :
18
- requests = None
19
+ requests = None # type: ignore[assignment]
19
20
20
21
21
22
INERTIA_REQUEST_ENCRYPT_HISTORY = "_inertia_encrypt_history"
26
27
27
28
28
29
class InertiaRequest (HttpRequest ):
29
- def __init__ (self , request ):
30
+ def __init__ (self , request : HttpRequest ):
30
31
super ().__init__ ()
31
32
self .__dict__ .update (request .__dict__ )
32
33
33
34
@property
34
- def inertia (self ):
35
+ def inertia (self ) -> dict [ str , Any ] :
35
36
inertia_attr = self .__dict__ .get ("inertia" )
36
37
return (
37
38
inertia_attr .all () if inertia_attr and hasattr (inertia_attr , "all" ) else {}
38
39
)
39
40
40
- def is_a_partial_render (self , component ) :
41
+ def is_a_partial_render (self , component : str ) -> bool :
41
42
return (
42
43
"X-Inertia-Partial-Data" in self .headers
43
44
and self .headers .get ("X-Inertia-Partial-Component" , "" ) == component
44
45
)
45
46
46
- def partial_keys (self ):
47
+ def partial_keys (self ) -> list [ str ] :
47
48
return self .headers .get ("X-Inertia-Partial-Data" , "" ).split ("," )
48
49
49
- def reset_keys (self ):
50
+ def reset_keys (self ) -> list [ str ] :
50
51
return self .headers .get ("X-Inertia-Reset" , "" ).split ("," )
51
52
52
- def is_inertia (self ):
53
+ def is_inertia (self ) -> bool :
53
54
return "X-Inertia" in self .headers
54
55
55
- def should_encrypt_history (self ):
56
- return validate_type (
57
- getattr (
58
- self ,
59
- INERTIA_REQUEST_ENCRYPT_HISTORY ,
60
- settings .INERTIA_ENCRYPT_HISTORY ,
61
- ),
62
- expected_type = bool ,
63
- name = "encrypt_history" ,
56
+ def should_encrypt_history (self ) -> bool :
57
+ should_encrypt = getattr (
58
+ self , INERTIA_REQUEST_ENCRYPT_HISTORY , settings .INERTIA_ENCRYPT_HISTORY
64
59
)
60
+ if not isinstance (should_encrypt , bool ):
61
+ raise TypeError (
62
+ f"Expected bool for encrypt_history, got { type (should_encrypt ).__name__ } "
63
+ )
64
+ return should_encrypt
65
65
66
66
67
67
class BaseInertiaResponseMixin :
68
- def page_data (self ):
69
- clear_history = validate_type (
70
- self .request .session .pop (INERTIA_SESSION_CLEAR_HISTORY , False ),
71
- expected_type = bool ,
72
- name = "clear_history" ,
73
- )
68
+ request : InertiaRequest
69
+ component : str
70
+ props : dict [str , Any ]
71
+ template_data : dict [str , Any ]
72
+
73
+ def page_data (self ) -> dict [str , Any ]:
74
+ clear_history = self .request .session .pop (INERTIA_SESSION_CLEAR_HISTORY , False )
75
+ if not isinstance (clear_history , bool ):
76
+ raise TypeError (
77
+ f"Expected bool for clear_history, got { type (clear_history ).__name__ } "
78
+ )
74
79
75
80
_page = {
76
81
"component" : self .component ,
@@ -91,7 +96,7 @@ def page_data(self):
91
96
92
97
return _page
93
98
94
- def build_props (self ):
99
+ def build_props (self ) -> Any :
95
100
_props = {
96
101
** (self .request .inertia ),
97
102
** self .props ,
@@ -107,18 +112,18 @@ def build_props(self):
107
112
108
113
return deep_transform_callables (_props )
109
114
110
- def build_deferred_props (self ):
115
+ def build_deferred_props (self ) -> dict [ str , Any ] | None :
111
116
if self .request .is_a_partial_render (self .component ):
112
117
return None
113
118
114
- _deferred_props = {}
119
+ _deferred_props : dict [ str , Any ] = {}
115
120
for key , prop in self .props .items ():
116
121
if isinstance (prop , DeferredProp ):
117
122
_deferred_props .setdefault (prop .group , []).append (key )
118
123
119
124
return _deferred_props
120
125
121
- def build_merge_props (self ):
126
+ def build_merge_props (self ) -> list [ str ] :
122
127
return [
123
128
key
124
129
for key , prop in self .props .items ()
@@ -129,7 +134,7 @@ def build_merge_props(self):
129
134
)
130
135
]
131
136
132
- def build_first_load (self , data ) :
137
+ def build_first_load (self , data : Any ) -> str :
133
138
context , template = self .build_first_load_context_and_template (data )
134
139
135
140
try :
@@ -151,7 +156,9 @@ def build_first_load(self, data):
151
156
using = None ,
152
157
)
153
158
154
- def build_first_load_context_and_template (self , data ):
159
+ def build_first_load_context_and_template (
160
+ self , data : Any
161
+ ) -> tuple [dict [str , Any ], str ]:
155
162
if settings .INERTIA_SSR_ENABLED :
156
163
try :
157
164
response = requests .post (
@@ -178,14 +185,14 @@ class InertiaResponse(BaseInertiaResponseMixin, HttpResponse):
178
185
179
186
def __init__ (
180
187
self ,
181
- request ,
182
- component ,
183
- props = None ,
184
- template_data = None ,
185
- headers = None ,
186
- * args ,
187
- ** kwargs ,
188
- ):
188
+ request : HttpRequest ,
189
+ component : str ,
190
+ props : dict [ str , Any ] | None = None ,
191
+ template_data : dict [ str , Any ] | None = None ,
192
+ headers : dict [ str , Any ] | None = None ,
193
+ * args : Any ,
194
+ ** kwargs : Any ,
195
+ ) -> None :
189
196
self .request = InertiaRequest (request )
190
197
self .component = component
191
198
self .props = props or {}
@@ -208,19 +215,30 @@ def __init__(
208
215
else :
209
216
content = self .build_first_load (data )
210
217
211
- super ().__init__ (
212
- * args ,
213
- content = content ,
214
- headers = _headers ,
215
- ** kwargs ,
216
- )
218
+ if args :
219
+ super ().__init__ (
220
+ * args ,
221
+ headers = _headers ,
222
+ ** kwargs ,
223
+ )
224
+ else :
225
+ super ().__init__ (
226
+ content = content ,
227
+ headers = _headers ,
228
+ ** kwargs ,
229
+ )
217
230
218
231
219
- def render (request , component , props = None , template_data = None ):
232
+ def render (
233
+ request : HttpRequest ,
234
+ component : str ,
235
+ props : dict [str , Any ] | None = None ,
236
+ template_data : dict [str , Any ] | None = None ,
237
+ ) -> InertiaResponse :
220
238
return InertiaResponse (request , component , props or {}, template_data or {})
221
239
222
240
223
- def location (location ) :
241
+ def location (location : str ) -> HttpResponse :
224
242
return HttpResponse (
225
243
"" ,
226
244
status = HTTPStatus .CONFLICT ,
@@ -230,18 +248,27 @@ def location(location):
230
248
)
231
249
232
250
233
- def encrypt_history (request , value = True ):
251
+ def encrypt_history (request : HttpRequest , value : bool = True ) -> None :
234
252
setattr (request , INERTIA_REQUEST_ENCRYPT_HISTORY , value )
235
253
236
254
237
- def clear_history (request ) :
255
+ def clear_history (request : HttpRequest ) -> None :
238
256
request .session [INERTIA_SESSION_CLEAR_HISTORY ] = True
239
257
240
258
241
- def inertia (component ):
242
- def decorator (func ):
259
+ def inertia (
260
+ component : str ,
261
+ ) -> Callable [
262
+ [Callable [..., HttpResponse | InertiaResponse | dict [str , Any ]]],
263
+ Callable [..., HttpResponse ],
264
+ ]:
265
+ def decorator (
266
+ func : Callable [..., HttpResponse | InertiaResponse | dict [str , Any ]],
267
+ ) -> Callable [..., HttpResponse ]:
243
268
@wraps (func )
244
- def process_inertia_response (request , * args , ** kwargs ):
269
+ def process_inertia_response (
270
+ request : HttpRequest , * args : Any , ** kwargs : Any
271
+ ) -> HttpResponse :
245
272
props = func (request , * args , ** kwargs )
246
273
247
274
# if a response is returned, return it
0 commit comments