uvicorn 0.31.1__tar.gz → 0.32.0__tar.gz
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.
- {uvicorn-0.31.1 → uvicorn-0.32.0}/PKG-INFO +2 -1
- {uvicorn-0.31.1 → uvicorn-0.32.0}/pyproject.toml +1 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_server.py +27 -1
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/__init__.py +1 -1
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/server.py +6 -2
- {uvicorn-0.31.1 → uvicorn-0.32.0}/.gitignore +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/LICENSE.md +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/README.md +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/requirements.txt +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/conftest.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/importer/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/importer/circular_import_a.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/importer/circular_import_b.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/importer/raise_import_error.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/importer/test_importer.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/middleware/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/middleware/test_logging.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/middleware/test_message_logger.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/middleware/test_proxy_headers.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/middleware/test_wsgi.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/protocols/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/protocols/test_http.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/protocols/test_utils.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/protocols/test_websocket.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/response.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/supervisors/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/supervisors/test_multiprocess.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/supervisors/test_reload.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/supervisors/test_signal.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_auto_detection.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_cli.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_config.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_default_headers.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_lifespan.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_main.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_ssl.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/test_subprocess.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/tests/utils.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/__main__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/_subprocess.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/_types.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/config.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/importer.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/lifespan/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/lifespan/off.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/lifespan/on.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/logging.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/loops/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/loops/asyncio.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/loops/auto.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/loops/uvloop.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/main.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/middleware/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/middleware/asgi2.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/middleware/message_logger.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/middleware/proxy_headers.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/middleware/wsgi.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/http/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/http/auto.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/http/flow_control.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/http/h11_impl.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/http/httptools_impl.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/utils.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/websockets/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/websockets/auto.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/websockets/websockets_impl.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/protocols/websockets/wsproto_impl.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/py.typed +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/__init__.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/basereload.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/multiprocess.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/statreload.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/watchfilesreload.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/supervisors/watchgodreload.py +0 -0
- {uvicorn-0.31.1 → uvicorn-0.32.0}/uvicorn/workers.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: uvicorn
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.32.0
|
4
4
|
Summary: The lightning-fast ASGI server.
|
5
5
|
Project-URL: Changelog, https://github.com/encode/uvicorn/blob/master/CHANGELOG.md
|
6
6
|
Project-URL: Funding, https://github.com/sponsors/encode
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
23
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
24
25
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
25
26
|
Classifier: Topic :: Internet :: WWW/HTTP
|
@@ -25,6 +25,7 @@ classifiers = [
|
|
25
25
|
"Programming Language :: Python :: 3.10",
|
26
26
|
"Programming Language :: Python :: 3.11",
|
27
27
|
"Programming Language :: Python :: 3.12",
|
28
|
+
"Programming Language :: Python :: 3.13",
|
28
29
|
"Programming Language :: Python :: Implementation :: CPython",
|
29
30
|
"Programming Language :: Python :: Implementation :: PyPy",
|
30
31
|
"Topic :: Internet :: WWW/HTTP",
|
@@ -2,15 +2,23 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import asyncio
|
4
4
|
import contextlib
|
5
|
+
import logging
|
5
6
|
import signal
|
6
7
|
import sys
|
7
8
|
from typing import Callable, ContextManager, Generator
|
8
9
|
|
10
|
+
import httpx
|
9
11
|
import pytest
|
10
12
|
|
13
|
+
from tests.utils import run_server
|
14
|
+
from uvicorn._types import ASGIReceiveCallable, ASGISendCallable, Scope
|
11
15
|
from uvicorn.config import Config
|
16
|
+
from uvicorn.protocols.http.h11_impl import H11Protocol
|
17
|
+
from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol
|
12
18
|
from uvicorn.server import Server
|
13
19
|
|
20
|
+
pytestmark = pytest.mark.anyio
|
21
|
+
|
14
22
|
|
15
23
|
# asyncio does NOT allow raising in signal handlers, so to detect
|
16
24
|
# raised signals raised a mutable `witness` receives the signal
|
@@ -37,6 +45,12 @@ async def dummy_app(scope, receive, send): # pragma: py-win32
|
|
37
45
|
pass
|
38
46
|
|
39
47
|
|
48
|
+
async def app(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
|
49
|
+
assert scope["type"] == "http"
|
50
|
+
await send({"type": "http.response.start", "status": 200, "headers": []})
|
51
|
+
await send({"type": "http.response.body", "body": b"", "more_body": False})
|
52
|
+
|
53
|
+
|
40
54
|
if sys.platform == "win32": # pragma: py-not-win32
|
41
55
|
signals = [signal.SIGBREAK]
|
42
56
|
signal_captures = [capture_signal_sync]
|
@@ -45,7 +59,6 @@ else: # pragma: py-win32
|
|
45
59
|
signal_captures = [capture_signal_sync, capture_signal_async]
|
46
60
|
|
47
61
|
|
48
|
-
@pytest.mark.anyio
|
49
62
|
@pytest.mark.parametrize("exception_signal", signals)
|
50
63
|
@pytest.mark.parametrize("capture_signal", signal_captures)
|
51
64
|
async def test_server_interrupt(
|
@@ -65,3 +78,16 @@ async def test_server_interrupt(
|
|
65
78
|
assert witness
|
66
79
|
# set by the server's graceful exit handler
|
67
80
|
assert server.should_exit
|
81
|
+
|
82
|
+
|
83
|
+
async def test_request_than_limit_max_requests_warn_log(
|
84
|
+
unused_tcp_port: int, http_protocol_cls: type[H11Protocol | HttpToolsProtocol], caplog: pytest.LogCaptureFixture
|
85
|
+
):
|
86
|
+
caplog.set_level(logging.WARNING, logger="uvicorn.error")
|
87
|
+
config = Config(app=app, limit_max_requests=1, port=unused_tcp_port, http=http_protocol_cls)
|
88
|
+
async with run_server(config):
|
89
|
+
async with httpx.AsyncClient() as client:
|
90
|
+
tasks = [client.get(f"http://127.0.0.1:{unused_tcp_port}") for _ in range(2)]
|
91
|
+
responses = await asyncio.gather(*tasks)
|
92
|
+
assert len(responses) == 2
|
93
|
+
assert "Maximum request limit of 1 exceeded. Terminating process." in caplog.text
|
@@ -250,8 +250,12 @@ class Server:
|
|
250
250
|
# Determine if we should exit.
|
251
251
|
if self.should_exit:
|
252
252
|
return True
|
253
|
-
|
254
|
-
|
253
|
+
|
254
|
+
max_requests = self.config.limit_max_requests
|
255
|
+
if max_requests is not None and self.server_state.total_requests >= max_requests:
|
256
|
+
logger.warning(f"Maximum request limit of {max_requests} exceeded. Terminating process.")
|
257
|
+
return True
|
258
|
+
|
255
259
|
return False
|
256
260
|
|
257
261
|
async def shutdown(self, sockets: list[socket.socket] | None = None) -> None:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|