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.0.3"
version = "25.1.0"
upstream_repository = "https://github.com/benoitc/gunicorn"
requires = ["types-gevent"]

Expand Down
28 changes: 28 additions & 0 deletions stubs/gunicorn/gunicorn/config.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1283,3 +1283,31 @@ class DirtyWorkerExit(Setting):
desc: ClassVar[str]

def dirty_worker_exit(arbiter: Arbiter, worker: Worker) -> None: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues]

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

class ControlSocketMode(Setting):
name: ClassVar[str]
section: ClassVar[str]
cli: ClassVar[list[str]]
meta: ClassVar[str]
validator: ClassVar[_IntValidatorType]
type: ClassVar[Callable[[Any, str], int]]
default: ClassVar[int]
desc: ClassVar[str]

class ControlSocketDisable(Setting):
name: ClassVar[str]
section: ClassVar[str]
cli: ClassVar[list[str]]
validator: ClassVar[_BoolValidatorType]
action: ClassVar[str]
default: ClassVar[bool]
desc: ClassVar[str]
5 changes: 5 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from gunicorn.ctl.client import ControlClient as ControlClient
from gunicorn.ctl.protocol import ControlProtocol as ControlProtocol
from gunicorn.ctl.server import ControlSocketServer as ControlSocketServer

__all__ = ["ControlSocketServer", "ControlClient", "ControlProtocol"]
13 changes: 13 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/cli.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from _typeshed import Incomplete

def format_workers(data: dict[str, Incomplete]) -> str: ...
def format_dirty(data: dict[str, Incomplete]) -> str: ...
def format_stats(data: dict[str, Incomplete]) -> str: ...
def format_listeners(data: dict[str, Incomplete]) -> str: ...
def format_config(data: dict[str, Incomplete]) -> str: ...
def format_help(data: dict[str, Incomplete]) -> str: ...
def format_all(data: dict[str, Incomplete]) -> str: ...
def format_response(command: str, data: dict[str, Incomplete]) -> str: ...
def run_command(socket_path: str, command: str, json_output: bool = False) -> int: ...
def run_interactive(socket_path: str, json_output: bool = False) -> int: ...
def main() -> int: ...
16 changes: 16 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/client.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from _typeshed import Incomplete, Unused
from typing_extensions import Self

class ControlClientError(Exception): ...

class ControlClient:
socket_path: str
timeout: float
def __init__(self, socket_path: str, timeout: float = 30.0) -> None: ...
def connect(self) -> None: ...
def close(self) -> None: ...
def send_command(self, command: str, args: list[str] | None = None) -> dict[Incomplete, Incomplete]: ...
def __enter__(self) -> Self: ...
def __exit__(self, *args: Unused) -> None: ...

def parse_command(line: str) -> tuple[str, list[str]]: ...
23 changes: 23 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/handlers.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from _typeshed import Incomplete

from gunicorn.arbiter import Arbiter

class CommandHandlers:
arbiter: Arbiter
def __init__(self, arbiter: Arbiter) -> None: ...
# TODO: Use TypedDict for next return types
def show_workers(self) -> dict[str, Incomplete]: ...
def show_dirty(self) -> dict[str, Incomplete]: ...
def show_config(self) -> dict[str, Incomplete]: ...
def show_stats(self) -> dict[str, Incomplete]: ...
def show_listeners(self) -> dict[str, Incomplete]: ...
def worker_add(self, count: int = 1) -> dict[str, Incomplete]: ...
def worker_remove(self, count: int = 1) -> dict[str, Incomplete]: ...
def worker_kill(self, pid: int) -> dict[str, Incomplete]: ...
def dirty_add(self, count: int = 1) -> dict[str, Incomplete]: ...
def dirty_remove(self, count: int = 1) -> dict[str, Incomplete]: ...
def reload(self) -> dict[str, Incomplete]: ...
def reopen(self) -> dict[str, Incomplete]: ...
def shutdown(self, mode: str = "graceful") -> dict[str, Incomplete]: ...
def show_all(self) -> dict[str, Incomplete]: ...
def help(self) -> dict[str, Incomplete]: ...
26 changes: 26 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/protocol.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from _typeshed import Incomplete
from asyncio import StreamReader, StreamWriter
from socket import socket
from typing import ClassVar

class ProtocolError(Exception): ...

