asgi-tools 1.1.0__cp311-cp311-macosx_10_9_universal2.whl → 1.3.1__cp311-cp311-macosx_10_9_universal2.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.
- asgi_tools/__init__.py +3 -2
- asgi_tools/_compat.py +10 -13
- asgi_tools/app.py +105 -51
- asgi_tools/forms.c +6646 -7185
- asgi_tools/forms.cpython-311-darwin.so +0 -0
- asgi_tools/forms.py +9 -9
- asgi_tools/middleware.py +38 -29
- asgi_tools/multipart.c +5818 -5562
- asgi_tools/multipart.cpython-311-darwin.so +0 -0
- asgi_tools/multipart.py +6 -9
- asgi_tools/request.py +63 -47
- asgi_tools/response.py +49 -60
- asgi_tools/tests.py +20 -21
- asgi_tools/view.py +2 -2
- {asgi_tools-1.1.0.dist-info → asgi_tools-1.3.1.dist-info}/METADATA +23 -23
- asgi_tools-1.3.1.dist-info/RECORD +29 -0
- {asgi_tools-1.1.0.dist-info → asgi_tools-1.3.1.dist-info}/WHEEL +2 -1
- asgi_tools-1.1.0.dist-info/RECORD +0 -29
- {asgi_tools-1.1.0.dist-info → asgi_tools-1.3.1.dist-info/licenses}/LICENSE +0 -0
- {asgi_tools-1.1.0.dist-info → asgi_tools-1.3.1.dist-info}/top_level.txt +0 -0
asgi_tools/tests.py
CHANGED
@@ -22,13 +22,10 @@ from typing import (
|
|
22
22
|
Callable,
|
23
23
|
Coroutine,
|
24
24
|
Deque,
|
25
|
-
Optional,
|
26
|
-
Union,
|
27
25
|
cast,
|
28
26
|
)
|
29
27
|
from urllib.parse import urlencode
|
30
28
|
|
31
|
-
from multidict import MultiDict
|
32
29
|
from yarl import URL
|
33
30
|
|
34
31
|
from ._compat import aio_cancel, aio_sleep, aio_spawn, aio_timeout, aio_wait
|
@@ -38,6 +35,8 @@ from .response import Response, ResponseJSON, ResponseWebSocket, parse_websocket
|
|
38
35
|
from .utils import CIMultiDict, parse_headers
|
39
36
|
|
40
37
|
if TYPE_CHECKING:
|
38
|
+
from multidict import MultiDict
|
39
|
+
|
41
40
|
from .types import TJSON, TASGIApp, TASGIMessage, TASGIReceive, TASGIScope, TASGISend
|
42
41
|
|
43
42
|
|
@@ -53,7 +52,7 @@ class TestResponse(Response):
|
|
53
52
|
msg = await self._receive()
|
54
53
|
assert msg.get("type") == "http.response.start", "Invalid Response"
|
55
54
|
self.status_code = int(msg.get("status", 502))
|
56
|
-
self.headers = cast(MultiDict, parse_headers(msg.get("headers", [])))
|
55
|
+
self.headers = cast("MultiDict", parse_headers(msg.get("headers", [])))
|
57
56
|
self.content_type = self.headers.get("content-type")
|
58
57
|
for cookie in self.headers.getall("set-cookie", []):
|
59
58
|
self.cookies.load(cookie)
|
@@ -123,7 +122,7 @@ class TestWebSocketResponse(ResponseWebSocket):
|
|
123
122
|
|
124
123
|
|
125
124
|
class ASGITestClient:
|
126
|
-
"""
|
125
|
+
"""Built-in test client for ASGI applications.
|
127
126
|
|
128
127
|
Features:
|
129
128
|
|
@@ -151,10 +150,10 @@ class ASGITestClient:
|
|
151
150
|
path: str,
|
152
151
|
method: str = "GET",
|
153
152
|
*,
|
154
|
-
query:
|
155
|
-
headers:
|
156
|
-
cookies:
|
157
|
-
data:
|
153
|
+
query: str | dict = "",
|
154
|
+
headers: dict[str, str] | None = None,
|
155
|
+
cookies: dict[str, str] | None = None,
|
156
|
+
data: bytes | str | dict | AsyncGenerator[Any, bytes] = b"",
|
158
157
|
json: TJSON = None,
|
159
158
|
follow_redirect: bool = True,
|
160
159
|
timeout: float = 10.0,
|
@@ -214,9 +213,9 @@ class ASGITestClient:
|
|
214
213
|
async def websocket(
|
215
214
|
self,
|
216
215
|
path: str,
|
217
|
-
query:
|
218
|
-
headers:
|
219
|
-
cookies:
|
216
|
+
query: str | dict | None = None,
|
217
|
+
headers: dict | None = None,
|
218
|
+
cookies: dict | None = None,
|
220
219
|
):
|
221
220
|
"""Connect to a websocket."""
|
222
221
|
pipe = Pipe()
|
@@ -250,9 +249,9 @@ class ASGITestClient:
|
|
250
249
|
def build_scope(
|
251
250
|
self,
|
252
251
|
path: str,
|
253
|
-
headers:
|
254
|
-
query:
|
255
|
-
cookies:
|
252
|
+
headers: dict | CIMultiDict | None = None,
|
253
|
+
query: str | dict | None = None,
|
254
|
+
cookies: dict | None = None,
|
256
255
|
**scope,
|
257
256
|
) -> TASGIScope:
|
258
257
|
"""Prepare a request scope."""
|
@@ -282,7 +281,7 @@ class ASGITestClient:
|
|
282
281
|
"query_string": url.raw_query_string.encode(),
|
283
282
|
"raw_path": url.raw_path.encode(),
|
284
283
|
"root_path": "",
|
285
|
-
"scheme": scope.get("type") == "http" and self.base_url.scheme or "ws",
|
284
|
+
"scheme": (scope.get("type") == "http" and self.base_url.scheme) or "ws",
|
286
285
|
"headers": [
|
287
286
|
(key.lower().encode(BASE_ENCODING), str(val).encode(BASE_ENCODING))
|
288
287
|
for key, val in (headers or {}).items()
|
@@ -321,11 +320,11 @@ def encode_multipart(data: dict) -> tuple[bytes, str]:
|
|
321
320
|
|
322
321
|
class Pipe:
|
323
322
|
__slots__ = (
|
324
|
-
"delay",
|
325
323
|
"app_is_closed",
|
326
|
-
"client_is_closed",
|
327
324
|
"app_queue",
|
325
|
+
"client_is_closed",
|
328
326
|
"client_queue",
|
327
|
+
"delay",
|
329
328
|
)
|
330
329
|
|
331
330
|
def __init__(self, delay: float = 1e-3):
|
@@ -366,7 +365,7 @@ class Pipe:
|
|
366
365
|
await aio_sleep(self.delay)
|
367
366
|
return self.app_queue.popleft()
|
368
367
|
|
369
|
-
async def stream(self, data:
|
368
|
+
async def stream(self, data: bytes | AsyncGenerator[Any, bytes]):
|
370
369
|
if isinstance(data, bytes):
|
371
370
|
return await self.send_to_app(
|
372
371
|
{"type": "http.request", "body": data, "more_body": False},
|
@@ -392,7 +391,7 @@ async def manage_lifespan(app, timeout: float = 3e-2):
|
|
392
391
|
async with aio_spawn(safe_spawn) as task:
|
393
392
|
await pipe.send_to_app({"type": "lifespan.startup"})
|
394
393
|
|
395
|
-
with suppress(TimeoutError, asyncio.TimeoutError): # python
|
394
|
+
with suppress(TimeoutError, asyncio.TimeoutError): # python 310
|
396
395
|
async with aio_timeout(timeout):
|
397
396
|
msg = await pipe.receive_from_client()
|
398
397
|
if msg["type"] == "lifespan.startup.failed":
|
@@ -401,6 +400,6 @@ async def manage_lifespan(app, timeout: float = 3e-2):
|
|
401
400
|
yield
|
402
401
|
|
403
402
|
await pipe.send_to_app({"type": "lifespan.shutdown"})
|
404
|
-
with suppress(TimeoutError, asyncio.TimeoutError): # python
|
403
|
+
with suppress(TimeoutError, asyncio.TimeoutError): # python 310
|
405
404
|
async with aio_timeout(timeout):
|
406
405
|
await pipe.receive_from_client()
|
asgi_tools/view.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import inspect
|
4
|
-
from typing import TYPE_CHECKING, Final
|
4
|
+
from typing import TYPE_CHECKING, Final
|
5
5
|
|
6
6
|
if TYPE_CHECKING:
|
7
7
|
from collections.abc import Awaitable
|
@@ -57,7 +57,7 @@ class HTTPView:
|
|
57
57
|
return self(request, **opts)
|
58
58
|
|
59
59
|
@classmethod
|
60
|
-
def __route__(cls, router: Router, *paths: str, methods:
|
60
|
+
def __route__(cls, router: Router, *paths: str, methods: TMethods | None = None, **params):
|
61
61
|
"""Bind the class view to the given router."""
|
62
62
|
view_methods = dict(inspect.getmembers(cls, inspect.isfunction))
|
63
63
|
methods = methods or [m for m in HTTP_METHODS if m.lower() in view_methods]
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: asgi-tools
|
3
|
-
Version: 1.1
|
3
|
+
Version: 1.3.1
|
4
4
|
Summary: ASGI Toolkit to build web applications
|
5
5
|
Author-email: Kirill Klenov <horneds@gmail.com>
|
6
6
|
License: MIT License
|
@@ -13,7 +13,6 @@ Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
14
14
|
Classifier: Programming Language :: Python
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
18
17
|
Classifier: Programming Language :: Python :: 3.11
|
19
18
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -23,41 +22,42 @@ Classifier: Programming Language :: Cython
|
|
23
22
|
Classifier: Topic :: Internet :: WWW/HTTP
|
24
23
|
Classifier: Framework :: AsyncIO
|
25
24
|
Classifier: Framework :: Trio
|
26
|
-
Requires-Python: >=3.
|
25
|
+
Requires-Python: >=3.10
|
27
26
|
Description-Content-Type: text/x-rst
|
28
27
|
License-File: LICENSE
|
29
28
|
Requires-Dist: http-router>=4.0.0
|
30
|
-
Requires-Dist: multidict
|
29
|
+
Requires-Dist: multidict>=6.6.3
|
31
30
|
Requires-Dist: sniffio
|
32
31
|
Requires-Dist: yarl>=1.8.2
|
33
32
|
Requires-Dist: async-timeout; python_version < "3.11"
|
34
|
-
Provides-Extra: dev
|
35
|
-
Requires-Dist: bump2version; extra == "dev"
|
36
|
-
Requires-Dist: tox; extra == "dev"
|
37
|
-
Requires-Dist: cython; extra == "dev"
|
38
|
-
Requires-Dist: pre-commit; extra == "dev"
|
39
|
-
Requires-Dist: sphinx; extra == "dev"
|
40
|
-
Requires-Dist: pydata-sphinx-theme; extra == "dev"
|
41
|
-
Provides-Extra: examples
|
42
|
-
Requires-Dist: uvicorn[standard]; extra == "examples"
|
43
|
-
Requires-Dist: jinja2; extra == "examples"
|
44
|
-
Requires-Dist: httpx; extra == "examples"
|
45
|
-
Provides-Extra: orjson
|
46
|
-
Requires-Dist: orjson; extra == "orjson"
|
47
33
|
Provides-Extra: tests
|
48
34
|
Requires-Dist: aiofile; extra == "tests"
|
49
35
|
Requires-Dist: pytest; extra == "tests"
|
50
|
-
Requires-Dist: pytest-aio[curio,trio]>=1.1
|
36
|
+
Requires-Dist: pytest-aio[curio,trio]>=1.3.1; extra == "tests"
|
51
37
|
Requires-Dist: pytest-benchmark; extra == "tests"
|
52
38
|
Requires-Dist: PyYAML; extra == "tests"
|
53
39
|
Requires-Dist: ruff; extra == "tests"
|
54
40
|
Requires-Dist: mypy; extra == "tests"
|
41
|
+
Requires-Dist: exceptiongroup; python_version < "3.11" and extra == "tests"
|
55
42
|
Requires-Dist: ujson; implementation_name == "cpython" and extra == "tests"
|
56
43
|
Requires-Dist: uvloop; implementation_name == "cpython" and extra == "tests"
|
57
44
|
Requires-Dist: pytest-mypy; implementation_name == "cpython" and extra == "tests"
|
58
|
-
Requires-Dist: exceptiongroup; python_version < "3.11" and extra == "tests"
|
59
45
|
Provides-Extra: ujson
|
60
46
|
Requires-Dist: ujson; extra == "ujson"
|
47
|
+
Provides-Extra: orjson
|
48
|
+
Requires-Dist: orjson; extra == "orjson"
|
49
|
+
Provides-Extra: examples
|
50
|
+
Requires-Dist: uvicorn[standard]; extra == "examples"
|
51
|
+
Requires-Dist: jinja2; extra == "examples"
|
52
|
+
Requires-Dist: httpx; extra == "examples"
|
53
|
+
Provides-Extra: dev
|
54
|
+
Requires-Dist: bump2version; extra == "dev"
|
55
|
+
Requires-Dist: tox; extra == "dev"
|
56
|
+
Requires-Dist: cython; extra == "dev"
|
57
|
+
Requires-Dist: pre-commit; extra == "dev"
|
58
|
+
Requires-Dist: sphinx; extra == "dev"
|
59
|
+
Requires-Dist: pydata-sphinx-theme; extra == "dev"
|
60
|
+
Dynamic: license-file
|
61
61
|
|
62
62
|
.. image:: https://raw.githubusercontent.com/klen/asgi-tools/develop/.github/assets/asgi-tools.png
|
63
63
|
:height: 100
|
@@ -124,7 +124,7 @@ For instance these middlewares were built with the library:
|
|
124
124
|
Requirements
|
125
125
|
=============
|
126
126
|
|
127
|
-
- python >= 3.
|
127
|
+
- python >= 3.10
|
128
128
|
|
129
129
|
.. note:: pypy3 is also supported
|
130
130
|
|
@@ -145,7 +145,7 @@ A Quick Example
|
|
145
145
|
|
146
146
|
You can use any of ASGI-Tools components independently.
|
147
147
|
|
148
|
-
|
148
|
+
Despite this ASGI-Tools contains App_ helper to quickly build ASGI
|
149
149
|
applications. For instance:
|
150
150
|
|
151
151
|
Save this to ``app.py``.
|
@@ -201,7 +201,7 @@ Licensed under a `MIT license`_.
|
|
201
201
|
.. _klen: https://github.com/klen
|
202
202
|
.. _uvicorn: http://www.uvicorn.org/
|
203
203
|
.. _daphne: https://github.com/django/daphne/
|
204
|
-
.. _hypercorn: https://
|
204
|
+
.. _hypercorn: https://github.com/pgjones/hypercorn/
|
205
205
|
|
206
206
|
.. _Request: https://klen.github.io/asgi-tools/api.html#request
|
207
207
|
.. _Response: https://klen.github.io/asgi-tools/api.html#responses
|
@@ -0,0 +1,29 @@
|
|
1
|
+
asgi_tools/multipart.py,sha256=8RkJm9JIjyjR7z2OIhYg8fgLKq21HBWCMEOwbhx-3GA,21707
|
2
|
+
asgi_tools/multipart.cpython-311-darwin.so,sha256=3FQ9ZQKmUmEHelNYRS-GnBZSc-m8eb8PUgQBE7hg4yE,310672
|
3
|
+
asgi_tools/multipart.pyx,sha256=pq-DzmAaRhS0yMJIFPNI-GP7OjJUt4k3Y8vMbXJOpKk,21929
|
4
|
+
asgi_tools/forms.c,sha256=v7t7ia5JTU68Eg1weG353v2IKfjQf_jTKUBSDmg8pgQ,826881
|
5
|
+
asgi_tools/multipart.c,sha256=EY4Z9r8PmtB-EuV7mI1evcyEGOFpKZCT-KeE5GPH2II,844007
|
6
|
+
asgi_tools/constants.py,sha256=B7fJabLdpSE4COX0vAudyC32xV0dSpLgg0kob-FlCkE,128
|
7
|
+
asgi_tools/request.py,sha256=s-CqT9JI-aPZz46YtKyvSDR7CfLxEhPrIuH9OG6npzk,10802
|
8
|
+
asgi_tools/__init__.py,sha256=tBnlggb3FJPK8tDrnpC580OfbQ0QpuKFRdyfxmIeu8w,1428
|
9
|
+
asgi_tools/response.py,sha256=-oePnVs5_lAjZWBgcVbdnhuStHMJoqnaqYS1Dqw3rFU,18494
|
10
|
+
asgi_tools/types.py,sha256=QWmrnhqc_jEUaXUcMm5iMpxpd6vrTcCnlq4O9moKANg,926
|
11
|
+
asgi_tools/forms.py,sha256=ers1A52YEAO1TBYWJP73K6q6jArNU7QbV0LjTlpKdeM,5059
|
12
|
+
asgi_tools/view.py,sha256=DO0Lr8euP98kMicDwmZLcbMpJ-Hzbhl3vYFYqAXpisw,1925
|
13
|
+
asgi_tools/utils.py,sha256=6qNwZbUsKatg75Gi1ltRsAeJhBaf1gwJkuR0LemitRw,2813
|
14
|
+
asgi_tools/logs.py,sha256=FaXJF5UYClU-JdqLL7VANxQ8O-eYAEemt0Zc_GaEC60,148
|
15
|
+
asgi_tools/app.py,sha256=OEkoRszSRJ9bwWQ3SKWm3Pv-R0B8uKcP9ciYsDMyCGg,10790
|
16
|
+
asgi_tools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
+
asgi_tools/errors.py,sha256=TTAtJL5w2EVm9dVNK2pqNBRWM1lGJXg7HnJTibjgkes,550
|
18
|
+
asgi_tools/multipart.pxd,sha256=bPnRLYuBw51OX7v-SZTOgOpb4PxM1MtR5dGWVoymX3A,725
|
19
|
+
asgi_tools/forms.pyx,sha256=ol1iEXDwS--9vNIoxFFvcTRvzUF14gQC3SDWW9K5-k8,5340
|
20
|
+
asgi_tools/router.py,sha256=1MCF5QLfYPWZH10AuXMRN0rTMTyQWciDSh3owgsFhk4,440
|
21
|
+
asgi_tools/_compat.py,sha256=3BTsysYhxa0itJzCWnzpnE-HuYGs7vXzZRgQRei0IW4,7483
|
22
|
+
asgi_tools/tests.py,sha256=elUGlBE8qklBzKAov1x1i0eVHfkFLzj5Oifd6_JjHv4,12944
|
23
|
+
asgi_tools/middleware.py,sha256=_hTALpm3Gv_3ssCyZfInzuFC8onNz2ZFVrDCdgOcnF8,15148
|
24
|
+
asgi_tools/forms.cpython-311-darwin.so,sha256=W3t96ID9UHa47I0hqodWLkjSffwTujFjysZPvc5kHp0,368880
|
25
|
+
asgi_tools-1.3.1.dist-info/RECORD,,
|
26
|
+
asgi_tools-1.3.1.dist-info/WHEEL,sha256=VWNc5NH4DDoQDkc74R-nMZPza3RGJ6ac2abjVbvC-0k,141
|
27
|
+
asgi_tools-1.3.1.dist-info/top_level.txt,sha256=-6i6ebKuJ0cSaXJ3KWPmJLKUbmBE2UsuA2b7BcZMJSk,11
|
28
|
+
asgi_tools-1.3.1.dist-info/METADATA,sha256=TRU5h3XpsqQiez8jDNuws_Vtwt_HGl9q7fifjNvXHdg,7139
|
29
|
+
asgi_tools-1.3.1.dist-info/licenses/LICENSE,sha256=ytogAgYcPT6gWj8aRc-cZwhSq9Y3wOzG-4KteKCyQOw,1070
|
@@ -1,29 +0,0 @@
|
|
1
|
-
asgi_tools/multipart.py,sha256=LNQzATAogrLEmr6Iu6ofRPbjoFZbIdyC1WeLyxxcMHA,21730
|
2
|
-
asgi_tools/multipart.cpython-311-darwin.so,sha256=mECyVFkEf7M3QLT_ok_v_X_qq46tIopIOW1ZyIx9ajE,308560
|
3
|
-
asgi_tools/multipart.pyx,sha256=pq-DzmAaRhS0yMJIFPNI-GP7OjJUt4k3Y8vMbXJOpKk,21929
|
4
|
-
asgi_tools/forms.c,sha256=0ONEEyzmLpS6MgbeLDz5D4dBEdBSsXpHNcpM8zHW_pU,816245
|
5
|
-
asgi_tools/multipart.c,sha256=biO6lYLL8Op7_Nzkg3CVt3Lrz6Bfl5Td5Z-KTMc_tlI,810039
|
6
|
-
asgi_tools/constants.py,sha256=B7fJabLdpSE4COX0vAudyC32xV0dSpLgg0kob-FlCkE,128
|
7
|
-
asgi_tools/request.py,sha256=1wJ6wq_lZaVxicu1YDSLwszfuZ4iyYa6z3FV2VLw0eg,10433
|
8
|
-
asgi_tools/__init__.py,sha256=ULbf6SyqMpqP_eKw8YvY45QjujIdDpSuYtaX8Gi12tU,1413
|
9
|
-
asgi_tools/response.py,sha256=UnZFWhiWGr5cxDGgu2l65xAez3NITjSOCyir_9gyFoo,18865
|
10
|
-
asgi_tools/types.py,sha256=QWmrnhqc_jEUaXUcMm5iMpxpd6vrTcCnlq4O9moKANg,926
|
11
|
-
asgi_tools/forms.py,sha256=r9J0suEl3GEuHX-MJUF-WT3lzyUZ69l3aQZOmbc9e_U,5091
|
12
|
-
asgi_tools/view.py,sha256=EgCWRjwO5IZ_VAK8s2FAK2yLLaAb9pQ4SNopIdST35U,1938
|
13
|
-
asgi_tools/utils.py,sha256=6qNwZbUsKatg75Gi1ltRsAeJhBaf1gwJkuR0LemitRw,2813
|
14
|
-
asgi_tools/logs.py,sha256=FaXJF5UYClU-JdqLL7VANxQ8O-eYAEemt0Zc_GaEC60,148
|
15
|
-
asgi_tools/app.py,sha256=zMg_R3lAnpzWfHzWkByR2msG9wKZAtECxEbtyJR_h8s,8111
|
16
|
-
asgi_tools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
asgi_tools/errors.py,sha256=TTAtJL5w2EVm9dVNK2pqNBRWM1lGJXg7HnJTibjgkes,550
|
18
|
-
asgi_tools/multipart.pxd,sha256=bPnRLYuBw51OX7v-SZTOgOpb4PxM1MtR5dGWVoymX3A,725
|
19
|
-
asgi_tools/forms.pyx,sha256=ol1iEXDwS--9vNIoxFFvcTRvzUF14gQC3SDWW9K5-k8,5340
|
20
|
-
asgi_tools/router.py,sha256=1MCF5QLfYPWZH10AuXMRN0rTMTyQWciDSh3owgsFhk4,440
|
21
|
-
asgi_tools/_compat.py,sha256=VHX73I6sKdhb0LyhShOddDNg5FlUZqODPFsQWlpZvTA,7523
|
22
|
-
asgi_tools/tests.py,sha256=xYDwDKooByo2b3DN7J1g4-rwzv9XAQ7hp_Bou-vhHM0,13043
|
23
|
-
asgi_tools/middleware.py,sha256=1gvvV7v4lO6LceqP36bZFpFvb-hEfSAvyH2_IzahKes,15003
|
24
|
-
asgi_tools/forms.cpython-311-darwin.so,sha256=c5DV7HqA-E5s4jAazlB1ZMJiXrGD1K2ZvBngCrx1h8E,383008
|
25
|
-
asgi_tools-1.1.0.dist-info/RECORD,,
|
26
|
-
asgi_tools-1.1.0.dist-info/LICENSE,sha256=ytogAgYcPT6gWj8aRc-cZwhSq9Y3wOzG-4KteKCyQOw,1070
|
27
|
-
asgi_tools-1.1.0.dist-info/WHEEL,sha256=pMJUQq7r6lG7OYeH6nBWcsfgc5PgMyySSuf8LR--6yU,114
|
28
|
-
asgi_tools-1.1.0.dist-info/top_level.txt,sha256=-6i6ebKuJ0cSaXJ3KWPmJLKUbmBE2UsuA2b7BcZMJSk,11
|
29
|
-
asgi_tools-1.1.0.dist-info/METADATA,sha256=3O8KNeCEsQLDBlXEm_3Bc2YQhgGYJ2AKiThvLC_6AXg,7157
|
File without changes
|
File without changes
|