Enabled all Ruff lint rules and resolved findings.
CI / Formatting (push) Successful in 27s
CI / Linting (push) Successful in 9s
CI / Tests (push) Successful in 34s
CI / Type Checking (push) Successful in 7s
CI / Spelling (push) Successful in 7s

This commit is contained in:
2026-05-18 11:10:46 -04:00
parent 48a4fb9bbf
commit 795184cd17
11 changed files with 211 additions and 123 deletions
+11 -7
View File
@@ -31,6 +31,9 @@ if TYPE_CHECKING:
_MARKDOWN_ESCAPE_TABLE = str.maketrans({c: f"\\{c}" for c in r"\*_[]()~`#+-=|{}.!<>&"})
_SECONDS_PER_MINUTE = 60
_SECONDS_PER_HOUR = 60 * _SECONDS_PER_MINUTE
_SECONDS_PER_DAY = 24 * _SECONDS_PER_HOUR
def _sanitize_for_plain_text(text: str) -> str:
@@ -67,18 +70,19 @@ def _format_duration(timestamp_str: str, now: datetime) -> str:
seconds = int(delta.total_seconds())
if seconds < 0:
return "unknown duration"
if seconds < 60:
if seconds < _SECONDS_PER_MINUTE:
return f"{seconds} second{'s' if seconds != 1 else ''}"
if seconds < 3600:
minutes = seconds // 60
if seconds < _SECONDS_PER_HOUR:
minutes = seconds // _SECONDS_PER_MINUTE
return f"{minutes} minute{'s' if minutes != 1 else ''}"
if seconds < 86400:
hours = seconds // 3600
if seconds < _SECONDS_PER_DAY:
hours = seconds // _SECONDS_PER_HOUR
return f"{hours} hour{'s' if hours != 1 else ''}"
days = seconds // 86400
return f"{days} day{'s' if days != 1 else ''}"
except TypeError, ValueError:
return "unknown duration"
else:
days = seconds // _SECONDS_PER_DAY
return f"{days} day{'s' if days != 1 else ''}"
class CommandHandler:
+3 -2
View File
@@ -66,7 +66,8 @@ class _ResponseTimer:
"""Mark the request as successful so the duration is recorded."""
self._should_observe = True
def _finalize(self) -> None:
def finalize(self) -> None:
"""Record or discard the timing observation when the block exits."""
if self._should_observe:
self._gauge.labels(domain=self._domain).set(
max(time.monotonic() - self._start, 0)
@@ -196,7 +197,7 @@ class MetricsService:
try:
yield timer
finally:
timer._finalize()
timer.finalize()
def set_build_info(self, version: str) -> None:
"""Set the build version info metric.
+4 -1
View File
@@ -101,7 +101,9 @@ class NotificationService:
return
# Build the notification message
body_text = self._format_message(name, title, domain, tags, title_change)
body_text = self._format_message(
name, title, domain, tags, title_change=title_change
)
# Send notifications to all subscribed rooms in parallel
successful, failed = await self._broadcast_to_rooms(domain, body_text)
@@ -223,6 +225,7 @@ class NotificationService:
title: str,
domain: str,
tags: Sequence[str],
*,
title_change: bool,
) -> str:
"""Format the notification message body.
+9 -4
View File
@@ -15,6 +15,7 @@
"""HTTP client for querying Owncast instance APIs."""
import json
from http import HTTPStatus
from typing import TYPE_CHECKING, Any
import aiohttp
@@ -118,7 +119,7 @@ class OwncastClient:
url = f"https://{domain}{path}"
try:
async with self.session.get(url, allow_redirects=False) as response:
if response.status != 200:
if response.status != HTTPStatus.OK:
self.log.warning(
"[%s] Response to request on %s was not 200, got %s instead.",
domain,
@@ -147,7 +148,6 @@ class OwncastClient:
path,
)
return None
return result
except ValueError as e:
self.log.warning(
"[%s] Rejecting response to request on %s as could not "
@@ -157,6 +157,8 @@ class OwncastClient:
e,
)
return None
else:
return result
except (aiohttp.ClientError, TimeoutError, OSError) as e:
self.log.warning("[%s] Error making GET request to %s: %s", domain, path, e)
return None
@@ -237,8 +239,11 @@ class OwncastClient:
connector = self.session.connector
if connector is None:
return 0
idle = sum(len(conns) for conns in connector._conns.values())
active = len(connector._acquired)
# aiohttp does not expose public live pool counts; this metric intentionally
# mirrors its internal idle and active connection pools.
idle = sum(len(conns) for conns in connector._conns.values()) # noqa: SLF001
active = len(connector._acquired) # noqa: SLF001
return idle + active
async def close(self) -> None:
+16 -8
View File
@@ -33,19 +33,27 @@ _TEMPORARY_OFFLINE_NOTIFICATION_COOLDOWN = 7 * 60
_CLEANUP_WARNING_THRESHOLD = 83 * 24 * 60
_CLEANUP_DELETE_THRESHOLD = 90 * 24 * 60
_QUERY_EVERY_MINUTE_FAILURE_LIMIT = 4
_QUERY_EVERY_2_MINUTES_FAILURE_LIMIT = 9
_QUERY_EVERY_3_MINUTES_FAILURE_LIMIT = 14
_QUERY_EVERY_5_MINUTES_FAILURE_LIMIT = 29
_QUERY_EVERY_2_MINUTES_INTERVAL = 2
_QUERY_EVERY_3_MINUTES_INTERVAL = 3
_QUERY_EVERY_5_MINUTES_INTERVAL = 5
_QUERY_EVERY_15_MINUTES_INTERVAL = 15
def _should_query_stream(failure_counter: int) -> bool:
"""Determine if a stream should be queried based on failure count."""
if failure_counter <= 4:
if failure_counter <= _QUERY_EVERY_MINUTE_FAILURE_LIMIT:
return True
if failure_counter <= 9:
return failure_counter % 2 == 0
if failure_counter <= 14:
return failure_counter % 3 == 0
if failure_counter <= 29:
return failure_counter % 5 == 0
return failure_counter % 15 == 0
if failure_counter <= _QUERY_EVERY_2_MINUTES_FAILURE_LIMIT:
return failure_counter % _QUERY_EVERY_2_MINUTES_INTERVAL == 0
if failure_counter <= _QUERY_EVERY_3_MINUTES_FAILURE_LIMIT:
return failure_counter % _QUERY_EVERY_3_MINUTES_INTERVAL == 0
if failure_counter <= _QUERY_EVERY_5_MINUTES_FAILURE_LIMIT:
return failure_counter % _QUERY_EVERY_5_MINUTES_INTERVAL == 0
return failure_counter % _QUERY_EVERY_15_MINUTES_INTERVAL == 0
class StreamMonitor: