Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stubs/gunicorn/METADATA.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "25.1.0"
version = "25.2.0"
upstream_repository = "https://github.com/benoitc/gunicorn"
requires = ["types-gevent"]

Expand Down
109 changes: 109 additions & 0 deletions stubs/gunicorn/gunicorn/asgi/parser.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from collections.abc import Callable, Iterable
from typing import Any, Literal, SupportsIndex
from typing_extensions import Self, TypeAlias

_H1CProtocol: TypeAlias = Any # gunicorn_h1c H1CProtocol class

class ParseError(Exception): ...
class LimitRequestLine(ParseError): ...
class LimitRequestHeaders(ParseError): ...
class InvalidRequestMethod(ParseError): ...
class InvalidHTTPVersion(ParseError): ...
class InvalidHeaderName(ParseError): ...
class InvalidHeader(ParseError): ...

class PythonProtocol:
__slots__ = (
"_on_message_begin",
"_on_url",
"_on_header",
"_on_headers_complete",
"_on_body",
"_on_message_complete",
"_state",
"_buffer",
"_headers_list",
"method",
"path",
"http_version",
"headers",
"content_length",
"is_chunked",
"should_keep_alive",
"is_complete",
"_body_remaining",
"_skip_body",
"_chunk_state",
"_chunk_size",
"_chunk_remaining",
"_limit_request_line",
"_limit_request_fields",
"_limit_request_field_size",
"_permit_unconventional_http_method",
"_permit_unconventional_http_version",
"_header_count",
)
method: bytes | None
path: bytes | None
http_version: tuple[int, int] | None
headers: list[tuple[bytes, bytes]]
content_length: int | None
is_chunked: bool
should_keep_alive: bool
is_complete: bool

def __init__(
self,
on_message_begin: Callable[[], object] | None = None,
on_url: Callable[[bytes], object] | None = None,
on_header: Callable[[bytes, bytes], object] | None = None,
on_headers_complete: Callable[[], bool] | None = None,
on_body: Callable[[bytes], object] | None = None,
on_message_complete: Callable[[], object] | None = None,
limit_request_line: int = 8190,
limit_request_fields: int = 100,
limit_request_field_size: int = 8190,
permit_unconventional_http_method: bool = False,
permit_unconventional_http_version: bool = False,
) -> None: ...
def feed(self, data: Iterable[SupportsIndex]) -> None: ...
def reset(self) -> None: ...

class CallbackRequest:
__slots__ = (
"method",
"uri",
"path",
"query",
"fragment",
"version",
"headers",
"headers_bytes",
"scheme",
"raw_path",
"content_length",
"chunked",
"must_close",
"proxy_protocol_info",
"_expect_100_continue",
)
method: str | None
uri: str | None
path: str | None
query: str | None
fragment: str | None
version: tuple[int, int] | None
headers: list[tuple[str, str]]
headers_bytes: list[tuple[bytes, bytes]]
scheme: Literal["https", "http"]
raw_path: bytes
content_length: int
chunked: bool
must_close: bool
proxy_protocol_info: dict[str, str | int | None] | None # TODO: Use TypedDict

def __init__(self) -> None: ...
@classmethod
def from_parser(cls, parser: _H1CProtocol | PythonProtocol, is_ssl: bool = False) -> Self: ...
def should_close(self) -> bool: ...
def get_header(self, name: str) -> str | None: ...
28 changes: 28 additions & 0 deletions stubs/gunicorn/gunicorn/asgi/protocol.pyi
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
import asyncio
from _typeshed import Incomplete
from collections.abc import Iterable
from typing import Final

from gunicorn.asgi.parser import CallbackRequest
from gunicorn.config import Config
from gunicorn.glogging import Logger as GLogger
from gunicorn.workers.gasgi import ASGIWorker

from .._types import _ASGIAppType

HIGH_WATER_LIMIT: Final = 65536

class FlowControl:
__slots__ = ("_transport", "read_paused", "write_paused", "_is_writable_event")
read_paused: bool
write_paused: bool

def __init__(self, transport: asyncio.BaseTransport) -> None: ...
async def drain(self) -> None: ...
def pause_reading(self) -> None: ...
def resume_reading(self) -> None: ...
def pause_writing(self) -> None: ...
def resume_writing(self) -> None: ...

class ASGIResponseInfo:
status: str | int
sent: int
headers: list[tuple[str, str]]

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

class BodyReceiver:
__slots__ = ("_chunks", "_complete", "_body_finished", "_closed", "_waiter", "request", "protocol")
request: CallbackRequest
protocol: ASGIProtocol

