mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-12 13:51:12 +03:00
Increase ruff coverage (#23644)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / Jetson Jetpack 6 (push) Waiting to run
* Pin ruff * Add python upgrade fixes This enables python upgrade checks in ruff to look for deprecated types and patterns. This namely fixes: - usage of deprecated `Typing` which is now built in - some specific exceptions which are caught and have new aliases Some specific UP checks were also ignored as they are stylistic / unimportant and likely to cause bugs * Remove async blocking calls Use asyncio.to_thread on two remaining blocking calls to fix hanging event thread loop. Enable this specific rule to block it in the future. * Use proper logging mechanism * Correctly format logs * Raise with context When raising an exception include the from context to improve debugging * Cleanup
This commit is contained in:
@@ -9,7 +9,6 @@ from abc import ABC, abstractmethod
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from logging.handlers import QueueHandler
|
||||
from types import FrameType
|
||||
from typing import Optional
|
||||
|
||||
import frigate.log
|
||||
|
||||
@@ -22,13 +21,13 @@ DEFAULT_STOP_TIMEOUT = 10 # seconds
|
||||
class BaseServiceProcess(Service, ABC):
|
||||
"""A Service the manages a multiprocessing.Process."""
|
||||
|
||||
_process: Optional[mp.Process]
|
||||
_process: mp.Process | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
manager: Optional[ServiceManager] = None,
|
||||
name: str | None = None,
|
||||
manager: ServiceManager | None = None,
|
||||
) -> None:
|
||||
super().__init__(name=name, manager=manager)
|
||||
|
||||
@@ -55,7 +54,7 @@ class BaseServiceProcess(Service, ABC):
|
||||
self,
|
||||
*,
|
||||
force: bool = False,
|
||||
timeout: Optional[float] = None,
|
||||
timeout: float | None = None,
|
||||
) -> None:
|
||||
if timeout is None:
|
||||
timeout = DEFAULT_STOP_TIMEOUT
|
||||
@@ -85,7 +84,7 @@ class BaseServiceProcess(Service, ABC):
|
||||
self.manager.logger.info(f"{self.name} stopped")
|
||||
|
||||
@property
|
||||
def pid(self) -> Optional[int]:
|
||||
def pid(self) -> int | None:
|
||||
return self._process.pid if self._process else None
|
||||
|
||||
def _run(self) -> None:
|
||||
@@ -143,7 +142,7 @@ class ServiceProcess(BaseServiceProcess):
|
||||
|
||||
faulthandler.enable()
|
||||
|
||||
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
||||
def receiveSignal(signalNumber: int, frame: FrameType | None) -> None:
|
||||
# Get the stop_event through the dict to bypass lazy initialization.
|
||||
stop_event = self.__dict__.get("stop_event")
|
||||
if stop_event is not None:
|
||||
|
||||
@@ -7,7 +7,7 @@ import threading
|
||||
from multiprocessing.connection import Connection
|
||||
from multiprocessing.connection import wait as mp_wait
|
||||
from socket import socket
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -118,10 +118,10 @@ class MultiprocessingWaiter(threading.Thread):
|
||||
|
||||
|
||||
waiter_lock = threading.Lock()
|
||||
waiter_thread: Optional[MultiprocessingWaiter] = None
|
||||
waiter_thread: MultiprocessingWaiter | None = None
|
||||
|
||||
|
||||
async def wait(object: Union[mp.Process, Connection, socket]) -> None:
|
||||
async def wait(object: mp.Process | Connection | socket) -> None:
|
||||
"""Wait for the supplied object to be ready.
|
||||
|
||||
Under the hood, this uses multiprocessing.connection.wait() and a background thread manage the
|
||||
@@ -129,7 +129,7 @@ async def wait(object: Union[mp.Process, Connection, socket]) -> None:
|
||||
"""
|
||||
global waiter_thread, waiter_lock
|
||||
|
||||
sentinel: Union[Connection, socket, int]
|
||||
sentinel: Connection | socket | int
|
||||
if isinstance(object, mp.Process):
|
||||
sentinel = object.sentinel
|
||||
elif isinstance(object, Connection) or isinstance(object, socket):
|
||||
|
||||
@@ -5,12 +5,11 @@ import atexit
|
||||
import logging
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Coroutine
|
||||
from contextvars import ContextVar
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import Coroutine, Optional, Union, cast
|
||||
|
||||
from typing_extensions import Self
|
||||
from typing import Self, cast
|
||||
|
||||
|
||||
class Service(ABC):
|
||||
@@ -19,8 +18,8 @@ class Service(ABC):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
manager: Optional[ServiceManager] = None,
|
||||
name: str | None = None,
|
||||
manager: ServiceManager | None = None,
|
||||
):
|
||||
if name:
|
||||
self.__dict__["name"] = name
|
||||
@@ -42,13 +41,13 @@ class Service(ABC):
|
||||
try:
|
||||
return self.__manager
|
||||
except AttributeError:
|
||||
raise RuntimeError("Cannot access associated service manager")
|
||||
raise RuntimeError("Cannot access associated service manager") from None
|
||||
|
||||
def start(
|
||||
self,
|
||||
*,
|
||||
wait: bool = False,
|
||||
wait_timeout: Optional[float] = None,
|
||||
wait_timeout: float | None = None,
|
||||
) -> Self:
|
||||
"""Start this service.
|
||||
|
||||
@@ -70,9 +69,9 @@ class Service(ABC):
|
||||
self,
|
||||
*,
|
||||
force: bool = False,
|
||||
timeout: Optional[float] = None,
|
||||
timeout: float | None = None,
|
||||
wait: bool = False,
|
||||
wait_timeout: Optional[float] = None,
|
||||
wait_timeout: float | None = None,
|
||||
) -> Self:
|
||||
"""Stop this service.
|
||||
|
||||
@@ -97,9 +96,9 @@ class Service(ABC):
|
||||
self,
|
||||
*,
|
||||
force: bool = False,
|
||||
stop_timeout: Optional[float] = None,
|
||||
stop_timeout: float | None = None,
|
||||
wait: bool = False,
|
||||
wait_timeout: Optional[float] = None,
|
||||
wait_timeout: float | None = None,
|
||||
) -> Self:
|
||||
"""Restart this service.
|
||||
|
||||
@@ -129,7 +128,7 @@ class Service(ABC):
|
||||
self,
|
||||
*,
|
||||
force: bool = False,
|
||||
timeout: Optional[float] = None,
|
||||
timeout: float | None = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
@@ -137,14 +136,14 @@ class Service(ABC):
|
||||
self,
|
||||
*,
|
||||
force: bool = False,
|
||||
stop_timeout: Optional[float] = None,
|
||||
stop_timeout: float | None = None,
|
||||
) -> None:
|
||||
await self.on_stop(force=force, timeout=stop_timeout)
|
||||
await self.on_start()
|
||||
|
||||
|
||||
default_service_manager_lock = threading.Lock()
|
||||
default_service_manager: Optional[ServiceManager] = None
|
||||
default_service_manager: ServiceManager | None = None
|
||||
|
||||
current_service_manager: ContextVar[ServiceManager] = ContextVar(
|
||||
"current_service_manager"
|
||||
@@ -162,8 +161,8 @@ class Command:
|
||||
"""
|
||||
|
||||
coro: Coroutine
|
||||
lock: Optional[asyncio.Lock] = None
|
||||
done: Optional[threading.Event] = None
|
||||
lock: asyncio.Lock | None = None
|
||||
done: threading.Event | None = None
|
||||
|
||||
|
||||
class ServiceManager:
|
||||
@@ -189,7 +188,7 @@ class ServiceManager:
|
||||
_services_lock: threading.Lock
|
||||
|
||||
# Commands will be queued with associated event loop. Queueing `None` signals shutdown.
|
||||
_command_queue: asyncio.Queue[Union[Command, None]]
|
||||
_command_queue: asyncio.Queue[Command | None]
|
||||
_event_loop: asyncio.AbstractEventLoop
|
||||
|
||||
# The pending command counter is used to ensure all commands have been queued before shutdown.
|
||||
@@ -204,7 +203,7 @@ class ServiceManager:
|
||||
# Will be acquired to ensure the shutdown sentinel is sent only once. Never released.
|
||||
_shutdown_lock: threading.Lock
|
||||
|
||||
def __init__(self, *, name: Optional[str] = None):
|
||||
def __init__(self, *, name: str | None = None):
|
||||
self._name = name if name is not None else (__package__ or __name__)
|
||||
self._logger = logging.getLogger(self.name)
|
||||
|
||||
@@ -276,8 +275,8 @@ class ServiceManager:
|
||||
coro: Coroutine,
|
||||
*,
|
||||
wait: bool = False,
|
||||
wait_timeout: Optional[float] = None,
|
||||
lock: Optional[asyncio.Lock] = None,
|
||||
wait_timeout: float | None = None,
|
||||
lock: asyncio.Lock | None = None,
|
||||
) -> None:
|
||||
"""Run an async task in the service manager thread.
|
||||
|
||||
@@ -299,7 +298,7 @@ class ServiceManager:
|
||||
cmd.done.wait(timeout=wait_timeout)
|
||||
|
||||
def shutdown(
|
||||
self, *, wait: bool = False, wait_timeout: Optional[float] = None
|
||||
self, *, wait: bool = False, wait_timeout: float | None = None
|
||||
) -> None:
|
||||
"""Shutdown the service manager thread.
|
||||
|
||||
@@ -321,7 +320,7 @@ class ServiceManager:
|
||||
if not self._manager_thread.is_alive():
|
||||
raise RuntimeError(f"ServiceManager {self.name} is not running")
|
||||
|
||||
def _send_command(self, command: Union[Command, None]) -> None:
|
||||
def _send_command(self, command: Command | None) -> None:
|
||||
self._ensure_running()
|
||||
|
||||
async def queue_command() -> None:
|
||||
@@ -336,7 +335,7 @@ class ServiceManager:
|
||||
|
||||
self._ensure_running()
|
||||
with self._services_lock:
|
||||
name_conflict: Optional[Service] = next(
|
||||
name_conflict: Service | None = next(
|
||||
(
|
||||
existing
|
||||
for name, existing in self._services.items()
|
||||
|
||||
Reference in New Issue
Block a user