Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 2 additions & 2 deletions aiopnsense/client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ def __init__(
username (str): Username for API authentication.
password (str): Password for API authentication.
session (aiohttp.ClientSession): HTTP client session used for API requests.
opts (MutableMapping[str, Any] | None, optional): Optional client configuration values
opts (MutableMapping[str, Any] | None): Optional client configuration values
(e.g. ``opts={"verify_ssl": True}``).
initial (bool | object): Deprecated alias for ``throw_errors``. When provided,
a ``DeprecationWarning`` is emitted. Ignored when ``throw_errors`` is also set.
name (str): Display name for the client instance.
throw_errors (bool | object): Whether request and decorator errors should be
re-raised instead of logged and suppressed. Defaults to ``False``.
name (str): Display name for the client instance.

Raises:
OPNsenseInvalidArgument: Raised when ``initial`` or ``throw_errors`` is not a ``bool``.
Expand Down
6 changes: 5 additions & 1 deletion aiopnsense/client_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ def _is_post_endpoint_probe_blocked(self, path: str) -> bool:

@deprecated("Endpoint style selection is internal. Direct calls are no longer needed.")
async def set_use_snake_case(self, initial: bool = False) -> None:
"""Deprecated wrapper that preserves legacy ``initial`` compatibility."""
"""Deprecated wrapper that preserves legacy ``initial`` compatibility.

Args:
initial (bool): Value used by `set_use_snake_case`.
"""
await self._set_use_snake_case(initial=initial)

async def _set_use_snake_case(self, initial: bool = False) -> None:
Expand Down
35 changes: 32 additions & 3 deletions aiopnsense/client_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,34 @@ async def _do_get(
*,
response_format: Literal["json", "text"] = "json",
) -> MutableMapping[str, Any] | list | str | None:
"""Execute a queued GET request."""
"""Execute an immediate GET transport request after it is dequeued.

Args:
path (str): API endpoint path to request.
caller (str): Calling method name used for diagnostics.
timeout_seconds (float | None): Optional transport request timeout.
response_format (Literal['json', 'text']): Expected response body format.

Returns:
MutableMapping[str, Any] | list | str | None: Decoded transport
response, if available.
"""
...

async def _do_get_from_stream(
self,
path: str,
caller: str = "Unknown",
) -> dict[str, Any]:
"""Execute a queued streaming GET request."""
"""Execute an immediate streaming GET transport request after dequeuing it.

Args:
path (str): Streaming API endpoint path to request.
caller (str): Calling method name used for diagnostics.

Returns:
dict[str, Any]: Decoded payload extracted from the stream response.
"""
...

async def _do_post(
Expand All @@ -43,7 +62,17 @@ async def _do_post(
payload: MutableMapping[str, Any] | None = None,
caller: str = "Unknown",
) -> MutableMapping[str, Any] | list | None:
"""Execute a queued POST request."""
"""Execute an immediate POST transport request after it is dequeued.

Args:
path (str): API endpoint path to request.
payload (MutableMapping[str, Any] | None): Optional request body.
caller (str): Calling method name used for diagnostics.

Returns:
MutableMapping[str, Any] | list | None: Decoded transport response,
if available.
"""
...

async def _ensure_workers_started(self) -> None:
Expand Down
19 changes: 17 additions & 2 deletions aiopnsense/client_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,28 @@ class ClientTransportMixin:
_verify_ssl: bool

async def _get(self, path: str) -> MutableMapping[str, Any] | list | None:
"""Queue a GET request and return the decoded payload."""
"""Queue a GET request and return the decoded payload.

Args:
path (str): Value used by `_get`.

Returns:
MutableMapping[str, Any] | list | None: Result returned by `_get`.
"""
...

async def _post(
self, path: str, payload: MutableMapping[str, Any] | None = None
) -> MutableMapping[str, Any] | list | None:
"""Queue a POST request and return the decoded payload."""
"""Queue a POST request and return the decoded payload.

Args:
path (str): Value used by `_post`.
payload (MutableMapping[str, Any] | None): Value used by `_post`.

Returns:
MutableMapping[str, Any] | list | None: Result returned by `_post`.
"""
...

async def _do_get_from_stream(self, path: str, caller: str = "Unknown") -> dict[str, Any]:
Expand Down
17 changes: 11 additions & 6 deletions aiopnsense/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ async def inner(self: Any, *args: Any, **kwargs: Any) -> Any:
"""Execute wrapped coroutine with shared timeout/exception logging.

Args:
*args (Any): Positional arguments forwarded to the wrapped callable.
**kwargs (Any): Keyword arguments forwarded to the wrapped callable.
self (Any): Client instance whose ``_throw_errors`` setting controls
whether caught errors are mapped and propagated or logged and
suppressed.
args (Any): Positional arguments forwarded to the wrapped coroutine.
kwargs (Any): Keyword arguments forwarded to the wrapped coroutine.

Returns:
Any: Value produced by the wrapped callable, or ``None`` when an
Expand Down Expand Up @@ -392,14 +395,16 @@ def normalize_lookup_token(value: Any) -> str:


def api_value_matches(value: object, expected: str) -> bool:
"""Compare OPNsense API values across string, numeric, and boolean forms.
"""Compare a normalized OPNsense API value with its expected string.

Args:
value: Raw value returned by OPNsense APIs.
expected: Normalized expected value.
value (object): API value to normalize; booleans become integer strings and
all other values are converted directly to strings.
expected (str): Expected normalized string value.

Returns:
``True`` when the normalized API value matches ``expected``.
``True`` when the normalized API value has the same string representation
as ``expected``.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"""
if isinstance(value, bool):
value = int(value)
Expand Down
23 changes: 14 additions & 9 deletions aiopnsense/traffic.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,15 @@ def normalize_traffic_payload(
interval: float,
include_per_second_rates: bool = True,
) -> dict[str, Any]:
"""Normalize OPNsense diagnostics traffic payloads.
"""Normalize a raw OPNsense diagnostics traffic payload.

Args:
payload: Raw traffic payload from ``/api/diagnostics/traffic`` or a stream event.
interval: Seconds represented by the traffic counters in the payload.
include_per_second_rates: Derive per-second rates when true.
payload (Mapping[str, Any]): Raw diagnostics payload containing interface
traffic counters.
interval (float): Elapsed sample interval used to calculate per-second
rates; non-positive values use one second.
include_per_second_rates (bool): Whether to add derived per-second rate
fields. When ``False``, only normalized counters are returned.

Returns:
dict[str, Any]: Normalized traffic sample with an ``interfaces`` mapping keyed by interface name.
Expand Down Expand Up @@ -200,13 +203,15 @@ async def stream_interface_traffic(
"""Yield normalized diagnostics traffic stream samples.

Args:
poll_interval: OPNsense stream sample interval in seconds. Values
less than 1 are clamped to 1.
poll_interval (int): Requested stream interval in seconds. Values below
1 are clamped to 1, and the clamped value selects the stream endpoint.

Yields:
Normalized traffic samples. The first stream event is discarded because
OPNsense stream endpoints commonly emit an initialization sample
before interval deltas stabilize.
dict[str, Any]: Normalized traffic samples after the initial valid timing
event is discarded because it cannot represent an interval delta.
Later samples use elapsed time between strictly increasing server
timestamps; after a timing reset, the next valid sample uses the
selected stream interval.
"""
interval = max(poll_interval, 1)
endpoint = f"{DIAGNOSTICS_TRAFFIC_STREAM_ENDPOINT_PREFIX}/{interval}"
Expand Down
2 changes: 1 addition & 1 deletion aiopnsense/vnstat.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def _collect_vnstat_interfaces(
"""Collect interface names present across parsed vnStat payloads.

Args:
*payloads (Mapping[str, Any] | MutableMapping[str, Any]): Parsed
payloads (Mapping[str, Any] | MutableMapping[str, Any]): Parsed
vnStat payload mappings whose ``interfaces`` keys should be
merged.

Expand Down
20 changes: 11 additions & 9 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,16 @@ def append_pep702_deprecation(
options: object,
lines: list[str],
) -> None:
"""Append PEP 702 deprecation metadata to autodoc docstrings.
"""Prepend PEP 702 deprecation metadata during an autodoc docstring event.

Args:
app: The Sphinx application emitting the event.
what: The type of object being documented.
name: The fully qualified object name.
obj: The object being documented.
options: The autodoc options for the object.
lines: The docstring lines Sphinx will render.
app (Sphinx): Sphinx application dispatching the event; unused by this hook.
what (str): Autodoc object type, such as ``"function"`` or ``"class"``.
name (str): Fully qualified name of the documented object.
obj (object): Documented object, inspected for PEP 702 metadata.
options (object): Autodoc directive options for the documented object.
lines (list[str]): Mutable docstring source lines, updated in place to
prepend the generated deprecation admonition.
"""
del app, what, name, options

Expand All @@ -103,10 +104,11 @@ def append_pep702_deprecation(


def setup(app: Sphinx) -> dict[str, bool]:
"""Register Sphinx event hooks.
"""Register this extension's Sphinx event hooks.

Args:
app: The Sphinx application to configure.
app (Sphinx): Sphinx application used to register the autodoc docstring
hook.

Returns:
Sphinx extension metadata.
Expand Down
7 changes: 7 additions & 0 deletions prek.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ additional_dependencies = [
"types-setuptools",
]

[[repos]]
repo = "https://github.com/jsh9/pydoclint"
rev = "0.9.1"

[[repos.hooks]]
id = "pydoclint"

[[repos]]
repo = "https://github.com/astral-sh/ruff-pre-commit"
rev = "v0.15.22"
Expand Down
13 changes: 13 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,16 @@ warn_unused_ignores = false
[[tool.mypy.overrides]]
module = "sphinx.*"
ignore_missing_imports = true

[tool.pydoclint]
style = "google"
should-document-private-class-attributes = true
skip-checking-short-docstrings = false
arg-type-hints-in-docstring = true
check-return-types = false
allow-init-docstring = true
skip-checking-raises = true
check-class-attributes = false
check-style-mismatch = true
should-document-star-arguments = true
omit-stars-when-documenting-varargs = true
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading
Loading