def __init__(self, request: CallbackRequest, protocol: ASGIProtocol) -> None: ...
def feed(self, chunk: bytes) -> None: ...
def set_complete(self) -> None: ...
def signal_disconnect(self) -> None: ...
async def receive(self) -> dict[str, Incomplete]: ... # TODO: Use TypedDict

class ASGIProtocol(asyncio.Protocol):
worker: ASGIWorker
cfg: Config
Expand Down
7 changes: 3 additions & 4 deletions stubs/gunicorn/gunicorn/asgi/websocket.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ WS_GUID: Final = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

class WebSocketProtocol:
transport: asyncio.Transport
reader: asyncio.StreamReader
scope: _ScopeType
app: _ASGIAppType
log: GLogger
Expand All @@ -35,7 +34,7 @@ class WebSocketProtocol:
close_code: int | None
close_reason: str | None

def __init__(
self, transport: asyncio.Transport, reader: asyncio.StreamReader, scope: _ScopeType, app: _ASGIAppType, log: GLogger
) -> None: ...
def __init__(self, transport: asyncio.Transport, scope: _ScopeType, app: _ASGIAppType, log: GLogger) -> None: ...
def feed_data(self, data: bytes) -> None: ...
def feed_eof(self) -> None: ...
async def run(self) -> None: ...
13 changes: 13 additions & 0 deletions stubs/gunicorn/gunicorn/config.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ _ASGILoopValidatorType: TypeAlias = Callable[[str | None], str]
_ASGILifespanValidatorType: TypeAlias = Callable[[str | None], str]
_HTTP2FrameSizeValidatorType: TypeAlias = Callable[[ConvertibleToInt], int]
_HTTPProtocolsValidatorType: TypeAlias = Callable[[str | None], list[str]]
_HttpParserValidatorType: TypeAlias = Callable[[str | None], str]

_ValidatorType: TypeAlias = ( # noqa: Y047
_BoolValidatorType
Expand All @@ -92,6 +93,7 @@ _ValidatorType: TypeAlias = ( # noqa: Y047
| _ASGILifespanValidatorType
| _HTTP2FrameSizeValidatorType
| _HTTPProtocolsValidatorType
| _HttpParserValidatorType
)

KNOWN_SETTINGS: list[Setting]
Expand Down Expand Up @@ -1156,6 +1158,7 @@ class HeaderMap(Setting):

def validate_asgi_loop(val: str | None) -> str: ...
def validate_asgi_lifespan(val: str | None) -> str: ...
def validate_http_parser(val: str | None) -> str: ...

class ASGILoop(Setting):
name: ClassVar[str]
Expand Down Expand Up @@ -1185,6 +1188,15 @@ class ASGIDisconnectGracePeriod(Setting):
default: ClassVar[int]
desc: ClassVar[str]

class HttpParser(Setting):
name: ClassVar[str]
section: ClassVar[str]
cli: ClassVar[list[str]]
meta: ClassVar[str]
validator: ClassVar[_HttpParserValidatorType]
default: ClassVar[str]
desc: ClassVar[str]

class RootPath(Setting):
name: ClassVar[str]
section: ClassVar[str]
Expand Down Expand Up @@ -1291,6 +1303,7 @@ class ControlSocket(Setting):
meta: ClassVar[str]
validator: ClassVar[_StringValidatorType]
default: ClassVar[str]
default_doc: ClassVar[str]
desc: ClassVar[str]

class ControlSocketMode(Setting):
Expand Down
2 changes: 2 additions & 0 deletions stubs/gunicorn/gunicorn/glogging.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ class Logger:
extra: Mapping[str, object] | None = None,
) -> None: ...
def atoms(self, resp: Response, req: Request, environ: _EnvironType, request_time: timedelta) -> _AtomsDict: ...
@property
def access_log_enabled(self) -> bool: ...
def access(self, resp: Response, req: Request, environ: _EnvironType, request_time: timedelta) -> None: ...
def now(self) -> str: ...
def reopen_files(self) -> None: ...
Expand Down
4 changes: 2 additions & 2 deletions stubs/gunicorn/gunicorn/http/errors.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class ChunkMissingTerminator(IOError):

class LimitRequestLine(ParseException):
size: int
max_size: int
max_size: int | None

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

class LimitRequestHeaders(ParseException):
msg: str
Expand Down
20 changes: 16 additions & 4 deletions stubs/gunicorn/gunicorn/http/wsgi.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import io
import logging
import re
import socket
from _typeshed import ReadableBuffer
from _typeshed import ReadableBuffer, Unused
from collections.abc import Callable
from typing import Any, Final
from typing import Any, Final, Protocol, type_check_only
from typing_extensions import Self

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

@type_check_only
class _FileLikeProtocol(Protocol):
def read(self, size: int, /) -> bytes: ...
def seek(self, offset: int, /) -> object: ...

