Skip to content

Commit 82533e5

Browse files
authored
[gunicorn] Update to 25.2.0 (#15555)
1 parent 1bf663e commit 82533e5

File tree

12 files changed

+188
-13
lines changed

12 files changed

+188
-13
lines changed

stubs/gunicorn/METADATA.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = "25.1.0"
1+
version = "25.2.0"
22
upstream_repository = "https://github.com/benoitc/gunicorn"
33
requires = ["types-gevent"]
44

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from collections.abc import Callable, Iterable
2+
from typing import Any, Literal, SupportsIndex
3+
from typing_extensions import Self, TypeAlias
4+
5+
_H1CProtocol: TypeAlias = Any # gunicorn_h1c H1CProtocol class
6+
7+
class ParseError(Exception): ...
8+
class LimitRequestLine(ParseError): ...
9+
class LimitRequestHeaders(ParseError): ...
10+
class InvalidRequestMethod(ParseError): ...
11+
class InvalidHTTPVersion(ParseError): ...
12+
class InvalidHeaderName(ParseError): ...
13+
class InvalidHeader(ParseError): ...
14+
15+
class PythonProtocol:
16+
__slots__ = (
17+
"_on_message_begin",
18+
"_on_url",
19+
"_on_header",
20+
"_on_headers_complete",
21+
"_on_body",
22+
"_on_message_complete",
23+
"_state",
24+
"_buffer",
25+
"_headers_list",
26+
"method",
27+
"path",
28+
"http_version",
29+
"headers",
30+
"content_length",
31+
"is_chunked",
32+
"should_keep_alive",
33+
"is_complete",
34+
"_body_remaining",
35+
"_skip_body",
36+
"_chunk_state",
37+
"_chunk_size",
38+
"_chunk_remaining",
39+
"_limit_request_line",
40+
"_limit_request_fields",
41+
"_limit_request_field_size",
42+
"_permit_unconventional_http_method",
43+
"_permit_unconventional_http_version",
44+
"_header_count",
45+
)
46+
method: bytes | None
47+
path: bytes | None
48+
http_version: tuple[int, int] | None
49+
headers: list[tuple[bytes, bytes]]
50+
content_length: int | None
51+
is_chunked: bool
52+
should_keep_alive: bool
53+
is_complete: bool
54+
55+
def __init__(
56+
self,
57+
on_message_begin: Callable[[], object] | None = None,
58+
on_url: Callable[[bytes], object] | None = None,
59+
on_header: Callable[[bytes, bytes], object] | None = None,
60+
on_headers_complete: Callable[[], bool] | None = None,
61+
on_body: Callable[[bytes], object] | None = None,
62+
on_message_complete: Callable[[], object] | None = None,
63+
limit_request_line: int = 8190,
64+
limit_request_fields: int = 100,
65+
limit_request_field_size: int = 8190,
66+
permit_unconventional_http_method: bool = False,
67+
permit_unconventional_http_version: bool = False,
68+
) -> None: ...
69+
def feed(self, data: Iterable[SupportsIndex]) -> None: ...
70+
def reset(self) -> None: ...
71+
72+
class CallbackRequest:
73+
__slots__ = (
74+
"method",
75+
"uri",
76+
"path",
77+
"query",
78+
"fragment",
79+
"version",
80+
"headers",
81+
"headers_bytes",
82+
"scheme",
83+
"raw_path",
84+
"content_length",
85+
"chunked",
86+
"must_close",
87+
"proxy_protocol_info",
88+
"_expect_100_continue",
89+
)
90+
method: str | None
91+
uri: str | None
92+
path: str | None
93+
query: str | None
94+
fragment: str | None
95+
version: tuple[int, int] | None
96+
headers: list[tuple[str, str]]
97+
headers_bytes: list[tuple[bytes, bytes]]
98+
scheme: Literal["https", "http"]
99+
raw_path: bytes
100+
content_length: int
101+
chunked: bool
102+
must_close: bool
103+
proxy_protocol_info: dict[str, str | int | None] | None # TODO: Use TypedDict
104+
105+
def __init__(self) -> None: ...
106+
@classmethod
107+
def from_parser(cls, parser: _H1CProtocol | PythonProtocol, is_ssl: bool = False) -> Self: ...
108+
def should_close(self) -> bool: ...
109+
def get_header(self, name: str) -> str | None: ...

stubs/gunicorn/gunicorn/asgi/protocol.pyi

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,47 @@
11
import asyncio
2+
from _typeshed import Incomplete
23
from collections.abc import Iterable
4+
from typing import Final
35

6+
from gunicorn.asgi.parser import CallbackRequest
47
from gunicorn.config import Config
58
from gunicorn.glogging import Logger as GLogger
69
from gunicorn.workers.gasgi import ASGIWorker
710

811
from .._types import _ASGIAppType
912

13+
HIGH_WATER_LIMIT: Final = 65536
14+
15+
class FlowControl:
16+
__slots__ = ("_transport", "read_paused", "write_paused", "_is_writable_event")
17+
read_paused: bool
18+
write_paused: bool
19+
20+
def __init__(self, transport: asyncio.BaseTransport) -> None: ...
21+
async def drain(self) -> None: ...
22+
def pause_reading(self) -> None: ...
23+
def resume_reading(self) -> None: ...
24+
def pause_writing(self) -> None: ...
25+
def resume_writing(self) -> None: ...
26+
1027
class ASGIResponseInfo:
1128
status: str | int
1229
sent: int
1330
headers: list[tuple[str, str]]
1431

1532
def __init__(self, status: str | int, headers: Iterable[tuple[str | bytes, str | bytes]], sent: int) -> None: ...
1633

34+
class BodyReceiver:
35+
__slots__ = ("_chunks", "_complete", "_body_finished", "_closed", "_waiter", "request", "protocol")
36+
request: CallbackRequest
37+
protocol: ASGIProtocol
38+
39+
def __init__(self, request: CallbackRequest, protocol: ASGIProtocol) -> None: ...
40+
def feed(self, chunk: bytes) -> None: ...
41+
def set_complete(self) -> None: ...
42+
def signal_disconnect(self) -> None: ...
43+
async def receive(self) -> dict[str, Incomplete]: ... # TODO: Use TypedDict
44+
1745
class ASGIProtocol(asyncio.Protocol):
1846
worker: ASGIWorker
1947
cfg: Config

stubs/gunicorn/gunicorn/asgi/websocket.pyi

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ WS_GUID: Final = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
2626

2727
class WebSocketProtocol:
2828
transport: asyncio.Transport
29-
reader: asyncio.StreamReader
3029
scope: _ScopeType
3130
app: _ASGIAppType
3231
log: GLogger
@@ -35,7 +34,7 @@ class WebSocketProtocol:
3534
close_code: int | None
3635
close_reason: str | None
3736

38-
def __init__(
39-
self, transport: asyncio.Transport, reader: asyncio.StreamReader, scope: _ScopeType, app: _ASGIAppType, log: GLogger
40-
) -> None: ...
37+
def __init__(self, transport: asyncio.Transport, scope: _ScopeType, app: _ASGIAppType, log: GLogger) -> None: ...
38+
def feed_data(self, data: bytes) -> None: ...
39+
def feed_eof(self) -> None: ...
4140
async def run(self) -> None: ...

stubs/gunicorn/gunicorn/config.pyi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ _ASGILoopValidatorType: TypeAlias = Callable[[str | None], str]
7676
_ASGILifespanValidatorType: TypeAlias = Callable[[str | None], str]
7777
_HTTP2FrameSizeValidatorType: TypeAlias = Callable[[ConvertibleToInt], int]
7878
_HTTPProtocolsValidatorType: TypeAlias = Callable[[str | None], list[str]]
79+
_HttpParserValidatorType: TypeAlias = Callable[[str | None], str]
7980

8081
_ValidatorType: TypeAlias = ( # noqa: Y047
8182
_BoolValidatorType
@@ -92,6 +93,7 @@ _ValidatorType: TypeAlias = ( # noqa: Y047
9293
| _ASGILifespanValidatorType
9394
| _HTTP2FrameSizeValidatorType
9495
| _HTTPProtocolsValidatorType
96+
| _HttpParserValidatorType
9597
)
9698

9799
KNOWN_SETTINGS: list[Setting]
@@ -1156,6 +1158,7 @@ class HeaderMap(Setting):
11561158

11571159
def validate_asgi_loop(val: str | None) -> str: ...
11581160
def validate_asgi_lifespan(val: str | None) -> str: ...
1161+
def validate_http_parser(val: str | None) -> str: ...
11591162

11601163
class ASGILoop(Setting):
11611164
name: ClassVar[str]
@@ -1185,6 +1188,15 @@ class ASGIDisconnectGracePeriod(Setting):
11851188
default: ClassVar[int]
11861189
desc: ClassVar[str]
11871190

1191+
class HttpParser(Setting):
1192+
name: ClassVar[str]
1193+
section: ClassVar[str]
1194+
cli: ClassVar[list[str]]
1195+
meta: ClassVar[str]
1196+
validator: ClassVar[_HttpParserValidatorType]
1197+
default: ClassVar[str]
1198+
desc: ClassVar[str]
1199+
11881200
class RootPath(Setting):
11891201
name: ClassVar[str]
11901202
section: ClassVar[str]
@@ -1291,6 +1303,7 @@ class ControlSocket(Setting):
12911303
meta: ClassVar[str]
12921304
validator: ClassVar[_StringValidatorType]
12931305
default: ClassVar[str]
1306+
default_doc: ClassVar[str]
12941307
desc: ClassVar[str]
12951308

12961309
class ControlSocketMode(Setting):

stubs/gunicorn/gunicorn/glogging.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ class Logger:
151151
extra: Mapping[str, object] | None = None,
152152
) -> None: ...
153153
def atoms(self, resp: Response, req: Request, environ: _EnvironType, request_time: timedelta) -> _AtomsDict: ...
154+
@property
155+
def access_log_enabled(self) -> bool: ...
154156
def access(self, resp: Response, req: Request, environ: _EnvironType, request_time: timedelta) -> None: ...
155157
def now(self) -> str: ...
156158
def reopen_files(self) -> None: ...

stubs/gunicorn/gunicorn/http/errors.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ class ChunkMissingTerminator(IOError):
7070

7171
class LimitRequestLine(ParseException):
7272
size: int
73-
max_size: int
73+
max_size: int | None
7474

75-
def __init__(self, size: int, max_size: int) -> None: ...
75+
def __init__(self, size: int, max_size: int | None = None) -> None: ...
7676

7777
class LimitRequestHeaders(ParseException):
7878
msg: str

stubs/gunicorn/gunicorn/http/wsgi.pyi

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import io
22
import logging
33
import re
44
import socket
5-
from _typeshed import ReadableBuffer
5+
from _typeshed import ReadableBuffer, Unused
66
from collections.abc import Callable
7-
from typing import Any, Final
7+
from typing import Any, Final, Protocol, type_check_only
8+
from typing_extensions import Self
89

910
from gunicorn.config import Config
1011
from gunicorn.http import Request
@@ -15,13 +16,24 @@ BLKSIZE: Final = 0x3FFFFFFF
1516
HEADER_VALUE_RE: Final[re.Pattern[str]]
1617
log: logging.Logger
1718

19+
@type_check_only
20+
class _FileLikeProtocol(Protocol):
21+
def read(self, size: int, /) -> bytes: ...
22+
def seek(self, offset: int, /) -> object: ...
23+
24+
# optional fields:
25+
# def close(self) -> None: ...
26+
# def fileno(self) -> int: ...
27+
1828
class FileWrapper:
1929
filelike: io.IOBase
2030
blksize: int
2131
close: Callable[[], None] | None
2232

23-
def __init__(self, filelike: io.IOBase, blksize: int = 8192) -> None: ...
24-
def __getitem__(self, key: Any) -> bytes: ...
33+
def __init__(self, filelike: _FileLikeProtocol, blksize: int = 8192) -> None: ...
34+
def __getitem__(self, key: Unused) -> bytes: ...
35+
def __iter__(self) -> Self: ...
36+
def __next__(self) -> bytes: ...
2537

2638
class WSGIErrorsWrapper(io.RawIOBase):
2739
streams: list[io.TextIOBase]

stubs/gunicorn/gunicorn/http2/stream.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class HTTP2Stream:
5252
self, weight: int | None = None, depends_on: int | None = None, exclusive: bool | None = None
5353
) -> None: ...
5454
def get_request_body(self) -> bytes: ...
55+
async def read_body_chunk(self) -> bytes | None: ...
5556
def get_pseudo_headers(self) -> dict[str, Incomplete]: ...
5657
def get_regular_headers(self) -> list[tuple[str, Incomplete]]: ...
5758

stubs/gunicorn/gunicorn/pidfile.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from _typeshed import StrOrBytesPath
22

33
class Pidfile:
4+
fname: StrOrBytesPath
5+
pid: int | None
6+
47
def __init__(self, fname: StrOrBytesPath) -> None: ...
58
def create(self, pid: int) -> None: ...
69
def rename(self, path: StrOrBytesPath) -> None: ...

0 commit comments

Comments
 (0)