refactor(types): PEP-604 union sweep + UP007/UP045 enforcement
ruff --select UP007,UP045 --fix converted ~1760 sites across the backend: `Optional[T]` → `T | None`, `Union[X, Y]` → `X | Y`. The remaining module-level alias targets that ruff conservatively skips (BindableFloatInput, ColorList, DeviceConfig) were converted by hand earlier in the pass. black -formatted the result so the wider unions fit cleanly under the 100-char line budget. pyproject.toml now sets [tool.ruff.lint] extend-select = ["UP007", "UP045"] so future legacy imports fire CI on every push. The pre-commit ruff hook was bumped from v0.8.0 -> v0.15.12 to recognise UP045 (split off from UP007 in v0.13).
This commit is contained in:
@@ -16,7 +16,6 @@ from ledgrab.storage.output_target_store import OutputTargetStore
|
||||
from ledgrab.core.processing.processor_manager import ProcessorManager
|
||||
from ledgrab.api import dependencies as deps
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# App + fixtures (isolated from the real main app)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -16,7 +16,6 @@ from ledgrab.core.game_integration.events import GameEvent
|
||||
from ledgrab.storage.game_integration_store import GameIntegrationStore
|
||||
from ledgrab.api import dependencies as deps
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test adapter for ingestion tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,6 @@ from ledgrab.storage.ha_light_output_target import HALightOutputTarget
|
||||
from ledgrab.storage.wled_output_target import WledOutputTarget
|
||||
from ledgrab.storage.z2m_light_output_target import Z2MLightOutputTarget
|
||||
|
||||
|
||||
EXPECTED_TARGET_CLASSES = {WledOutputTarget, HALightOutputTarget, Z2MLightOutputTarget}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import pytest
|
||||
|
||||
from ledgrab.api.routes.webhooks import _check_rate_limit, _rate_hits
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rate limiter unit tests (pure function, no HTTP)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -58,7 +58,6 @@ from ledgrab.storage.automation import Automation # noqa: E402
|
||||
from ledgrab.storage.automation_store import AutomationStore # noqa: E402
|
||||
from ledgrab.storage.value_source_store import ValueSourceStore # noqa: E402
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Directory / path fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -9,7 +9,6 @@ from ledgrab.core.capture.edge_interpolation import (
|
||||
fallback_edge_to_leds,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# average_edge_to_leds
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -17,7 +17,6 @@ from ledgrab.core.processing.effect_stream import (
|
||||
_effect_renderer,
|
||||
)
|
||||
|
||||
|
||||
EXPECTED_EFFECTS = frozenset(
|
||||
{
|
||||
"fire",
|
||||
|
||||
@@ -21,7 +21,6 @@ from ledgrab.core.processing.metric_readers import (
|
||||
get_spec,
|
||||
)
|
||||
|
||||
|
||||
EXPECTED_METRICS = {
|
||||
"cpu_load",
|
||||
"ram_usage",
|
||||
|
||||
@@ -13,7 +13,6 @@ import ledgrab.core.audio.filters # noqa: F401
|
||||
|
||||
from ledgrab.core.filters.filter_instance import FilterInstance
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -17,7 +17,6 @@ from ledgrab.storage.automation import (
|
||||
)
|
||||
from ledgrab.storage.automation_store import AutomationStore
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -27,7 +27,6 @@ from ledgrab.storage.automation import (
|
||||
WebhookRule,
|
||||
)
|
||||
|
||||
|
||||
EXPECTED_RULE_TYPES = {
|
||||
StartupRule,
|
||||
ApplicationRule,
|
||||
|
||||
@@ -4,7 +4,6 @@ import pytest
|
||||
|
||||
from ledgrab.core.game_integration.adapters.cs2_adapter import CS2Adapter
|
||||
|
||||
|
||||
# ── Realistic CS2 GSI payload samples ────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from ledgrab.storage.color_strip_source import (
|
||||
GameEventColorStripSource,
|
||||
)
|
||||
|
||||
|
||||
# ── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ from ledgrab.storage.value_source import (
|
||||
ValueSource,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GameEventValueSource model tests (Task 5)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
@@ -12,7 +12,6 @@ from ledgrab.core.processing.target_processor import TargetContext
|
||||
from ledgrab.storage.bindable import BindableFloat
|
||||
from ledgrab.storage.ha_light_output_target import HALightMapping
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test doubles
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -115,9 +114,9 @@ class _FakeCSSManager:
|
||||
|
||||
def _make_ctx(
|
||||
*,
|
||||
ha_manager: Optional[_FakeHAManager] = None,
|
||||
css_manager: Optional[_FakeCSSManager] = None,
|
||||
vs_manager: Optional[_FakeVSManager] = None,
|
||||
ha_manager: _FakeHAManager | None = None,
|
||||
css_manager: _FakeCSSManager | None = None,
|
||||
vs_manager: _FakeVSManager | None = None,
|
||||
) -> TargetContext:
|
||||
return TargetContext(
|
||||
live_stream_manager=None, # type: ignore[arg-type]
|
||||
|
||||
@@ -11,7 +11,6 @@ from ledgrab.core.game_integration.mapping_adapter import (
|
||||
validate_adapter_yaml,
|
||||
)
|
||||
|
||||
|
||||
# ── YAML validation tests ───────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ helpers to make unauthenticated requests by temporarily removing the header.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
def _unauth_get(client, url):
|
||||
"""Make a GET request without the Authorization header."""
|
||||
saved = client.headers.pop("Authorization", None)
|
||||
@@ -54,7 +52,9 @@ class TestAuthEnforcement:
|
||||
def test_request_with_wrong_key_returns_401(self, client):
|
||||
"""Protected endpoint with an incorrect API key returns 401."""
|
||||
resp = _with_header(
|
||||
client, "GET", "/api/v1/devices",
|
||||
client,
|
||||
"GET",
|
||||
"/api/v1/devices",
|
||||
auth_value="Bearer wrong-key-12345",
|
||||
)
|
||||
assert resp.status_code == 401
|
||||
@@ -82,7 +82,9 @@ class TestAuthEnforcement:
|
||||
def test_post_without_auth_returns_401(self, client):
|
||||
"""Creating a device without auth fails."""
|
||||
resp = _unauth_request(
|
||||
client, "POST", "/api/v1/devices",
|
||||
client,
|
||||
"POST",
|
||||
"/api/v1/devices",
|
||||
json={
|
||||
"name": "Unauthorized Device",
|
||||
"url": "mock://test",
|
||||
@@ -115,7 +117,9 @@ class TestAuthEnforcement:
|
||||
def test_malformed_bearer_token_returns_401_or_403(self, client):
|
||||
"""A malformed Authorization header is rejected."""
|
||||
resp = _with_header(
|
||||
client, "GET", "/api/v1/devices",
|
||||
client,
|
||||
"GET",
|
||||
"/api/v1/devices",
|
||||
auth_value="just-a-key",
|
||||
)
|
||||
# FastAPI's HTTPBearer returns 403 for malformed format,
|
||||
|
||||
@@ -5,7 +5,6 @@ create -> get -> update -> brightness -> power -> delete -> verify gone.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class TestDeviceLifecycle:
|
||||
"""A user creates a device, inspects it, modifies it, and deletes it."""
|
||||
|
||||
@@ -76,12 +75,15 @@ class TestDeviceLifecycle:
|
||||
def test_create_multiple_devices_and_list(self, client):
|
||||
"""Creating multiple devices shows all in the list."""
|
||||
for i in range(3):
|
||||
resp = client.post("/api/v1/devices", json={
|
||||
"name": f"Device {i}",
|
||||
"url": "mock://test",
|
||||
"device_type": "mock",
|
||||
"led_count": 30,
|
||||
})
|
||||
resp = client.post(
|
||||
"/api/v1/devices",
|
||||
json={
|
||||
"name": f"Device {i}",
|
||||
"url": "mock://test",
|
||||
"device_type": "mock",
|
||||
"led_count": 30,
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
|
||||
resp = client.get("/api/v1/devices")
|
||||
@@ -108,13 +110,16 @@ class TestDeviceLifecycle:
|
||||
|
||||
def test_update_tags(self, client):
|
||||
"""Tags can be updated independently."""
|
||||
resp = client.post("/api/v1/devices", json={
|
||||
"name": "Tag Device",
|
||||
"url": "mock://test",
|
||||
"device_type": "mock",
|
||||
"led_count": 10,
|
||||
"tags": ["original"],
|
||||
})
|
||||
resp = client.post(
|
||||
"/api/v1/devices",
|
||||
json={
|
||||
"name": "Tag Device",
|
||||
"url": "mock://test",
|
||||
"device_type": "mock",
|
||||
"led_count": 10,
|
||||
"tags": ["original"],
|
||||
},
|
||||
)
|
||||
device_id = resp.json()["id"]
|
||||
|
||||
resp = client.put(
|
||||
|
||||
@@ -9,7 +9,6 @@ import pytest
|
||||
|
||||
from ledgrab.storage.base_store import BaseJsonStore, EntityNotFoundError
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimal concrete store for testing the base class
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -6,7 +6,6 @@ import pytest
|
||||
|
||||
from ledgrab.storage.device_store import Device, DeviceStore
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,6 @@ from ledgrab.storage.value_source import (
|
||||
_VALUE_SOURCE_MAP,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Coverage / shape
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -15,7 +15,6 @@ import pytest
|
||||
|
||||
from ledgrab.core.capture_engines import camera_engine as ce
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _parse_resolution — pure function, no stubs needed
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -5,7 +5,6 @@ import pytest
|
||||
from ledgrab.storage.color_strip_store import ColorStripStore, MAX_COMPOSITE_DEPTH
|
||||
from ledgrab.storage.database import Database
|
||||
|
||||
|
||||
# ── Fixtures ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ from ledgrab.core.devices.ddp_provider import DDPDeviceProvider
|
||||
from ledgrab.core.devices.device_config import DDPConfig
|
||||
from ledgrab.core.devices.led_client import ProviderDeps
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# parse_ddp_url
|
||||
# ============================================================================
|
||||
|
||||
@@ -15,7 +15,6 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
_REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
_SERVER_SRC = _REPO_ROOT / "src" / "ledgrab"
|
||||
_EVENTS_WS = _SERVER_SRC / "static" / "js" / "core" / "events-ws.ts"
|
||||
|
||||
@@ -19,7 +19,6 @@ from ledgrab.core.devices.govee_client import (
|
||||
from ledgrab.core.devices.govee_provider import GoveeDeviceProvider
|
||||
from ledgrab.core.devices.led_client import ProviderDeps
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# URL parsing
|
||||
# ============================================================================
|
||||
|
||||
@@ -8,7 +8,6 @@ from ledgrab.core.devices.led_client import ProviderDeps
|
||||
from ledgrab.storage.database import Database
|
||||
from ledgrab.storage.device_store import Device, DeviceStore
|
||||
|
||||
|
||||
# ── Fixtures ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ from ledgrab.core.devices.lifx_client import (
|
||||
)
|
||||
from ledgrab.core.devices.lifx_provider import LIFXDeviceProvider
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# URL parsing
|
||||
# ============================================================================
|
||||
|
||||
@@ -20,7 +20,6 @@ from ledgrab.core.devices.nanoleaf_client import (
|
||||
)
|
||||
from ledgrab.core.devices.nanoleaf_provider import NanoleafDeviceProvider
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# URL parsing
|
||||
# ============================================================================
|
||||
|
||||
@@ -18,7 +18,6 @@ from ledgrab.core.devices.opc_client import (
|
||||
)
|
||||
from ledgrab.core.devices.opc_provider import OPCDeviceProvider
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# URL parsing
|
||||
# ============================================================================
|
||||
|
||||
@@ -16,7 +16,6 @@ from ledgrab.core.devices.serial_transport import (
|
||||
port_exists,
|
||||
)
|
||||
|
||||
|
||||
# ── URL parsing ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ from ledgrab.core.devices.wiz_client import (
|
||||
)
|
||||
from ledgrab.core.devices.wiz_provider import WiZDeviceProvider
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# parse_wiz_url
|
||||
# ============================================================================
|
||||
|
||||
@@ -9,7 +9,6 @@ from fastapi.testclient import TestClient
|
||||
import ledgrab.config as config_mod
|
||||
from ledgrab.config import AuthConfig, Config, ServerConfig, StorageConfig
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimal app with a single WS endpoint using verify_ws_auth
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -20,7 +20,6 @@ from ledgrab.core.devices.yeelight_client import (
|
||||
)
|
||||
from ledgrab.core.devices.yeelight_provider import YeelightDeviceProvider
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# parse_yeelight_url
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user