class ControlProtocol:
MAX_MESSAGE_SIZE: ClassVar[int]
@staticmethod
def encode_message(data: dict[Incomplete, Incomplete]) -> bytes: ...
@staticmethod
def decode_message(data: bytes) -> dict[Incomplete, Incomplete]: ...
@staticmethod
def read_message(sock: socket) -> dict[Incomplete, Incomplete]: ...
@staticmethod
def write_message(sock: socket, data: dict[Incomplete, Incomplete]) -> None: ...
@staticmethod
async def read_message_async(reader: StreamReader) -> dict[Incomplete, Incomplete]: ...
@staticmethod
async def write_message_async(writer: StreamWriter, data: dict[Incomplete, Incomplete]) -> None: ...

# TODO: Use TypedDict for next return types
def make_request(request_id: int, command: str, args: list[str] | None = None) -> dict[str, Incomplete]: ...
def make_response(request_id: int, data: dict[Incomplete, Incomplete] | None = None) -> dict[str, Incomplete]: ...
def make_error_response(request_id: int, error: str) -> dict[str, Incomplete]: ...
11 changes: 11 additions & 0 deletions stubs/gunicorn/gunicorn/ctl/server.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from gunicorn.arbiter import Arbiter
from gunicorn.ctl.handlers import CommandHandlers

