fresco 3.4.0__py3-none-any.whl → 3.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fresco might be problematic. Click here for more details.
- fresco/__init__.py +55 -56
- fresco/core.py +36 -26
- fresco/decorators.py +6 -3
- fresco/defaults.py +1 -0
- fresco/middleware.py +45 -24
- fresco/multidict.py +35 -51
- fresco/options.py +182 -70
- fresco/py.typed +0 -0
- fresco/request.py +155 -34
- fresco/requestcontext.py +3 -0
- fresco/response.py +12 -9
- fresco/routeargs.py +23 -9
- fresco/routing.py +133 -71
- fresco/static.py +1 -1
- fresco/subrequests.py +3 -5
- fresco/tests/test_core.py +4 -4
- fresco/tests/test_multidict.py +2 -2
- fresco/tests/test_options.py +59 -15
- fresco/tests/test_request.py +21 -10
- fresco/tests/test_routing.py +86 -33
- fresco/tests/util/test_http.py +1 -3
- fresco/types.py +28 -2
- fresco/util/cache.py +2 -1
- fresco/util/http.py +66 -46
- fresco/util/urls.py +13 -11
- fresco/util/wsgi.py +15 -14
- {fresco-3.4.0.dist-info → fresco-3.6.0.dist-info}/METADATA +3 -2
- fresco-3.6.0.dist-info/RECORD +58 -0
- {fresco-3.4.0.dist-info → fresco-3.6.0.dist-info}/WHEEL +1 -1
- fresco/typing.py +0 -11
- fresco-3.4.0.dist-info/RECORD +0 -57
- {fresco-3.4.0.dist-info → fresco-3.6.0.dist-info/licenses}/LICENSE.txt +0 -0
- {fresco-3.4.0.dist-info → fresco-3.6.0.dist-info}/top_level.txt +0 -0
fresco/response.py
CHANGED
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
The :class:`Response` class models the response from your application to a
|
|
17
17
|
single request.
|
|
18
18
|
"""
|
|
19
|
+
from collections.abc import Iterable
|
|
19
20
|
from datetime import datetime
|
|
20
21
|
from itertools import chain
|
|
21
22
|
from typing import Callable
|
|
22
23
|
from typing import List
|
|
23
24
|
from typing import Tuple
|
|
24
25
|
from typing import Set
|
|
26
|
+
import typing as t
|
|
25
27
|
import re
|
|
26
28
|
import json as stdlib_json
|
|
27
29
|
|
|
@@ -331,6 +333,7 @@ class Response(object):
|
|
|
331
333
|
"""
|
|
332
334
|
|
|
333
335
|
default_content_type = "text/html; charset=UTF-8"
|
|
336
|
+
content_iterator: Iterable[bytes]
|
|
334
337
|
|
|
335
338
|
def __init__(
|
|
336
339
|
self,
|
|
@@ -386,7 +389,7 @@ class Response(object):
|
|
|
386
389
|
self.status = "200 OK"
|
|
387
390
|
else:
|
|
388
391
|
try:
|
|
389
|
-
self.status = f"{status} {HTTP_STATUS_CODES[status]}"
|
|
392
|
+
self.status = f"{status} {HTTP_STATUS_CODES[status]}" # type: ignore
|
|
390
393
|
except KeyError:
|
|
391
394
|
self.status = str(status)
|
|
392
395
|
|
|
@@ -441,7 +444,7 @@ class Response(object):
|
|
|
441
444
|
else:
|
|
442
445
|
self.content_iterator = encoder(content, self.charset)
|
|
443
446
|
|
|
444
|
-
def __call__(self, environ, start_response, exc_info=None):
|
|
447
|
+
def __call__(self, environ, start_response, exc_info=None) -> Iterable[bytes]:
|
|
445
448
|
"""
|
|
446
449
|
WSGI callable. Calls ``start_response`` with assigned headers and
|
|
447
450
|
returns an iterator over ``content``.
|
|
@@ -449,7 +452,7 @@ class Response(object):
|
|
|
449
452
|
start_response(self.status, self.headers, exc_info)
|
|
450
453
|
result = self.content_iterator
|
|
451
454
|
if self.onclose:
|
|
452
|
-
result = ClosingIterator(result, *self.onclose)
|
|
455
|
+
result = ClosingIterator[bytes](result, *self.onclose)
|
|
453
456
|
return result
|
|
454
457
|
|
|
455
458
|
def add_onclose(self, *funcs):
|
|
@@ -610,12 +613,12 @@ class Response(object):
|
|
|
610
613
|
value,
|
|
611
614
|
max_age=None,
|
|
612
615
|
expires=None,
|
|
613
|
-
path="/",
|
|
614
|
-
secure=
|
|
615
|
-
domain=None,
|
|
616
|
-
comment=None,
|
|
617
|
-
httponly=False,
|
|
618
|
-
samesite="Lax",
|
|
616
|
+
path: str = "/",
|
|
617
|
+
secure: bool = False,
|
|
618
|
+
domain: t.Optional[str] = None,
|
|
619
|
+
comment: t.Optional[str] = None,
|
|
620
|
+
httponly: bool = False,
|
|
621
|
+
samesite: str = "Lax",
|
|
619
622
|
):
|
|
620
623
|
"""
|
|
621
624
|
Return a new response object with the given cookie added.
|
fresco/routeargs.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
|
+
from collections.abc import Sequence
|
|
15
16
|
from operator import attrgetter, itemgetter, methodcaller
|
|
16
17
|
from fresco.exceptions import MissingRouteArg
|
|
17
18
|
from fresco.request import Request
|
|
@@ -19,6 +20,7 @@ from itertools import cycle
|
|
|
19
20
|
from typing import Any
|
|
20
21
|
from typing import Callable
|
|
21
22
|
from typing import Mapping
|
|
23
|
+
from typing import Union
|
|
22
24
|
|
|
23
25
|
__all__ = (
|
|
24
26
|
"routearg",
|
|
@@ -138,7 +140,7 @@ def map_magics(dest):
|
|
|
138
140
|
|
|
139
141
|
|
|
140
142
|
@map_magics("raise_exception")
|
|
141
|
-
class LazyException
|
|
143
|
+
class LazyException:
|
|
142
144
|
"""
|
|
143
145
|
A lazy exception uses magic methods to intercept any access to the object
|
|
144
146
|
and raise an exception.
|
|
@@ -151,7 +153,7 @@ class LazyException(object):
|
|
|
151
153
|
raise self.__dict__["_exception"]
|
|
152
154
|
|
|
153
155
|
|
|
154
|
-
class RouteArg
|
|
156
|
+
class RouteArg:
|
|
155
157
|
"""
|
|
156
158
|
RouteArg objects can be used as keyword arguments in a route definition.
|
|
157
159
|
RouteArgs can extract information from the request and make it available
|
|
@@ -194,7 +196,7 @@ class RouteArg(object):
|
|
|
194
196
|
self.route = route
|
|
195
197
|
self.name = name
|
|
196
198
|
|
|
197
|
-
def __call__(self, request):
|
|
199
|
+
def __call__(self, request: Request) -> Any:
|
|
198
200
|
return None
|
|
199
201
|
|
|
200
202
|
|
|
@@ -225,7 +227,7 @@ def routearg(func, *args, **kwargs):
|
|
|
225
227
|
|
|
226
228
|
|
|
227
229
|
class RequestArg(RouteArg):
|
|
228
|
-
"""
|
|
230
|
+
"""
|
|
229
231
|
Extract a view keyword argument from the request object.
|
|
230
232
|
"""
|
|
231
233
|
|
|
@@ -241,9 +243,19 @@ class RequestArg(RouteArg):
|
|
|
241
243
|
#: input
|
|
242
244
|
converter_exceptions = (ValueError, TypeError)
|
|
243
245
|
|
|
246
|
+
converter: Union[
|
|
247
|
+
Callable[[list[str]], Any],
|
|
248
|
+
Callable[[str], Any],
|
|
249
|
+
]
|
|
250
|
+
|
|
244
251
|
def __init__(
|
|
245
252
|
self,
|
|
246
|
-
converter
|
|
253
|
+
converter: Union[
|
|
254
|
+
Sequence[
|
|
255
|
+
Callable[[str], Any],
|
|
256
|
+
],
|
|
257
|
+
Callable[[str], Any]
|
|
258
|
+
] = str,
|
|
247
259
|
key=None,
|
|
248
260
|
default=_marker,
|
|
249
261
|
exception=MissingRouteArg,
|
|
@@ -251,11 +263,13 @@ class RequestArg(RouteArg):
|
|
|
251
263
|
super(RequestArg, self).__init__(default, exception)
|
|
252
264
|
self.formkey = key
|
|
253
265
|
self.getter: Callable[[Mapping], Any]
|
|
254
|
-
self.is_list = isinstance(converter,
|
|
266
|
+
self.is_list = isinstance(converter, Sequence)
|
|
255
267
|
if self.is_list:
|
|
256
|
-
|
|
268
|
+
def list_converter(vs: list[str]) -> list[Any]:
|
|
269
|
+
return [c(v) for c, v in zip(cycle(converter), vs)] # type: ignore
|
|
270
|
+
self.converter = list_converter
|
|
257
271
|
else:
|
|
258
|
-
self.converter = converter
|
|
272
|
+
self.converter = converter # type: ignore
|
|
259
273
|
|
|
260
274
|
def configure(self, route, name):
|
|
261
275
|
if self.formkey is None:
|
|
@@ -372,7 +386,7 @@ class CookieArg(RequestArg):
|
|
|
372
386
|
|
|
373
387
|
source = RequestArg.cookies
|
|
374
388
|
|
|
375
|
-
def getter(self, cookies):
|
|
389
|
+
def getter(self, cookies): # type: ignore
|
|
376
390
|
if self.is_list:
|
|
377
391
|
return cookies.getlist(self.formkey)
|
|
378
392
|
else:
|