fresco 3.3.4__py3-none-any.whl → 3.9.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.
- fresco/__init__.py +55 -56
- fresco/core.py +39 -27
- fresco/decorators.py +6 -3
- fresco/defaults.py +1 -0
- fresco/middleware.py +45 -24
- fresco/multidict.py +35 -51
- fresco/options.py +188 -70
- fresco/py.typed +0 -0
- fresco/request.py +157 -36
- fresco/requestcontext.py +3 -0
- fresco/response.py +66 -57
- fresco/routeargs.py +23 -9
- fresco/routing.py +152 -74
- 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_response.py +16 -0
- fresco/tests/test_routing.py +113 -33
- fresco/tests/util/test_http.py +1 -3
- fresco/tests/util/test_urls.py +20 -0
- fresco/types.py +28 -2
- fresco/util/cache.py +2 -1
- fresco/util/http.py +66 -46
- fresco/util/urls.py +44 -12
- fresco/util/wsgi.py +15 -14
- {fresco-3.3.4.dist-info → fresco-3.9.0.dist-info}/METADATA +4 -4
- fresco-3.9.0.dist-info/RECORD +58 -0
- {fresco-3.3.4.dist-info → fresco-3.9.0.dist-info}/WHEEL +1 -1
- fresco/typing.py +0 -11
- fresco-3.3.4.dist-info/RECORD +0 -57
- {fresco-3.3.4.dist-info → fresco-3.9.0.dist-info/licenses}/LICENSE.txt +0 -0
- {fresco-3.3.4.dist-info → fresco-3.9.0.dist-info}/top_level.txt +0 -0
fresco/util/http.py
CHANGED
|
@@ -20,6 +20,8 @@ Utilities for working with data on the HTTP level
|
|
|
20
20
|
from binascii import hexlify
|
|
21
21
|
from collections import namedtuple
|
|
22
22
|
from collections import deque
|
|
23
|
+
from collections.abc import Collection
|
|
24
|
+
from collections.abc import Mapping
|
|
23
25
|
from email.header import Header
|
|
24
26
|
from email.message import Message
|
|
25
27
|
from email.parser import BytesFeedParser
|
|
@@ -43,6 +45,7 @@ from urllib.parse import unquote_plus
|
|
|
43
45
|
from shutil import copyfileobj
|
|
44
46
|
|
|
45
47
|
import fresco
|
|
48
|
+
from fresco.defaults import DEFAULT_CHARSET
|
|
46
49
|
from fresco.exceptions import RequestParseError
|
|
47
50
|
from fresco.util.io import io_iterator
|
|
48
51
|
from fresco.util.io import ByteIterator
|
|
@@ -90,23 +93,23 @@ def get_content_type_info(
|
|
|
90
93
|
|
|
91
94
|
|
|
92
95
|
class TooBig(RequestParseError):
|
|
93
|
-
"""
|
|
96
|
+
"""
|
|
94
97
|
Request body is too big
|
|
95
98
|
"""
|
|
96
99
|
|
|
97
100
|
def __init__(self, *args, **kwargs):
|
|
98
101
|
super(TooBig, self).__init__(*args, **kwargs)
|
|
99
|
-
self.response = fresco.
|
|
102
|
+
self.response = fresco.Response.payload_too_large()
|
|
100
103
|
|
|
101
104
|
|
|
102
105
|
class MissingContentLength(RequestParseError):
|
|
103
|
-
"""
|
|
106
|
+
"""
|
|
104
107
|
No ``Content-Length`` header given
|
|
105
108
|
"""
|
|
106
109
|
|
|
107
110
|
def __init__(self, *args, **kwargs):
|
|
108
111
|
super(MissingContentLength, self).__init__(*args, **kwargs)
|
|
109
|
-
self.response = fresco.
|
|
112
|
+
self.response = fresco.Response.length_required()
|
|
110
113
|
|
|
111
114
|
|
|
112
115
|
def parse_parameters(s, preserve_backslashes=False) -> Dict[str, str]:
|
|
@@ -212,7 +215,7 @@ def parse_querystring(
|
|
|
212
215
|
|
|
213
216
|
:param data: The query string to parse.
|
|
214
217
|
:param charset: Character encoding used to decode values. If not specified,
|
|
215
|
-
``fresco.DEFAULT_CHARSET`` will be used.
|
|
218
|
+
``fresco.defaults.DEFAULT_CHARSET`` will be used.
|
|
216
219
|
|
|
217
220
|
:param keep_blank_values: if True, keys without associated values will be
|
|
218
221
|
returned as empty strings. if False, no key,
|
|
@@ -223,7 +226,7 @@ def parse_querystring(
|
|
|
223
226
|
"""
|
|
224
227
|
|
|
225
228
|
if charset is None:
|
|
226
|
-
charset =
|
|
229
|
+
charset = DEFAULT_CHARSET
|
|
227
230
|
|
|
228
231
|
result: List[Tuple[str, str]] = []
|
|
229
232
|
append = result.append
|
|
@@ -275,7 +278,7 @@ def parse_post(
|
|
|
275
278
|
ct, charset, ct_params = get_content_type_info(
|
|
276
279
|
environ,
|
|
277
280
|
"application/x-www-form-urlencoded",
|
|
278
|
-
default_charset or
|
|
281
|
+
default_charset or DEFAULT_CHARSET,
|
|
279
282
|
)
|
|
280
283
|
|
|
281
284
|
try:
|
|
@@ -454,14 +457,15 @@ def parse_multipart(
|
|
|
454
457
|
f.close()
|
|
455
458
|
raise
|
|
456
459
|
|
|
457
|
-
close: Optional[Callable]
|
|
460
|
+
close: Optional[Callable] # type: ignore
|
|
458
461
|
if open_files:
|
|
459
462
|
|
|
460
463
|
def close():
|
|
461
464
|
for f in open_files:
|
|
462
465
|
f.close()
|
|
466
|
+
|
|
463
467
|
else:
|
|
464
|
-
close = None
|
|
468
|
+
close = None # type: ignore
|
|
465
469
|
|
|
466
470
|
return fields, close
|
|
467
471
|
|
|
@@ -554,7 +558,6 @@ def read_until(
|
|
|
554
558
|
return
|
|
555
559
|
|
|
556
560
|
def remainder():
|
|
557
|
-
nonlocal buf
|
|
558
561
|
if buf:
|
|
559
562
|
yield buf
|
|
560
563
|
yield from stream
|
|
@@ -591,7 +594,21 @@ class FileUpload(object):
|
|
|
591
594
|
copyfileobj(self.file, fileob)
|
|
592
595
|
|
|
593
596
|
|
|
594
|
-
def encode_multipart(
|
|
597
|
+
def encode_multipart(
|
|
598
|
+
data: Optional[
|
|
599
|
+
Union[
|
|
600
|
+
Mapping[str, str],
|
|
601
|
+
Collection[tuple[str, str]],
|
|
602
|
+
]
|
|
603
|
+
] = None,
|
|
604
|
+
files: Optional[
|
|
605
|
+
Collection[
|
|
606
|
+
tuple[str, str, str, Union[bytes, t.Iterable[bytes], t.BinaryIO]]
|
|
607
|
+
]
|
|
608
|
+
] = None,
|
|
609
|
+
charset="UTF-8",
|
|
610
|
+
**kwargs
|
|
611
|
+
) -> tuple[bytes, dict[str, str]]:
|
|
595
612
|
"""
|
|
596
613
|
Encode ``data`` using multipart/form-data encoding, returning a tuple
|
|
597
614
|
of ``(<encoded data>, <environ items>)``.
|
|
@@ -602,7 +619,7 @@ def encode_multipart(data=None, files=None, charset="UTF-8", **kwargs):
|
|
|
602
619
|
:param charset: Encoding used for any string values encountered in
|
|
603
620
|
``data``
|
|
604
621
|
|
|
605
|
-
:param files:
|
|
622
|
+
:param files: collection of ``(name, filename, content_type, data)`` tuples.
|
|
606
623
|
``data`` may be either a byte string, iterator or
|
|
607
624
|
file-like object.
|
|
608
625
|
|
|
@@ -614,45 +631,22 @@ def encode_multipart(data=None, files=None, charset="UTF-8", **kwargs):
|
|
|
614
631
|
dict.
|
|
615
632
|
"""
|
|
616
633
|
|
|
617
|
-
def header_block(name):
|
|
618
|
-
return [("Content-Disposition", 'form-data; name="%s"' % (name,))]
|
|
619
|
-
|
|
620
|
-
def file_header_block(name, filename, content_type):
|
|
621
|
-
return [
|
|
622
|
-
(
|
|
623
|
-
"Content-Disposition",
|
|
624
|
-
'form-data; name="%s"; filename="%s"' % (name, filename),
|
|
625
|
-
),
|
|
626
|
-
("Content-Type", content_type),
|
|
627
|
-
]
|
|
628
|
-
|
|
629
|
-
def write_payload(stream, data):
|
|
630
|
-
"Write ``data`` to ``stream``, encoding as required"
|
|
631
|
-
if hasattr(data, "read"):
|
|
632
|
-
copyfileobj(data, stream)
|
|
633
|
-
elif isinstance(data, bytes):
|
|
634
|
-
stream.write(data)
|
|
635
|
-
elif isinstance(data, str):
|
|
636
|
-
stream.write(data.encode(charset))
|
|
637
|
-
else:
|
|
638
|
-
raise ValueError(data)
|
|
639
|
-
|
|
640
|
-
if data is None:
|
|
641
|
-
data = {}
|
|
642
|
-
|
|
643
634
|
if files is None:
|
|
644
635
|
files = []
|
|
645
636
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
637
|
+
data_items: Iterable[tuple[str, str]]
|
|
638
|
+
if data is None:
|
|
639
|
+
data_items = []
|
|
640
|
+
elif isinstance(data, Mapping):
|
|
641
|
+
data_items = iter(data.items()) # type: ignore
|
|
642
|
+
else:
|
|
643
|
+
data_items = data
|
|
650
644
|
|
|
651
|
-
|
|
645
|
+
data_items = chain(data_items, kwargs.items())
|
|
652
646
|
|
|
653
647
|
boundary = b"-------" + hexlify(os.urandom(16))
|
|
654
648
|
alldata = chain(
|
|
655
|
-
((header_block(k), payload) for k, payload in
|
|
649
|
+
((header_block(k), payload) for k, payload in data_items),
|
|
656
650
|
((file_header_block(k, fn, ct), payload) for k, fn, ct, payload in files),
|
|
657
651
|
)
|
|
658
652
|
|
|
@@ -664,7 +658,7 @@ def encode_multipart(data=None, files=None, charset="UTF-8", **kwargs):
|
|
|
664
658
|
for name, value in headers:
|
|
665
659
|
post_data.write("{0}: {1}\r\n".format(name, value).encode("ascii"))
|
|
666
660
|
post_data.write(CRLF)
|
|
667
|
-
write_payload(post_data, payload)
|
|
661
|
+
write_payload(post_data, payload, charset)
|
|
668
662
|
post_data.write(b"\r\n--" + boundary)
|
|
669
663
|
post_data.write(b"--\r\n")
|
|
670
664
|
length = post_data.tell()
|
|
@@ -676,4 +670,30 @@ def encode_multipart(data=None, files=None, charset="UTF-8", **kwargs):
|
|
|
676
670
|
),
|
|
677
671
|
}
|
|
678
672
|
|
|
679
|
-
return (post_data, wsgienv)
|
|
673
|
+
return (post_data.getvalue(), wsgienv)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def header_block(name):
|
|
677
|
+
return [("Content-Disposition", 'form-data; name="%s"' % (name,))]
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def file_header_block(name, filename, content_type):
|
|
681
|
+
return [
|
|
682
|
+
(
|
|
683
|
+
"Content-Disposition",
|
|
684
|
+
'form-data; name="%s"; filename="%s"' % (name, filename),
|
|
685
|
+
),
|
|
686
|
+
("Content-Type", content_type),
|
|
687
|
+
]
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def write_payload(stream, data, charset):
|
|
691
|
+
"Write ``data`` to ``stream``, encoding as required"
|
|
692
|
+
if hasattr(data, "read"):
|
|
693
|
+
copyfileobj(data, stream)
|
|
694
|
+
elif isinstance(data, bytes):
|
|
695
|
+
stream.write(data)
|
|
696
|
+
elif isinstance(data, str):
|
|
697
|
+
stream.write(data.encode(charset))
|
|
698
|
+
else:
|
|
699
|
+
raise ValueError(data)
|
fresco/util/urls.py
CHANGED
|
@@ -23,15 +23,17 @@ from typing import List
|
|
|
23
23
|
from urllib.parse import quote_plus
|
|
24
24
|
from urllib.parse import urlparse
|
|
25
25
|
from urllib.parse import urlunparse
|
|
26
|
+
from urllib.parse import urlencode
|
|
27
|
+
from urllib.parse import parse_qsl
|
|
26
28
|
import posixpath
|
|
27
29
|
import re
|
|
28
30
|
import typing as t
|
|
29
31
|
|
|
30
|
-
import
|
|
32
|
+
from fresco.defaults import DEFAULT_CHARSET
|
|
31
33
|
from fresco.multidict import MultiDict
|
|
32
34
|
from fresco.types import QuerySpec
|
|
33
35
|
|
|
34
|
-
__all__ = "join_path", "url_join", "strip_trailing_slashes", "normpath"
|
|
36
|
+
__all__ = "join_path", "url_join", "strip_trailing_slashes", "normpath", "add_query"
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def join_path(a, b):
|
|
@@ -174,13 +176,13 @@ def make_query(
|
|
|
174
176
|
data: QuerySpec = [],
|
|
175
177
|
separator: str = "&",
|
|
176
178
|
charset: t.Optional[str] = None,
|
|
177
|
-
**kwargs,
|
|
179
|
+
**kwargs: t.Any,
|
|
178
180
|
) -> str:
|
|
179
181
|
"""
|
|
180
182
|
Return a query string formed from the given dictionary data.
|
|
181
183
|
|
|
182
184
|
If no encoding is given, unicode values are encoded using the character set
|
|
183
|
-
specified by ``fresco.DEFAULT_CHARSET``.
|
|
185
|
+
specified by ``fresco.defaults.DEFAULT_CHARSET``.
|
|
184
186
|
|
|
185
187
|
Basic usage::
|
|
186
188
|
|
|
@@ -210,46 +212,48 @@ def make_query(
|
|
|
210
212
|
:param charset: encoding to be used for unicode values
|
|
211
213
|
:rtype: str
|
|
212
214
|
"""
|
|
213
|
-
items: t.Iterable[
|
|
215
|
+
items: t.Iterable[tuple[str, t.Any]]
|
|
214
216
|
if isinstance(data, MultiDict):
|
|
215
217
|
items = data.allitems()
|
|
216
218
|
elif isinstance(data, Mapping):
|
|
217
|
-
items = data.items()
|
|
219
|
+
items = data.items() # type: ignore
|
|
218
220
|
else:
|
|
219
221
|
items = data
|
|
220
222
|
if kwargs:
|
|
221
223
|
items = chain(items, kwargs.items())
|
|
222
224
|
|
|
223
225
|
if charset is None:
|
|
224
|
-
charset =
|
|
226
|
+
charset = DEFAULT_CHARSET
|
|
225
227
|
|
|
226
|
-
pairs:
|
|
228
|
+
pairs: list[str] = []
|
|
227
229
|
append = pairs.append
|
|
228
230
|
for k, v in items:
|
|
229
231
|
if isinstance(v, (str, bytes)):
|
|
230
232
|
append(f"{quote_plus(k, charset)}={quote_plus(v, charset)}")
|
|
233
|
+
elif v is None:
|
|
234
|
+
pass
|
|
231
235
|
elif hasattr(v, "__iter__"):
|
|
232
236
|
for v in v:
|
|
233
237
|
append(f"{quote_plus(k, charset)}={quote_plus(str(v), charset)}")
|
|
234
|
-
|
|
238
|
+
else:
|
|
235
239
|
append(f"{quote_plus(k, charset)}={quote_plus(str(v), charset)}")
|
|
236
240
|
return separator.join(pairs)
|
|
237
241
|
|
|
238
242
|
|
|
239
243
|
def _qs_frag(key, value, charset=None):
|
|
240
|
-
"""
|
|
244
|
+
"""
|
|
241
245
|
Return a fragment of a query string in the format 'key=value'::
|
|
242
246
|
|
|
243
247
|
>>> _qs_frag('search-by', 'author, editor')
|
|
244
248
|
'search-by=author%2C+editor'
|
|
245
249
|
|
|
246
250
|
If no encoding is specified, unicode values are encoded using the character
|
|
247
|
-
set specified by ``fresco.DEFAULT_CHARSET``.
|
|
251
|
+
set specified by ``fresco.defaults.DEFAULT_CHARSET``.
|
|
248
252
|
|
|
249
253
|
:rtype: str
|
|
250
254
|
"""
|
|
251
255
|
if charset is None:
|
|
252
|
-
charset =
|
|
256
|
+
charset = DEFAULT_CHARSET
|
|
253
257
|
|
|
254
258
|
key = str(key).encode(charset)
|
|
255
259
|
value = str(value).encode(charset)
|
|
@@ -327,3 +331,31 @@ def is_safe_url(
|
|
|
327
331
|
or (scheme == "" and netloc == "")
|
|
328
332
|
or (scheme == "" and netloc in allowed_hosts)
|
|
329
333
|
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def add_query(
|
|
337
|
+
url: str,
|
|
338
|
+
data: t.Union[t.Sequence[tuple[str, t.Any]], t.Mapping[str, t.Any]] = [],
|
|
339
|
+
**kwargs: t.Any,
|
|
340
|
+
) -> str:
|
|
341
|
+
"""
|
|
342
|
+
Return the given URL with the given query data appended
|
|
343
|
+
|
|
344
|
+
:param url:
|
|
345
|
+
The base URL
|
|
346
|
+
:param data:
|
|
347
|
+
Optional data items, supplied either as a mapping or list of (key,
|
|
348
|
+
value) tuples
|
|
349
|
+
:param kwargs:
|
|
350
|
+
Query data supplied as keyword arguments
|
|
351
|
+
"""
|
|
352
|
+
parsed = urlparse(url)
|
|
353
|
+
return urlunparse(
|
|
354
|
+
parsed._replace(
|
|
355
|
+
query=urlencode(
|
|
356
|
+
parse_qsl(parsed.query)
|
|
357
|
+
+ list(dict(data).items())
|
|
358
|
+
+ list(kwargs.items())
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
)
|
fresco/util/wsgi.py
CHANGED
|
@@ -22,15 +22,16 @@ from io import BytesIO
|
|
|
22
22
|
from urllib.parse import unquote
|
|
23
23
|
from urllib.parse import urlparse
|
|
24
24
|
from typing import List
|
|
25
|
-
|
|
26
|
-
from typing import Tuple
|
|
25
|
+
import typing as t
|
|
27
26
|
import sys
|
|
28
27
|
|
|
29
|
-
from fresco.
|
|
30
|
-
from fresco.
|
|
31
|
-
from fresco.
|
|
28
|
+
from fresco.types import WSGIApplication
|
|
29
|
+
from fresco.types import WriteCallable
|
|
30
|
+
from fresco.types import OptionalExcInfo
|
|
31
|
+
from fresco.types import HeaderList
|
|
32
32
|
|
|
33
33
|
logger = logging.getLogger(__name__)
|
|
34
|
+
T = t.TypeVar("T")
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
__all__ = [
|
|
@@ -102,7 +103,6 @@ REQUEST_HEADER_NAMES = {
|
|
|
102
103
|
"dnt": "DNT",
|
|
103
104
|
"x_forwarded_for": "X-Forwarded-For",
|
|
104
105
|
"x_forwarded_host": "X-Forwarded-Host",
|
|
105
|
-
"x_forwarded_host": "X-Forwarded-Host",
|
|
106
106
|
"x_forwarded_proto": "X-Forwarded-Proto",
|
|
107
107
|
"front_end_https": "Front-End-Https",
|
|
108
108
|
"x_http_method_override": "X-Http-Method-Override",
|
|
@@ -245,8 +245,8 @@ class StartResponseWrapper(object):
|
|
|
245
245
|
self.exc_info = None
|
|
246
246
|
|
|
247
247
|
|
|
248
|
-
class ClosingIterator(
|
|
249
|
-
"""
|
|
248
|
+
class ClosingIterator(t.Generic[T]):
|
|
249
|
+
"""
|
|
250
250
|
Wrap a WSGI iterator to allow additional close functions to be called on
|
|
251
251
|
application exit.
|
|
252
252
|
|
|
@@ -275,7 +275,7 @@ class ClosingIterator(object):
|
|
|
275
275
|
|
|
276
276
|
__slots__ = ("_iterable", "_next", "_close_funcs", "_closed")
|
|
277
277
|
|
|
278
|
-
def __init__(self, iterable, *close_funcs):
|
|
278
|
+
def __init__(self, iterable: t.Iterable[T], *close_funcs: t.Callable[[], None]):
|
|
279
279
|
"""
|
|
280
280
|
Initialize a ``ClosingIterator`` to wrap iterable ``iterable``, and
|
|
281
281
|
call any functions listed in ``*close_funcs`` on the instance's
|
|
@@ -406,19 +406,20 @@ def make_environ(url="/", environ=None, wsgi_input=b"", **kwargs):
|
|
|
406
406
|
|
|
407
407
|
|
|
408
408
|
def apply_request(
|
|
409
|
-
request, wsgicallable:
|
|
410
|
-
) ->
|
|
409
|
+
request, wsgicallable: WSGIApplication
|
|
410
|
+
) -> tuple[str, HeaderList, OptionalExcInfo, list[bytes]]:
|
|
411
411
|
"""
|
|
412
412
|
Execute ``wsgicallable`` with the given request, exhaust and close the
|
|
413
413
|
content iterator and return the result.
|
|
414
414
|
"""
|
|
415
415
|
|
|
416
|
-
_start_response_result:
|
|
416
|
+
_start_response_result: list[tuple[str, HeaderList, OptionalExcInfo]] = []
|
|
417
417
|
|
|
418
418
|
def start_response(
|
|
419
|
-
status: str, headers:
|
|
420
|
-
):
|
|
419
|
+
status: str, headers: HeaderList, exc_info: OptionalExcInfo = None
|
|
420
|
+
) -> WriteCallable:
|
|
421
421
|
_start_response_result.append((status, headers, exc_info))
|
|
422
|
+
return lambda s: None
|
|
422
423
|
|
|
423
424
|
contentiter = wsgicallable(request.environ, start_response)
|
|
424
425
|
assert len(_start_response_result) == 1
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fresco
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.9.0
|
|
4
4
|
Summary: A Web/WSGI micro-framework
|
|
5
5
|
Author-email: Oliver Cope <oliver@redgecko.org>
|
|
6
|
-
License: Apache
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://ollycope.com/software/fresco/latest/
|
|
8
8
|
Keywords: wsgi,web,www,framework
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Environment :: Web Environment
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
12
|
Classifier: Operating System :: OS Independent
|
|
14
13
|
Classifier: Programming Language :: Python :: 3
|
|
15
14
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
16
15
|
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
|
|
17
16
|
Description-Content-Type: text/x-rst
|
|
18
17
|
License-File: LICENSE.txt
|
|
18
|
+
Dynamic: license-file
|
|
19
19
|
|
|
20
20
|
Fresco, a web micro-framework for Python
|
|
21
21
|
========================================
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
fresco/__init__.py,sha256=gy3VchKsKsoWqZFqIbMhgzIjNCeFlcNnTl225TC_8qw,3537
|
|
2
|
+
fresco/cookie.py,sha256=Qnx8yOjU4LUJ1fqi7YvqbhAA01rCsclJGl_fxI68slw,7055
|
|
3
|
+
fresco/core.py,sha256=5sV6dTOhtEgEpMH_4sjoI0ewZYLvAPnRjyTfNkm490Q,27037
|
|
4
|
+
fresco/decorators.py,sha256=JL4MlsJz4RWRAuOCCB3fx3rtd-E1CvwO2MD7bf94yHM,3324
|
|
5
|
+
fresco/defaults.py,sha256=YStD4MPcCtq-fREFoupSaAS0SY8lH1oEnKDONlR86zs,26
|
|
6
|
+
fresco/exceptions.py,sha256=KE-LoYUGnho6KltzkU6cnm9vUiUhAiDIjPqn5ba-YCA,4410
|
|
7
|
+
fresco/middleware.py,sha256=TH1I5NthLDwnOdluOSFpP_9SQQYhYqh-8lGuAXT74dc,4811
|
|
8
|
+
fresco/multidict.py,sha256=lKRpSP1XNghLp2-i5cXPfPQxuoJclHpNkWk91F4GI1o,13152
|
|
9
|
+
fresco/options.py,sha256=xMh23WS6HB7P9ka_S0X3DoGSSvb8ESl1m8Pqb52Mork,17152
|
|
10
|
+
fresco/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
fresco/request.py,sha256=B3OeD4H_2HrgRbg5HhkjiHZ6JWiXTe98wYdtpLbNBCw,30046
|
|
12
|
+
fresco/requestcontext.py,sha256=_AJ7DMT5vlIO4Uc-WlRsYJdRge4WRO7ygibKImOS0iM,3601
|
|
13
|
+
fresco/response.py,sha256=9RB9f6tgS_voM-MK36vGzWpkpp6JISnbF--F2FsAT7g,37605
|
|
14
|
+
fresco/routeargs.py,sha256=E-LQutqg6AojtagZojF7NeMjFBk9joRNMGo842IMTBk,10598
|
|
15
|
+
fresco/routing.py,sha256=d8Z2QyW-X5W4_7wrG39G7PgzwSgLe-8RvxeBJfoh0L0,61615
|
|
16
|
+
fresco/static.py,sha256=rNQz_8-PVhSGup_w-HycqatLEbFes7VSlnNQ0rz24pU,2529
|
|
17
|
+
fresco/subrequests.py,sha256=fOG9Bd3w9Ova0S3qv5ssxQ_otrSxaFcKG7TOy6CxNCg,11068
|
|
18
|
+
fresco/types.py,sha256=PbXppEcckX4ohU8npteU1mCkHOuXQxrnqxk1RNEFXkE,797
|
|
19
|
+
fresco/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
fresco/tests/fixtures.py,sha256=eyo2zPivB3fItDkrJqWnOCvIS_A1q1JEhT4AutAB--o,1871
|
|
21
|
+
fresco/tests/test_cookie.py,sha256=HTLmNCjcPoZDeFnZAzY3lJPeduzgU4mi9C-74eSQCec,2171
|
|
22
|
+
fresco/tests/test_core.py,sha256=-eibrVd8UqPqTvcar54kt24m6_lX3mxXR8L7v-WDrWw,34003
|
|
23
|
+
fresco/tests/test_decorators.py,sha256=VFXHo1gm2jldQXeaEF3NNo5fnpdJ-LXc8-vNymPJKTQ,1480
|
|
24
|
+
fresco/tests/test_exceptions.py,sha256=R0Tn86m33iTKecZ69TgH4CqY9XSFP0FsLMH10O5Jth8,973
|
|
25
|
+
fresco/tests/test_middleware.py,sha256=D_sWfX-w3bhItOm54nB_cuYPGoWopISvZCFIuMX68cU,3137
|
|
26
|
+
fresco/tests/test_multidict.py,sha256=uIa1cu5DMAukX2nLOjTiB12oh0icBeSPfsUnqsu85m0,7577
|
|
27
|
+
fresco/tests/test_options.py,sha256=394MLLTyf4vmfkUyqQ8EGIiTTJsQh7P9M6eta2wgUbw,12764
|
|
28
|
+
fresco/tests/test_request.py,sha256=wGDwxCZMbzyGgQJwM2Nlsf0ogcGenXN3srO8dQEhE24,16777
|
|
29
|
+
fresco/tests/test_requestcontext.py,sha256=t8hm-lzIk85ryb3sdlpVoPQyLDWpCjB86dg8nVG1yRw,3115
|
|
30
|
+
fresco/tests/test_response.py,sha256=PYMEr7aJfHMU3eIkBnGN5I6TpYf0xua2-95aNhU1Y7w,9544
|
|
31
|
+
fresco/tests/test_routeargs.py,sha256=VMWUbrXegTLN9Tx2AcrpbjAAEaxAANzkcy02SmpFOmY,8162
|
|
32
|
+
fresco/tests/test_routing.py,sha256=smRhdbru9mRXd0x_bmawCSZbZV7bR1z-9BRiFB9hOJc,40408
|
|
33
|
+
fresco/tests/test_static.py,sha256=y73dqzE2flpACQ_dvNhDzk_WlvNQfkhYF_8YY4MMGDo,4686
|
|
34
|
+
fresco/tests/test_subrequests.py,sha256=7rluJnw-elXRXfrzvAQvGBHRBU93zwnL827mTxBGd3Y,7909
|
|
35
|
+
fresco/tests/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
fresco/tests/util/form_data.py,sha256=TalOuv4BGM3JNrf14tE47o9wAwZ7jA1CvRDnGJFifno,10570
|
|
37
|
+
fresco/tests/util/test_common.py,sha256=NvKX8KIAUki7b2kDLILWqARbOQmR3XyInLlbcwFEhiU,1117
|
|
38
|
+
fresco/tests/util/test_http.py,sha256=mdHDc-4m9sMNkEgHToIsgFuSSXQzNUcYSehPehYvJYo,10748
|
|
39
|
+
fresco/tests/util/test_security.py,sha256=MtpDDKyDhAeRT766Lt3peOv4Jj55TM1lvJk1_5TKaes,1492
|
|
40
|
+
fresco/tests/util/test_urls.py,sha256=U12T9MlP7zCpf-ufoyaZI5nAswi0xCSBOxHjHB2K_0I,8320
|
|
41
|
+
fresco/tests/util/test_wsgi.py,sha256=VsHUCo8yck_40nsYm-H-M0R8QYEE8JcboeGPbcrzsO0,3038
|
|
42
|
+
fresco/util/__init__.py,sha256=mJkaZzvYgBnxsBAGv8y_P1yzonHqWgw6VF2Zs4rmJEA,7
|
|
43
|
+
fresco/util/cache.py,sha256=0xINmBecCYo3h5-zU_yRyJeWmROygE3pO9w9Y3ZONcs,1661
|
|
44
|
+
fresco/util/common.py,sha256=8lvrjhELvYsUWxu7DZi1OJcUOFk2ILYndNsnaS0IqjM,1258
|
|
45
|
+
fresco/util/contentencodings.py,sha256=cCP-nSlXiBAZWoJdlnrQREi9jYRu8UY327bQdfBNlkg,5527
|
|
46
|
+
fresco/util/file.py,sha256=Vp7qJTo9RouUeHq25ExyBGkGTHuW-9Q7D_0GB54DFe8,1383
|
|
47
|
+
fresco/util/http.py,sha256=hxMKjF6FWvugDvToRqSscDhCD1KdVY1bmV4Unwd_Uhs,22672
|
|
48
|
+
fresco/util/io.py,sha256=xxwDNJOcewY8lAR4Ce3cmB_zlrys8JGsESgwGWE198Y,1289
|
|
49
|
+
fresco/util/object.py,sha256=FjYNfPHzvBqq1rn0Y6As-2AVZ_SZOjH-lrSy4EbYmHY,370
|
|
50
|
+
fresco/util/security.py,sha256=nXEdoCak_2c4OA1L1wGwhZygS22s2fzwR0Kp-DdwKZg,1058
|
|
51
|
+
fresco/util/textproc.py,sha256=e5jLTofKCqdm6_Fy8XOyR43AJr5APtL59Kd8cNA9PrQ,2309
|
|
52
|
+
fresco/util/urls.py,sha256=V6-s2WgeARkEcuzpwqtiM8ebOXe5-mNUKOJ8N9LNBHA,10051
|
|
53
|
+
fresco/util/wsgi.py,sha256=RYw4KeOUjzzPOL_HhEtgLyCngofjMdAT8BTLOSKU6KA,13021
|
|
54
|
+
fresco-3.9.0.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
55
|
+
fresco-3.9.0.dist-info/METADATA,sha256=wQn0fuVCpyBdudhkG3lu_8azHj5P__kApDRqeYHDs6M,1523
|
|
56
|
+
fresco-3.9.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
57
|
+
fresco-3.9.0.dist-info/top_level.txt,sha256=p_1aMce5Shjq9fIfdbB-aN8wCDhjF_iYnn98bUebbII,7
|
|
58
|
+
fresco-3.9.0.dist-info/RECORD,,
|
fresco/typing.py
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from types import TracebackType
|
|
2
|
-
from typing import Any
|
|
3
|
-
from typing import Callable
|
|
4
|
-
from typing import Dict
|
|
5
|
-
from typing import Iterable
|
|
6
|
-
from typing import List
|
|
7
|
-
from typing import Tuple
|
|
8
|
-
|
|
9
|
-
WSGICallable = Callable[[Dict[str, Any], Callable], Iterable[bytes]]
|
|
10
|
-
ExcInfoTuple = Tuple[type, BaseException, TracebackType]
|
|
11
|
-
HeadersList = List[Tuple[str, str]]
|
fresco-3.3.4.dist-info/RECORD
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
fresco/__init__.py,sha256=DkBKfTdD88kXZYGi5Pv686Es1twTgZ4fVO3mA2nf0GQ,3520
|
|
2
|
-
fresco/cookie.py,sha256=Qnx8yOjU4LUJ1fqi7YvqbhAA01rCsclJGl_fxI68slw,7055
|
|
3
|
-
fresco/core.py,sha256=mwYR6UP0zRSjcFlNZf51-otX9EcmvgjEZ7GDVQoQexg,26615
|
|
4
|
-
fresco/decorators.py,sha256=84NUpRJ-M7GK6wDl42bmCRSvgoWzCsy1huyvGnSAPPw,3232
|
|
5
|
-
fresco/exceptions.py,sha256=KE-LoYUGnho6KltzkU6cnm9vUiUhAiDIjPqn5ba-YCA,4410
|
|
6
|
-
fresco/middleware.py,sha256=uCAuOtBnvaVBJGrQa8ecvLkSZ6aSKmWaJqxB8Rv4SsQ,4173
|
|
7
|
-
fresco/multidict.py,sha256=0CaNNIcFnZ1hLk3NExhNvjc_BtK4zVB26L9gP_7MeNM,13362
|
|
8
|
-
fresco/options.py,sha256=0RzwO1eyCUC70GxKFnCHNKDyZwsKc9Q-AmtlMAnfZ-Q,14004
|
|
9
|
-
fresco/request.py,sha256=dC7pMg-4Kxa6PcqaaWFL4JviANQotuBjoKwlxZYywRY,27048
|
|
10
|
-
fresco/requestcontext.py,sha256=P-SkKJkKLYVqNiR2zwooRROnSnE2VMj2P2-eD5DW5Qg,3504
|
|
11
|
-
fresco/response.py,sha256=ADKHbtAGyhwtaUJxB7m_1nqVdZRKUryebmG4FDUjZVY,37072
|
|
12
|
-
fresco/routeargs.py,sha256=dxNlqbQ1FrgIY6OCFzcEMdZ0OVyjlMQdQGLmUJgdPYU,10176
|
|
13
|
-
fresco/routing.py,sha256=kTFqJ9Nn9cOHlul-lHqKDurBwqlEO4fg8tertb1jkoI,58709
|
|
14
|
-
fresco/static.py,sha256=9SKQ3P1YFTP45Qiic-ycvkpKRvqIURp1XSzPazTmYLI,2513
|
|
15
|
-
fresco/subrequests.py,sha256=wFJWLuhVAcei5imYc5NBSCBaHBEm-X4_XswPtK3O4Zw,11081
|
|
16
|
-
fresco/types.py,sha256=UHITRMDoS90s2zV2wNpqLFhRWESfaBAMuQnL4c21mqY,106
|
|
17
|
-
fresco/typing.py,sha256=jQ1r_wme54J08XZUdmuuW4M8ve-gEhm1Wriwctls3r8,347
|
|
18
|
-
fresco/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
fresco/tests/fixtures.py,sha256=eyo2zPivB3fItDkrJqWnOCvIS_A1q1JEhT4AutAB--o,1871
|
|
20
|
-
fresco/tests/test_cookie.py,sha256=HTLmNCjcPoZDeFnZAzY3lJPeduzgU4mi9C-74eSQCec,2171
|
|
21
|
-
fresco/tests/test_core.py,sha256=lniN-UslszeRAuWlbBU536LDGTo8Hp2nb8kLebXvim0,34019
|
|
22
|
-
fresco/tests/test_decorators.py,sha256=VFXHo1gm2jldQXeaEF3NNo5fnpdJ-LXc8-vNymPJKTQ,1480
|
|
23
|
-
fresco/tests/test_exceptions.py,sha256=R0Tn86m33iTKecZ69TgH4CqY9XSFP0FsLMH10O5Jth8,973
|
|
24
|
-
fresco/tests/test_middleware.py,sha256=D_sWfX-w3bhItOm54nB_cuYPGoWopISvZCFIuMX68cU,3137
|
|
25
|
-
fresco/tests/test_multidict.py,sha256=uDwDYII0dvVxaEyDO85zRTWlIWw3LO3StzYemJVm0E0,7565
|
|
26
|
-
fresco/tests/test_options.py,sha256=Zx1tLVLeok8tO3dWua2PyTPZgeWbXFMXtN3FnorBmC8,10998
|
|
27
|
-
fresco/tests/test_request.py,sha256=hoANrergrohlAeTbQufDMfIbvYURsPyPjCxOVKz7bVo,16389
|
|
28
|
-
fresco/tests/test_requestcontext.py,sha256=t8hm-lzIk85ryb3sdlpVoPQyLDWpCjB86dg8nVG1yRw,3115
|
|
29
|
-
fresco/tests/test_response.py,sha256=MrhHIDg81pJlTeEcn2rGtU-i59s1KzEccF81u4Up6xs,8934
|
|
30
|
-
fresco/tests/test_routeargs.py,sha256=VMWUbrXegTLN9Tx2AcrpbjAAEaxAANzkcy02SmpFOmY,8162
|
|
31
|
-
fresco/tests/test_routing.py,sha256=yfZGon6vKwszFp3pCP2Mtnf3W3u4WdELdvVcgIKHOVU,37890
|
|
32
|
-
fresco/tests/test_static.py,sha256=y73dqzE2flpACQ_dvNhDzk_WlvNQfkhYF_8YY4MMGDo,4686
|
|
33
|
-
fresco/tests/test_subrequests.py,sha256=7rluJnw-elXRXfrzvAQvGBHRBU93zwnL827mTxBGd3Y,7909
|
|
34
|
-
fresco/tests/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
fresco/tests/util/form_data.py,sha256=TalOuv4BGM3JNrf14tE47o9wAwZ7jA1CvRDnGJFifno,10570
|
|
36
|
-
fresco/tests/util/test_common.py,sha256=NvKX8KIAUki7b2kDLILWqARbOQmR3XyInLlbcwFEhiU,1117
|
|
37
|
-
fresco/tests/util/test_http.py,sha256=VYcrxKisRhI19AvuZWLuJGdpZo-IN19y4gDUKwuFy0I,10803
|
|
38
|
-
fresco/tests/util/test_security.py,sha256=MtpDDKyDhAeRT766Lt3peOv4Jj55TM1lvJk1_5TKaes,1492
|
|
39
|
-
fresco/tests/util/test_urls.py,sha256=xKiE6oq0bB-9u8kNYlMQmeCwuAKr1KLQovB-i24wKVQ,7643
|
|
40
|
-
fresco/tests/util/test_wsgi.py,sha256=VsHUCo8yck_40nsYm-H-M0R8QYEE8JcboeGPbcrzsO0,3038
|
|
41
|
-
fresco/util/__init__.py,sha256=mJkaZzvYgBnxsBAGv8y_P1yzonHqWgw6VF2Zs4rmJEA,7
|
|
42
|
-
fresco/util/cache.py,sha256=EjzF9EzzDw4U4coOykkJEgh_8HMDpwhEbYKBo_TeOZQ,1609
|
|
43
|
-
fresco/util/common.py,sha256=8lvrjhELvYsUWxu7DZi1OJcUOFk2ILYndNsnaS0IqjM,1258
|
|
44
|
-
fresco/util/contentencodings.py,sha256=cCP-nSlXiBAZWoJdlnrQREi9jYRu8UY327bQdfBNlkg,5527
|
|
45
|
-
fresco/util/file.py,sha256=Vp7qJTo9RouUeHq25ExyBGkGTHuW-9Q7D_0GB54DFe8,1383
|
|
46
|
-
fresco/util/http.py,sha256=6LSzCxr8avha3rRwsU8kUrkHWnQTuOw49mfi1PSBEgo,22199
|
|
47
|
-
fresco/util/io.py,sha256=xxwDNJOcewY8lAR4Ce3cmB_zlrys8JGsESgwGWE198Y,1289
|
|
48
|
-
fresco/util/object.py,sha256=FjYNfPHzvBqq1rn0Y6As-2AVZ_SZOjH-lrSy4EbYmHY,370
|
|
49
|
-
fresco/util/security.py,sha256=nXEdoCak_2c4OA1L1wGwhZygS22s2fzwR0Kp-DdwKZg,1058
|
|
50
|
-
fresco/util/textproc.py,sha256=e5jLTofKCqdm6_Fy8XOyR43AJr5APtL59Kd8cNA9PrQ,2309
|
|
51
|
-
fresco/util/urls.py,sha256=aaVovLyXNlVoGviiLN94ImqXf-LTQs_xooEIyi3LBc4,9195
|
|
52
|
-
fresco/util/wsgi.py,sha256=2cr2b92RpvPSgS_P46X2mlYepoFg9Qji-V-fzxpSNzw,12971
|
|
53
|
-
fresco-3.3.4.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
54
|
-
fresco-3.3.4.dist-info/METADATA,sha256=v9NcXIhYp5MqENOecCV7XIsFrg7sC9GdRmIHuS912HI,1549
|
|
55
|
-
fresco-3.3.4.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
56
|
-
fresco-3.3.4.dist-info/top_level.txt,sha256=p_1aMce5Shjq9fIfdbB-aN8wCDhjF_iYnn98bUebbII,7
|
|
57
|
-
fresco-3.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|