class ControlSocketServer:
arbiter: Arbiter
socket_path: str
socket_mode: int
handlers: CommandHandlers
def __init__(self, arbiter: Arbiter, socket_path: str, socket_mode: int = 0o600) -> None: ...
def start(self) -> None: ...
def stop(self) -> None: ...
14 changes: 14 additions & 0 deletions stubs/gunicorn/gunicorn/dirty/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import stash as stash
from .app import DirtyApp as DirtyApp
from .arbiter import DirtyArbiter as DirtyArbiter
from .client import (
Expand All @@ -17,6 +18,13 @@ from .errors import (
DirtyTimeoutError as DirtyTimeoutError,
DirtyWorkerError as DirtyWorkerError,
)
from .stash import (
StashClient as StashClient,
StashError as StashError,
StashKeyNotFoundError as StashKeyNotFoundError,
StashTable as StashTable,
StashTableNotFoundError as StashTableNotFoundError,
)

__all__ = [
"DirtyError",
Expand All @@ -32,6 +40,12 @@ __all__ = [
"get_dirty_client_async",
"close_dirty_client",
"close_dirty_client_async",
"stash",
"StashClient",
"StashTable",
"StashError",
"StashTableNotFoundError",
"StashKeyNotFoundError",
"DirtyArbiter",
"set_dirty_socket_path",
]
7 changes: 6 additions & 1 deletion stubs/gunicorn/gunicorn/dirty/arbiter.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,22 @@ class DirtyArbiter:
worker_consumers: dict[int, asyncio.Task[None]]
worker_age: int
alive: bool
num_workers: int
app_specs: dict[str, dict[Incomplete, Incomplete]]
app_worker_map: dict[str, set[Incomplete]]
worker_app_map: dict[int, list[Incomplete]]
stash_tables: dict[str, dict[Incomplete, Incomplete]]

def __init__(self, cfg: Config, log: GLogger, socket_path: str | None = None, pidfile: str | None = None) -> None: ...
def run(self) -> None: ...
def init_signals(self) -> None: ...
async def handle_client(self, reader: StreamReader, writer: StreamWriter) -> None: ...
async def route_request(self, request: dict[str, Incomplete], client_writer: StreamWriter) -> None: ...
async def handle_status_request(self, message: dict[str, Incomplete], client_writer: StreamWriter) -> None: ...
async def handle_manage_request(self, message: dict[str, Incomplete], client_writer: StreamWriter) -> None: ...
async def handle_stash_request(self, message: dict[str, Incomplete], client_writer: StreamWriter) -> None: ...
async def manage_workers(self) -> None: ...
def spawn_worker(self) -> int | None: ...
def spawn_worker(self, force_all_apps: bool = False) -> int | None: ...
def kill_worker(self, pid: int, sig: int) -> None: ...
async def murder_workers(self) -> None: ...
def reap_workers(self) -> None: ...
Expand Down
100 changes: 86 additions & 14 deletions stubs/gunicorn/gunicorn/dirty/protocol.pyi
Original file line number Diff line number Diff line change
@@ -1,40 +1,112 @@
import asyncio
import socket
from _typeshed import Incomplete
from typing import ClassVar
from typing import ClassVar, Final

class DirtyProtocol:
HEADER_FORMAT: ClassVar[str]
MAGIC: Final = b"GD"
VERSION: Final = 0x01
MSG_TYPE_REQUEST: Final = 0x01
MSG_TYPE_RESPONSE: Final = 0x02
MSG_TYPE_ERROR: Final = 0x03
MSG_TYPE_CHUNK: Final = 0x04
MSG_TYPE_END: Final = 0x05
MSG_TYPE_STASH: Final = 0x10
MSG_TYPE_STATUS: Final = 0x11
MSG_TYPE_MANAGE: Final = 0x12
MSG_TYPE_REQUEST_STR: Final = "request"
MSG_TYPE_RESPONSE_STR: Final = "response"
MSG_TYPE_ERROR_STR: Final = "error"
MSG_TYPE_CHUNK_STR: Final = "chunk"
MSG_TYPE_END_STR: Final = "end"
MSG_TYPE_STASH_STR: Final = "stash"
MSG_TYPE_STATUS_STR: Final = "status"
MSG_TYPE_MANAGE_STR: Final = "manage"
MSG_TYPE_TO_STR: Final[dict[int, str]]
MSG_TYPE_FROM_STR: Final[dict[str, int]]
STASH_OP_PUT: Final = 1
STASH_OP_GET: Final = 2
STASH_OP_DELETE: Final = 3
STASH_OP_KEYS: Final = 4
STASH_OP_CLEAR: Final = 5
STASH_OP_INFO: Final = 6
STASH_OP_ENSURE: Final = 7
STASH_OP_DELETE_TABLE: Final = 8
STASH_OP_TABLES: Final = 9
STASH_OP_EXISTS: Final = 10
MANAGE_OP_ADD: Final = 1
MANAGE_OP_REMOVE: Final = 2
HEADER_FORMAT: Final = ">2sBBIQ"
HEADER_SIZE: Final[int]
MAX_MESSAGE_SIZE: Final = 67108864

class BinaryProtocol:
HEADER_SIZE: ClassVar[int]
MAX_MESSAGE_SIZE: ClassVar[int]
MSG_TYPE_REQUEST: ClassVar[str]
MSG_TYPE_RESPONSE: ClassVar[str]
MSG_TYPE_ERROR: ClassVar[str]
MSG_TYPE_CHUNK: ClassVar[str]
MSG_TYPE_END: ClassVar[str]
MSG_TYPE_STASH: ClassVar[str]
MSG_TYPE_STATUS: ClassVar[str]
MSG_TYPE_MANAGE: ClassVar[str]

@staticmethod
def encode(message: dict[Incomplete, Incomplete]) -> bytes: ...
def encode_header(msg_type: int, request_id: int, payload_length: int) -> bytes: ...
@staticmethod
def decode_header(data: bytes) -> tuple[int, int, int]: ...
@staticmethod
def encode_request(
request_id: int,
app_path: str,
action: str,
args: tuple[Incomplete, ...] | None = None,
kwargs: dict[str, Incomplete] | None = None,
) -> bytes: ...
@staticmethod
def encode_response(request_id: int, result) -> bytes: ...
@staticmethod
def encode_error(request_id: int, error: BaseException | dict[str, Incomplete]) -> bytes: ...
@staticmethod
def encode_chunk(request_id: int, data) -> bytes: ...
@staticmethod
def encode_end(request_id: int) -> bytes: ...
@staticmethod
def decode(data: bytes) -> dict[Incomplete, Incomplete]: ...
def encode_status(request_id: int) -> bytes: ...
@staticmethod
async def read_message_async(reader: asyncio.StreamReader) -> dict[Incomplete, Incomplete]: ...
def encode_manage(request_id: int, op: int, count: int = 1) -> bytes: ...
@staticmethod
async def write_message_async(writer: asyncio.StreamWriter, message: dict[Incomplete, Incomplete]) -> None: ...
def encode_stash(request_id: int, op: int, table: str, key=None, value=None, pattern=None) -> bytes: ...
@staticmethod
def read_message(sock: socket.socket) -> dict[Incomplete, Incomplete]: ...
def decode_message(data: bytes) -> tuple[str, int, Incomplete]: ...
@staticmethod
def write_message(sock: socket.socket, message: dict[Incomplete, Incomplete]) -> None: ...
async def read_message_async(reader: asyncio.StreamReader) -> dict[str, Incomplete]: ...
@staticmethod
async def write_message_async(writer: asyncio.StreamWriter, message: dict[str, Incomplete]) -> None: ...
@staticmethod
def _recv_exactly(sock: socket.socket, n: int) -> bytes: ...
@staticmethod
def read_message(sock: socket.socket) -> dict[str, Incomplete]: ...
@staticmethod
def write_message(sock: socket.socket, message: dict[str, Incomplete]) -> None: ...
@staticmethod
def _encode_from_dict(message: dict[str, Incomplete]) -> bytes: ...

DirtyProtocol = BinaryProtocol

# TODO: Use TypedDict for results
def make_request(
request_id: str,
request_id: int | str,
app_path: str,
action: str,
args: tuple[Incomplete, ...] | None = None,
kwargs: dict[str, Incomplete] | None = None,
) -> dict[str, Incomplete]: ...
def make_response(request_id: str, result) -> dict[str, Incomplete]: ...
def make_error_response(request_id: str, error) -> dict[str, Incomplete]: ...
def make_chunk_message(request_id: str, data) -> dict[str, Incomplete]: ...
def make_end_message(request_id: str) -> dict[str, Incomplete]: ...
def make_response(request_id: int | str, result) -> dict[str, Incomplete]: ...
def make_error_response(request_id: int | str, error) -> dict[str, Incomplete]: ...
def make_chunk_message(request_id: int | str, data) -> dict[str, Incomplete]: ...
def make_end_message(request_id: int | str) -> dict[str, Incomplete]: ...
def make_stash_message(
request_id: int | str, op: int, table: str, key=None, value=None, pattern=None
) -> dict[str, Incomplete]: ...
def make_manage_message(request_id: int | str, op: int, count: int = 1) -> dict[str, Incomplete]: ...
71 changes: 71 additions & 0 deletions stubs/gunicorn/gunicorn/dirty/stash.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from _typeshed import Incomplete
from collections.abc import Iterator
from types import TracebackType
from typing_extensions import Self

from .errors import DirtyError

class StashError(DirtyError): ...

class StashTableNotFoundError(StashError):
table_name: str

def __init__(self, table_name: str) -> None: ...

class StashKeyNotFoundError(StashError):
table_name: str
key: str

def __init__(self, table_name: str, key: str) -> None: ...

class StashClient:
socket_path: str
timeout: float

def __init__(self, socket_path: str, timeout: float = 30.0) -> None: ...
def put(self, table: str, key: str, value) -> None: ...
def get(self, table: str, key: str, default=None): ...
def delete(self, table: str, key: str) -> bool: ...
def keys(self, table: str, pattern: str | None = None) -> list[str]: ...
def clear(self, table: str) -> None: ...
def info(self, table: str) -> dict[str, Incomplete]: ...
def ensure(self, table: str) -> None: ...
def exists(self, table: str, key=None) -> bool: ...
def delete_table(self, table: str) -> None: ...
def tables(self) -> list[str]: ...
def table(self, name: str) -> StashTable: ...
def close(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> None: ...

class StashTable:
def __init__(self, client: StashClient, name: str) -> None: ...
@property
def name(self) -> str: ...
def __getitem__(self, key: str): ...
def __setitem__(self, key: str, value) -> None: ...
def __delitem__(self, key: str) -> None: ...
def __contains__(self, key: str) -> bool: ...
def __iter__(self) -> Iterator[str]: ...
def __len__(self) -> int: ...
def get(self, key: str, default=None): ...
def keys(self, pattern: str | None = None) -> list[str]: ...
def clear(self) -> None: ...
def items(self) -> Iterator[tuple[Incomplete, Incomplete]]: ...
def values(self) -> Iterator[Incomplete]: ...

def set_stash_socket_path(path: str) -> None: ...
def get_stash_socket_path() -> str: ...
def put(table: str, key: str, value) -> None: ...
def get(table: str, key: str, default=None): ...
def delete(table: str, key: str) -> bool: ...
def keys(table: str, pattern: str | None = None) -> list[str]: ...
def clear(table: str) -> None: ...
def info(table: str) -> dict[str, Incomplete]: ...
def ensure(table: str) -> None: ...
def exists(table: str, key: str | None = None) -> bool: ...
def delete_table(table: str) -> None: ...
def tables() -> list[str]: ...
def table(name: str) -> StashTable: ...
Loading