summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/uvicorn
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/uvicorn')
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__init__.py5
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__main__.py4
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/__init__.cpython-311.pycbin428 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/__main__.cpython-311.pycbin317 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/_subprocess.cpython-311.pycbin2994 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/_types.cpython-311.pycbin13675 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/config.cpython-311.pycbin25835 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/importer.cpython-311.pycbin2033 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/logging.cpython-311.pycbin8607 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/main.cpython-311.pycbin19857 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/server.cpython-311.pycbin16865 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/__pycache__/workers.cpython-311.pycbin6538 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/_subprocess.py78
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/_types.py293
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/config.py528
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/importer.py34
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-311.pycbin200 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/off.cpython-311.pycbin1155 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/on.cpython-311.pycbin8386 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/off.py17
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/lifespan/on.py137
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/logging.py117
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/__init__.cpython-311.pycbin197 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-311.pycbin816 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/auto.cpython-311.pycbin787 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-311.pycbin590 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/asyncio.py10
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/auto.py11
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/loops/uvloop.py7
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/main.py584
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-311.pycbin202 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-311.pycbin1219 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-311.pycbin4905 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-311.pycbin4331 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-311.pycbin10902 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/asgi2.py15
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py87
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py69
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/middleware/wsgi.py200
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-311.pycbin201 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/utils.cpython-311.pycbin3585 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-311.pycbin206 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-311.pycbin705 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-311.pycbin3410 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-311.pycbin27291 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-311.pycbin30083 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/auto.py15
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/flow_control.py64
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py547
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py575
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/utils.py57
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-311.pycbin212 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-311.pycbin924 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-311.pycbin22107 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-311.pycbin22222 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/auto.py21
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/websockets_impl.py388
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/wsproto_impl.py377
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/py.typed1
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/server.py335
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__init__.py23
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-311.pycbin1115 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-311.pycbin7329 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-311.pycbin4430 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-311.pycbin3238 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-311.pycbin5554 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchgodreload.cpython-311.pycbin8488 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/basereload.py121
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/multiprocess.py70
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/statreload.py52
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/watchfilesreload.py88
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/supervisors/watchgodreload.py152
-rw-r--r--venv/lib/python3.11/site-packages/uvicorn/workers.py107
79 files changed, 0 insertions, 5189 deletions
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/__init__.py
deleted file mode 100644
index 4df960e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from uvicorn.config import Config
-from uvicorn.main import Server, main, run
-
-__version__ = "0.29.0"
-__all__ = ["main", "run", "Config", "Server"]
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__main__.py b/venv/lib/python3.11/site-packages/uvicorn/__main__.py
deleted file mode 100644
index 8a1dc97..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__main__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import uvicorn
-
-if __name__ == "__main__":
- uvicorn.main()
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index ca2251a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__main__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__main__.cpython-311.pyc
deleted file mode 100644
index b9b0e05..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/__main__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_subprocess.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_subprocess.cpython-311.pyc
deleted file mode 100644
index 315201a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_subprocess.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_types.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_types.cpython-311.pyc
deleted file mode 100644
index 9273f99..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/_types.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/config.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/config.cpython-311.pyc
deleted file mode 100644
index 95e5ab1..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/config.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/importer.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/importer.cpython-311.pyc
deleted file mode 100644
index 3faca2d..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/importer.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/logging.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/logging.cpython-311.pyc
deleted file mode 100644
index dd70008..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/logging.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/main.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/main.cpython-311.pyc
deleted file mode 100644
index 89edd30..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/main.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/server.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/server.cpython-311.pyc
deleted file mode 100644
index 6244d66..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/server.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/workers.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/__pycache__/workers.cpython-311.pyc
deleted file mode 100644
index d0ff7eb..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/__pycache__/workers.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/_subprocess.py b/venv/lib/python3.11/site-packages/uvicorn/_subprocess.py
deleted file mode 100644
index 5eb8353..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/_subprocess.py
+++ /dev/null
@@ -1,78 +0,0 @@
-"""
-Some light wrappers around Python's multiprocessing, to deal with cleanly
-starting child processes.
-"""
-from __future__ import annotations
-
-import multiprocessing
-import os
-import sys
-from multiprocessing.context import SpawnProcess
-from socket import socket
-from typing import Callable
-
-from uvicorn.config import Config
-
-multiprocessing.allow_connection_pickling()
-spawn = multiprocessing.get_context("spawn")
-
-
-def get_subprocess(
- config: Config,
- target: Callable[..., None],
- sockets: list[socket],
-) -> SpawnProcess:
- """
- Called in the parent process, to instantiate a new child process instance.
- The child is not yet started at this point.
-
- * config - The Uvicorn configuration instance.
- * target - A callable that accepts a list of sockets. In practice this will
- be the `Server.run()` method.
- * sockets - A list of sockets to pass to the server. Sockets are bound once
- by the parent process, and then passed to the child processes.
- """
- # We pass across the stdin fileno, and reopen it in the child process.
- # This is required for some debugging environments.
- try:
- stdin_fileno = sys.stdin.fileno()
- # The `sys.stdin` can be `None`, see https://docs.python.org/3/library/sys.html#sys.__stdin__.
- except (AttributeError, OSError):
- stdin_fileno = None
-
- kwargs = {
- "config": config,
- "target": target,
- "sockets": sockets,
- "stdin_fileno": stdin_fileno,
- }
-
- return spawn.Process(target=subprocess_started, kwargs=kwargs)
-
-
-def subprocess_started(
- config: Config,
- target: Callable[..., None],
- sockets: list[socket],
- stdin_fileno: int | None,
-) -> None:
- """
- Called when the child process starts.
-
- * config - The Uvicorn configuration instance.
- * target - A callable that accepts a list of sockets. In practice this will
- be the `Server.run()` method.
- * sockets - A list of sockets to pass to the server. Sockets are bound once
- by the parent process, and then passed to the child processes.
- * stdin_fileno - The file number of sys.stdin, so that it can be reattached
- to the child process.
- """
- # Re-open stdin.
- if stdin_fileno is not None:
- sys.stdin = os.fdopen(stdin_fileno)
-
- # Logging needs to be setup again for each child.
- config.configure_logging()
-
- # Now we can call into `Server.run(sockets=sockets)`
- target(sockets=sockets)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/_types.py b/venv/lib/python3.11/site-packages/uvicorn/_types.py
deleted file mode 100644
index 7546262..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/_types.py
+++ /dev/null
@@ -1,293 +0,0 @@
-"""
-Copyright (c) Django Software Foundation and individual contributors.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of Django nor the names of its contributors may be used
- to endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""
-from __future__ import annotations
-
-import sys
-import types
-from typing import (
- Any,
- Awaitable,
- Callable,
- Iterable,
- Literal,
- MutableMapping,
- Optional,
- Protocol,
- Tuple,
- Type,
- TypedDict,
- Union,
-)
-
-if sys.version_info >= (3, 11): # pragma: py-lt-311
- from typing import NotRequired
-else: # pragma: py-gte-311
- from typing_extensions import NotRequired
-
-# WSGI
-Environ = MutableMapping[str, Any]
-ExcInfo = Tuple[Type[BaseException], BaseException, Optional[types.TracebackType]]
-StartResponse = Callable[[str, Iterable[Tuple[str, str]], Optional[ExcInfo]], None]
-WSGIApp = Callable[[Environ, StartResponse], Union[Iterable[bytes], BaseException]]
-
-
-# ASGI
-class ASGIVersions(TypedDict):
- spec_version: str
- version: Literal["2.0"] | Literal["3.0"]
-
-
-class HTTPScope(TypedDict):
- type: Literal["http"]
- asgi: ASGIVersions
- http_version: str
- method: str
- scheme: str
- path: str
- raw_path: bytes
- query_string: bytes
- root_path: str
- headers: Iterable[tuple[bytes, bytes]]
- client: tuple[str, int] | None
- server: tuple[str, int | None] | None
- state: NotRequired[dict[str, Any]]
- extensions: NotRequired[dict[str, dict[object, object]]]
-
-
-class WebSocketScope(TypedDict):
- type: Literal["websocket"]
- asgi: ASGIVersions
- http_version: str
- scheme: str
- path: str
- raw_path: bytes
- query_string: bytes
- root_path: str
- headers: Iterable[tuple[bytes, bytes]]
- client: tuple[str, int] | None
- server: tuple[str, int | None] | None
- subprotocols: Iterable[str]
- state: NotRequired[dict[str, Any]]
- extensions: NotRequired[dict[str, dict[object, object]]]
-
-
-class LifespanScope(TypedDict):
- type: Literal["lifespan"]
- asgi: ASGIVersions
- state: NotRequired[dict[str, Any]]
-
-
-WWWScope = Union[HTTPScope, WebSocketScope]
-Scope = Union[HTTPScope, WebSocketScope, LifespanScope]
-
-
-class HTTPRequestEvent(TypedDict):
- type: Literal["http.request"]
- body: bytes
- more_body: bool
-
-
-class HTTPResponseDebugEvent(TypedDict):
- type: Literal["http.response.debug"]
- info: dict[str, object]
-
-
-class HTTPResponseStartEvent(TypedDict):
- type: Literal["http.response.start"]
- status: int
- headers: NotRequired[Iterable[tuple[bytes, bytes]]]
- trailers: NotRequired[bool]
-
-
-class HTTPResponseBodyEvent(TypedDict):
- type: Literal["http.response.body"]
- body: bytes
- more_body: NotRequired[bool]
-
-
-class HTTPResponseTrailersEvent(TypedDict):
- type: Literal["http.response.trailers"]
- headers: Iterable[tuple[bytes, bytes]]
- more_trailers: bool
-
-
-class HTTPServerPushEvent(TypedDict):
- type: Literal["http.response.push"]
- path: str
- headers: Iterable[tuple[bytes, bytes]]
-
-
-class HTTPDisconnectEvent(TypedDict):
- type: Literal["http.disconnect"]
-
-
-class WebSocketConnectEvent(TypedDict):
- type: Literal["websocket.connect"]
-
-
-class WebSocketAcceptEvent(TypedDict):
- type: Literal["websocket.accept"]
- subprotocol: NotRequired[str | None]
- headers: NotRequired[Iterable[tuple[bytes, bytes]]]
-
-
-class _WebSocketReceiveEventBytes(TypedDict):
- type: Literal["websocket.receive"]
- bytes: bytes
- text: NotRequired[None]
-
-
-class _WebSocketReceiveEventText(TypedDict):
- type: Literal["websocket.receive"]
- bytes: NotRequired[None]
- text: str
-
-
-WebSocketReceiveEvent = Union[_WebSocketReceiveEventBytes, _WebSocketReceiveEventText]
-
-
-class _WebSocketSendEventBytes(TypedDict):
- type: Literal["websocket.send"]
- bytes: bytes
- text: NotRequired[None]
-
-
-class _WebSocketSendEventText(TypedDict):
- type: Literal["websocket.send"]
- bytes: NotRequired[None]
- text: str
-
-
-WebSocketSendEvent = Union[_WebSocketSendEventBytes, _WebSocketSendEventText]
-
-
-class WebSocketResponseStartEvent(TypedDict):
- type: Literal["websocket.http.response.start"]
- status: int
- headers: Iterable[tuple[bytes, bytes]]
-
-
-class WebSocketResponseBodyEvent(TypedDict):
- type: Literal["websocket.http.response.body"]
- body: bytes
- more_body: NotRequired[bool]
-
-
-class WebSocketDisconnectEvent(TypedDict):
- type: Literal["websocket.disconnect"]
- code: int
-
-
-class WebSocketCloseEvent(TypedDict):
- type: Literal["websocket.close"]
- code: NotRequired[int]
- reason: NotRequired[str | None]
-
-
-class LifespanStartupEvent(TypedDict):
- type: Literal["lifespan.startup"]
-
-
-class LifespanShutdownEvent(TypedDict):
- type: Literal["lifespan.shutdown"]
-
-
-class LifespanStartupCompleteEvent(TypedDict):
- type: Literal["lifespan.startup.complete"]
-
-
-class LifespanStartupFailedEvent(TypedDict):
- type: Literal["lifespan.startup.failed"]
- message: str
-
-
-class LifespanShutdownCompleteEvent(TypedDict):
- type: Literal["lifespan.shutdown.complete"]
-
-
-class LifespanShutdownFailedEvent(TypedDict):
- type: Literal["lifespan.shutdown.failed"]
- message: str
-
-
-WebSocketEvent = Union[WebSocketReceiveEvent, WebSocketDisconnectEvent, WebSocketConnectEvent]
-
-
-ASGIReceiveEvent = Union[
- HTTPRequestEvent,
- HTTPDisconnectEvent,
- WebSocketConnectEvent,
- WebSocketReceiveEvent,
- WebSocketDisconnectEvent,
- LifespanStartupEvent,
- LifespanShutdownEvent,
-]
-
-
-ASGISendEvent = Union[
- HTTPResponseStartEvent,
- HTTPResponseBodyEvent,
- HTTPResponseTrailersEvent,
- HTTPServerPushEvent,
- HTTPDisconnectEvent,
- WebSocketAcceptEvent,
- WebSocketSendEvent,
- WebSocketResponseStartEvent,
- WebSocketResponseBodyEvent,
- WebSocketCloseEvent,
- LifespanStartupCompleteEvent,
- LifespanStartupFailedEvent,
- LifespanShutdownCompleteEvent,
- LifespanShutdownFailedEvent,
-]
-
-
-ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]]
-ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]]
-
-
-class ASGI2Protocol(Protocol):
- def __init__(self, scope: Scope) -> None:
- ... # pragma: no cover
-
- async def __call__(self, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
- ... # pragma: no cover
-
-
-ASGI2Application = Type[ASGI2Protocol]
-ASGI3Application = Callable[
- [
- Scope,
- ASGIReceiveCallable,
- ASGISendCallable,
- ],
- Awaitable[None],
-]
-ASGIApplication = Union[ASGI2Application, ASGI3Application]
diff --git a/venv/lib/python3.11/site-packages/uvicorn/config.py b/venv/lib/python3.11/site-packages/uvicorn/config.py
deleted file mode 100644
index 3cad1d9..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/config.py
+++ /dev/null
@@ -1,528 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import inspect
-import json
-import logging
-import logging.config
-import os
-import socket
-import ssl
-import sys
-from pathlib import Path
-from typing import Any, Awaitable, Callable, Literal
-
-import click
-
-from uvicorn._types import ASGIApplication
-from uvicorn.importer import ImportFromStringError, import_from_string
-from uvicorn.logging import TRACE_LOG_LEVEL
-from uvicorn.middleware.asgi2 import ASGI2Middleware
-from uvicorn.middleware.message_logger import MessageLoggerMiddleware
-from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
-from uvicorn.middleware.wsgi import WSGIMiddleware
-
-HTTPProtocolType = Literal["auto", "h11", "httptools"]
-WSProtocolType = Literal["auto", "none", "websockets", "wsproto"]
-LifespanType = Literal["auto", "on", "off"]
-LoopSetupType = Literal["none", "auto", "asyncio", "uvloop"]
-InterfaceType = Literal["auto", "asgi3", "asgi2", "wsgi"]
-
-LOG_LEVELS: dict[str, int] = {
- "critical": logging.CRITICAL,
- "error": logging.ERROR,
- "warning": logging.WARNING,
- "info": logging.INFO,
- "debug": logging.DEBUG,
- "trace": TRACE_LOG_LEVEL,
-}
-HTTP_PROTOCOLS: dict[HTTPProtocolType, str] = {
- "auto": "uvicorn.protocols.http.auto:AutoHTTPProtocol",
- "h11": "uvicorn.protocols.http.h11_impl:H11Protocol",
- "httptools": "uvicorn.protocols.http.httptools_impl:HttpToolsProtocol",
-}
-WS_PROTOCOLS: dict[WSProtocolType, str | None] = {
- "auto": "uvicorn.protocols.websockets.auto:AutoWebSocketsProtocol",
- "none": None,
- "websockets": "uvicorn.protocols.websockets.websockets_impl:WebSocketProtocol",
- "wsproto": "uvicorn.protocols.websockets.wsproto_impl:WSProtocol",
-}
-LIFESPAN: dict[LifespanType, str] = {
- "auto": "uvicorn.lifespan.on:LifespanOn",
- "on": "uvicorn.lifespan.on:LifespanOn",
- "off": "uvicorn.lifespan.off:LifespanOff",
-}
-LOOP_SETUPS: dict[LoopSetupType, str | None] = {
- "none": None,
- "auto": "uvicorn.loops.auto:auto_loop_setup",
- "asyncio": "uvicorn.loops.asyncio:asyncio_setup",
- "uvloop": "uvicorn.loops.uvloop:uvloop_setup",
-}
-INTERFACES: list[InterfaceType] = ["auto", "asgi3", "asgi2", "wsgi"]
-
-SSL_PROTOCOL_VERSION: int = ssl.PROTOCOL_TLS_SERVER
-
-LOGGING_CONFIG: dict[str, Any] = {
- "version": 1,
- "disable_existing_loggers": False,
- "formatters": {
- "default": {
- "()": "uvicorn.logging.DefaultFormatter",
- "fmt": "%(levelprefix)s %(message)s",
- "use_colors": None,
- },
- "access": {
- "()": "uvicorn.logging.AccessFormatter",
- "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501
- },
- },
- "handlers": {
- "default": {
- "formatter": "default",
- "class": "logging.StreamHandler",
- "stream": "ext://sys.stderr",
- },
- "access": {
- "formatter": "access",
- "class": "logging.StreamHandler",
- "stream": "ext://sys.stdout",
- },
- },
- "loggers": {
- "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},
- "uvicorn.error": {"level": "INFO"},
- "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
- },
-}
-
-logger = logging.getLogger("uvicorn.error")
-
-
-def create_ssl_context(
- certfile: str | os.PathLike[str],
- keyfile: str | os.PathLike[str] | None,
- password: str | None,
- ssl_version: int,
- cert_reqs: int,
- ca_certs: str | os.PathLike[str] | None,
- ciphers: str | None,
-) -> ssl.SSLContext:
- ctx = ssl.SSLContext(ssl_version)
- get_password = (lambda: password) if password else None
- ctx.load_cert_chain(certfile, keyfile, get_password)
- ctx.verify_mode = ssl.VerifyMode(cert_reqs)
- if ca_certs:
- ctx.load_verify_locations(ca_certs)
- if ciphers:
- ctx.set_ciphers(ciphers)
- return ctx
-
-
-def is_dir(path: Path) -> bool:
- try:
- if not path.is_absolute():
- path = path.resolve()
- return path.is_dir()
- except OSError:
- return False
-
-
-def resolve_reload_patterns(patterns_list: list[str], directories_list: list[str]) -> tuple[list[str], list[Path]]:
- directories: list[Path] = list(set(map(Path, directories_list.copy())))
- patterns: list[str] = patterns_list.copy()
-
- current_working_directory = Path.cwd()
- for pattern in patterns_list:
- # Special case for the .* pattern, otherwise this would only match
- # hidden directories which is probably undesired
- if pattern == ".*":
- continue
- patterns.append(pattern)
- if is_dir(Path(pattern)):
- directories.append(Path(pattern))
- else:
- for match in current_working_directory.glob(pattern):
- if is_dir(match):
- directories.append(match)
-
- directories = list(set(directories))
- directories = list(map(Path, directories))
- directories = list(map(lambda x: x.resolve(), directories))
- directories = list({reload_path for reload_path in directories if is_dir(reload_path)})
-
- children = []
- for j in range(len(directories)):
- for k in range(j + 1, len(directories)):
- if directories[j] in directories[k].parents:
- children.append(directories[k]) # pragma: py-darwin
- elif directories[k] in directories[j].parents:
- children.append(directories[j])
-
- directories = list(set(directories).difference(set(children)))
-
- return list(set(patterns)), directories
-
-
-def _normalize_dirs(dirs: list[str] | str | None) -> list[str]:
- if dirs is None:
- return []
- if isinstance(dirs, str):
- return [dirs]
- return list(set(dirs))
-
-
-class Config:
- def __init__(
- self,
- app: ASGIApplication | Callable[..., Any] | str,
- host: str = "127.0.0.1",
- port: int = 8000,
- uds: str | None = None,
- fd: int | None = None,
- loop: LoopSetupType = "auto",
- http: type[asyncio.Protocol] | HTTPProtocolType = "auto",
- ws: type[asyncio.Protocol] | WSProtocolType = "auto",
- ws_max_size: int = 16 * 1024 * 1024,
- ws_max_queue: int = 32,
- ws_ping_interval: float | None = 20.0,
- ws_ping_timeout: float | None = 20.0,
- ws_per_message_deflate: bool = True,
- lifespan: LifespanType = "auto",
- env_file: str | os.PathLike[str] | None = None,
- log_config: dict[str, Any] | str | None = LOGGING_CONFIG,
- log_level: str | int | None = None,
- access_log: bool = True,
- use_colors: bool | None = None,
- interface: InterfaceType = "auto",
- reload: bool = False,
- reload_dirs: list[str] | str | None = None,
- reload_delay: float = 0.25,
- reload_includes: list[str] | str | None = None,
- reload_excludes: list[str] | str | None = None,
- workers: int | None = None,
- proxy_headers: bool = True,
- server_header: bool = True,
- date_header: bool = True,
- forwarded_allow_ips: list[str] | str | None = None,
- root_path: str = "",
- limit_concurrency: int | None = None,
- limit_max_requests: int | None = None,
- backlog: int = 2048,
- timeout_keep_alive: int = 5,
- timeout_notify: int = 30,
- timeout_graceful_shutdown: int | None = None,
- callback_notify: Callable[..., Awaitable[None]] | None = None,
- ssl_keyfile: str | None = None,
- ssl_certfile: str | os.PathLike[str] | None = None,
- ssl_keyfile_password: str | None = None,
- ssl_version: int = SSL_PROTOCOL_VERSION,
- ssl_cert_reqs: int = ssl.CERT_NONE,
- ssl_ca_certs: str | None = None,
- ssl_ciphers: str = "TLSv1",
- headers: list[tuple[str, str]] | None = None,
- factory: bool = False,
- h11_max_incomplete_event_size: int | None = None,
- ):
- self.app = app
- self.host = host
- self.port = port
- self.uds = uds
- self.fd = fd
- self.loop = loop
- self.http = http
- self.ws = ws
- self.ws_max_size = ws_max_size
- self.ws_max_queue = ws_max_queue
- self.ws_ping_interval = ws_ping_interval
- self.ws_ping_timeout = ws_ping_timeout
- self.ws_per_message_deflate = ws_per_message_deflate
- self.lifespan = lifespan
- self.log_config = log_config
- self.log_level = log_level
- self.access_log = access_log
- self.use_colors = use_colors
- self.interface = interface
- self.reload = reload
- self.reload_delay = reload_delay
- self.workers = workers or 1
- self.proxy_headers = proxy_headers
- self.server_header = server_header
- self.date_header = date_header
- self.root_path = root_path
- self.limit_concurrency = limit_concurrency
- self.limit_max_requests = limit_max_requests
- self.backlog = backlog
- self.timeout_keep_alive = timeout_keep_alive
- self.timeout_notify = timeout_notify
- self.timeout_graceful_shutdown = timeout_graceful_shutdown
- self.callback_notify = callback_notify
- self.ssl_keyfile = ssl_keyfile
- self.ssl_certfile = ssl_certfile
- self.ssl_keyfile_password = ssl_keyfile_password
- self.ssl_version = ssl_version
- self.ssl_cert_reqs = ssl_cert_reqs
- self.ssl_ca_certs = ssl_ca_certs
- self.ssl_ciphers = ssl_ciphers
- self.headers: list[tuple[str, str]] = headers or []
- self.encoded_headers: list[tuple[bytes, bytes]] = []
- self.factory = factory
- self.h11_max_incomplete_event_size = h11_max_incomplete_event_size
-
- self.loaded = False
- self.configure_logging()
-
- self.reload_dirs: list[Path] = []
- self.reload_dirs_excludes: list[Path] = []
- self.reload_includes: list[str] = []
- self.reload_excludes: list[str] = []
-
- if (reload_dirs or reload_includes or reload_excludes) and not self.should_reload:
- logger.warning(
- "Current configuration will not reload as not all conditions are met, " "please refer to documentation."
- )
-
- if self.should_reload:
- reload_dirs = _normalize_dirs(reload_dirs)
- reload_includes = _normalize_dirs(reload_includes)
- reload_excludes = _normalize_dirs(reload_excludes)
-
- self.reload_includes, self.reload_dirs = resolve_reload_patterns(reload_includes, reload_dirs)
-
- self.reload_excludes, self.reload_dirs_excludes = resolve_reload_patterns(reload_excludes, [])
-
- reload_dirs_tmp = self.reload_dirs.copy()
-
- for directory in self.reload_dirs_excludes:
- for reload_directory in reload_dirs_tmp:
- if directory == reload_directory or directory in reload_directory.parents:
- try:
- self.reload_dirs.remove(reload_directory)
- except ValueError:
- pass
-
- for pattern in self.reload_excludes:
- if pattern in self.reload_includes:
- self.reload_includes.remove(pattern)
-
- if not self.reload_dirs:
- if reload_dirs:
- logger.warning(
- "Provided reload directories %s did not contain valid "
- + "directories, watching current working directory.",
- reload_dirs,
- )
- self.reload_dirs = [Path(os.getcwd())]
-
- logger.info(
- "Will watch for changes in these directories: %s",
- sorted(list(map(str, self.reload_dirs))),
- )
-
- if env_file is not None:
- from dotenv import load_dotenv
-
- logger.info("Loading environment from '%s'", env_file)
- load_dotenv(dotenv_path=env_file)
-
- if workers is None and "WEB_CONCURRENCY" in os.environ:
- self.workers = int(os.environ["WEB_CONCURRENCY"])
-
- self.forwarded_allow_ips: list[str] | str
- if forwarded_allow_ips is None:
- self.forwarded_allow_ips = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1")
- else:
- self.forwarded_allow_ips = forwarded_allow_ips
-
- if self.reload and self.workers > 1:
- logger.warning('"workers" flag is ignored when reloading is enabled.')
-
- @property
- def asgi_version(self) -> Literal["2.0", "3.0"]:
- mapping: dict[str, Literal["2.0", "3.0"]] = {
- "asgi2": "2.0",
- "asgi3": "3.0",
- "wsgi": "3.0",
- }
- return mapping[self.interface]
-
- @property
- def is_ssl(self) -> bool:
- return bool(self.ssl_keyfile or self.ssl_certfile)
-
- @property
- def use_subprocess(self) -> bool:
- return bool(self.reload or self.workers > 1)
-
- def configure_logging(self) -> None:
- logging.addLevelName(TRACE_LOG_LEVEL, "TRACE")
-
- if self.log_config is not None:
- if isinstance(self.log_config, dict):
- if self.use_colors in (True, False):
- self.log_config["formatters"]["default"]["use_colors"] = self.use_colors
- self.log_config["formatters"]["access"]["use_colors"] = self.use_colors
- logging.config.dictConfig(self.log_config)
- elif self.log_config.endswith(".json"):
- with open(self.log_config) as file:
- loaded_config = json.load(file)
- logging.config.dictConfig(loaded_config)
- elif self.log_config.endswith((".yaml", ".yml")):
- # Install the PyYAML package or the uvicorn[standard] optional
- # dependencies to enable this functionality.
- import yaml
-
- with open(self.log_config) as file:
- loaded_config = yaml.safe_load(file)
- logging.config.dictConfig(loaded_config)
- else:
- # See the note about fileConfig() here:
- # https://docs.python.org/3/library/logging.config.html#configuration-file-format
- logging.config.fileConfig(self.log_config, disable_existing_loggers=False)
-
- if self.log_level is not None:
- if isinstance(self.log_level, str):
- log_level = LOG_LEVELS[self.log_level]
- else:
- log_level = self.log_level
- logging.getLogger("uvicorn.error").setLevel(log_level)
- logging.getLogger("uvicorn.access").setLevel(log_level)
- logging.getLogger("uvicorn.asgi").setLevel(log_level)
- if self.access_log is False:
- logging.getLogger("uvicorn.access").handlers = []
- logging.getLogger("uvicorn.access").propagate = False
-
- def load(self) -> None:
- assert not self.loaded
-
- if self.is_ssl:
- assert self.ssl_certfile
- self.ssl: ssl.SSLContext | None = create_ssl_context(
- keyfile=self.ssl_keyfile,
- certfile=self.ssl_certfile,
- password=self.ssl_keyfile_password,
- ssl_version=self.ssl_version,
- cert_reqs=self.ssl_cert_reqs,
- ca_certs=self.ssl_ca_certs,
- ciphers=self.ssl_ciphers,
- )
- else:
- self.ssl = None
-
- encoded_headers = [(key.lower().encode("latin1"), value.encode("latin1")) for key, value in self.headers]
- self.encoded_headers = (
- [(b"server", b"uvicorn")] + encoded_headers
- if b"server" not in dict(encoded_headers) and self.server_header
- else encoded_headers
- )
-
- if isinstance(self.http, str):
- http_protocol_class = import_from_string(HTTP_PROTOCOLS[self.http])
- self.http_protocol_class: type[asyncio.Protocol] = http_protocol_class
- else:
- self.http_protocol_class = self.http
-
- if isinstance(self.ws, str):
- ws_protocol_class = import_from_string(WS_PROTOCOLS[self.ws])
- self.ws_protocol_class: type[asyncio.Protocol] | None = ws_protocol_class
- else:
- self.ws_protocol_class = self.ws
-
- self.lifespan_class = import_from_string(LIFESPAN[self.lifespan])
-
- try:
- self.loaded_app = import_from_string(self.app)
- except ImportFromStringError as exc:
- logger.error("Error loading ASGI app. %s" % exc)
- sys.exit(1)
-
- try:
- self.loaded_app = self.loaded_app()
- except TypeError as exc:
- if self.factory:
- logger.error("Error loading ASGI app factory: %s", exc)
- sys.exit(1)
- else:
- if not self.factory:
- logger.warning(
- "ASGI app factory detected. Using it, " "but please consider setting the --factory flag explicitly."
- )
-
- if self.interface == "auto":
- if inspect.isclass(self.loaded_app):
- use_asgi_3 = hasattr(self.loaded_app, "__await__")
- elif inspect.isfunction(self.loaded_app):
- use_asgi_3 = asyncio.iscoroutinefunction(self.loaded_app)
- else:
- call = getattr(self.loaded_app, "__call__", None)
- use_asgi_3 = asyncio.iscoroutinefunction(call)
- self.interface = "asgi3" if use_asgi_3 else "asgi2"
-
- if self.interface == "wsgi":
- self.loaded_app = WSGIMiddleware(self.loaded_app)
- self.ws_protocol_class = None
- elif self.interface == "asgi2":
- self.loaded_app = ASGI2Middleware(self.loaded_app)
-
- if logger.getEffectiveLevel() <= TRACE_LOG_LEVEL:
- self.loaded_app = MessageLoggerMiddleware(self.loaded_app)
- if self.proxy_headers:
- self.loaded_app = ProxyHeadersMiddleware(self.loaded_app, trusted_hosts=self.forwarded_allow_ips)
-
- self.loaded = True
-
- def setup_event_loop(self) -> None:
- loop_setup: Callable | None = import_from_string(LOOP_SETUPS[self.loop])
- if loop_setup is not None:
- loop_setup(use_subprocess=self.use_subprocess)
-
- def bind_socket(self) -> socket.socket:
- logger_args: list[str | int]
- if self.uds: # pragma: py-win32
- path = self.uds
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- try:
- sock.bind(path)
- uds_perms = 0o666
- os.chmod(self.uds, uds_perms)
- except OSError as exc:
- logger.error(exc)
- sys.exit(1)
-
- message = "Uvicorn running on unix socket %s (Press CTRL+C to quit)"
- sock_name_format = "%s"
- color_message = "Uvicorn running on " + click.style(sock_name_format, bold=True) + " (Press CTRL+C to quit)"
- logger_args = [self.uds]
- elif self.fd: # pragma: py-win32
- sock = socket.fromfd(self.fd, socket.AF_UNIX, socket.SOCK_STREAM)
- message = "Uvicorn running on socket %s (Press CTRL+C to quit)"
- fd_name_format = "%s"
- color_message = "Uvicorn running on " + click.style(fd_name_format, bold=True) + " (Press CTRL+C to quit)"
- logger_args = [sock.getsockname()]
- else:
- family = socket.AF_INET
- addr_format = "%s://%s:%d"
-
- if self.host and ":" in self.host: # pragma: py-win32
- # It's an IPv6 address.
- family = socket.AF_INET6
- addr_format = "%s://[%s]:%d"
-
- sock = socket.socket(family=family)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- try:
- sock.bind((self.host, self.port))
- except OSError as exc:
- logger.error(exc)
- sys.exit(1)
-
- message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)"
- color_message = "Uvicorn running on " + click.style(addr_format, bold=True) + " (Press CTRL+C to quit)"
- protocol_name = "https" if self.is_ssl else "http"
- logger_args = [protocol_name, self.host, sock.getsockname()[1]]
- logger.info(message, *logger_args, extra={"color_message": color_message})
- sock.set_inheritable(True)
- return sock
-
- @property
- def should_reload(self) -> bool:
- return isinstance(self.app, str) and self.reload
diff --git a/venv/lib/python3.11/site-packages/uvicorn/importer.py b/venv/lib/python3.11/site-packages/uvicorn/importer.py
deleted file mode 100644
index f77520e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/importer.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import importlib
-from typing import Any
-
-
-class ImportFromStringError(Exception):
- pass
-
-
-def import_from_string(import_str: Any) -> Any:
- if not isinstance(import_str, str):
- return import_str
-
- module_str, _, attrs_str = import_str.partition(":")
- if not module_str or not attrs_str:
- message = 'Import string "{import_str}" must be in format "<module>:<attribute>".'
- raise ImportFromStringError(message.format(import_str=import_str))
-
- try:
- module = importlib.import_module(module_str)
- except ModuleNotFoundError as exc:
- if exc.name != module_str:
- raise exc from None
- message = 'Could not import module "{module_str}".'
- raise ImportFromStringError(message.format(module_str=module_str))
-
- instance = module
- try:
- for attr_str in attrs_str.split("."):
- instance = getattr(instance, attr_str)
- except AttributeError:
- message = 'Attribute "{attrs_str}" not found in module "{module_str}".'
- raise ImportFromStringError(message.format(attrs_str=attrs_str, module_str=module_str))
-
- return instance
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/lifespan/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 4efab48..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/off.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/off.cpython-311.pyc
deleted file mode 100644
index ca66309..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/off.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/on.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/on.cpython-311.pyc
deleted file mode 100644
index 52c3ab4..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/__pycache__/on.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/off.py b/venv/lib/python3.11/site-packages/uvicorn/lifespan/off.py
deleted file mode 100644
index 74554b1..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/off.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from __future__ import annotations
-
-from typing import Any
-
-from uvicorn import Config
-
-
-class LifespanOff:
- def __init__(self, config: Config) -> None:
- self.should_exit = False
- self.state: dict[str, Any] = {}
-
- async def startup(self) -> None:
- pass
-
- async def shutdown(self) -> None:
- pass
diff --git a/venv/lib/python3.11/site-packages/uvicorn/lifespan/on.py b/venv/lib/python3.11/site-packages/uvicorn/lifespan/on.py
deleted file mode 100644
index 09df984..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/lifespan/on.py
+++ /dev/null
@@ -1,137 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import logging
-from asyncio import Queue
-from typing import Any, Union
-
-from uvicorn import Config
-from uvicorn._types import (
- LifespanScope,
- LifespanShutdownCompleteEvent,
- LifespanShutdownEvent,
- LifespanShutdownFailedEvent,
- LifespanStartupCompleteEvent,
- LifespanStartupEvent,
- LifespanStartupFailedEvent,
-)
-
-LifespanReceiveMessage = Union[LifespanStartupEvent, LifespanShutdownEvent]
-LifespanSendMessage = Union[
- LifespanStartupFailedEvent,
- LifespanShutdownFailedEvent,
- LifespanStartupCompleteEvent,
- LifespanShutdownCompleteEvent,
-]
-
-
-STATE_TRANSITION_ERROR = "Got invalid state transition on lifespan protocol."
-
-
-class LifespanOn:
- def __init__(self, config: Config) -> None:
- if not config.loaded:
- config.load()
-
- self.config = config
- self.logger = logging.getLogger("uvicorn.error")
- self.startup_event = asyncio.Event()
- self.shutdown_event = asyncio.Event()
- self.receive_queue: Queue[LifespanReceiveMessage] = asyncio.Queue()
- self.error_occured = False
- self.startup_failed = False
- self.shutdown_failed = False
- self.should_exit = False
- self.state: dict[str, Any] = {}
-
- async def startup(self) -> None:
- self.logger.info("Waiting for application startup.")
-
- loop = asyncio.get_event_loop()
- main_lifespan_task = loop.create_task(self.main()) # noqa: F841
- # Keep a hard reference to prevent garbage collection
- # See https://github.com/encode/uvicorn/pull/972
- startup_event: LifespanStartupEvent = {"type": "lifespan.startup"}
- await self.receive_queue.put(startup_event)
- await self.startup_event.wait()
-
- if self.startup_failed or (self.error_occured and self.config.lifespan == "on"):
- self.logger.error("Application startup failed. Exiting.")
- self.should_exit = True
- else:
- self.logger.info("Application startup complete.")
-
- async def shutdown(self) -> None:
- if self.error_occured:
- return
- self.logger.info("Waiting for application shutdown.")
- shutdown_event: LifespanShutdownEvent = {"type": "lifespan.shutdown"}
- await self.receive_queue.put(shutdown_event)
- await self.shutdown_event.wait()
-
- if self.shutdown_failed or (self.error_occured and self.config.lifespan == "on"):
- self.logger.error("Application shutdown failed. Exiting.")
- self.should_exit = True
- else:
- self.logger.info("Application shutdown complete.")
-
- async def main(self) -> None:
- try:
- app = self.config.loaded_app
- scope: LifespanScope = {
- "type": "lifespan",
- "asgi": {"version": self.config.asgi_version, "spec_version": "2.0"},
- "state": self.state,
- }
- await app(scope, self.receive, self.send)
- except BaseException as exc:
- self.asgi = None
- self.error_occured = True
- if self.startup_failed or self.shutdown_failed:
- return
- if self.config.lifespan == "auto":
- msg = "ASGI 'lifespan' protocol appears unsupported."
- self.logger.info(msg)
- else:
- msg = "Exception in 'lifespan' protocol\n"
- self.logger.error(msg, exc_info=exc)
- finally:
- self.startup_event.set()
- self.shutdown_event.set()
-
- async def send(self, message: LifespanSendMessage) -> None:
- assert message["type"] in (
- "lifespan.startup.complete",
- "lifespan.startup.failed",
- "lifespan.shutdown.complete",
- "lifespan.shutdown.failed",
- )
-
- if message["type"] == "lifespan.startup.complete":
- assert not self.startup_event.is_set(), STATE_TRANSITION_ERROR
- assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR
- self.startup_event.set()
-
- elif message["type"] == "lifespan.startup.failed":
- assert not self.startup_event.is_set(), STATE_TRANSITION_ERROR
- assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR
- self.startup_event.set()
- self.startup_failed = True
- if message.get("message"):
- self.logger.error(message["message"])
-
- elif message["type"] == "lifespan.shutdown.complete":
- assert self.startup_event.is_set(), STATE_TRANSITION_ERROR
- assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR
- self.shutdown_event.set()
-
- elif message["type"] == "lifespan.shutdown.failed":
- assert self.startup_event.is_set(), STATE_TRANSITION_ERROR
- assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR
- self.shutdown_event.set()
- self.shutdown_failed = True
- if message.get("message"):
- self.logger.error(message["message"])
-
- async def receive(self) -> LifespanReceiveMessage:
- return await self.receive_queue.get()
diff --git a/venv/lib/python3.11/site-packages/uvicorn/logging.py b/venv/lib/python3.11/site-packages/uvicorn/logging.py
deleted file mode 100644
index ab6261d..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/logging.py
+++ /dev/null
@@ -1,117 +0,0 @@
-from __future__ import annotations
-
-import http
-import logging
-import sys
-from copy import copy
-from typing import Literal
-
-import click
-
-TRACE_LOG_LEVEL = 5
-
-
-class ColourizedFormatter(logging.Formatter):
- """
- A custom log formatter class that:
-
- * Outputs the LOG_LEVEL with an appropriate color.
- * If a log call includes an `extras={"color_message": ...}` it will be used
- for formatting the output, instead of the plain text message.
- """
-
- level_name_colors = {
- TRACE_LOG_LEVEL: lambda level_name: click.style(str(level_name), fg="blue"),
- logging.DEBUG: lambda level_name: click.style(str(level_name), fg="cyan"),
- logging.INFO: lambda level_name: click.style(str(level_name), fg="green"),
- logging.WARNING: lambda level_name: click.style(str(level_name), fg="yellow"),
- logging.ERROR: lambda level_name: click.style(str(level_name), fg="red"),
- logging.CRITICAL: lambda level_name: click.style(str(level_name), fg="bright_red"),
- }
-
- def __init__(
- self,
- fmt: str | None = None,
- datefmt: str | None = None,
- style: Literal["%", "{", "$"] = "%",
- use_colors: bool | None = None,
- ):
- if use_colors in (True, False):
- self.use_colors = use_colors
- else:
- self.use_colors = sys.stdout.isatty()
- super().__init__(fmt=fmt, datefmt=datefmt, style=style)
-
- def color_level_name(self, level_name: str, level_no: int) -> str:
- def default(level_name: str) -> str:
- return str(level_name) # pragma: no cover
-
- func = self.level_name_colors.get(level_no, default)
- return func(level_name)
-
- def should_use_colors(self) -> bool:
- return True # pragma: no cover
-
- def formatMessage(self, record: logging.LogRecord) -> str:
- recordcopy = copy(record)
- levelname = recordcopy.levelname
- seperator = " " * (8 - len(recordcopy.levelname))
- if self.use_colors:
- levelname = self.color_level_name(levelname, recordcopy.levelno)
- if "color_message" in recordcopy.__dict__:
- recordcopy.msg = recordcopy.__dict__["color_message"]
- recordcopy.__dict__["message"] = recordcopy.getMessage()
- recordcopy.__dict__["levelprefix"] = levelname + ":" + seperator
- return super().formatMessage(recordcopy)
-
-
-class DefaultFormatter(ColourizedFormatter):
- def should_use_colors(self) -> bool:
- return sys.stderr.isatty() # pragma: no cover
-
-
-class AccessFormatter(ColourizedFormatter):
- status_code_colours = {
- 1: lambda code: click.style(str(code), fg="bright_white"),
- 2: lambda code: click.style(str(code), fg="green"),
- 3: lambda code: click.style(str(code), fg="yellow"),
- 4: lambda code: click.style(str(code), fg="red"),
- 5: lambda code: click.style(str(code), fg="bright_red"),
- }
-
- def get_status_code(self, status_code: int) -> str:
- try:
- status_phrase = http.HTTPStatus(status_code).phrase
- except ValueError:
- status_phrase = ""
- status_and_phrase = f"{status_code} {status_phrase}"
- if self.use_colors:
-
- def default(code: int) -> str:
- return status_and_phrase # pragma: no cover
-
- func = self.status_code_colours.get(status_code // 100, default)
- return func(status_and_phrase)
- return status_and_phrase
-
- def formatMessage(self, record: logging.LogRecord) -> str:
- recordcopy = copy(record)
- (
- client_addr,
- method,
- full_path,
- http_version,
- status_code,
- ) = recordcopy.args # type: ignore[misc]
- status_code = self.get_status_code(int(status_code)) # type: ignore[arg-type]
- request_line = f"{method} {full_path} HTTP/{http_version}"
- if self.use_colors:
- request_line = click.style(request_line, bold=True)
- recordcopy.__dict__.update(
- {
- "client_addr": client_addr,
- "request_line": request_line,
- "status_code": status_code,
- }
- )
- return super().formatMessage(recordcopy)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/loops/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 7bf402c..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-311.pyc
deleted file mode 100644
index d1bdfe7..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/auto.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/auto.cpython-311.pyc
deleted file mode 100644
index 74bbf27..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/auto.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-311.pyc
deleted file mode 100644
index 62ad95c..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/asyncio.py b/venv/lib/python3.11/site-packages/uvicorn/loops/asyncio.py
deleted file mode 100644
index b24f4fe..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/asyncio.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import asyncio
-import logging
-import sys
-
-logger = logging.getLogger("uvicorn.error")
-
-
-def asyncio_setup(use_subprocess: bool = False) -> None:
- if sys.platform == "win32" and use_subprocess:
- asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/auto.py b/venv/lib/python3.11/site-packages/uvicorn/loops/auto.py
deleted file mode 100644
index 2285457..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/auto.py
+++ /dev/null
@@ -1,11 +0,0 @@
-def auto_loop_setup(use_subprocess: bool = False) -> None:
- try:
- import uvloop # noqa
- except ImportError: # pragma: no cover
- from uvicorn.loops.asyncio import asyncio_setup as loop_setup
-
- loop_setup(use_subprocess=use_subprocess)
- else: # pragma: no cover
- from uvicorn.loops.uvloop import uvloop_setup
-
- uvloop_setup(use_subprocess=use_subprocess)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/loops/uvloop.py b/venv/lib/python3.11/site-packages/uvicorn/loops/uvloop.py
deleted file mode 100644
index 0e2fd1e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/loops/uvloop.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import asyncio
-
-import uvloop
-
-
-def uvloop_setup(use_subprocess: bool = False) -> None:
- asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
diff --git a/venv/lib/python3.11/site-packages/uvicorn/main.py b/venv/lib/python3.11/site-packages/uvicorn/main.py
deleted file mode 100644
index ace2b70..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/main.py
+++ /dev/null
@@ -1,584 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import logging
-import os
-import platform
-import ssl
-import sys
-from typing import Any, Callable
-
-import click
-
-import uvicorn
-from uvicorn._types import ASGIApplication
-from uvicorn.config import (
- HTTP_PROTOCOLS,
- INTERFACES,
- LIFESPAN,
- LOG_LEVELS,
- LOGGING_CONFIG,
- LOOP_SETUPS,
- SSL_PROTOCOL_VERSION,
- WS_PROTOCOLS,
- Config,
- HTTPProtocolType,
- InterfaceType,
- LifespanType,
- LoopSetupType,
- WSProtocolType,
-)
-from uvicorn.server import Server, ServerState # noqa: F401 # Used to be defined here.
-from uvicorn.supervisors import ChangeReload, Multiprocess
-
-LEVEL_CHOICES = click.Choice(list(LOG_LEVELS.keys()))
-HTTP_CHOICES = click.Choice(list(HTTP_PROTOCOLS.keys()))
-WS_CHOICES = click.Choice(list(WS_PROTOCOLS.keys()))
-LIFESPAN_CHOICES = click.Choice(list(LIFESPAN.keys()))
-LOOP_CHOICES = click.Choice([key for key in LOOP_SETUPS.keys() if key != "none"])
-INTERFACE_CHOICES = click.Choice(INTERFACES)
-
-STARTUP_FAILURE = 3
-
-logger = logging.getLogger("uvicorn.error")
-
-
-def print_version(ctx: click.Context, param: click.Parameter, value: bool) -> None:
- if not value or ctx.resilient_parsing:
- return
- click.echo(
- "Running uvicorn {version} with {py_implementation} {py_version} on {system}".format(
- version=uvicorn.__version__,
- py_implementation=platform.python_implementation(),
- py_version=platform.python_version(),
- system=platform.system(),
- )
- )
- ctx.exit()
-
-
-@click.command(context_settings={"auto_envvar_prefix": "UVICORN"})
-@click.argument("app", envvar="UVICORN_APP")
-@click.option(
- "--host",
- type=str,
- default="127.0.0.1",
- help="Bind socket to this host.",
- show_default=True,
-)
-@click.option(
- "--port",
- type=int,
- default=8000,
- help="Bind socket to this port. If 0, an available port will be picked.",
- show_default=True,
-)
-@click.option("--uds", type=str, default=None, help="Bind to a UNIX domain socket.")
-@click.option("--fd", type=int, default=None, help="Bind to socket from this file descriptor.")
-@click.option("--reload", is_flag=True, default=False, help="Enable auto-reload.")
-@click.option(
- "--reload-dir",
- "reload_dirs",
- multiple=True,
- help="Set reload directories explicitly, instead of using the current working" " directory.",
- type=click.Path(exists=True),
-)
-@click.option(
- "--reload-include",
- "reload_includes",
- multiple=True,
- help="Set glob patterns to include while watching for files. Includes '*.py' "
- "by default; these defaults can be overridden with `--reload-exclude`. "
- "This option has no effect unless watchfiles is installed.",
-)
-@click.option(
- "--reload-exclude",
- "reload_excludes",
- multiple=True,
- help="Set glob patterns to exclude while watching for files. Includes "
- "'.*, .py[cod], .sw.*, ~*' by default; these defaults can be overridden "
- "with `--reload-include`. This option has no effect unless watchfiles is "
- "installed.",
-)
-@click.option(
- "--reload-delay",
- type=float,
- default=0.25,
- show_default=True,
- help="Delay between previous and next check if application needs to be." " Defaults to 0.25s.",
-)
-@click.option(
- "--workers",
- default=None,
- type=int,
- help="Number of worker processes. Defaults to the $WEB_CONCURRENCY environment"
- " variable if available, or 1. Not valid with --reload.",
-)
-@click.option(
- "--loop",
- type=LOOP_CHOICES,
- default="auto",
- help="Event loop implementation.",
- show_default=True,
-)
-@click.option(
- "--http",
- type=HTTP_CHOICES,
- default="auto",
- help="HTTP protocol implementation.",
- show_default=True,
-)
-@click.option(
- "--ws",
- type=WS_CHOICES,
- default="auto",
- help="WebSocket protocol implementation.",
- show_default=True,
-)
-@click.option(
- "--ws-max-size",
- type=int,
- default=16777216,
- help="WebSocket max size message in bytes",
- show_default=True,
-)
-@click.option(
- "--ws-max-queue",
- type=int,
- default=32,
- help="The maximum length of the WebSocket message queue.",
- show_default=True,
-)
-@click.option(
- "--ws-ping-interval",
- type=float,
- default=20.0,
- help="WebSocket ping interval in seconds.",
- show_default=True,
-)
-@click.option(
- "--ws-ping-timeout",
- type=float,
- default=20.0,
- help="WebSocket ping timeout in seconds.",
- show_default=True,
-)
-@click.option(
- "--ws-per-message-deflate",
- type=bool,
- default=True,
- help="WebSocket per-message-deflate compression",
- show_default=True,
-)
-@click.option(
- "--lifespan",
- type=LIFESPAN_CHOICES,
- default="auto",
- help="Lifespan implementation.",
- show_default=True,
-)
-@click.option(
- "--interface",
- type=INTERFACE_CHOICES,
- default="auto",
- help="Select ASGI3, ASGI2, or WSGI as the application interface.",
- show_default=True,
-)
-@click.option(
- "--env-file",
- type=click.Path(exists=True),
- default=None,
- help="Environment configuration file.",
- show_default=True,
-)
-@click.option(
- "--log-config",
- type=click.Path(exists=True),
- default=None,
- help="Logging configuration file. Supported formats: .ini, .json, .yaml.",
- show_default=True,
-)
-@click.option(
- "--log-level",
- type=LEVEL_CHOICES,
- default=None,
- help="Log level. [default: info]",
- show_default=True,
-)
-@click.option(
- "--access-log/--no-access-log",
- is_flag=True,
- default=True,
- help="Enable/Disable access log.",
-)
-@click.option(
- "--use-colors/--no-use-colors",
- is_flag=True,
- default=None,
- help="Enable/Disable colorized logging.",
-)
-@click.option(
- "--proxy-headers/--no-proxy-headers",
- is_flag=True,
- default=True,
- help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For, X-Forwarded-Port to " "populate remote address info.",
-)
-@click.option(
- "--server-header/--no-server-header",
- is_flag=True,
- default=True,
- help="Enable/Disable default Server header.",
-)
-@click.option(
- "--date-header/--no-date-header",
- is_flag=True,
- default=True,
- help="Enable/Disable default Date header.",
-)
-@click.option(
- "--forwarded-allow-ips",
- type=str,
- default=None,
- help="Comma separated list of IPs to trust with proxy headers. Defaults to"
- " the $FORWARDED_ALLOW_IPS environment variable if available, or '127.0.0.1'.",
-)
-@click.option(
- "--root-path",
- type=str,
- default="",
- help="Set the ASGI 'root_path' for applications submounted below a given URL path.",
-)
-@click.option(
- "--limit-concurrency",
- type=int,
- default=None,
- help="Maximum number of concurrent connections or tasks to allow, before issuing" " HTTP 503 responses.",
-)
-@click.option(
- "--backlog",
- type=int,
- default=2048,
- help="Maximum number of connections to hold in backlog",
-)
-@click.option(
- "--limit-max-requests",
- type=int,
- default=None,
- help="Maximum number of requests to service before terminating the process.",
-)
-@click.option(
- "--timeout-keep-alive",
- type=int,
- default=5,
- help="Close Keep-Alive connections if no new data is received within this timeout.",
- show_default=True,
-)
-@click.option(
- "--timeout-graceful-shutdown",
- type=int,
- default=None,
- help="Maximum number of seconds to wait for graceful shutdown.",
-)
-@click.option("--ssl-keyfile", type=str, default=None, help="SSL key file", show_default=True)
-@click.option(
- "--ssl-certfile",
- type=str,
- default=None,
- help="SSL certificate file",
- show_default=True,
-)
-@click.option(
- "--ssl-keyfile-password",
- type=str,
- default=None,
- help="SSL keyfile password",
- show_default=True,
-)
-@click.option(
- "--ssl-version",
- type=int,
- default=int(SSL_PROTOCOL_VERSION),
- help="SSL version to use (see stdlib ssl module's)",
- show_default=True,
-)
-@click.option(
- "--ssl-cert-reqs",
- type=int,
- default=int(ssl.CERT_NONE),
- help="Whether client certificate is required (see stdlib ssl module's)",
- show_default=True,
-)
-@click.option(
- "--ssl-ca-certs",
- type=str,
- default=None,
- help="CA certificates file",
- show_default=True,
-)
-@click.option(
- "--ssl-ciphers",
- type=str,
- default="TLSv1",
- help="Ciphers to use (see stdlib ssl module's)",
- show_default=True,
-)
-@click.option(
- "--header",
- "headers",
- multiple=True,
- help="Specify custom default HTTP response headers as a Name:Value pair",
-)
-@click.option(
- "--version",
- is_flag=True,
- callback=print_version,
- expose_value=False,
- is_eager=True,
- help="Display the uvicorn version and exit.",
-)
-@click.option(
- "--app-dir",
- default="",
- show_default=True,
- help="Look for APP in the specified directory, by adding this to the PYTHONPATH."
- " Defaults to the current working directory.",
-)
-@click.option(
- "--h11-max-incomplete-event-size",
- "h11_max_incomplete_event_size",
- type=int,
- default=None,
- help="For h11, the maximum number of bytes to buffer of an incomplete event.",
-)
-@click.option(
- "--factory",
- is_flag=True,
- default=False,
- help="Treat APP as an application factory, i.e. a () -> <ASGI app> callable.",
- show_default=True,
-)
-def main(
- app: str,
- host: str,
- port: int,
- uds: str,
- fd: int,
- loop: LoopSetupType,
- http: HTTPProtocolType,
- ws: WSProtocolType,
- ws_max_size: int,
- ws_max_queue: int,
- ws_ping_interval: float,
- ws_ping_timeout: float,
- ws_per_message_deflate: bool,
- lifespan: LifespanType,
- interface: InterfaceType,
- reload: bool,
- reload_dirs: list[str],
- reload_includes: list[str],
- reload_excludes: list[str],
- reload_delay: float,
- workers: int,
- env_file: str,
- log_config: str,
- log_level: str,
- access_log: bool,
- proxy_headers: bool,
- server_header: bool,
- date_header: bool,
- forwarded_allow_ips: str,
- root_path: str,
- limit_concurrency: int,
- backlog: int,
- limit_max_requests: int,
- timeout_keep_alive: int,
- timeout_graceful_shutdown: int | None,
- ssl_keyfile: str,
- ssl_certfile: str,
- ssl_keyfile_password: str,
- ssl_version: int,
- ssl_cert_reqs: int,
- ssl_ca_certs: str,
- ssl_ciphers: str,
- headers: list[str],
- use_colors: bool,
- app_dir: str,
- h11_max_incomplete_event_size: int | None,
- factory: bool,
-) -> None:
- run(
- app,
- host=host,
- port=port,
- uds=uds,
- fd=fd,
- loop=loop,
- http=http,
- ws=ws,
- ws_max_size=ws_max_size,
- ws_max_queue=ws_max_queue,
- ws_ping_interval=ws_ping_interval,
- ws_ping_timeout=ws_ping_timeout,
- ws_per_message_deflate=ws_per_message_deflate,
- lifespan=lifespan,
- env_file=env_file,
- log_config=LOGGING_CONFIG if log_config is None else log_config,
- log_level=log_level,
- access_log=access_log,
- interface=interface,
- reload=reload,
- reload_dirs=reload_dirs or None,
- reload_includes=reload_includes or None,
- reload_excludes=reload_excludes or None,
- reload_delay=reload_delay,
- workers=workers,
- proxy_headers=proxy_headers,
- server_header=server_header,
- date_header=date_header,
- forwarded_allow_ips=forwarded_allow_ips,
- root_path=root_path,
- limit_concurrency=limit_concurrency,
- backlog=backlog,
- limit_max_requests=limit_max_requests,
- timeout_keep_alive=timeout_keep_alive,
- timeout_graceful_shutdown=timeout_graceful_shutdown,
- ssl_keyfile=ssl_keyfile,
- ssl_certfile=ssl_certfile,
- ssl_keyfile_password=ssl_keyfile_password,
- ssl_version=ssl_version,
- ssl_cert_reqs=ssl_cert_reqs,
- ssl_ca_certs=ssl_ca_certs,
- ssl_ciphers=ssl_ciphers,
- headers=[header.split(":", 1) for header in headers], # type: ignore[misc]
- use_colors=use_colors,
- factory=factory,
- app_dir=app_dir,
- h11_max_incomplete_event_size=h11_max_incomplete_event_size,
- )
-
-
-def run(
- app: ASGIApplication | Callable[..., Any] | str,
- *,
- host: str = "127.0.0.1",
- port: int = 8000,
- uds: str | None = None,
- fd: int | None = None,
- loop: LoopSetupType = "auto",
- http: type[asyncio.Protocol] | HTTPProtocolType = "auto",
- ws: type[asyncio.Protocol] | WSProtocolType = "auto",
- ws_max_size: int = 16777216,
- ws_max_queue: int = 32,
- ws_ping_interval: float | None = 20.0,
- ws_ping_timeout: float | None = 20.0,
- ws_per_message_deflate: bool = True,
- lifespan: LifespanType = "auto",
- interface: InterfaceType = "auto",
- reload: bool = False,
- reload_dirs: list[str] | str | None = None,
- reload_includes: list[str] | str | None = None,
- reload_excludes: list[str] | str | None = None,
- reload_delay: float = 0.25,
- workers: int | None = None,
- env_file: str | os.PathLike[str] | None = None,
- log_config: dict[str, Any] | str | None = LOGGING_CONFIG,
- log_level: str | int | None = None,
- access_log: bool = True,
- proxy_headers: bool = True,
- server_header: bool = True,
- date_header: bool = True,
- forwarded_allow_ips: list[str] | str | None = None,
- root_path: str = "",
- limit_concurrency: int | None = None,
- backlog: int = 2048,
- limit_max_requests: int | None = None,
- timeout_keep_alive: int = 5,
- timeout_graceful_shutdown: int | None = None,
- ssl_keyfile: str | None = None,
- ssl_certfile: str | os.PathLike[str] | None = None,
- ssl_keyfile_password: str | None = None,
- ssl_version: int = SSL_PROTOCOL_VERSION,
- ssl_cert_reqs: int = ssl.CERT_NONE,
- ssl_ca_certs: str | None = None,
- ssl_ciphers: str = "TLSv1",
- headers: list[tuple[str, str]] | None = None,
- use_colors: bool | None = None,
- app_dir: str | None = None,
- factory: bool = False,
- h11_max_incomplete_event_size: int | None = None,
-) -> None:
- if app_dir is not None:
- sys.path.insert(0, app_dir)
-
- config = Config(
- app,
- host=host,
- port=port,
- uds=uds,
- fd=fd,
- loop=loop,
- http=http,
- ws=ws,
- ws_max_size=ws_max_size,
- ws_max_queue=ws_max_queue,
- ws_ping_interval=ws_ping_interval,
- ws_ping_timeout=ws_ping_timeout,
- ws_per_message_deflate=ws_per_message_deflate,
- lifespan=lifespan,
- interface=interface,
- reload=reload,
- reload_dirs=reload_dirs,
- reload_includes=reload_includes,
- reload_excludes=reload_excludes,
- reload_delay=reload_delay,
- workers=workers,
- env_file=env_file,
- log_config=log_config,
- log_level=log_level,
- access_log=access_log,
- proxy_headers=proxy_headers,
- server_header=server_header,
- date_header=date_header,
- forwarded_allow_ips=forwarded_allow_ips,
- root_path=root_path,
- limit_concurrency=limit_concurrency,
- backlog=backlog,
- limit_max_requests=limit_max_requests,
- timeout_keep_alive=timeout_keep_alive,
- timeout_graceful_shutdown=timeout_graceful_shutdown,
- ssl_keyfile=ssl_keyfile,
- ssl_certfile=ssl_certfile,
- ssl_keyfile_password=ssl_keyfile_password,
- ssl_version=ssl_version,
- ssl_cert_reqs=ssl_cert_reqs,
- ssl_ca_certs=ssl_ca_certs,
- ssl_ciphers=ssl_ciphers,
- headers=headers,
- use_colors=use_colors,
- factory=factory,
- h11_max_incomplete_event_size=h11_max_incomplete_event_size,
- )
- server = Server(config=config)
-
- if (config.reload or config.workers > 1) and not isinstance(app, str):
- logger = logging.getLogger("uvicorn.error")
- logger.warning("You must pass the application as an import string to enable 'reload' or " "'workers'.")
- sys.exit(1)
-
- if config.should_reload:
- sock = config.bind_socket()
- ChangeReload(config, target=server.run, sockets=[sock]).run()
- elif config.workers > 1:
- sock = config.bind_socket()
- Multiprocess(config, target=server.run, sockets=[sock]).run()
- else:
- server.run()
- if config.uds and os.path.exists(config.uds):
- os.remove(config.uds) # pragma: py-win32
-
- if not server.started and not config.should_reload and config.workers == 1:
- sys.exit(STARTUP_FAILURE)
-
-
-if __name__ == "__main__":
- main() # pragma: no cover
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/middleware/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 5f70c5b..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-311.pyc
deleted file mode 100644
index 905a366..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-311.pyc
deleted file mode 100644
index 87303e2..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-311.pyc
deleted file mode 100644
index 5f8e2c9..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-311.pyc
deleted file mode 100644
index 2dfa1f9..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/asgi2.py b/venv/lib/python3.11/site-packages/uvicorn/middleware/asgi2.py
deleted file mode 100644
index 4e15d15..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/asgi2.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from uvicorn._types import (
- ASGI2Application,
- ASGIReceiveCallable,
- ASGISendCallable,
- Scope,
-)
-
-
-class ASGI2Middleware:
- def __init__(self, app: "ASGI2Application"):
- self.app = app
-
- async def __call__(self, scope: "Scope", receive: "ASGIReceiveCallable", send: "ASGISendCallable") -> None:
- instance = self.app(scope)
- await instance(receive, send)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py b/venv/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py
deleted file mode 100644
index 0174bcc..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/message_logger.py
+++ /dev/null
@@ -1,87 +0,0 @@
-import logging
-from typing import Any
-
-from uvicorn._types import (
- ASGI3Application,
- ASGIReceiveCallable,
- ASGIReceiveEvent,
- ASGISendCallable,
- ASGISendEvent,
- WWWScope,
-)
-from uvicorn.logging import TRACE_LOG_LEVEL
-
-PLACEHOLDER_FORMAT = {
- "body": "<{length} bytes>",
- "bytes": "<{length} bytes>",
- "text": "<{length} chars>",
- "headers": "<...>",
-}
-
-
-def message_with_placeholders(message: Any) -> Any:
- """
- Return an ASGI message, with any body-type content omitted and replaced
- with a placeholder.
- """
- new_message = message.copy()
- for attr in PLACEHOLDER_FORMAT.keys():
- if message.get(attr) is not None:
- content = message[attr]
- placeholder = PLACEHOLDER_FORMAT[attr].format(length=len(content))
- new_message[attr] = placeholder
- return new_message
-
-
-class MessageLoggerMiddleware:
- def __init__(self, app: "ASGI3Application"):
- self.task_counter = 0
- self.app = app
- self.logger = logging.getLogger("uvicorn.asgi")
-
- def trace(message: Any, *args: Any, **kwargs: Any) -> None:
- self.logger.log(TRACE_LOG_LEVEL, message, *args, **kwargs)
-
- self.logger.trace = trace # type: ignore
-
- async def __call__(
- self,
- scope: "WWWScope",
- receive: "ASGIReceiveCallable",
- send: "ASGISendCallable",
- ) -> None:
- self.task_counter += 1
-
- task_counter = self.task_counter
- client = scope.get("client")
- prefix = "%s:%d - ASGI" % (client[0], client[1]) if client else "ASGI"
-
- async def inner_receive() -> "ASGIReceiveEvent":
- message = await receive()
- logged_message = message_with_placeholders(message)
- log_text = "%s [%d] Receive %s"
- self.logger.trace( # type: ignore
- log_text, prefix, task_counter, logged_message
- )
- return message
-
- async def inner_send(message: "ASGISendEvent") -> None:
- logged_message = message_with_placeholders(message)
- log_text = "%s [%d] Send %s"
- self.logger.trace( # type: ignore
- log_text, prefix, task_counter, logged_message
- )
- await send(message)
-
- logged_scope = message_with_placeholders(scope)
- log_text = "%s [%d] Started scope=%s"
- self.logger.trace(log_text, prefix, task_counter, logged_scope) # type: ignore
- try:
- await self.app(scope, inner_receive, inner_send)
- except BaseException as exc:
- log_text = "%s [%d] Raised exception"
- self.logger.trace(log_text, prefix, task_counter) # type: ignore
- raise exc from None
- else:
- log_text = "%s [%d] Completed"
- self.logger.trace(log_text, prefix, task_counter) # type: ignore
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py b/venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py
deleted file mode 100644
index 8f987ab..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""
-This middleware can be used when a known proxy is fronting the application,
-and is trusted to be properly setting the `X-Forwarded-Proto` and
-`X-Forwarded-For` headers with the connecting client information.
-
-Modifies the `client` and `scheme` information so that they reference
-the connecting client, rather that the connecting proxy.
-
-https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#Proxies
-"""
-from __future__ import annotations
-
-from typing import Union, cast
-
-from uvicorn._types import ASGI3Application, ASGIReceiveCallable, ASGISendCallable, HTTPScope, Scope, WebSocketScope
-
-
-class ProxyHeadersMiddleware:
- def __init__(
- self,
- app: ASGI3Application,
- trusted_hosts: list[str] | str = "127.0.0.1",
- ) -> None:
- self.app = app
- if isinstance(trusted_hosts, str):
- self.trusted_hosts = {item.strip() for item in trusted_hosts.split(",")}
- else:
- self.trusted_hosts = set(trusted_hosts)
- self.always_trust = "*" in self.trusted_hosts
-
- def get_trusted_client_host(self, x_forwarded_for_hosts: list[str]) -> str | None:
- if self.always_trust:
- return x_forwarded_for_hosts[0]
-
- for host in reversed(x_forwarded_for_hosts):
- if host not in self.trusted_hosts:
- return host
-
- return None
-
- async def __call__(self, scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
- if scope["type"] in ("http", "websocket"):
- scope = cast(Union["HTTPScope", "WebSocketScope"], scope)
- client_addr: tuple[str, int] | None = scope.get("client")
- client_host = client_addr[0] if client_addr else None
-
- if self.always_trust or client_host in self.trusted_hosts:
- headers = dict(scope["headers"])
-
- if b"x-forwarded-proto" in headers:
- # Determine if the incoming request was http or https based on
- # the X-Forwarded-Proto header.
- x_forwarded_proto = headers[b"x-forwarded-proto"].decode("latin1").strip()
- if scope["type"] == "websocket":
- scope["scheme"] = x_forwarded_proto.replace("http", "ws")
- else:
- scope["scheme"] = x_forwarded_proto
-
- if b"x-forwarded-for" in headers:
- # Determine the client address from the last trusted IP in the
- # X-Forwarded-For header. We've lost the connecting client's port
- # information by now, so only include the host.
- x_forwarded_for = headers[b"x-forwarded-for"].decode("latin1")
- x_forwarded_for_hosts = [item.strip() for item in x_forwarded_for.split(",")]
- host = self.get_trusted_client_host(x_forwarded_for_hosts)
- port = 0
- scope["client"] = (host, port) # type: ignore[arg-type]
-
- return await self.app(scope, receive, send)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/middleware/wsgi.py b/venv/lib/python3.11/site-packages/uvicorn/middleware/wsgi.py
deleted file mode 100644
index 078de1a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/middleware/wsgi.py
+++ /dev/null
@@ -1,200 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import concurrent.futures
-import io
-import sys
-import warnings
-from collections import deque
-from typing import Iterable
-
-from uvicorn._types import (
- ASGIReceiveCallable,
- ASGIReceiveEvent,
- ASGISendCallable,
- ASGISendEvent,
- Environ,
- ExcInfo,
- HTTPRequestEvent,
- HTTPResponseBodyEvent,
- HTTPResponseStartEvent,
- HTTPScope,
- StartResponse,
- WSGIApp,
-)
-
-
-def build_environ(scope: HTTPScope, message: ASGIReceiveEvent, body: io.BytesIO) -> Environ:
- """
- Builds a scope and request message into a WSGI environ object.
- """
- script_name = scope.get("root_path", "").encode("utf8").decode("latin1")
- path_info = scope["path"].encode("utf8").decode("latin1")
- if path_info.startswith(script_name):
- path_info = path_info[len(script_name) :]
- environ = {
- "REQUEST_METHOD": scope["method"],
- "SCRIPT_NAME": script_name,
- "PATH_INFO": path_info,
- "QUERY_STRING": scope["query_string"].decode("ascii"),
- "SERVER_PROTOCOL": "HTTP/%s" % scope["http_version"],
- "wsgi.version": (1, 0),
- "wsgi.url_scheme": scope.get("scheme", "http"),
- "wsgi.input": body,
- "wsgi.errors": sys.stdout,
- "wsgi.multithread": True,
- "wsgi.multiprocess": True,
- "wsgi.run_once": False,
- }
-
- # Get server name and port - required in WSGI, not in ASGI
- server = scope.get("server")
- if server is None:
- server = ("localhost", 80)
- environ["SERVER_NAME"] = server[0]
- environ["SERVER_PORT"] = server[1]
-
- # Get client IP address
- client = scope.get("client")
- if client is not None:
- environ["REMOTE_ADDR"] = client[0]
-
- # Go through headers and make them into environ entries
- for name, value in scope.get("headers", []):
- name_str: str = name.decode("latin1")
- if name_str == "content-length":
- corrected_name = "CONTENT_LENGTH"
- elif name_str == "content-type":
- corrected_name = "CONTENT_TYPE"
- else:
- corrected_name = "HTTP_%s" % name_str.upper().replace("-", "_")
- # HTTPbis say only ASCII chars are allowed in headers, but we latin1
- # just in case
- value_str: str = value.decode("latin1")
- if corrected_name in environ:
- corrected_name_environ = environ[corrected_name]
- assert isinstance(corrected_name_environ, str)
- value_str = corrected_name_environ + "," + value_str
- environ[corrected_name] = value_str
- return environ
-
-
-class _WSGIMiddleware:
- def __init__(self, app: WSGIApp, workers: int = 10):
- warnings.warn(
- "Uvicorn's native WSGI implementation is deprecated, you "
- "should switch to a2wsgi (`pip install a2wsgi`).",
- DeprecationWarning,
- )
- self.app = app
- self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=workers)
-
- async def __call__(
- self,
- scope: HTTPScope,
- receive: ASGIReceiveCallable,
- send: ASGISendCallable,
- ) -> None:
- assert scope["type"] == "http"
- instance = WSGIResponder(self.app, self.executor, scope)
- await instance(receive, send)
-
-
-class WSGIResponder:
- def __init__(
- self,
- app: WSGIApp,
- executor: concurrent.futures.ThreadPoolExecutor,
- scope: HTTPScope,
- ):
- self.app = app
- self.executor = executor
- self.scope = scope
- self.status = None
- self.response_headers = None
- self.send_event = asyncio.Event()
- self.send_queue: deque[ASGISendEvent | None] = deque()
- self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()
- self.response_started = False
- self.exc_info: ExcInfo | None = None
-
- async def __call__(self, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
- message: HTTPRequestEvent = await receive() # type: ignore[assignment]
- body = io.BytesIO(message.get("body", b""))
- more_body = message.get("more_body", False)
- if more_body:
- body.seek(0, io.SEEK_END)
- while more_body:
- body_message: HTTPRequestEvent = (
- await receive() # type: ignore[assignment]
- )
- body.write(body_message.get("body", b""))
- more_body = body_message.get("more_body", False)
- body.seek(0)
- environ = build_environ(self.scope, message, body)
- self.loop = asyncio.get_event_loop()
- wsgi = self.loop.run_in_executor(self.executor, self.wsgi, environ, self.start_response)
- sender = self.loop.create_task(self.sender(send))
- try:
- await asyncio.wait_for(wsgi, None)
- finally:
- self.send_queue.append(None)
- self.send_event.set()
- await asyncio.wait_for(sender, None)
- if self.exc_info is not None:
- raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2])
-
- async def sender(self, send: ASGISendCallable) -> None:
- while True:
- if self.send_queue:
- message = self.send_queue.popleft()
- if message is None:
- return
- await send(message)
- else:
- await self.send_event.wait()
- self.send_event.clear()
-
- def start_response(
- self,
- status: str,
- response_headers: Iterable[tuple[str, str]],
- exc_info: ExcInfo | None = None,
- ) -> None:
- self.exc_info = exc_info
- if not self.response_started:
- self.response_started = True
- status_code_str, _ = status.split(" ", 1)
- status_code = int(status_code_str)
- headers = [(name.encode("ascii"), value.encode("ascii")) for name, value in response_headers]
- http_response_start_event: HTTPResponseStartEvent = {
- "type": "http.response.start",
- "status": status_code,
- "headers": headers,
- }
- self.send_queue.append(http_response_start_event)
- self.loop.call_soon_threadsafe(self.send_event.set)
-
- def wsgi(self, environ: Environ, start_response: StartResponse) -> None:
- for chunk in self.app(environ, start_response): # type: ignore
- response_body: HTTPResponseBodyEvent = {
- "type": "http.response.body",
- "body": chunk,
- "more_body": True,
- }
- self.send_queue.append(response_body)
- self.loop.call_soon_threadsafe(self.send_event.set)
-
- empty_body: HTTPResponseBodyEvent = {
- "type": "http.response.body",
- "body": b"",
- "more_body": False,
- }
- self.send_queue.append(empty_body)
- self.loop.call_soon_threadsafe(self.send_event.set)
-
-
-try:
- from a2wsgi import WSGIMiddleware
-except ModuleNotFoundError: # pragma: no cover
- WSGIMiddleware = _WSGIMiddleware # type: ignore[misc, assignment]
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 5ff273e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/utils.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/utils.cpython-311.pyc
deleted file mode 100644
index da51e43..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/__pycache__/utils.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index c56186b..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-311.pyc
deleted file mode 100644
index a598e8a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-311.pyc
deleted file mode 100644
index a925cb4..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-311.pyc
deleted file mode 100644
index 2379bb6..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-311.pyc
deleted file mode 100644
index ba76184..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/auto.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/auto.py
deleted file mode 100644
index a14bec1..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/auto.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-
-AutoHTTPProtocol: type[asyncio.Protocol]
-try:
- import httptools # noqa
-except ImportError: # pragma: no cover
- from uvicorn.protocols.http.h11_impl import H11Protocol
-
- AutoHTTPProtocol = H11Protocol
-else: # pragma: no cover
- from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol
-
- AutoHTTPProtocol = HttpToolsProtocol
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/flow_control.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/flow_control.py
deleted file mode 100644
index 893a26c..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/flow_control.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import asyncio
-
-from uvicorn._types import (
- ASGIReceiveCallable,
- ASGISendCallable,
- HTTPResponseBodyEvent,
- HTTPResponseStartEvent,
- Scope,
-)
-
-CLOSE_HEADER = (b"connection", b"close")
-
-HIGH_WATER_LIMIT = 65536
-
-
-class FlowControl:
- def __init__(self, transport: asyncio.Transport) -> None:
- self._transport = transport
- self.read_paused = False
- self.write_paused = False
- self._is_writable_event = asyncio.Event()
- self._is_writable_event.set()
-
- async def drain(self) -> None:
- await self._is_writable_event.wait()
-
- def pause_reading(self) -> None:
- if not self.read_paused:
- self.read_paused = True
- self._transport.pause_reading()
-
- def resume_reading(self) -> None:
- if self.read_paused:
- self.read_paused = False
- self._transport.resume_reading()
-
- def pause_writing(self) -> None:
- if not self.write_paused:
- self.write_paused = True
- self._is_writable_event.clear()
-
- def resume_writing(self) -> None:
- if self.write_paused:
- self.write_paused = False
- self._is_writable_event.set()
-
-
-async def service_unavailable(scope: "Scope", receive: "ASGIReceiveCallable", send: "ASGISendCallable") -> None:
- response_start: "HTTPResponseStartEvent" = {
- "type": "http.response.start",
- "status": 503,
- "headers": [
- (b"content-type", b"text/plain; charset=utf-8"),
- (b"connection", b"close"),
- ],
- }
- await send(response_start)
-
- response_body: "HTTPResponseBodyEvent" = {
- "type": "http.response.body",
- "body": b"Service Unavailable",
- "more_body": False,
- }
- await send(response_body)
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py
deleted file mode 100644
index d0f2b2a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py
+++ /dev/null
@@ -1,547 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import http
-import logging
-from typing import Any, Callable, Literal, cast
-from urllib.parse import unquote
-
-import h11
-from h11._connection import DEFAULT_MAX_INCOMPLETE_EVENT_SIZE
-
-from uvicorn._types import (
- ASGI3Application,
- ASGIReceiveEvent,
- ASGISendEvent,
- HTTPRequestEvent,
- HTTPResponseBodyEvent,
- HTTPResponseStartEvent,
- HTTPScope,
-)
-from uvicorn.config import Config
-from uvicorn.logging import TRACE_LOG_LEVEL
-from uvicorn.protocols.http.flow_control import (
- CLOSE_HEADER,
- HIGH_WATER_LIMIT,
- FlowControl,
- service_unavailable,
-)
-from uvicorn.protocols.utils import (
- get_client_addr,
- get_local_addr,
- get_path_with_query_string,
- get_remote_addr,
- is_ssl,
-)
-from uvicorn.server import ServerState
-
-
-def _get_status_phrase(status_code: int) -> bytes:
- try:
- return http.HTTPStatus(status_code).phrase.encode()
- except ValueError:
- return b""
-
-
-STATUS_PHRASES = {status_code: _get_status_phrase(status_code) for status_code in range(100, 600)}
-
-
-class H11Protocol(asyncio.Protocol):
- def __init__(
- self,
- config: Config,
- server_state: ServerState,
- app_state: dict[str, Any],
- _loop: asyncio.AbstractEventLoop | None = None,
- ) -> None:
- if not config.loaded:
- config.load()
-
- self.config = config
- self.app = config.loaded_app
- self.loop = _loop or asyncio.get_event_loop()
- self.logger = logging.getLogger("uvicorn.error")
- self.access_logger = logging.getLogger("uvicorn.access")
- self.access_log = self.access_logger.hasHandlers()
- self.conn = h11.Connection(
- h11.SERVER,
- config.h11_max_incomplete_event_size
- if config.h11_max_incomplete_event_size is not None
- else DEFAULT_MAX_INCOMPLETE_EVENT_SIZE,
- )
- self.ws_protocol_class = config.ws_protocol_class
- self.root_path = config.root_path
- self.limit_concurrency = config.limit_concurrency
- self.app_state = app_state
-
- # Timeouts
- self.timeout_keep_alive_task: asyncio.TimerHandle | None = None
- self.timeout_keep_alive = config.timeout_keep_alive
-
- # Shared server state
- self.server_state = server_state
- self.connections = server_state.connections
- self.tasks = server_state.tasks
-
- # Per-connection state
- self.transport: asyncio.Transport = None # type: ignore[assignment]
- self.flow: FlowControl = None # type: ignore[assignment]
- self.server: tuple[str, int] | None = None
- self.client: tuple[str, int] | None = None
- self.scheme: Literal["http", "https"] | None = None
-
- # Per-request state
- self.scope: HTTPScope = None # type: ignore[assignment]
- self.headers: list[tuple[bytes, bytes]] = None # type: ignore[assignment]
- self.cycle: RequestResponseCycle = None # type: ignore[assignment]
-
- # Protocol interface
- def connection_made( # type: ignore[override]
- self, transport: asyncio.Transport
- ) -> None:
- self.connections.add(self)
-
- self.transport = transport
- self.flow = FlowControl(transport)
- self.server = get_local_addr(transport)
- self.client = get_remote_addr(transport)
- self.scheme = "https" if is_ssl(transport) else "http"
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection made", prefix)
-
- def connection_lost(self, exc: Exception | None) -> None:
- self.connections.discard(self)
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection lost", prefix)
-
- if self.cycle and not self.cycle.response_complete:
- self.cycle.disconnected = True
- if self.conn.our_state != h11.ERROR:
- event = h11.ConnectionClosed()
- try:
- self.conn.send(event)
- except h11.LocalProtocolError:
- # Premature client disconnect
- pass
-
- if self.cycle is not None:
- self.cycle.message_event.set()
- if self.flow is not None:
- self.flow.resume_writing()
- if exc is None:
- self.transport.close()
- self._unset_keepalive_if_required()
-
- def eof_received(self) -> None:
- pass
-
- def _unset_keepalive_if_required(self) -> None:
- if self.timeout_keep_alive_task is not None:
- self.timeout_keep_alive_task.cancel()
- self.timeout_keep_alive_task = None
-
- def _get_upgrade(self) -> bytes | None:
- connection = []
- upgrade = None
- for name, value in self.headers:
- if name == b"connection":
- connection = [token.lower().strip() for token in value.split(b",")]
- if name == b"upgrade":
- upgrade = value.lower()
- if b"upgrade" in connection:
- return upgrade
- return None
-
- def _should_upgrade_to_ws(self) -> bool:
- if self.ws_protocol_class is None:
- if self.config.ws == "auto":
- msg = "Unsupported upgrade request."
- self.logger.warning(msg)
- msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
- self.logger.warning(msg)
- return False
- return True
-
- def data_received(self, data: bytes) -> None:
- self._unset_keepalive_if_required()
-
- self.conn.receive_data(data)
- self.handle_events()
-
- def handle_events(self) -> None:
- while True:
- try:
- event = self.conn.next_event()
- except h11.RemoteProtocolError:
- msg = "Invalid HTTP request received."
- self.logger.warning(msg)
- self.send_400_response(msg)
- return
-
- if event is h11.NEED_DATA:
- break
-
- elif event is h11.PAUSED:
- # This case can occur in HTTP pipelining, so we need to
- # stop reading any more data, and ensure that at the end
- # of the active request/response cycle we handle any
- # events that have been buffered up.
- self.flow.pause_reading()
- break
-
- elif isinstance(event, h11.Request):
- self.headers = [(key.lower(), value) for key, value in event.headers]
- raw_path, _, query_string = event.target.partition(b"?")
- path = unquote(raw_path.decode("ascii"))
- full_path = self.root_path + path
- full_raw_path = self.root_path.encode("ascii") + raw_path
- self.scope = {
- "type": "http",
- "asgi": {
- "version": self.config.asgi_version,
- "spec_version": "2.4",
- },
- "http_version": event.http_version.decode("ascii"),
- "server": self.server,
- "client": self.client,
- "scheme": self.scheme, # type: ignore[typeddict-item]
- "method": event.method.decode("ascii"),
- "root_path": self.root_path,
- "path": full_path,
- "raw_path": full_raw_path,
- "query_string": query_string,
- "headers": self.headers,
- "state": self.app_state.copy(),
- }
-
- upgrade = self._get_upgrade()
- if upgrade == b"websocket" and self._should_upgrade_to_ws():
- self.handle_websocket_upgrade(event)
- return
-
- # Handle 503 responses when 'limit_concurrency' is exceeded.
- if self.limit_concurrency is not None and (
- len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency
- ):
- app = service_unavailable
- message = "Exceeded concurrency limit."
- self.logger.warning(message)
- else:
- app = self.app
-
- # When starting to process a request, disable the keep-alive
- # timeout. Normally we disable this when receiving data from
- # client and set back when finishing processing its request.
- # However, for pipelined requests processing finishes after
- # already receiving the next request and thus the timer may
- # be set here, which we don't want.
- self._unset_keepalive_if_required()
-
- self.cycle = RequestResponseCycle(
- scope=self.scope,
- conn=self.conn,
- transport=self.transport,
- flow=self.flow,
- logger=self.logger,
- access_logger=self.access_logger,
- access_log=self.access_log,
- default_headers=self.server_state.default_headers,
- message_event=asyncio.Event(),
- on_response=self.on_response_complete,
- )
- task = self.loop.create_task(self.cycle.run_asgi(app))
- task.add_done_callback(self.tasks.discard)
- self.tasks.add(task)
-
- elif isinstance(event, h11.Data):
- if self.conn.our_state is h11.DONE:
- continue
- self.cycle.body += event.data
- if len(self.cycle.body) > HIGH_WATER_LIMIT:
- self.flow.pause_reading()
- self.cycle.message_event.set()
-
- elif isinstance(event, h11.EndOfMessage):
- if self.conn.our_state is h11.DONE:
- self.transport.resume_reading()
- self.conn.start_next_cycle()
- continue
- self.cycle.more_body = False
- self.cycle.message_event.set()
-
- def handle_websocket_upgrade(self, event: h11.Request) -> None:
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sUpgrading to WebSocket", prefix)
-
- self.connections.discard(self)
- output = [event.method, b" ", event.target, b" HTTP/1.1\r\n"]
- for name, value in self.headers:
- output += [name, b": ", value, b"\r\n"]
- output.append(b"\r\n")
- protocol = self.ws_protocol_class( # type: ignore[call-arg, misc]
- config=self.config,
- server_state=self.server_state,
- app_state=self.app_state,
- )
- protocol.connection_made(self.transport)
- protocol.data_received(b"".join(output))
- self.transport.set_protocol(protocol)
-
- def send_400_response(self, msg: str) -> None:
- reason = STATUS_PHRASES[400]
- headers: list[tuple[bytes, bytes]] = [
- (b"content-type", b"text/plain; charset=utf-8"),
- (b"connection", b"close"),
- ]
- event = h11.Response(status_code=400, headers=headers, reason=reason)
- output = self.conn.send(event)
- self.transport.write(output)
-
- output = self.conn.send(event=h11.Data(data=msg.encode("ascii")))
- self.transport.write(output)
-
- output = self.conn.send(event=h11.EndOfMessage())
- self.transport.write(output)
-
- self.transport.close()
-
- def on_response_complete(self) -> None:
- self.server_state.total_requests += 1
-
- if self.transport.is_closing():
- return
-
- # Set a short Keep-Alive timeout.
- self._unset_keepalive_if_required()
-
- self.timeout_keep_alive_task = self.loop.call_later(self.timeout_keep_alive, self.timeout_keep_alive_handler)
-
- # Unpause data reads if needed.
- self.flow.resume_reading()
-
- # Unblock any pipelined events.
- if self.conn.our_state is h11.DONE and self.conn.their_state is h11.DONE:
- self.conn.start_next_cycle()
- self.handle_events()
-
- def shutdown(self) -> None:
- """
- Called by the server to commence a graceful shutdown.
- """
- if self.cycle is None or self.cycle.response_complete:
- event = h11.ConnectionClosed()
- self.conn.send(event)
- self.transport.close()
- else:
- self.cycle.keep_alive = False
-
- def pause_writing(self) -> None:
- """
- Called by the transport when the write buffer exceeds the high water mark.
- """
- self.flow.pause_writing()
-
- def resume_writing(self) -> None:
- """
- Called by the transport when the write buffer drops below the low water mark.
- """
- self.flow.resume_writing()
-
- def timeout_keep_alive_handler(self) -> None:
- """
- Called on a keep-alive connection if no new data is received after a short
- delay.
- """
- if not self.transport.is_closing():
- event = h11.ConnectionClosed()
- self.conn.send(event)
- self.transport.close()
-
-
-class RequestResponseCycle:
- def __init__(
- self,
- scope: HTTPScope,
- conn: h11.Connection,
- transport: asyncio.Transport,
- flow: FlowControl,
- logger: logging.Logger,
- access_logger: logging.Logger,
- access_log: bool,
- default_headers: list[tuple[bytes, bytes]],
- message_event: asyncio.Event,
- on_response: Callable[..., None],
- ) -> None:
- self.scope = scope
- self.conn = conn
- self.transport = transport
- self.flow = flow
- self.logger = logger
- self.access_logger = access_logger
- self.access_log = access_log
- self.default_headers = default_headers
- self.message_event = message_event
- self.on_response = on_response
-
- # Connection state
- self.disconnected = False
- self.keep_alive = True
- self.waiting_for_100_continue = conn.they_are_waiting_for_100_continue
-
- # Request state
- self.body = b""
- self.more_body = True
-
- # Response state
- self.response_started = False
- self.response_complete = False
-
- # ASGI exception wrapper
- async def run_asgi(self, app: ASGI3Application) -> None:
- try:
- result = await app( # type: ignore[func-returns-value]
- self.scope, self.receive, self.send
- )
- except BaseException as exc:
- msg = "Exception in ASGI application\n"
- self.logger.error(msg, exc_info=exc)
- if not self.response_started:
- await self.send_500_response()
- else:
- self.transport.close()
- else:
- if result is not None:
- msg = "ASGI callable should return None, but returned '%s'."
- self.logger.error(msg, result)
- self.transport.close()
- elif not self.response_started and not self.disconnected:
- msg = "ASGI callable returned without starting response."
- self.logger.error(msg)
- await self.send_500_response()
- elif not self.response_complete and not self.disconnected:
- msg = "ASGI callable returned without completing response."
- self.logger.error(msg)
- self.transport.close()
- finally:
- self.on_response = lambda: None
-
- async def send_500_response(self) -> None:
- response_start_event: HTTPResponseStartEvent = {
- "type": "http.response.start",
- "status": 500,
- "headers": [
- (b"content-type", b"text/plain; charset=utf-8"),
- (b"connection", b"close"),
- ],
- }
- await self.send(response_start_event)
- response_body_event: HTTPResponseBodyEvent = {
- "type": "http.response.body",
- "body": b"Internal Server Error",
- "more_body": False,
- }
- await self.send(response_body_event)
-
- # ASGI interface
- async def send(self, message: ASGISendEvent) -> None:
- message_type = message["type"]
-
- if self.flow.write_paused and not self.disconnected:
- await self.flow.drain()
-
- if self.disconnected:
- return
-
- if not self.response_started:
- # Sending response status line and headers
- if message_type != "http.response.start":
- msg = "Expected ASGI message 'http.response.start', but got '%s'."
- raise RuntimeError(msg % message_type)
- message = cast("HTTPResponseStartEvent", message)
-
- self.response_started = True
- self.waiting_for_100_continue = False
-
- status = message["status"]
- headers = self.default_headers + list(message.get("headers", []))
-
- if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers:
- headers = headers + [CLOSE_HEADER]
-
- if self.access_log:
- self.access_logger.info(
- '%s - "%s %s HTTP/%s" %d',
- get_client_addr(self.scope),
- self.scope["method"],
- get_path_with_query_string(self.scope),
- self.scope["http_version"],
- status,
- )
-
- # Write response status line and headers
- reason = STATUS_PHRASES[status]
- response = h11.Response(status_code=status, headers=headers, reason=reason)
- output = self.conn.send(event=response)
- self.transport.write(output)
-
- elif not self.response_complete:
- # Sending response body
- if message_type != "http.response.body":
- msg = "Expected ASGI message 'http.response.body', but got '%s'."
- raise RuntimeError(msg % message_type)
- message = cast("HTTPResponseBodyEvent", message)
-
- body = message.get("body", b"")
- more_body = message.get("more_body", False)
-
- # Write response body
- data = b"" if self.scope["method"] == "HEAD" else body
- output = self.conn.send(event=h11.Data(data=data))
- self.transport.write(output)
-
- # Handle response completion
- if not more_body:
- self.response_complete = True
- self.message_event.set()
- output = self.conn.send(event=h11.EndOfMessage())
- self.transport.write(output)
-
- else:
- # Response already sent
- msg = "Unexpected ASGI message '%s' sent, after response already completed."
- raise RuntimeError(msg % message_type)
-
- if self.response_complete:
- if self.conn.our_state is h11.MUST_CLOSE or not self.keep_alive:
- self.conn.send(event=h11.ConnectionClosed())
- self.transport.close()
- self.on_response()
-
- async def receive(self) -> ASGIReceiveEvent:
- if self.waiting_for_100_continue and not self.transport.is_closing():
- headers: list[tuple[str, str]] = []
- event = h11.InformationalResponse(status_code=100, headers=headers, reason="Continue")
- output = self.conn.send(event=event)
- self.transport.write(output)
- self.waiting_for_100_continue = False
-
- if not self.disconnected and not self.response_complete:
- self.flow.resume_reading()
- await self.message_event.wait()
- self.message_event.clear()
-
- if self.disconnected or self.response_complete:
- return {"type": "http.disconnect"}
-
- message: HTTPRequestEvent = {
- "type": "http.request",
- "body": self.body,
- "more_body": self.more_body,
- }
- self.body = b""
- return message
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py
deleted file mode 100644
index 997c6bb..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py
+++ /dev/null
@@ -1,575 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import http
-import logging
-import re
-import urllib
-from asyncio.events import TimerHandle
-from collections import deque
-from typing import Any, Callable, Literal, cast
-
-import httptools
-
-from uvicorn._types import (
- ASGI3Application,
- ASGIReceiveEvent,
- ASGISendEvent,
- HTTPRequestEvent,
- HTTPResponseBodyEvent,
- HTTPResponseStartEvent,
- HTTPScope,
-)
-from uvicorn.config import Config
-from uvicorn.logging import TRACE_LOG_LEVEL
-from uvicorn.protocols.http.flow_control import (
- CLOSE_HEADER,
- HIGH_WATER_LIMIT,
- FlowControl,
- service_unavailable,
-)
-from uvicorn.protocols.utils import (
- get_client_addr,
- get_local_addr,
- get_path_with_query_string,
- get_remote_addr,
- is_ssl,
-)
-from uvicorn.server import ServerState
-
-HEADER_RE = re.compile(b'[\x00-\x1F\x7F()<>@,;:[]={} \t\\"]')
-HEADER_VALUE_RE = re.compile(b"[\x00-\x1F\x7F]")
-
-
-def _get_status_line(status_code: int) -> bytes:
- try:
- phrase = http.HTTPStatus(status_code).phrase.encode()
- except ValueError:
- phrase = b""
- return b"".join([b"HTTP/1.1 ", str(status_code).encode(), b" ", phrase, b"\r\n"])
-
-
-STATUS_LINE = {status_code: _get_status_line(status_code) for status_code in range(100, 600)}
-
-
-class HttpToolsProtocol(asyncio.Protocol):
- def __init__(
- self,
- config: Config,
- server_state: ServerState,
- app_state: dict[str, Any],
- _loop: asyncio.AbstractEventLoop | None = None,
- ) -> None:
- if not config.loaded:
- config.load()
-
- self.config = config
- self.app = config.loaded_app
- self.loop = _loop or asyncio.get_event_loop()
- self.logger = logging.getLogger("uvicorn.error")
- self.access_logger = logging.getLogger("uvicorn.access")
- self.access_log = self.access_logger.hasHandlers()
- self.parser = httptools.HttpRequestParser(self)
- self.ws_protocol_class = config.ws_protocol_class
- self.root_path = config.root_path
- self.limit_concurrency = config.limit_concurrency
- self.app_state = app_state
-
- # Timeouts
- self.timeout_keep_alive_task: TimerHandle | None = None
- self.timeout_keep_alive = config.timeout_keep_alive
-
- # Global state
- self.server_state = server_state
- self.connections = server_state.connections
- self.tasks = server_state.tasks
-
- # Per-connection state
- self.transport: asyncio.Transport = None # type: ignore[assignment]
- self.flow: FlowControl = None # type: ignore[assignment]
- self.server: tuple[str, int] | None = None
- self.client: tuple[str, int] | None = None
- self.scheme: Literal["http", "https"] | None = None
- self.pipeline: deque[tuple[RequestResponseCycle, ASGI3Application]] = deque()
-
- # Per-request state
- self.scope: HTTPScope = None # type: ignore[assignment]
- self.headers: list[tuple[bytes, bytes]] = None # type: ignore[assignment]
- self.expect_100_continue = False
- self.cycle: RequestResponseCycle = None # type: ignore[assignment]
-
- # Protocol interface
- def connection_made( # type: ignore[override]
- self, transport: asyncio.Transport
- ) -> None:
- self.connections.add(self)
-
- self.transport = transport
- self.flow = FlowControl(transport)
- self.server = get_local_addr(transport)
- self.client = get_remote_addr(transport)
- self.scheme = "https" if is_ssl(transport) else "http"
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection made", prefix)
-
- def connection_lost(self, exc: Exception | None) -> None:
- self.connections.discard(self)
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection lost", prefix)
-
- if self.cycle and not self.cycle.response_complete:
- self.cycle.disconnected = True
- if self.cycle is not None:
- self.cycle.message_event.set()
- if self.flow is not None:
- self.flow.resume_writing()
- if exc is None:
- self.transport.close()
- self._unset_keepalive_if_required()
-
- self.parser = None
-
- def eof_received(self) -> None:
- pass
-
- def _unset_keepalive_if_required(self) -> None:
- if self.timeout_keep_alive_task is not None:
- self.timeout_keep_alive_task.cancel()
- self.timeout_keep_alive_task = None
-
- def _get_upgrade(self) -> bytes | None:
- connection = []
- upgrade = None
- for name, value in self.headers:
- if name == b"connection":
- connection = [token.lower().strip() for token in value.split(b",")]
- if name == b"upgrade":
- upgrade = value.lower()
- if b"upgrade" in connection:
- return upgrade
- return None
-
- def _should_upgrade_to_ws(self, upgrade: bytes | None) -> bool:
- if upgrade == b"websocket" and self.ws_protocol_class is not None:
- return True
- if self.config.ws == "auto":
- msg = "Unsupported upgrade request."
- self.logger.warning(msg)
- msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
- self.logger.warning(msg)
- return False
-
- def _should_upgrade(self) -> bool:
- upgrade = self._get_upgrade()
- return self._should_upgrade_to_ws(upgrade)
-
- def data_received(self, data: bytes) -> None:
- self._unset_keepalive_if_required()
-
- try:
- self.parser.feed_data(data)
- except httptools.HttpParserError:
- msg = "Invalid HTTP request received."
- self.logger.warning(msg)
- self.send_400_response(msg)
- return
- except httptools.HttpParserUpgrade:
- upgrade = self._get_upgrade()
- if self._should_upgrade_to_ws(upgrade):
- self.handle_websocket_upgrade()
-
- def handle_websocket_upgrade(self) -> None:
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sUpgrading to WebSocket", prefix)
-
- self.connections.discard(self)
- method = self.scope["method"].encode()
- output = [method, b" ", self.url, b" HTTP/1.1\r\n"]
- for name, value in self.scope["headers"]:
- output += [name, b": ", value, b"\r\n"]
- output.append(b"\r\n")
- protocol = self.ws_protocol_class( # type: ignore[call-arg, misc]
- config=self.config,
- server_state=self.server_state,
- app_state=self.app_state,
- )
- protocol.connection_made(self.transport)
- protocol.data_received(b"".join(output))
- self.transport.set_protocol(protocol)
-
- def send_400_response(self, msg: str) -> None:
- content = [STATUS_LINE[400]]
- for name, value in self.server_state.default_headers:
- content.extend([name, b": ", value, b"\r\n"])
- content.extend(
- [
- b"content-type: text/plain; charset=utf-8\r\n",
- b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n",
- b"connection: close\r\n",
- b"\r\n",
- msg.encode("ascii"),
- ]
- )
- self.transport.write(b"".join(content))
- self.transport.close()
-
- def on_message_begin(self) -> None:
- self.url = b""
- self.expect_100_continue = False
- self.headers = []
- self.scope = { # type: ignore[typeddict-item]
- "type": "http",
- "asgi": {"version": self.config.asgi_version, "spec_version": "2.4"},
- "http_version": "1.1",
- "server": self.server,
- "client": self.client,
- "scheme": self.scheme, # type: ignore[typeddict-item]
- "root_path": self.root_path,
- "headers": self.headers,
- "state": self.app_state.copy(),
- }
-
- # Parser callbacks
- def on_url(self, url: bytes) -> None:
- self.url += url
-
- def on_header(self, name: bytes, value: bytes) -> None:
- name = name.lower()
- if name == b"expect" and value.lower() == b"100-continue":
- self.expect_100_continue = True
- self.headers.append((name, value))
-
- def on_headers_complete(self) -> None:
- http_version = self.parser.get_http_version()
- method = self.parser.get_method()
- self.scope["method"] = method.decode("ascii")
- if http_version != "1.1":
- self.scope["http_version"] = http_version
- if self.parser.should_upgrade() and self._should_upgrade():
- return
- parsed_url = httptools.parse_url(self.url)
- raw_path = parsed_url.path
- path = raw_path.decode("ascii")
- if "%" in path:
- path = urllib.parse.unquote(path)
- full_path = self.root_path + path
- full_raw_path = self.root_path.encode("ascii") + raw_path
- self.scope["path"] = full_path
- self.scope["raw_path"] = full_raw_path
- self.scope["query_string"] = parsed_url.query or b""
-
- # Handle 503 responses when 'limit_concurrency' is exceeded.
- if self.limit_concurrency is not None and (
- len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency
- ):
- app = service_unavailable
- message = "Exceeded concurrency limit."
- self.logger.warning(message)
- else:
- app = self.app
-
- existing_cycle = self.cycle
- self.cycle = RequestResponseCycle(
- scope=self.scope,
- transport=self.transport,
- flow=self.flow,
- logger=self.logger,
- access_logger=self.access_logger,
- access_log=self.access_log,
- default_headers=self.server_state.default_headers,
- message_event=asyncio.Event(),
- expect_100_continue=self.expect_100_continue,
- keep_alive=http_version != "1.0",
- on_response=self.on_response_complete,
- )
- if existing_cycle is None or existing_cycle.response_complete:
- # Standard case - start processing the request.
- task = self.loop.create_task(self.cycle.run_asgi(app))
- task.add_done_callback(self.tasks.discard)
- self.tasks.add(task)
- else:
- # Pipelined HTTP requests need to be queued up.
- self.flow.pause_reading()
- self.pipeline.appendleft((self.cycle, app))
-
- def on_body(self, body: bytes) -> None:
- if (self.parser.should_upgrade() and self._should_upgrade()) or self.cycle.response_complete:
- return
- self.cycle.body += body
- if len(self.cycle.body) > HIGH_WATER_LIMIT:
- self.flow.pause_reading()
- self.cycle.message_event.set()
-
- def on_message_complete(self) -> None:
- if (self.parser.should_upgrade() and self._should_upgrade()) or self.cycle.response_complete:
- return
- self.cycle.more_body = False
- self.cycle.message_event.set()
-
- def on_response_complete(self) -> None:
- # Callback for pipelined HTTP requests to be started.
- self.server_state.total_requests += 1
-
- if self.transport.is_closing():
- return
-
- self._unset_keepalive_if_required()
-
- # Unpause data reads if needed.
- self.flow.resume_reading()
-
- # Unblock any pipelined events. If there are none, arm the
- # Keep-Alive timeout instead.
- if self.pipeline:
- cycle, app = self.pipeline.pop()
- task = self.loop.create_task(cycle.run_asgi(app))
- task.add_done_callback(self.tasks.discard)
- self.tasks.add(task)
- else:
- self.timeout_keep_alive_task = self.loop.call_later(
- self.timeout_keep_alive, self.timeout_keep_alive_handler
- )
-
- def shutdown(self) -> None:
- """
- Called by the server to commence a graceful shutdown.
- """
- if self.cycle is None or self.cycle.response_complete:
- self.transport.close()
- else:
- self.cycle.keep_alive = False
-
- def pause_writing(self) -> None:
- """
- Called by the transport when the write buffer exceeds the high water mark.
- """
- self.flow.pause_writing()
-
- def resume_writing(self) -> None:
- """
- Called by the transport when the write buffer drops below the low water mark.
- """
- self.flow.resume_writing()
-
- def timeout_keep_alive_handler(self) -> None:
- """
- Called on a keep-alive connection if no new data is received after a short
- delay.
- """
- if not self.transport.is_closing():
- self.transport.close()
-
-
-class RequestResponseCycle:
- def __init__(
- self,
- scope: HTTPScope,
- transport: asyncio.Transport,
- flow: FlowControl,
- logger: logging.Logger,
- access_logger: logging.Logger,
- access_log: bool,
- default_headers: list[tuple[bytes, bytes]],
- message_event: asyncio.Event,
- expect_100_continue: bool,
- keep_alive: bool,
- on_response: Callable[..., None],
- ):
- self.scope = scope
- self.transport = transport
- self.flow = flow
- self.logger = logger
- self.access_logger = access_logger
- self.access_log = access_log
- self.default_headers = default_headers
- self.message_event = message_event
- self.on_response = on_response
-
- # Connection state
- self.disconnected = False
- self.keep_alive = keep_alive
- self.waiting_for_100_continue = expect_100_continue
-
- # Request state
- self.body = b""
- self.more_body = True
-
- # Response state
- self.response_started = False
- self.response_complete = False
- self.chunked_encoding: bool | None = None
- self.expected_content_length = 0
-
- # ASGI exception wrapper
- async def run_asgi(self, app: ASGI3Application) -> None:
- try:
- result = await app( # type: ignore[func-returns-value]
- self.scope, self.receive, self.send
- )
- except BaseException as exc:
- msg = "Exception in ASGI application\n"
- self.logger.error(msg, exc_info=exc)
- if not self.response_started:
- await self.send_500_response()
- else:
- self.transport.close()
- else:
- if result is not None:
- msg = "ASGI callable should return None, but returned '%s'."
- self.logger.error(msg, result)
- self.transport.close()
- elif not self.response_started and not self.disconnected:
- msg = "ASGI callable returned without starting response."
- self.logger.error(msg)
- await self.send_500_response()
- elif not self.response_complete and not self.disconnected:
- msg = "ASGI callable returned without completing response."
- self.logger.error(msg)
- self.transport.close()
- finally:
- self.on_response = lambda: None
-
- async def send_500_response(self) -> None:
- response_start_event: HTTPResponseStartEvent = {
- "type": "http.response.start",
- "status": 500,
- "headers": [
- (b"content-type", b"text/plain; charset=utf-8"),
- (b"connection", b"close"),
- ],
- }
- await self.send(response_start_event)
- response_body_event: HTTPResponseBodyEvent = {
- "type": "http.response.body",
- "body": b"Internal Server Error",
- "more_body": False,
- }
- await self.send(response_body_event)
-
- # ASGI interface
- async def send(self, message: ASGISendEvent) -> None:
- message_type = message["type"]
-
- if self.flow.write_paused and not self.disconnected:
- await self.flow.drain()
-
- if self.disconnected:
- return
-
- if not self.response_started:
- # Sending response status line and headers
- if message_type != "http.response.start":
- msg = "Expected ASGI message 'http.response.start', but got '%s'."
- raise RuntimeError(msg % message_type)
- message = cast("HTTPResponseStartEvent", message)
-
- self.response_started = True
- self.waiting_for_100_continue = False
-
- status_code = message["status"]
- headers = self.default_headers + list(message.get("headers", []))
-
- if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers:
- headers = headers + [CLOSE_HEADER]
-
- if self.access_log:
- self.access_logger.info(
- '%s - "%s %s HTTP/%s" %d',
- get_client_addr(self.scope),
- self.scope["method"],
- get_path_with_query_string(self.scope),
- self.scope["http_version"],
- status_code,
- )
-
- # Write response status line and headers
- content = [STATUS_LINE[status_code]]
-
- for name, value in headers:
- if HEADER_RE.search(name):
- raise RuntimeError("Invalid HTTP header name.")
- if HEADER_VALUE_RE.search(value):
- raise RuntimeError("Invalid HTTP header value.")
-
- name = name.lower()
- if name == b"content-length" and self.chunked_encoding is None:
- self.expected_content_length = int(value.decode())
- self.chunked_encoding = False
- elif name == b"transfer-encoding" and value.lower() == b"chunked":
- self.expected_content_length = 0
- self.chunked_encoding = True
- elif name == b"connection" and value.lower() == b"close":
- self.keep_alive = False
- content.extend([name, b": ", value, b"\r\n"])
-
- if self.chunked_encoding is None and self.scope["method"] != "HEAD" and status_code not in (204, 304):
- # Neither content-length nor transfer-encoding specified
- self.chunked_encoding = True
- content.append(b"transfer-encoding: chunked\r\n")
-
- content.append(b"\r\n")
- self.transport.write(b"".join(content))
-
- elif not self.response_complete:
- # Sending response body
- if message_type != "http.response.body":
- msg = "Expected ASGI message 'http.response.body', but got '%s'."
- raise RuntimeError(msg % message_type)
-
- body = cast(bytes, message.get("body", b""))
- more_body = message.get("more_body", False)
-
- # Write response body
- if self.scope["method"] == "HEAD":
- self.expected_content_length = 0
- elif self.chunked_encoding:
- if body:
- content = [b"%x\r\n" % len(body), body, b"\r\n"]
- else:
- content = []
- if not more_body:
- content.append(b"0\r\n\r\n")
- self.transport.write(b"".join(content))
- else:
- num_bytes = len(body)
- if num_bytes > self.expected_content_length:
- raise RuntimeError("Response content longer than Content-Length")
- else:
- self.expected_content_length -= num_bytes
- self.transport.write(body)
-
- # Handle response completion
- if not more_body:
- if self.expected_content_length != 0:
- raise RuntimeError("Response content shorter than Content-Length")
- self.response_complete = True
- self.message_event.set()
- if not self.keep_alive:
- self.transport.close()
- self.on_response()
-
- else:
- # Response already sent
- msg = "Unexpected ASGI message '%s' sent, after response already completed."
- raise RuntimeError(msg % message_type)
-
- async def receive(self) -> ASGIReceiveEvent:
- if self.waiting_for_100_continue and not self.transport.is_closing():
- self.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")
- self.waiting_for_100_continue = False
-
- if not self.disconnected and not self.response_complete:
- self.flow.resume_reading()
- await self.message_event.wait()
- self.message_event.clear()
-
- if self.disconnected or self.response_complete:
- return {"type": "http.disconnect"}
- message: HTTPRequestEvent = {"type": "http.request", "body": self.body, "more_body": self.more_body}
- self.body = b""
- return message
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/utils.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/utils.py
deleted file mode 100644
index 4e65806..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/utils.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import urllib.parse
-
-from uvicorn._types import WWWScope
-
-
-class ClientDisconnected(IOError):
- ...
-
-
-def get_remote_addr(transport: asyncio.Transport) -> tuple[str, int] | None:
- socket_info = transport.get_extra_info("socket")
- if socket_info is not None:
- try:
- info = socket_info.getpeername()
- return (str(info[0]), int(info[1])) if isinstance(info, tuple) else None
- except OSError: # pragma: no cover
- # This case appears to inconsistently occur with uvloop
- # bound to a unix domain socket.
- return None
-
- info = transport.get_extra_info("peername")
- if info is not None and isinstance(info, (list, tuple)) and len(info) == 2:
- return (str(info[0]), int(info[1]))
- return None
-
-
-def get_local_addr(transport: asyncio.Transport) -> tuple[str, int] | None:
- socket_info = transport.get_extra_info("socket")
- if socket_info is not None:
- info = socket_info.getsockname()
-
- return (str(info[0]), int(info[1])) if isinstance(info, tuple) else None
- info = transport.get_extra_info("sockname")
- if info is not None and isinstance(info, (list, tuple)) and len(info) == 2:
- return (str(info[0]), int(info[1]))
- return None
-
-
-def is_ssl(transport: asyncio.Transport) -> bool:
- return bool(transport.get_extra_info("sslcontext"))
-
-
-def get_client_addr(scope: WWWScope) -> str:
- client = scope.get("client")
- if not client:
- return ""
- return "%s:%d" % client
-
-
-def get_path_with_query_string(scope: WWWScope) -> str:
- path_with_query_string = urllib.parse.quote(scope["path"])
- if scope["query_string"]:
- path_with_query_string = "{}?{}".format(path_with_query_string, scope["query_string"].decode("ascii"))
- return path_with_query_string
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index d216ab9..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-311.pyc
deleted file mode 100644
index e8c06fa..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-311.pyc
deleted file mode 100644
index 334a441..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-311.pyc
deleted file mode 100644
index 3b1911e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/auto.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/auto.py
deleted file mode 100644
index 08fd136..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/auto.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import typing
-
-AutoWebSocketsProtocol: typing.Callable[..., asyncio.Protocol] | None
-try:
- import websockets # noqa
-except ImportError: # pragma: no cover
- try:
- import wsproto # noqa
- except ImportError:
- AutoWebSocketsProtocol = None
- else:
- from uvicorn.protocols.websockets.wsproto_impl import WSProtocol
-
- AutoWebSocketsProtocol = WSProtocol
-else:
- from uvicorn.protocols.websockets.websockets_impl import WebSocketProtocol
-
- AutoWebSocketsProtocol = WebSocketProtocol
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/websockets_impl.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/websockets_impl.py
deleted file mode 100644
index 6d098d5..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/websockets_impl.py
+++ /dev/null
@@ -1,388 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import http
-import logging
-from typing import Any, Literal, Optional, Sequence, cast
-from urllib.parse import unquote
-
-import websockets
-from websockets.datastructures import Headers
-from websockets.exceptions import ConnectionClosed
-from websockets.extensions.permessage_deflate import ServerPerMessageDeflateFactory
-from websockets.legacy.server import HTTPResponse
-from websockets.server import WebSocketServerProtocol
-from websockets.typing import Subprotocol
-
-from uvicorn._types import (
- ASGISendEvent,
- WebSocketAcceptEvent,
- WebSocketCloseEvent,
- WebSocketConnectEvent,
- WebSocketDisconnectEvent,
- WebSocketReceiveEvent,
- WebSocketResponseBodyEvent,
- WebSocketResponseStartEvent,
- WebSocketScope,
- WebSocketSendEvent,
-)
-from uvicorn.config import Config
-from uvicorn.logging import TRACE_LOG_LEVEL
-from uvicorn.protocols.utils import (
- ClientDisconnected,
- get_local_addr,
- get_path_with_query_string,
- get_remote_addr,
- is_ssl,
-)
-from uvicorn.server import ServerState
-
-
-class Server:
- closing = False
-
- def register(self, ws: WebSocketServerProtocol) -> None:
- pass
-
- def unregister(self, ws: WebSocketServerProtocol) -> None:
- pass
-
- def is_serving(self) -> bool:
- return not self.closing
-
-
-class WebSocketProtocol(WebSocketServerProtocol):
- extra_headers: list[tuple[str, str]]
-
- def __init__(
- self,
- config: Config,
- server_state: ServerState,
- app_state: dict[str, Any],
- _loop: asyncio.AbstractEventLoop | None = None,
- ):
- if not config.loaded:
- config.load()
-
- self.config = config
- self.app = config.loaded_app
- self.loop = _loop or asyncio.get_event_loop()
- self.root_path = config.root_path
- self.app_state = app_state
-
- # Shared server state
- self.connections = server_state.connections
- self.tasks = server_state.tasks
-
- # Connection state
- self.transport: asyncio.Transport = None # type: ignore[assignment]
- self.server: tuple[str, int] | None = None
- self.client: tuple[str, int] | None = None
- self.scheme: Literal["wss", "ws"] = None # type: ignore[assignment]
-
- # Connection events
- self.scope: WebSocketScope
- self.handshake_started_event = asyncio.Event()
- self.handshake_completed_event = asyncio.Event()
- self.closed_event = asyncio.Event()
- self.initial_response: HTTPResponse | None = None
- self.connect_sent = False
- self.lost_connection_before_handshake = False
- self.accepted_subprotocol: Subprotocol | None = None
-
- self.ws_server: Server = Server() # type: ignore[assignment]
-
- extensions = []
- if self.config.ws_per_message_deflate:
- extensions.append(ServerPerMessageDeflateFactory())
-
- super().__init__(
- ws_handler=self.ws_handler,
- ws_server=self.ws_server, # type: ignore[arg-type]
- max_size=self.config.ws_max_size,
- max_queue=self.config.ws_max_queue,
- ping_interval=self.config.ws_ping_interval,
- ping_timeout=self.config.ws_ping_timeout,
- extensions=extensions,
- logger=logging.getLogger("uvicorn.error"),
- )
- self.server_header = None
- self.extra_headers = [
- (name.decode("latin-1"), value.decode("latin-1")) for name, value in server_state.default_headers
- ]
-
- def connection_made( # type: ignore[override]
- self, transport: asyncio.Transport
- ) -> None:
- self.connections.add(self)
- self.transport = transport
- self.server = get_local_addr(transport)
- self.client = get_remote_addr(transport)
- self.scheme = "wss" if is_ssl(transport) else "ws"
-
- if self.logger.isEnabledFor(TRACE_LOG_LEVEL):
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection made", prefix)
-
- super().connection_made(transport)
-
- def connection_lost(self, exc: Exception | None) -> None:
- self.connections.remove(self)
-
- if self.logger.isEnabledFor(TRACE_LOG_LEVEL):
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix)
-
- self.lost_connection_before_handshake = not self.handshake_completed_event.is_set()
- self.handshake_completed_event.set()
- super().connection_lost(exc)
- if exc is None:
- self.transport.close()
-
- def shutdown(self) -> None:
- self.ws_server.closing = True
- if self.handshake_completed_event.is_set():
- self.fail_connection(1012)
- else:
- self.send_500_response()
- self.transport.close()
-
- def on_task_complete(self, task: asyncio.Task) -> None:
- self.tasks.discard(task)
-
- async def process_request(self, path: str, headers: Headers) -> HTTPResponse | None:
- """
- This hook is called to determine if the websocket should return
- an HTTP response and close.
-
- Our behavior here is to start the ASGI application, and then wait
- for either `accept` or `close` in order to determine if we should
- close the connection.
- """
- path_portion, _, query_string = path.partition("?")
-
- websockets.legacy.handshake.check_request(headers)
-
- subprotocols = []
- for header in headers.get_all("Sec-WebSocket-Protocol"):
- subprotocols.extend([token.strip() for token in header.split(",")])
-
- asgi_headers = [
- (name.encode("ascii"), value.encode("ascii", errors="surrogateescape"))
- for name, value in headers.raw_items()
- ]
- path = unquote(path_portion)
- full_path = self.root_path + path
- full_raw_path = self.root_path.encode("ascii") + path_portion.encode("ascii")
-
- self.scope = {
- "type": "websocket",
- "asgi": {"version": self.config.asgi_version, "spec_version": "2.4"},
- "http_version": "1.1",
- "scheme": self.scheme,
- "server": self.server,
- "client": self.client,
- "root_path": self.root_path,
- "path": full_path,
- "raw_path": full_raw_path,
- "query_string": query_string.encode("ascii"),
- "headers": asgi_headers,
- "subprotocols": subprotocols,
- "state": self.app_state.copy(),
- "extensions": {"websocket.http.response": {}},
- }
- task = self.loop.create_task(self.run_asgi())
- task.add_done_callback(self.on_task_complete)
- self.tasks.add(task)
- await self.handshake_started_event.wait()
- return self.initial_response
-
- def process_subprotocol(
- self, headers: Headers, available_subprotocols: Sequence[Subprotocol] | None
- ) -> Subprotocol | None:
- """
- We override the standard 'process_subprotocol' behavior here so that
- we return whatever subprotocol is sent in the 'accept' message.
- """
- return self.accepted_subprotocol
-
- def send_500_response(self) -> None:
- msg = b"Internal Server Error"
- content = [
- b"HTTP/1.1 500 Internal Server Error\r\n" b"content-type: text/plain; charset=utf-8\r\n",
- b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n",
- b"connection: close\r\n",
- b"\r\n",
- msg,
- ]
- self.transport.write(b"".join(content))
- # Allow handler task to terminate cleanly, as websockets doesn't cancel it by
- # itself (see https://github.com/encode/uvicorn/issues/920)
- self.handshake_started_event.set()
-
- async def ws_handler( # type: ignore[override]
- self, protocol: WebSocketServerProtocol, path: str
- ) -> Any:
- """
- This is the main handler function for the 'websockets' implementation
- to call into. We just wait for close then return, and instead allow
- 'send' and 'receive' events to drive the flow.
- """
- self.handshake_completed_event.set()
- await self.wait_closed()
-
- async def run_asgi(self) -> None:
- """
- Wrapper around the ASGI callable, handling exceptions and unexpected
- termination states.
- """
- try:
- result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
- except ClientDisconnected:
- self.closed_event.set()
- self.transport.close()
- except BaseException as exc:
- self.closed_event.set()
- msg = "Exception in ASGI application\n"
- self.logger.error(msg, exc_info=exc)
- if not self.handshake_started_event.is_set():
- self.send_500_response()
- else:
- await self.handshake_completed_event.wait()
- self.transport.close()
- else:
- self.closed_event.set()
- if not self.handshake_started_event.is_set():
- msg = "ASGI callable returned without sending handshake."
- self.logger.error(msg)
- self.send_500_response()
- self.transport.close()
- elif result is not None:
- msg = "ASGI callable should return None, but returned '%s'."
- self.logger.error(msg, result)
- await self.handshake_completed_event.wait()
- self.transport.close()
-
- async def asgi_send(self, message: ASGISendEvent) -> None:
- message_type = message["type"]
-
- if not self.handshake_started_event.is_set():
- if message_type == "websocket.accept":
- message = cast("WebSocketAcceptEvent", message)
- self.logger.info(
- '%s - "WebSocket %s" [accepted]',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- )
- self.initial_response = None
- self.accepted_subprotocol = cast(Optional[Subprotocol], message.get("subprotocol"))
- if "headers" in message:
- self.extra_headers.extend(
- # ASGI spec requires bytes
- # But for compatibility we need to convert it to strings
- (name.decode("latin-1"), value.decode("latin-1"))
- for name, value in message["headers"]
- )
- self.handshake_started_event.set()
-
- elif message_type == "websocket.close":
- message = cast("WebSocketCloseEvent", message)
- self.logger.info(
- '%s - "WebSocket %s" 403',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- )
- self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"")
- self.handshake_started_event.set()
- self.closed_event.set()
-
- elif message_type == "websocket.http.response.start":
- message = cast("WebSocketResponseStartEvent", message)
- self.logger.info(
- '%s - "WebSocket %s" %d',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- message["status"],
- )
- # websockets requires the status to be an enum. look it up.
- status = http.HTTPStatus(message["status"])
- headers = [
- (name.decode("latin-1"), value.decode("latin-1")) for name, value in message.get("headers", [])
- ]
- self.initial_response = (status, headers, b"")
- self.handshake_started_event.set()
-
- else:
- msg = (
- "Expected ASGI message 'websocket.accept', 'websocket.close', "
- "or 'websocket.http.response.start' but got '%s'."
- )
- raise RuntimeError(msg % message_type)
-
- elif not self.closed_event.is_set() and self.initial_response is None:
- await self.handshake_completed_event.wait()
-
- try:
- if message_type == "websocket.send":
- message = cast("WebSocketSendEvent", message)
- bytes_data = message.get("bytes")
- text_data = message.get("text")
- data = text_data if bytes_data is None else bytes_data
- await self.send(data) # type: ignore[arg-type]
-
- elif message_type == "websocket.close":
- message = cast("WebSocketCloseEvent", message)
- code = message.get("code", 1000)
- reason = message.get("reason", "") or ""
- await self.close(code, reason)
- self.closed_event.set()
-
- else:
- msg = "Expected ASGI message 'websocket.send' or 'websocket.close'," " but got '%s'."
- raise RuntimeError(msg % message_type)
- except ConnectionClosed as exc:
- raise ClientDisconnected from exc
-
- elif self.initial_response is not None:
- if message_type == "websocket.http.response.body":
- message = cast("WebSocketResponseBodyEvent", message)
- body = self.initial_response[2] + message["body"]
- self.initial_response = self.initial_response[:2] + (body,)
- if not message.get("more_body", False):
- self.closed_event.set()
- else:
- msg = "Expected ASGI message 'websocket.http.response.body' " "but got '%s'."
- raise RuntimeError(msg % message_type)
-
- else:
- msg = "Unexpected ASGI message '%s', after sending 'websocket.close' " "or response already completed."
- raise RuntimeError(msg % message_type)
-
- async def asgi_receive(
- self,
- ) -> WebSocketDisconnectEvent | WebSocketConnectEvent | WebSocketReceiveEvent:
- if not self.connect_sent:
- self.connect_sent = True
- return {"type": "websocket.connect"}
-
- await self.handshake_completed_event.wait()
-
- if self.lost_connection_before_handshake:
- # If the handshake failed or the app closed before handshake completion,
- # use 1006 Abnormal Closure.
- return {"type": "websocket.disconnect", "code": 1006}
-
- if self.closed_event.is_set():
- return {"type": "websocket.disconnect", "code": 1005}
-
- try:
- data = await self.recv()
- except ConnectionClosed as exc:
- self.closed_event.set()
- if self.ws_server.closing:
- return {"type": "websocket.disconnect", "code": 1012}
- return {"type": "websocket.disconnect", "code": exc.code}
-
- if isinstance(data, str):
- return {"type": "websocket.receive", "text": data}
- return {"type": "websocket.receive", "bytes": data}
diff --git a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/wsproto_impl.py b/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/wsproto_impl.py
deleted file mode 100644
index c926252..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/protocols/websockets/wsproto_impl.py
+++ /dev/null
@@ -1,377 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import logging
-import typing
-from typing import Literal
-from urllib.parse import unquote
-
-import wsproto
-from wsproto import ConnectionType, events
-from wsproto.connection import ConnectionState
-from wsproto.extensions import Extension, PerMessageDeflate
-from wsproto.utilities import LocalProtocolError, RemoteProtocolError
-
-from uvicorn._types import (
- ASGISendEvent,
- WebSocketAcceptEvent,
- WebSocketCloseEvent,
- WebSocketEvent,
- WebSocketResponseBodyEvent,
- WebSocketResponseStartEvent,
- WebSocketScope,
- WebSocketSendEvent,
-)
-from uvicorn.config import Config
-from uvicorn.logging import TRACE_LOG_LEVEL
-from uvicorn.protocols.utils import (
- ClientDisconnected,
- get_local_addr,
- get_path_with_query_string,
- get_remote_addr,
- is_ssl,
-)
-from uvicorn.server import ServerState
-
-
-class WSProtocol(asyncio.Protocol):
- def __init__(
- self,
- config: Config,
- server_state: ServerState,
- app_state: dict[str, typing.Any],
- _loop: asyncio.AbstractEventLoop | None = None,
- ) -> None:
- if not config.loaded:
- config.load()
-
- self.config = config
- self.app = config.loaded_app
- self.loop = _loop or asyncio.get_event_loop()
- self.logger = logging.getLogger("uvicorn.error")
- self.root_path = config.root_path
- self.app_state = app_state
-
- # Shared server state
- self.connections = server_state.connections
- self.tasks = server_state.tasks
- self.default_headers = server_state.default_headers
-
- # Connection state
- self.transport: asyncio.Transport = None # type: ignore[assignment]
- self.server: tuple[str, int] | None = None
- self.client: tuple[str, int] | None = None
- self.scheme: Literal["wss", "ws"] = None # type: ignore[assignment]
-
- # WebSocket state
- self.queue: asyncio.Queue[WebSocketEvent] = asyncio.Queue()
- self.handshake_complete = False
- self.close_sent = False
-
- # Rejection state
- self.response_started = False
-
- self.conn = wsproto.WSConnection(connection_type=ConnectionType.SERVER)
-
- self.read_paused = False
- self.writable = asyncio.Event()
- self.writable.set()
-
- # Buffers
- self.bytes = b""
- self.text = ""
-
- # Protocol interface
-
- def connection_made( # type: ignore[override]
- self, transport: asyncio.Transport
- ) -> None:
- self.connections.add(self)
- self.transport = transport
- self.server = get_local_addr(transport)
- self.client = get_remote_addr(transport)
- self.scheme = "wss" if is_ssl(transport) else "ws"
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection made", prefix)
-
- def connection_lost(self, exc: Exception | None) -> None:
- code = 1005 if self.handshake_complete else 1006
- self.queue.put_nowait({"type": "websocket.disconnect", "code": code})
- self.connections.remove(self)
-
- if self.logger.level <= TRACE_LOG_LEVEL:
- prefix = "%s:%d - " % self.client if self.client else ""
- self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix)
-
- self.handshake_complete = True
- if exc is None:
- self.transport.close()
-
- def eof_received(self) -> None:
- pass
-
- def data_received(self, data: bytes) -> None:
- try:
- self.conn.receive_data(data)
- except RemoteProtocolError as err:
- # TODO: Remove `type: ignore` when wsproto fixes the type annotation.
- self.transport.write(self.conn.send(err.event_hint)) # type: ignore[arg-type] # noqa: E501
- self.transport.close()
- else:
- self.handle_events()
-
- def handle_events(self) -> None:
- for event in self.conn.events():
- if isinstance(event, events.Request):
- self.handle_connect(event)
- elif isinstance(event, events.TextMessage):
- self.handle_text(event)
- elif isinstance(event, events.BytesMessage):
- self.handle_bytes(event)
- elif isinstance(event, events.CloseConnection):
- self.handle_close(event)
- elif isinstance(event, events.Ping):
- self.handle_ping(event)
-
- def pause_writing(self) -> None:
- """
- Called by the transport when the write buffer exceeds the high water mark.
- """
- self.writable.clear()
-
- def resume_writing(self) -> None:
- """
- Called by the transport when the write buffer drops below the low water mark.
- """
- self.writable.set()
-
- def shutdown(self) -> None:
- if self.handshake_complete:
- self.queue.put_nowait({"type": "websocket.disconnect", "code": 1012})
- output = self.conn.send(wsproto.events.CloseConnection(code=1012))
- self.transport.write(output)
- else:
- self.send_500_response()
- self.transport.close()
-
- def on_task_complete(self, task: asyncio.Task) -> None:
- self.tasks.discard(task)
-
- # Event handlers
-
- def handle_connect(self, event: events.Request) -> None:
- headers = [(b"host", event.host.encode())]
- headers += [(key.lower(), value) for key, value in event.extra_headers]
- raw_path, _, query_string = event.target.partition("?")
- path = unquote(raw_path)
- full_path = self.root_path + path
- full_raw_path = self.root_path.encode("ascii") + raw_path.encode("ascii")
- self.scope: WebSocketScope = {
- "type": "websocket",
- "asgi": {"version": self.config.asgi_version, "spec_version": "2.4"},
- "http_version": "1.1",
- "scheme": self.scheme,
- "server": self.server,
- "client": self.client,
- "root_path": self.root_path,
- "path": full_path,
- "raw_path": full_raw_path,
- "query_string": query_string.encode("ascii"),
- "headers": headers,
- "subprotocols": event.subprotocols,
- "state": self.app_state.copy(),
- "extensions": {"websocket.http.response": {}},
- }
- self.queue.put_nowait({"type": "websocket.connect"})
- task = self.loop.create_task(self.run_asgi())
- task.add_done_callback(self.on_task_complete)
- self.tasks.add(task)
-
- def handle_text(self, event: events.TextMessage) -> None:
- self.text += event.data
- if event.message_finished:
- self.queue.put_nowait({"type": "websocket.receive", "text": self.text})
- self.text = ""
- if not self.read_paused:
- self.read_paused = True
- self.transport.pause_reading()
-
- def handle_bytes(self, event: events.BytesMessage) -> None:
- self.bytes += event.data
- # todo: we may want to guard the size of self.bytes and self.text
- if event.message_finished:
- self.queue.put_nowait({"type": "websocket.receive", "bytes": self.bytes})
- self.bytes = b""
- if not self.read_paused:
- self.read_paused = True
- self.transport.pause_reading()
-
- def handle_close(self, event: events.CloseConnection) -> None:
- if self.conn.state == ConnectionState.REMOTE_CLOSING:
- self.transport.write(self.conn.send(event.response()))
- self.queue.put_nowait({"type": "websocket.disconnect", "code": event.code})
- self.transport.close()
-
- def handle_ping(self, event: events.Ping) -> None:
- self.transport.write(self.conn.send(event.response()))
-
- def send_500_response(self) -> None:
- if self.response_started or self.handshake_complete:
- return # we cannot send responses anymore
- headers = [
- (b"content-type", b"text/plain; charset=utf-8"),
- (b"connection", b"close"),
- ]
- output = self.conn.send(wsproto.events.RejectConnection(status_code=500, headers=headers, has_body=True))
- output += self.conn.send(wsproto.events.RejectData(data=b"Internal Server Error"))
- self.transport.write(output)
-
- async def run_asgi(self) -> None:
- try:
- result = await self.app(self.scope, self.receive, self.send)
- except ClientDisconnected:
- self.transport.close()
- except BaseException:
- self.logger.exception("Exception in ASGI application\n")
- self.send_500_response()
- self.transport.close()
- else:
- if not self.handshake_complete:
- msg = "ASGI callable returned without completing handshake."
- self.logger.error(msg)
- self.send_500_response()
- self.transport.close()
- elif result is not None:
- msg = "ASGI callable should return None, but returned '%s'."
- self.logger.error(msg, result)
- self.transport.close()
-
- async def send(self, message: ASGISendEvent) -> None:
- await self.writable.wait()
-
- message_type = message["type"]
-
- if not self.handshake_complete:
- if message_type == "websocket.accept":
- message = typing.cast(WebSocketAcceptEvent, message)
- self.logger.info(
- '%s - "WebSocket %s" [accepted]',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- )
- subprotocol = message.get("subprotocol")
- extra_headers = self.default_headers + list(message.get("headers", []))
- extensions: list[Extension] = []
- if self.config.ws_per_message_deflate:
- extensions.append(PerMessageDeflate())
- if not self.transport.is_closing():
- self.handshake_complete = True
- output = self.conn.send(
- wsproto.events.AcceptConnection(
- subprotocol=subprotocol,
- extensions=extensions,
- extra_headers=extra_headers,
- )
- )
- self.transport.write(output)
-
- elif message_type == "websocket.close":
- self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006})
- self.logger.info(
- '%s - "WebSocket %s" 403',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- )
- self.handshake_complete = True
- self.close_sent = True
- event = events.RejectConnection(status_code=403, headers=[])
- output = self.conn.send(event)
- self.transport.write(output)
- self.transport.close()
-
- elif message_type == "websocket.http.response.start":
- message = typing.cast(WebSocketResponseStartEvent, message)
- # ensure status code is in the valid range
- if not (100 <= message["status"] < 600):
- msg = "Invalid HTTP status code '%d' in response."
- raise RuntimeError(msg % message["status"])
- self.logger.info(
- '%s - "WebSocket %s" %d',
- self.scope["client"],
- get_path_with_query_string(self.scope),
- message["status"],
- )
- self.handshake_complete = True
- event = events.RejectConnection(
- status_code=message["status"],
- headers=list(message["headers"]),
- has_body=True,
- )
- output = self.conn.send(event)
- self.transport.write(output)
- self.response_started = True
-
- else:
- msg = (
- "Expected ASGI message 'websocket.accept', 'websocket.close' "
- "or 'websocket.http.response.start' "
- "but got '%s'."
- )
- raise RuntimeError(msg % message_type)
-
- elif not self.close_sent and not self.response_started:
- try:
- if message_type == "websocket.send":
- message = typing.cast(WebSocketSendEvent, message)
- bytes_data = message.get("bytes")
- text_data = message.get("text")
- data = text_data if bytes_data is None else bytes_data
- output = self.conn.send(wsproto.events.Message(data=data)) # type: ignore
- if not self.transport.is_closing():
- self.transport.write(output)
-
- elif message_type == "websocket.close":
- message = typing.cast(WebSocketCloseEvent, message)
- self.close_sent = True
- code = message.get("code", 1000)
- reason = message.get("reason", "") or ""
- self.queue.put_nowait({"type": "websocket.disconnect", "code": code})
- output = self.conn.send(wsproto.events.CloseConnection(code=code, reason=reason))
- if not self.transport.is_closing():
- self.transport.write(output)
- self.transport.close()
-
- else:
- msg = "Expected ASGI message 'websocket.send' or 'websocket.close'," " but got '%s'."
- raise RuntimeError(msg % message_type)
- except LocalProtocolError as exc:
- raise ClientDisconnected from exc
- elif self.response_started:
- if message_type == "websocket.http.response.body":
- message = typing.cast("WebSocketResponseBodyEvent", message)
- body_finished = not message.get("more_body", False)
- reject_data = events.RejectData(data=message["body"], body_finished=body_finished)
- output = self.conn.send(reject_data)
- self.transport.write(output)
-
- if body_finished:
- self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006})
- self.close_sent = True
- self.transport.close()
-
- else:
- msg = "Expected ASGI message 'websocket.http.response.body' " "but got '%s'."
- raise RuntimeError(msg % message_type)
-
- else:
- msg = "Unexpected ASGI message '%s', after sending 'websocket.close'."
- raise RuntimeError(msg % message_type)
-
- async def receive(self) -> WebSocketEvent:
- message = await self.queue.get()
- if self.read_paused and self.queue.empty():
- self.read_paused = False
- self.transport.resume_reading()
- return message
diff --git a/venv/lib/python3.11/site-packages/uvicorn/py.typed b/venv/lib/python3.11/site-packages/uvicorn/py.typed
deleted file mode 100644
index 8b13789..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/py.typed
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/venv/lib/python3.11/site-packages/uvicorn/server.py b/venv/lib/python3.11/site-packages/uvicorn/server.py
deleted file mode 100644
index bfce1b1..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/server.py
+++ /dev/null
@@ -1,335 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import contextlib
-import logging
-import os
-import platform
-import signal
-import socket
-import sys
-import threading
-import time
-from email.utils import formatdate
-from types import FrameType
-from typing import TYPE_CHECKING, Generator, Sequence, Union
-
-import click
-
-from uvicorn.config import Config
-
-if TYPE_CHECKING:
- from uvicorn.protocols.http.h11_impl import H11Protocol
- from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol
- from uvicorn.protocols.websockets.websockets_impl import WebSocketProtocol
- from uvicorn.protocols.websockets.wsproto_impl import WSProtocol
-
- Protocols = Union[H11Protocol, HttpToolsProtocol, WSProtocol, WebSocketProtocol]
-
-HANDLED_SIGNALS = (
- signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
- signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`.
-)
-if sys.platform == "win32": # pragma: py-not-win32
- HANDLED_SIGNALS += (signal.SIGBREAK,) # Windows signal 21. Sent by Ctrl+Break.
-
-logger = logging.getLogger("uvicorn.error")
-
-
-class ServerState:
- """
- Shared servers state that is available between all protocol instances.
- """
-
- def __init__(self) -> None:
- self.total_requests = 0
- self.connections: set[Protocols] = set()
- self.tasks: set[asyncio.Task[None]] = set()
- self.default_headers: list[tuple[bytes, bytes]] = []
-
-
-class Server:
- def __init__(self, config: Config) -> None:
- self.config = config
- self.server_state = ServerState()
-
- self.started = False
- self.should_exit = False
- self.force_exit = False
- self.last_notified = 0.0
-
- self._captured_signals: list[int] = []
-
- def run(self, sockets: list[socket.socket] | None = None) -> None:
- self.config.setup_event_loop()
- return asyncio.run(self.serve(sockets=sockets))
-
- async def serve(self, sockets: list[socket.socket] | None = None) -> None:
- with self.capture_signals():
- await self._serve(sockets)
-
- async def _serve(self, sockets: list[socket.socket] | None = None) -> None:
- process_id = os.getpid()
-
- config = self.config
- if not config.loaded:
- config.load()
-
- self.lifespan = config.lifespan_class(config)
-
- message = "Started server process [%d]"
- color_message = "Started server process [" + click.style("%d", fg="cyan") + "]"
- logger.info(message, process_id, extra={"color_message": color_message})
-
- await self.startup(sockets=sockets)
- if self.should_exit:
- return
- await self.main_loop()
- await self.shutdown(sockets=sockets)
-
- message = "Finished server process [%d]"
- color_message = "Finished server process [" + click.style("%d", fg="cyan") + "]"
- logger.info(message, process_id, extra={"color_message": color_message})
-
- async def startup(self, sockets: list[socket.socket] | None = None) -> None:
- await self.lifespan.startup()
- if self.lifespan.should_exit:
- self.should_exit = True
- return
-
- config = self.config
-
- def create_protocol(
- _loop: asyncio.AbstractEventLoop | None = None,
- ) -> asyncio.Protocol:
- return config.http_protocol_class( # type: ignore[call-arg]
- config=config,
- server_state=self.server_state,
- app_state=self.lifespan.state,
- _loop=_loop,
- )
-
- loop = asyncio.get_running_loop()
-
- listeners: Sequence[socket.SocketType]
- if sockets is not None:
- # Explicitly passed a list of open sockets.
- # We use this when the server is run from a Gunicorn worker.
-
- def _share_socket(
- sock: socket.SocketType,
- ) -> socket.SocketType: # pragma py-linux pragma: py-darwin
- # Windows requires the socket be explicitly shared across
- # multiple workers (processes).
- from socket import fromshare # type: ignore[attr-defined]
-
- sock_data = sock.share(os.getpid()) # type: ignore[attr-defined]
- return fromshare(sock_data)
-
- self.servers: list[asyncio.base_events.Server] = []
- for sock in sockets:
- is_windows = platform.system() == "Windows"
- if config.workers > 1 and is_windows: # pragma: py-not-win32
- sock = _share_socket(sock) # type: ignore[assignment]
- server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog)
- self.servers.append(server)
- listeners = sockets
-
- elif config.fd is not None: # pragma: py-win32
- # Use an existing socket, from a file descriptor.
- sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)
- server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog)
- assert server.sockets is not None # mypy
- listeners = server.sockets
- self.servers = [server]
-
- elif config.uds is not None: # pragma: py-win32
- # Create a socket using UNIX domain socket.
- uds_perms = 0o666
- if os.path.exists(config.uds):
- uds_perms = os.stat(config.uds).st_mode
- server = await loop.create_unix_server(
- create_protocol, path=config.uds, ssl=config.ssl, backlog=config.backlog
- )
- os.chmod(config.uds, uds_perms)
- assert server.sockets is not None # mypy
- listeners = server.sockets
- self.servers = [server]
-
- else:
- # Standard case. Create a socket from a host/port pair.
- try:
- server = await loop.create_server(
- create_protocol,
- host=config.host,
- port=config.port,
- ssl=config.ssl,
- backlog=config.backlog,
- )
- except OSError as exc:
- logger.error(exc)
- await self.lifespan.shutdown()
- sys.exit(1)
-
- assert server.sockets is not None
- listeners = server.sockets
- self.servers = [server]
-
- if sockets is None:
- self._log_started_message(listeners)
- else:
- # We're most likely running multiple workers, so a message has already been
- # logged by `config.bind_socket()`.
- pass
-
- self.started = True
-
- def _log_started_message(self, listeners: Sequence[socket.SocketType]) -> None:
- config = self.config
-
- if config.fd is not None: # pragma: py-win32
- sock = listeners[0]
- logger.info(
- "Uvicorn running on socket %s (Press CTRL+C to quit)",
- sock.getsockname(),
- )
-
- elif config.uds is not None: # pragma: py-win32
- logger.info("Uvicorn running on unix socket %s (Press CTRL+C to quit)", config.uds)
-
- else:
- addr_format = "%s://%s:%d"
- host = "0.0.0.0" if config.host is None else config.host
- if ":" in host:
- # It's an IPv6 address.
- addr_format = "%s://[%s]:%d"
-
- port = config.port
- if port == 0:
- port = listeners[0].getsockname()[1]
-
- protocol_name = "https" if config.ssl else "http"
- message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)"
- color_message = "Uvicorn running on " + click.style(addr_format, bold=True) + " (Press CTRL+C to quit)"
- logger.info(
- message,
- protocol_name,
- host,
- port,
- extra={"color_message": color_message},
- )
-
- async def main_loop(self) -> None:
- counter = 0
- should_exit = await self.on_tick(counter)
- while not should_exit:
- counter += 1
- counter = counter % 864000
- await asyncio.sleep(0.1)
- should_exit = await self.on_tick(counter)
-
- async def on_tick(self, counter: int) -> bool:
- # Update the default headers, once per second.
- if counter % 10 == 0:
- current_time = time.time()
- current_date = formatdate(current_time, usegmt=True).encode()
-
- if self.config.date_header:
- date_header = [(b"date", current_date)]
- else:
- date_header = []
-
- self.server_state.default_headers = date_header + self.config.encoded_headers
-
- # Callback to `callback_notify` once every `timeout_notify` seconds.
- if self.config.callback_notify is not None:
- if current_time - self.last_notified > self.config.timeout_notify:
- self.last_notified = current_time
- await self.config.callback_notify()
-
- # Determine if we should exit.
- if self.should_exit:
- return True
- if self.config.limit_max_requests is not None:
- return self.server_state.total_requests >= self.config.limit_max_requests
- return False
-
- async def shutdown(self, sockets: list[socket.socket] | None = None) -> None:
- logger.info("Shutting down")
-
- # Stop accepting new connections.
- for server in self.servers:
- server.close()
- for sock in sockets or []:
- sock.close()
-
- # Request shutdown on all existing connections.
- for connection in list(self.server_state.connections):
- connection.shutdown()
- await asyncio.sleep(0.1)
-
- # When 3.10 is not supported anymore, use `async with asyncio.timeout(...):`.
- try:
- await asyncio.wait_for(
- self._wait_tasks_to_complete(),
- timeout=self.config.timeout_graceful_shutdown,
- )
- except asyncio.TimeoutError:
- logger.error(
- "Cancel %s running task(s), timeout graceful shutdown exceeded",
- len(self.server_state.tasks),
- )
- for t in self.server_state.tasks:
- if sys.version_info < (3, 9): # pragma: py-gte-39
- t.cancel()
- else: # pragma: py-lt-39
- t.cancel(msg="Task cancelled, timeout graceful shutdown exceeded")
-
- # Send the lifespan shutdown event, and wait for application shutdown.
- if not self.force_exit:
- await self.lifespan.shutdown()
-
- async def _wait_tasks_to_complete(self) -> None:
- # Wait for existing connections to finish sending responses.
- if self.server_state.connections and not self.force_exit:
- msg = "Waiting for connections to close. (CTRL+C to force quit)"
- logger.info(msg)
- while self.server_state.connections and not self.force_exit:
- await asyncio.sleep(0.1)
-
- # Wait for existing tasks to complete.
- if self.server_state.tasks and not self.force_exit:
- msg = "Waiting for background tasks to complete. (CTRL+C to force quit)"
- logger.info(msg)
- while self.server_state.tasks and not self.force_exit:
- await asyncio.sleep(0.1)
-
- for server in self.servers:
- await server.wait_closed()
-
- @contextlib.contextmanager
- def capture_signals(self) -> Generator[None, None, None]:
- # Signals can only be listened to from the main thread.
- if threading.current_thread() is not threading.main_thread():
- yield
- return
- # always use signal.signal, even if loop.add_signal_handler is available
- # this allows to restore previous signal handlers later on
- original_handlers = {sig: signal.signal(sig, self.handle_exit) for sig in HANDLED_SIGNALS}
- try:
- yield
- finally:
- for sig, handler in original_handlers.items():
- signal.signal(sig, handler)
- # If we did gracefully shut down due to a signal, try to
- # trigger the expected behaviour now; multiple signals would be
- # done LIFO, see https://stackoverflow.com/questions/48434964
- for captured_signal in reversed(self._captured_signals):
- signal.raise_signal(captured_signal)
-
- def handle_exit(self, sig: int, frame: FrameType | None) -> None:
- self._captured_signals.append(sig)
- if self.should_exit and sig == signal.SIGINT:
- self.force_exit = True
- else:
- self.should_exit = True
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__init__.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__init__.py
deleted file mode 100644
index c90f24e..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-from uvicorn.supervisors.basereload import BaseReload
-from uvicorn.supervisors.multiprocess import Multiprocess
-
-if TYPE_CHECKING:
- ChangeReload: type[BaseReload]
-else:
- try:
- from uvicorn.supervisors.watchfilesreload import (
- WatchFilesReload as ChangeReload,
- )
- except ImportError: # pragma: no cover
- try:
- from uvicorn.supervisors.watchgodreload import (
- WatchGodReload as ChangeReload,
- )
- except ImportError:
- from uvicorn.supervisors.statreload import StatReload as ChangeReload
-
-__all__ = ["Multiprocess", "ChangeReload"]
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index a382a61..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-311.pyc
deleted file mode 100644
index 7745978..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-311.pyc
deleted file mode 100644
index f448ec4..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-311.pyc
deleted file mode 100644
index ebfb6a2..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-311.pyc
deleted file mode 100644
index 536049f..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchgodreload.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchgodreload.cpython-311.pyc
deleted file mode 100644
index c92ed1a..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/__pycache__/watchgodreload.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/basereload.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/basereload.py
deleted file mode 100644
index 1c791a8..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/basereload.py
+++ /dev/null
@@ -1,121 +0,0 @@
-from __future__ import annotations
-
-import logging
-import os
-import signal
-import sys
-import threading
-from pathlib import Path
-from socket import socket
-from types import FrameType
-from typing import Callable, Iterator
-
-import click
-
-from uvicorn._subprocess import get_subprocess
-from uvicorn.config import Config
-
-HANDLED_SIGNALS = (
- signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
- signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`.
-)
-
-logger = logging.getLogger("uvicorn.error")
-
-
-class BaseReload:
- def __init__(
- self,
- config: Config,
- target: Callable[[list[socket] | None], None],
- sockets: list[socket],
- ) -> None:
- self.config = config
- self.target = target
- self.sockets = sockets
- self.should_exit = threading.Event()
- self.pid = os.getpid()
- self.is_restarting = False
- self.reloader_name: str | None = None
-
- def signal_handler(self, sig: int, frame: FrameType | None) -> None:
- """
- A signal handler that is registered with the parent process.
- """
- if sys.platform == "win32" and self.is_restarting:
- self.is_restarting = False # pragma: py-not-win32
- else:
- self.should_exit.set() # pragma: py-win32
-
- def run(self) -> None:
- self.startup()
- for changes in self:
- if changes:
- logger.warning(
- "%s detected changes in %s. Reloading...",
- self.reloader_name,
- ", ".join(map(_display_path, changes)),
- )
- self.restart()
-
- self.shutdown()
-
- def pause(self) -> None:
- if self.should_exit.wait(self.config.reload_delay):
- raise StopIteration()
-
- def __iter__(self) -> Iterator[list[Path] | None]:
- return self
-
- def __next__(self) -> list[Path] | None:
- return self.should_restart()
-
- def startup(self) -> None:
- message = f"Started reloader process [{self.pid}] using {self.reloader_name}"
- color_message = "Started reloader process [{}] using {}".format(
- click.style(str(self.pid), fg="cyan", bold=True),
- click.style(str(self.reloader_name), fg="cyan", bold=True),
- )
- logger.info(message, extra={"color_message": color_message})
-
- for sig in HANDLED_SIGNALS:
- signal.signal(sig, self.signal_handler)
-
- self.process = get_subprocess(config=self.config, target=self.target, sockets=self.sockets)
- self.process.start()
-
- def restart(self) -> None:
- if sys.platform == "win32": # pragma: py-not-win32
- self.is_restarting = True
- assert self.process.pid is not None
- os.kill(self.process.pid, signal.CTRL_C_EVENT)
- else: # pragma: py-win32
- self.process.terminate()
- self.process.join()
-
- self.process = get_subprocess(config=self.config, target=self.target, sockets=self.sockets)
- self.process.start()
-
- def shutdown(self) -> None:
- if sys.platform == "win32":
- self.should_exit.set() # pragma: py-not-win32
- else:
- self.process.terminate() # pragma: py-win32
- self.process.join()
-
- for sock in self.sockets:
- sock.close()
-
- message = f"Stopping reloader process [{str(self.pid)}]"
- color_message = "Stopping reloader process [{}]".format(click.style(str(self.pid), fg="cyan", bold=True))
- logger.info(message, extra={"color_message": color_message})
-
- def should_restart(self) -> list[Path] | None:
- raise NotImplementedError("Reload strategies should override should_restart()")
-
-
-def _display_path(path: Path) -> str:
- try:
- return f"'{path.relative_to(Path.cwd())}'"
- except ValueError:
- return f"'{path}'"
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/multiprocess.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/multiprocess.py
deleted file mode 100644
index e091672..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/multiprocess.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import annotations
-
-import logging
-import os
-import signal
-import threading
-from multiprocessing.context import SpawnProcess
-from socket import socket
-from types import FrameType
-from typing import Callable
-
-import click
-
-from uvicorn._subprocess import get_subprocess
-from uvicorn.config import Config
-
-HANDLED_SIGNALS = (
- signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
- signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`.
-)
-
-logger = logging.getLogger("uvicorn.error")
-
-
-class Multiprocess:
- def __init__(
- self,
- config: Config,
- target: Callable[[list[socket] | None], None],
- sockets: list[socket],
- ) -> None:
- self.config = config
- self.target = target
- self.sockets = sockets
- self.processes: list[SpawnProcess] = []
- self.should_exit = threading.Event()
- self.pid = os.getpid()
-
- def signal_handler(self, sig: int, frame: FrameType | None) -> None:
- """
- A signal handler that is registered with the parent process.
- """
- self.should_exit.set()
-
- def run(self) -> None:
- self.startup()
- self.should_exit.wait()
- self.shutdown()
-
- def startup(self) -> None:
- message = f"Started parent process [{str(self.pid)}]"
- color_message = "Started parent process [{}]".format(click.style(str(self.pid), fg="cyan", bold=True))
- logger.info(message, extra={"color_message": color_message})
-
- for sig in HANDLED_SIGNALS:
- signal.signal(sig, self.signal_handler)
-
- for _idx in range(self.config.workers):
- process = get_subprocess(config=self.config, target=self.target, sockets=self.sockets)
- process.start()
- self.processes.append(process)
-
- def shutdown(self) -> None:
- for process in self.processes:
- process.terminate()
- process.join()
-
- message = f"Stopping parent process [{str(self.pid)}]"
- color_message = "Stopping parent process [{}]".format(click.style(str(self.pid), fg="cyan", bold=True))
- logger.info(message, extra={"color_message": color_message})
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/statreload.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/statreload.py
deleted file mode 100644
index 70d0a6d..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/statreload.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from __future__ import annotations
-
-import logging
-from pathlib import Path
-from socket import socket
-from typing import Callable, Iterator
-
-from uvicorn.config import Config
-from uvicorn.supervisors.basereload import BaseReload
-
-logger = logging.getLogger("uvicorn.error")
-
-
-class StatReload(BaseReload):
- def __init__(
- self,
- config: Config,
- target: Callable[[list[socket] | None], None],
- sockets: list[socket],
- ) -> None:
- super().__init__(config, target, sockets)
- self.reloader_name = "StatReload"
- self.mtimes: dict[Path, float] = {}
-
- if config.reload_excludes or config.reload_includes:
- logger.warning("--reload-include and --reload-exclude have no effect unless " "watchfiles is installed.")
-
- def should_restart(self) -> list[Path] | None:
- self.pause()
-
- for file in self.iter_py_files():
- try:
- mtime = file.stat().st_mtime
- except OSError: # pragma: nocover
- continue
-
- old_time = self.mtimes.get(file)
- if old_time is None:
- self.mtimes[file] = mtime
- continue
- elif mtime > old_time:
- return [file]
- return None
-
- def restart(self) -> None:
- self.mtimes = {}
- return super().restart()
-
- def iter_py_files(self) -> Iterator[Path]:
- for reload_dir in self.config.reload_dirs:
- for path in list(reload_dir.rglob("*.py")):
- yield path.resolve()
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchfilesreload.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchfilesreload.py
deleted file mode 100644
index 292a7ba..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchfilesreload.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from __future__ import annotations
-
-from pathlib import Path
-from socket import socket
-from typing import Callable
-
-from watchfiles import watch
-
-from uvicorn.config import Config
-from uvicorn.supervisors.basereload import BaseReload
-
-
-class FileFilter:
- def __init__(self, config: Config):
- default_includes = ["*.py"]
- self.includes = [default for default in default_includes if default not in config.reload_excludes]
- self.includes.extend(config.reload_includes)
- self.includes = list(set(self.includes))
-
- default_excludes = [".*", ".py[cod]", ".sw.*", "~*"]
- self.excludes = [default for default in default_excludes if default not in config.reload_includes]
- self.exclude_dirs = []
- for e in config.reload_excludes:
- p = Path(e)
- try:
- is_dir = p.is_dir()
- except OSError: # pragma: no cover
- # gets raised on Windows for values like "*.py"
- is_dir = False
-
- if is_dir:
- self.exclude_dirs.append(p)
- else:
- self.excludes.append(e)
- self.excludes = list(set(self.excludes))
-
- def __call__(self, path: Path) -> bool:
- for include_pattern in self.includes:
- if path.match(include_pattern):
- if str(path).endswith(include_pattern):
- return True
-
- for exclude_dir in self.exclude_dirs:
- if exclude_dir in path.parents:
- return False
-
- for exclude_pattern in self.excludes:
- if path.match(exclude_pattern):
- return False
-
- return True
- return False
-
-
-class WatchFilesReload(BaseReload):
- def __init__(
- self,
- config: Config,
- target: Callable[[list[socket] | None], None],
- sockets: list[socket],
- ) -> None:
- super().__init__(config, target, sockets)
- self.reloader_name = "WatchFiles"
- self.reload_dirs = []
- for directory in config.reload_dirs:
- if Path.cwd() not in directory.parents:
- self.reload_dirs.append(directory)
- if Path.cwd() not in self.reload_dirs:
- self.reload_dirs.append(Path.cwd())
-
- self.watch_filter = FileFilter(config)
- self.watcher = watch(
- *self.reload_dirs,
- watch_filter=None,
- stop_event=self.should_exit,
- # using yield_on_timeout here mostly to make sure tests don't
- # hang forever, won't affect the class's behavior
- yield_on_timeout=True,
- )
-
- def should_restart(self) -> list[Path] | None:
- self.pause()
-
- changes = next(self.watcher)
- if changes:
- unique_paths = {Path(c[1]) for c in changes}
- return [p for p in unique_paths if self.watch_filter(p)]
- return None
diff --git a/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchgodreload.py b/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchgodreload.py
deleted file mode 100644
index 6f248fa..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/supervisors/watchgodreload.py
+++ /dev/null
@@ -1,152 +0,0 @@
-from __future__ import annotations
-
-import logging
-import warnings
-from pathlib import Path
-from socket import socket
-from typing import TYPE_CHECKING, Callable
-
-from watchgod import DefaultWatcher
-
-from uvicorn.config import Config
-from uvicorn.supervisors.basereload import BaseReload
-
-if TYPE_CHECKING:
- import os
-
- DirEntry = os.DirEntry[str]
-
-logger = logging.getLogger("uvicorn.error")
-
-
-class CustomWatcher(DefaultWatcher):
- def __init__(self, root_path: Path, config: Config):
- default_includes = ["*.py"]
- self.includes = [default for default in default_includes if default not in config.reload_excludes]
- self.includes.extend(config.reload_includes)
- self.includes = list(set(self.includes))
-
- default_excludes = [".*", ".py[cod]", ".sw.*", "~*"]
- self.excludes = [default for default in default_excludes if default not in config.reload_includes]
- self.excludes.extend(config.reload_excludes)
- self.excludes = list(set(self.excludes))
-
- self.watched_dirs: dict[str, bool] = {}
- self.watched_files: dict[str, bool] = {}
- self.dirs_includes = set(config.reload_dirs)
- self.dirs_excludes = set(config.reload_dirs_excludes)
- self.resolved_root = root_path
- super().__init__(str(root_path))
-
- def should_watch_file(self, entry: DirEntry) -> bool:
- cached_result = self.watched_files.get(entry.path)
- if cached_result is not None:
- return cached_result
-
- entry_path = Path(entry)
-
- # cwd is not verified through should_watch_dir, so we need to verify here
- if entry_path.parent == Path.cwd() and Path.cwd() not in self.dirs_includes:
- self.watched_files[entry.path] = False
- return False
- for include_pattern in self.includes:
- if str(entry_path).endswith(include_pattern):
- self.watched_files[entry.path] = True
- return True
- if entry_path.match(include_pattern):
- for exclude_pattern in self.excludes:
- if entry_path.match(exclude_pattern):
- self.watched_files[entry.path] = False
- return False
- self.watched_files[entry.path] = True
- return True
- self.watched_files[entry.path] = False
- return False
-
- def should_watch_dir(self, entry: DirEntry) -> bool:
- cached_result = self.watched_dirs.get(entry.path)
- if cached_result is not None:
- return cached_result
-
- entry_path = Path(entry)
-
- if entry_path in self.dirs_excludes:
- self.watched_dirs[entry.path] = False
- return False
-
- for exclude_pattern in self.excludes:
- if entry_path.match(exclude_pattern):
- is_watched = False
- if entry_path in self.dirs_includes:
- is_watched = True
-
- for directory in self.dirs_includes:
- if directory in entry_path.parents:
- is_watched = True
-
- if is_watched:
- logger.debug(
- "WatchGodReload detected a new excluded dir '%s' in '%s'; " "Adding to exclude list.",
- entry_path.relative_to(self.resolved_root),
- str(self.resolved_root),
- )
- self.watched_dirs[entry.path] = False
- self.dirs_excludes.add(entry_path)
- return False
-
- if entry_path in self.dirs_includes:
- self.watched_dirs[entry.path] = True
- return True
-
- for directory in self.dirs_includes:
- if directory in entry_path.parents:
- self.watched_dirs[entry.path] = True
- return True
-
- for include_pattern in self.includes:
- if entry_path.match(include_pattern):
- logger.info(
- "WatchGodReload detected a new reload dir '%s' in '%s'; " "Adding to watch list.",
- str(entry_path.relative_to(self.resolved_root)),
- str(self.resolved_root),
- )
- self.dirs_includes.add(entry_path)
- self.watched_dirs[entry.path] = True
- return True
-
- self.watched_dirs[entry.path] = False
- return False
-
-
-class WatchGodReload(BaseReload):
- def __init__(
- self,
- config: Config,
- target: Callable[[list[socket] | None], None],
- sockets: list[socket],
- ) -> None:
- warnings.warn(
- '"watchgod" is deprecated, you should switch ' "to watchfiles (`pip install watchfiles`).",
- DeprecationWarning,
- )
- super().__init__(config, target, sockets)
- self.reloader_name = "WatchGod"
- self.watchers = []
- reload_dirs = []
- for directory in config.reload_dirs:
- if Path.cwd() not in directory.parents:
- reload_dirs.append(directory)
- if Path.cwd() not in reload_dirs:
- reload_dirs.append(Path.cwd())
- for w in reload_dirs:
- self.watchers.append(CustomWatcher(w.resolve(), self.config))
-
- def should_restart(self) -> list[Path] | None:
- self.pause()
-
- for watcher in self.watchers:
- change = watcher.check()
- if change != set():
- return list({Path(c[1]) for c in change})
-
- return None
diff --git a/venv/lib/python3.11/site-packages/uvicorn/workers.py b/venv/lib/python3.11/site-packages/uvicorn/workers.py
deleted file mode 100644
index 3b46471..0000000
--- a/venv/lib/python3.11/site-packages/uvicorn/workers.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from __future__ import annotations
-
-import asyncio
-import logging
-import signal
-import sys
-from typing import Any
-
-from gunicorn.arbiter import Arbiter
-from gunicorn.workers.base import Worker
-
-from uvicorn.config import Config
-from uvicorn.main import Server
-
-
-class UvicornWorker(Worker):
- """
- A worker class for Gunicorn that interfaces with an ASGI consumer callable,
- rather than a WSGI callable.
- """
-
- CONFIG_KWARGS: dict[str, Any] = {"loop": "auto", "http": "auto"}
-
- def __init__(self, *args: Any, **kwargs: Any) -> None:
- super().__init__(*args, **kwargs)
-
- logger = logging.getLogger("uvicorn.error")
- logger.handlers = self.log.error_log.handlers
- logger.setLevel(self.log.error_log.level)
- logger.propagate = False
-
- logger = logging.getLogger("uvicorn.access")
- logger.handlers = self.log.access_log.handlers
- logger.setLevel(self.log.access_log.level)
- logger.propagate = False
-
- config_kwargs: dict = {
- "app": None,
- "log_config": None,
- "timeout_keep_alive": self.cfg.keepalive,
- "timeout_notify": self.timeout,
- "callback_notify": self.callback_notify,
- "limit_max_requests": self.max_requests,
- "forwarded_allow_ips": self.cfg.forwarded_allow_ips,
- }
-
- if self.cfg.is_ssl:
- ssl_kwargs = {
- "ssl_keyfile": self.cfg.ssl_options.get("keyfile"),
- "ssl_certfile": self.cfg.ssl_options.get("certfile"),
- "ssl_keyfile_password": self.cfg.ssl_options.get("password"),
- "ssl_version": self.cfg.ssl_options.get("ssl_version"),
- "ssl_cert_reqs": self.cfg.ssl_options.get("cert_reqs"),
- "ssl_ca_certs": self.cfg.ssl_options.get("ca_certs"),
- "ssl_ciphers": self.cfg.ssl_options.get("ciphers"),
- }
- config_kwargs.update(ssl_kwargs)
-
- if self.cfg.settings["backlog"].value:
- config_kwargs["backlog"] = self.cfg.settings["backlog"].value
-
- config_kwargs.update(self.CONFIG_KWARGS)
-
- self.config = Config(**config_kwargs)
-
- def init_process(self) -> None:
- self.config.setup_event_loop()
- super().init_process()
-
- def init_signals(self) -> None:
- # Reset signals so Gunicorn doesn't swallow subprocess return codes
- # other signals are set up by Server.install_signal_handlers()
- # See: https://github.com/encode/uvicorn/issues/894
- for s in self.SIGNALS:
- signal.signal(s, signal.SIG_DFL)
-
- signal.signal(signal.SIGUSR1, self.handle_usr1)
- # Don't let SIGUSR1 disturb active requests by interrupting system calls
- signal.siginterrupt(signal.SIGUSR1, False)
-
- def _install_sigquit_handler(self) -> None:
- """Install a SIGQUIT handler on workers.
-
- - https://github.com/encode/uvicorn/issues/1116
- - https://github.com/benoitc/gunicorn/issues/2604
- """
-
- loop = asyncio.get_running_loop()
- loop.add_signal_handler(signal.SIGQUIT, self.handle_exit, signal.SIGQUIT, None)
-
- async def _serve(self) -> None:
- self.config.app = self.wsgi
- server = Server(config=self.config)
- self._install_sigquit_handler()
- await server.serve(sockets=self.sockets)
- if not server.started:
- sys.exit(Arbiter.WORKER_BOOT_ERROR)
-
- def run(self) -> None:
- return asyncio.run(self._serve())
-
- async def callback_notify(self) -> None:
- self.notify()
-
-
-class UvicornH11Worker(UvicornWorker):
- CONFIG_KWARGS = {"loop": "asyncio", "http": "h11"}