1
1
"""Helpers for WebOb requests and responses."""
2
+ from __future__ import annotations
3
+
2
4
from collections .abc import MutableMapping
3
5
from itertools import chain , repeat
4
6
from lazy import lazy
7
+ import typing as t
5
8
6
9
import webob
7
- from django .http import HttpResponse
8
- from webob .multidict import MultiDict , NestedMultiDict , NoVars
10
+ import webob .multidict
11
+ import django .core .files .uploadedfile
12
+ import django .http
13
+ import django .utils .datastructures
9
14
10
15
11
- def webob_to_django_response (webob_response ) :
16
+ def webob_to_django_response (webob_response : webob . Response ) -> django . http . HttpResponse :
12
17
"""Returns a django response to the `webob_response`"""
13
- django_response = HttpResponse (
18
+ django_response = django . http . HttpResponse (
14
19
webob_response .app_iter ,
15
20
content_type = webob_response .content_type ,
16
21
status = webob_response .status_code ,
@@ -28,11 +33,11 @@ class HeaderDict(MutableMapping):
28
33
"""
29
34
UNPREFIXED_HEADERS = ('CONTENT_TYPE' , 'CONTENT_LENGTH' )
30
35
31
- def __init__ (self , meta ):
36
+ def __init__ (self , meta : dict [ str , str ] ):
32
37
super ().__init__ ()
33
38
self ._meta = meta
34
39
35
- def _meta_name (self , name ) :
40
+ def _meta_name (self , name : str ) -> str :
36
41
"""
37
42
Translate HTTP header names to the format used by Django request objects.
38
43
@@ -43,41 +48,43 @@ def _meta_name(self, name):
43
48
name = 'HTTP_' + name
44
49
return name
45
50
46
- def _un_meta_name (self , name ) :
51
+ def _un_meta_name (self , name : str ) -> str :
47
52
"""
48
53
Reverse of _meta_name
49
54
"""
50
55
if name .startswith ('HTTP_' ):
51
56
name = name [5 :]
52
57
return name .replace ('_' , '-' ).title ()
53
58
54
- def __getitem__ (self , name ):
59
+ def __getitem__ (self , name : str ):
55
60
return self ._meta [self ._meta_name (name )]
56
61
57
- def __setitem__ (self , name , value ):
62
+ def __setitem__ (self , name : str , value : str ):
58
63
self ._meta [self ._meta_name (name )] = value
59
64
60
- def __delitem__ (self , name ):
65
+ def __delitem__ (self , name : str ):
61
66
del self ._meta [self ._meta_name (name )]
62
67
63
- def __iter__ (self ):
68
+ def __iter__ (self ) -> t . Iterator [ str ] :
64
69
for key in self ._meta :
65
70
if key in self .UNPREFIXED_HEADERS or key .startswith ('HTTP_' ):
66
71
yield self ._un_meta_name (key )
67
72
68
- def __len__ (self ):
73
+ def __len__ (self ) -> int :
69
74
return len (list (self ))
70
75
71
76
72
- def querydict_to_multidict (query_dict , wrap = None ):
77
+ def querydict_to_multidict (
78
+ query_dict : django .utils .datastructures .MultiValueDict ,
79
+ wrap : t .Callable [[t .Any ], t .Any ] | None = None
80
+ ) -> webob .multidict .MultiDict :
73
81
"""
74
82
Returns a new `webob.MultiDict` from a `django.http.QueryDict`.
75
83
76
84
If `wrap` is provided, it's used to wrap the values.
77
-
78
85
"""
79
86
wrap = wrap or (lambda val : val )
80
- return MultiDict (chain .from_iterable (
87
+ return webob . multidict . MultiDict (chain .from_iterable (
81
88
zip (repeat (key ), (wrap (v ) for v in vals ))
82
89
for key , vals in query_dict .lists ()
83
90
))
@@ -87,32 +94,35 @@ class DjangoUploadedFile:
87
94
"""
88
95
Looks like a cgi.FieldStorage, but wraps a Django UploadedFile.
89
96
"""
90
- def __init__ (self , uploaded ):
97
+ def __init__ (self , uploaded : django . core . files . uploadedfile . UploadedFile ):
91
98
# FieldStorage needs a file attribute.
92
- self .file = uploaded
99
+ self .file : t . Any = uploaded
93
100
94
101
@property
95
- def name (self ):
102
+ def name (self ) -> str :
96
103
"""The name of the input element used to upload the file."""
97
104
return self .file .field_name
98
105
99
106
@property
100
- def filename (self ):
107
+ def filename (self ) -> str :
101
108
"""The name of the uploaded file."""
102
109
return self .file .name
103
110
104
111
105
112
class DjangoWebobRequest (webob .Request ):
106
113
"""
107
- An implementation of the webob request api, backed
108
- by a django request
114
+ An implementation of the webob request api, backed by a django request
109
115
"""
110
- def __init__ (self , request ):
116
+ # Note:
117
+ # This implementation is close enough to webob.Request for it to work OK, but it does
118
+ # make mypy complain that the type signatures are different, hence the 'type: ignore' pragmas.
119
+
120
+ def __init__ (self , request : django .http .HttpRequest ):
111
121
self ._request = request
112
122
super ().__init__ (self .environ )
113
123
114
124
@lazy
115
- def environ (self ):
125
+ def environ (self ) -> dict [ str , str ]: # type: ignore[override]
116
126
"""
117
127
Add path_info to the request's META dictionary.
118
128
"""
@@ -123,40 +133,40 @@ def environ(self):
123
133
return environ
124
134
125
135
@property
126
- def GET (self ):
136
+ def GET (self ) -> webob . multidict . MultiDict : # type: ignore[override]
127
137
"""
128
138
Returns a new `webob.MultiDict` from the request's GET query.
129
139
"""
130
140
return querydict_to_multidict (self ._request .GET )
131
141
132
142
@property
133
- def POST (self ):
143
+ def POST (self ) -> webob . multidict . MultiDict | webob . multidict . NoVars : # type: ignore[override]
134
144
if self .method not in ('POST' , 'PUT' , 'PATCH' ):
135
- return NoVars ('Not a form request' )
145
+ return webob . multidict . NoVars ('Not a form request' )
136
146
137
147
# Webob puts uploaded files into the POST dictionary, so here we
138
148
# combine the Django POST data and uploaded FILES data into a single
139
149
# dict.
140
- return NestedMultiDict (
150
+ return webob . multidict . NestedMultiDict (
141
151
querydict_to_multidict (self ._request .POST ),
142
152
querydict_to_multidict (self ._request .FILES , wrap = DjangoUploadedFile ),
143
153
)
144
154
145
155
@property
146
- def body (self ):
156
+ def body (self ) -> bytes : # type: ignore[override]
147
157
"""
148
158
Return the content of the request body.
149
159
"""
150
160
return self ._request .body
151
161
152
- @property
153
- def body_file (self ):
162
+ @property # type: ignore[misc]
163
+ def body_file (self ) -> django . http . HttpRequest : # type: ignore[override]
154
164
"""
155
165
Input stream of the request
156
166
"""
157
167
return self ._request
158
168
159
169
160
- def django_to_webob_request (django_request ) :
170
+ def django_to_webob_request (django_request : django . http . HttpRequest ) -> webob . Request :
161
171
"""Returns a WebOb request to the `django_request`"""
162
172
return DjangoWebobRequest (django_request )
0 commit comments