# optional fields:
# def close(self) -> None: ...
# def fileno(self) -> int: ...

class FileWrapper:
filelike: io.IOBase
blksize: int
close: Callable[[], None] | None

def __init__(self, filelike: io.IOBase, blksize: int = 8192) -> None: ...
def __getitem__(self, key: Any) -> bytes: ...
def __init__(self, filelike: _FileLikeProtocol, blksize: int = 8192) -> None: ...
def __getitem__(self, key: Unused) -> bytes: ...
def __iter__(self) -> Self: ...
def __next__(self) -> bytes: ...

class WSGIErrorsWrapper(io.RawIOBase):
streams: list[io.TextIOBase]
Expand Down
1 change: 1 addition & 0 deletions stubs/gunicorn/gunicorn/http2/stream.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class HTTP2Stream:
self, weight: int | None = None, depends_on: int | None = None, exclusive: bool | None = None
) -> None: ...
def get_request_body(self) -> bytes: ...
async def read_body_chunk(self) -> bytes | None: ...
def get_pseudo_headers(self) -> dict[str, Incomplete]: ...
def get_regular_headers(self) -> list[tuple[str, Incomplete]]: ...

Expand Down
3 changes: 3 additions & 0 deletions stubs/gunicorn/gunicorn/pidfile.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from _typeshed import StrOrBytesPath

class Pidfile:
fname: StrOrBytesPath
pid: int | None

def __init__(self, fname: StrOrBytesPath) -> None: ...
def create(self, pid: int) -> None: ...
def rename(self, path: StrOrBytesPath) -> None: ...
Expand Down
4 changes: 2 additions & 2 deletions stubs/gunicorn/gunicorn/util.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import types
from _typeshed import FileDescriptorLike, FileDescriptorOrPath, HasFileno, StrOrBytesPath
from _typeshed import FileDescriptorLike, FileDescriptorOrPath, StrOrBytesPath
from inspect import _IntrospectableCallable, _ParameterKind
from socket import socket
from typing import Any, Literal, NoReturn
Expand Down Expand Up @@ -39,7 +39,7 @@ def daemonize(enable_stdio_inheritance: bool = False) -> None: ...
def seed() -> None: ...
def check_is_writable(path: FileDescriptorOrPath) -> None: ...
def to_bytestring(value: str | bytes, encoding: str = "utf8") -> bytes: ...
def has_fileno(obj: HasFileno) -> bool: ...
def has_fileno(obj: object) -> bool: ...
def warn(msg: str) -> None: ...
def make_fail_app(msg: str) -> _WSGIAppType: ...
def split_request_uri(uri: str) -> SplitResult: ...
Expand Down
8 changes: 8 additions & 0 deletions stubs/gunicorn/gunicorn/workers/gthread.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ from collections.abc import Callable
from concurrent.futures import Future, ThreadPoolExecutor
from selectors import DefaultSelector
from types import FrameType
from typing import Final

from gunicorn.config import Config
from gunicorn.glogging import Logger as GLogger
Expand All @@ -15,6 +16,8 @@ from gunicorn.uwsgi.parser import UWSGIParser
from .._types import _AddressType
from . import base

DEFAULT_WORKER_DATA_TIMEOUT: Final = 5.0

class TConn:
cfg: Config
sock: socket.socket
Expand All @@ -24,10 +27,12 @@ class TConn:
parser: HTTP2ServerConnection | UWSGIParser | RequestParser | None
initialized: bool
is_http2: bool
data_ready: bool

def __init__(self, cfg: Config, sock: socket.socket, client: _AddressType, server: _AddressType) -> None: ...
def init(self) -> None: ...
def set_timeout(self) -> None: ...
def wait_for_data(self, timeout: float | None) -> bool: ...
def close(self) -> None: ...

class PollableMethodQueue:
Expand All @@ -48,6 +53,7 @@ class ThreadWorker(base.Worker):
poller: DefaultSelector
method_queue: PollableMethodQueue
keepalived_conns: deque[TConn]
pending_conns: deque[TConn]
nr_conns: int
alive: bool

Expand All @@ -61,7 +67,9 @@ class ThreadWorker(base.Worker):
def enqueue_req(self, conn: TConn) -> None: ...
def accept(self, listener: socket.socket) -> None: ...
def on_client_socket_readable(self, conn: TConn, client: socket.socket) -> None: ...
def on_pending_socket_readable(self, conn: TConn, client: socket.socket) -> None: ...
def murder_keepalived(self) -> None: ...
def murder_pending(self) -> None: ...
def is_parent_alive(self) -> bool: ...
def wait_for_and_dispatch_events(self, timeout: float | None) -> None: ...
def run(self) -> None: ...
Expand Down
Loading