refactor: improve backend type safety and import organization
- Add TYPE_CHECKING guards for runtime-expensive imports (aiohttp, aiosqlite) - Reorganize imports to follow PEP 8 conventions - Convert TypeAlias to modern PEP 695 type syntax (where appropriate) - Use Sequence/Mapping from collections.abc for type hints (covariant) - Replace string literals with cast() for improved type inference - Fix casting of Fail2BanResponse and TypedDict patterns - Add IpLookupResult TypedDict for precise return type annotation - Reformat overlong lines for readability (120 char limit) - Add asyncio_mode and filterwarnings to pytest config - Update test fixtures with improved type hints This improves mypy type checking and makes type relationships explicit.
This commit is contained in:
@@ -21,34 +21,52 @@ import contextlib
|
||||
import errno
|
||||
import socket
|
||||
import time
|
||||
from collections.abc import Mapping, Sequence, Set
|
||||
from pickle import HIGHEST_PROTOCOL, dumps, loads
|
||||
from typing import TYPE_CHECKING, TypeAlias
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import structlog
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Types
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Fail2BanToken: TypeAlias = str | int | float | bool | None | dict[str, object] | list[object]
|
||||
# Use covariant container types so callers can pass ``list[int]`` / ``dict[str, str]``
|
||||
# without needing to cast. At runtime we only accept the basic built-in
|
||||
# containers supported by fail2ban's protocol (list/dict/set) and stringify
|
||||
# anything else.
|
||||
#
|
||||
# NOTE: ``Sequence`` will also accept tuples, but tuples are stringified at
|
||||
# runtime because fail2ban only understands lists.
|
||||
|
||||
type Fail2BanToken = (
|
||||
str
|
||||
| int
|
||||
| float
|
||||
| bool
|
||||
| None
|
||||
| Mapping[str, object]
|
||||
| Sequence[object]
|
||||
| Set[object]
|
||||
)
|
||||
"""A single token in a fail2ban command.
|
||||
|
||||
Fail2ban accepts simple types (str/int/float/bool) plus compound types
|
||||
(list/dict). Complex objects are stringified before being sent.
|
||||
(list/dict/set). Complex objects are stringified before being sent.
|
||||
"""
|
||||
|
||||
Fail2BanCommand: TypeAlias = list[Fail2BanToken]
|
||||
type Fail2BanCommand = Sequence[Fail2BanToken]
|
||||
"""A command sent to fail2ban over the socket.
|
||||
|
||||
Commands are pickle serialised lists of tokens.
|
||||
Commands are pickle serialised sequences of tokens.
|
||||
"""
|
||||
|
||||
Fail2BanResponse: TypeAlias = tuple[int, object]
|
||||
type Fail2BanResponse = tuple[int, object]
|
||||
"""A typical fail2ban response containing a status code and payload."""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from types import TracebackType
|
||||
|
||||
import structlog
|
||||
|
||||
log: structlog.stdlib.BoundLogger = structlog.get_logger()
|
||||
|
||||
# fail2ban protocol constants — inline to avoid a hard import dependency
|
||||
@@ -200,7 +218,7 @@ def _send_command_sync(
|
||||
) from last_oserror
|
||||
|
||||
|
||||
def _coerce_command_token(token: Fail2BanToken) -> Fail2BanToken:
|
||||
def _coerce_command_token(token: object) -> Fail2BanToken:
|
||||
"""Coerce a command token to a type that fail2ban understands.
|
||||
|
||||
fail2ban's ``CSocket.convert`` accepts ``str``, ``bool``, ``int``,
|
||||
|
||||
Reference in New Issue
Block a user