mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-13 02:02:48 +03:00
fix mypy errors from types-peewee 4.0 (#24323)
types-peewee 4.0 types model fields precisely, so 17 `type: ignore` comments and 2 `cast(str, ...)` calls are no longer needed. Its stubs type `.namedtuples()` and `.dicts()` queries as returning model instances, so the review cleanup reads namedtuple fields by name and the storage usage query casts its dict rows. `start_time` is declared `DateTimeField` but stores unix timestamps, so two reads cast it like `debug_replay.py` already does. `Export` gets an annotation for the `export_case_id` attribute peewee adds at runtime.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
ruff == 0.15.20
|
ruff == 0.15.20
|
||||||
|
|
||||||
# types
|
# types
|
||||||
types-peewee == 3.17.*
|
types-peewee == 4.0.*
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
|
|||||||
# Crop snapshot based on region
|
# Crop snapshot based on region
|
||||||
# provide full image if region doesn't exist (manual events)
|
# provide full image if region doesn't exist (manual events)
|
||||||
height, width = img.shape[:2]
|
height, width = img.shape[:2]
|
||||||
x1_rel, y1_rel, width_rel, height_rel = event.data.get( # type: ignore[attr-defined]
|
x1_rel, y1_rel, width_rel, height_rel = event.data.get(
|
||||||
"region", [0, 0, 1, 1]
|
"region", [0, 0, 1, 1]
|
||||||
)
|
)
|
||||||
x1, y1 = int(x1_rel * width), int(y1_rel * height)
|
x1, y1 = int(x1_rel * width), int(y1_rel * height)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any, cast
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
from peewee import DoesNotExist
|
from peewee import DoesNotExist
|
||||||
@@ -528,7 +528,8 @@ class ReviewDescriptionProcessor(PostProcessorApi):
|
|||||||
.get()
|
.get()
|
||||||
)
|
)
|
||||||
|
|
||||||
time_in_segment = ts - recording.start_time
|
# start_time is a DateTimeField holding a unix timestamp
|
||||||
|
time_in_segment = ts - cast(float, recording.start_time)
|
||||||
return get_image_from_recording(
|
return get_image_from_recording(
|
||||||
self.config.ffmpeg,
|
self.config.ffmpeg,
|
||||||
recording.path,
|
recording.path,
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ class SemanticTriggerProcessor(PostProcessorApi):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Skip the event if not an object
|
# Skip the event if not an object
|
||||||
if event.data.get("type") != "object": # type: ignore[attr-defined]
|
if event.data.get("type") != "object":
|
||||||
return
|
return
|
||||||
|
|
||||||
thumbnail_bytes = get_event_thumbnail_bytes(event)
|
thumbnail_bytes = get_event_thumbnail_bytes(event)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class EventCleanup(threading.Thread):
|
|||||||
if self.removed_camera_labels is None:
|
if self.removed_camera_labels is None:
|
||||||
self.removed_camera_labels = list(
|
self.removed_camera_labels = list(
|
||||||
Event.select(Event.label)
|
Event.select(Event.label)
|
||||||
.where(Event.camera.not_in(self.camera_keys)) # type: ignore[arg-type,call-arg,misc]
|
.where(Event.camera.not_in(self.camera_keys))
|
||||||
.distinct()
|
.distinct()
|
||||||
.execute()
|
.execute()
|
||||||
)
|
)
|
||||||
@@ -89,7 +89,7 @@ class EventCleanup(threading.Thread):
|
|||||||
Event.thumbnail,
|
Event.thumbnail,
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc]
|
Event.camera.not_in(self.camera_keys),
|
||||||
Event.start_time < expire_after,
|
Event.start_time < expire_after,
|
||||||
Event.label == event.label,
|
Event.label == event.label,
|
||||||
Event.retain_indefinitely == False,
|
Event.retain_indefinitely == False,
|
||||||
@@ -111,7 +111,7 @@ class EventCleanup(threading.Thread):
|
|||||||
|
|
||||||
# update the clips attribute for the db entry
|
# update the clips attribute for the db entry
|
||||||
query = Event.select(Event.id).where(
|
query = Event.select(Event.id).where(
|
||||||
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc]
|
Event.camera.not_in(self.camera_keys),
|
||||||
Event.start_time < expire_after,
|
Event.start_time < expire_after,
|
||||||
Event.label == event.label,
|
Event.label == event.label,
|
||||||
Event.retain_indefinitely == False,
|
Event.retain_indefinitely == False,
|
||||||
@@ -218,7 +218,7 @@ class EventCleanup(threading.Thread):
|
|||||||
Event.camera,
|
Event.camera,
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc]
|
Event.camera.not_in(self.camera_keys),
|
||||||
Event.start_time < expire_after,
|
Event.start_time < expire_after,
|
||||||
Event.retain_indefinitely == False,
|
Event.retain_indefinitely == False,
|
||||||
)
|
)
|
||||||
@@ -249,7 +249,7 @@ class EventCleanup(threading.Thread):
|
|||||||
|
|
||||||
# update the clips attribute for the db entry
|
# update the clips attribute for the db entry
|
||||||
query = Event.select(Event.id).where(
|
query = Event.select(Event.id).where(
|
||||||
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc]
|
Event.camera.not_in(self.camera_keys),
|
||||||
Event.start_time < expire_after,
|
Event.start_time < expire_after,
|
||||||
Event.retain_indefinitely == False,
|
Event.retain_indefinitely == False,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -216,11 +216,11 @@ class ExportDebugReplaySource(DebugReplaySource):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, export: Export, duration: float) -> None:
|
def __init__(self, export: Export, duration: float) -> None:
|
||||||
self._camera = cast(str, export.camera)
|
self._camera = export.camera
|
||||||
# Export.date is declared DateTimeField but Frigate writes raw unix
|
# Export.date is declared DateTimeField but Frigate writes raw unix
|
||||||
# timestamps to the column.
|
# timestamps to the column.
|
||||||
self._start_ts = float(cast(Any, export.date))
|
self._start_ts = float(cast(Any, export.date))
|
||||||
self._video_path = cast(str, export.video_path)
|
self._video_path = export.video_path
|
||||||
self._duration = duration
|
self._duration = duration
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ class Export(Model):
|
|||||||
backref="exports",
|
backref="exports",
|
||||||
column_name="export_case_id",
|
column_name="export_case_id",
|
||||||
)
|
)
|
||||||
|
# peewee adds this accessor for the export_case column at runtime
|
||||||
|
export_case_id: str | None
|
||||||
|
|
||||||
|
|
||||||
class ReviewSegment(Model):
|
class ReviewSegment(Model):
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ class NoticeRegistry:
|
|||||||
deleted = (
|
deleted = (
|
||||||
Notice.delete()
|
Notice.delete()
|
||||||
.where(
|
.where(
|
||||||
Notice.kind.in_(camera_kinds), # type: ignore[call-arg, arg-type, misc]
|
Notice.kind.in_(camera_kinds),
|
||||||
Notice.scope == camera,
|
Notice.scope == camera,
|
||||||
)
|
)
|
||||||
.execute()
|
.execute()
|
||||||
@@ -257,7 +257,7 @@ class NoticeRegistry:
|
|||||||
"""Dismissed config and stream check rows, newest first."""
|
"""Dismissed config and stream check rows, newest first."""
|
||||||
rows = (
|
rows = (
|
||||||
Notice.select()
|
Notice.select()
|
||||||
.where(Notice.kind.in_(list(CHECK_KINDS))) # type: ignore[call-arg, arg-type, misc]
|
.where(Notice.kind.in_(list(CHECK_KINDS)))
|
||||||
.order_by(Notice.dismissed_at.desc())
|
.order_by(Notice.dismissed_at.desc())
|
||||||
)
|
)
|
||||||
return [{"id": row.id, "dismissed_at": row.dismissed_at} for row in rows]
|
return [{"id": row.id, "dismissed_at": row.dismissed_at} for row in rows]
|
||||||
@@ -351,7 +351,7 @@ class NoticeRegistry:
|
|||||||
)
|
)
|
||||||
Notice.delete().where(
|
Notice.delete().where(
|
||||||
Notice.kind == kind,
|
Notice.kind == kind,
|
||||||
Notice.id.not_in(newest), # type: ignore[call-arg, misc]
|
Notice.id.not_in(newest),
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
def _bump_occurrences(self, kind: str, count: int, now: float) -> None:
|
def _bump_occurrences(self, kind: str, count: int, now: float) -> None:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import itertools
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
from collections.abc import Iterable
|
||||||
from multiprocessing.synchronize import Event as MpEvent
|
from multiprocessing.synchronize import Event as MpEvent
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -28,7 +29,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _filter_reviews_for_pass(
|
def _filter_reviews_for_pass(
|
||||||
reviews: list[Any],
|
reviews: Iterable[Any],
|
||||||
now: datetime.datetime,
|
now: datetime.datetime,
|
||||||
alerts_days: float,
|
alerts_days: float,
|
||||||
detections_days: float,
|
detections_days: float,
|
||||||
@@ -121,14 +122,14 @@ class RecordingCleanup(threading.Thread):
|
|||||||
)
|
)
|
||||||
|
|
||||||
maybe_empty_dirs = set()
|
maybe_empty_dirs = set()
|
||||||
thumbs_to_delete = list(map(lambda x: x[1], expired_reviews))
|
thumbs_to_delete = list(map(lambda x: x.thumb_path, expired_reviews))
|
||||||
for thumb_path in thumbs_to_delete:
|
for thumb in thumbs_to_delete:
|
||||||
thumb_path = Path(thumb_path)
|
thumb_path = Path(thumb)
|
||||||
thumb_path.unlink(missing_ok=True)
|
thumb_path.unlink(missing_ok=True)
|
||||||
maybe_empty_dirs.add(thumb_path.parent)
|
maybe_empty_dirs.add(thumb_path.parent)
|
||||||
|
|
||||||
max_deletes = 100000
|
max_deletes = 100000
|
||||||
deleted_reviews_list = list(map(lambda x: x[0], expired_reviews))
|
deleted_reviews_list = list(map(lambda x: x.id, expired_reviews))
|
||||||
for i in range(0, len(deleted_reviews_list), max_deletes):
|
for i in range(0, len(deleted_reviews_list), max_deletes):
|
||||||
ReviewSegment.delete().where(
|
ReviewSegment.delete().where(
|
||||||
ReviewSegment.id << deleted_reviews_list[i : i + max_deletes]
|
ReviewSegment.id << deleted_reviews_list[i : i + max_deletes]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from collections.abc import Callable
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any, cast
|
||||||
|
|
||||||
import pytz # type: ignore[import-untyped]
|
import pytz # type: ignore[import-untyped]
|
||||||
from pathvalidate import sanitize_filename
|
from pathvalidate import sanitize_filename
|
||||||
@@ -1055,7 +1055,10 @@ class RecordingExporter(threading.Thread):
|
|||||||
except DoesNotExist:
|
except DoesNotExist:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
diff = max(0.0, float(self.start_time) - float(preview.start_time))
|
# start_time is a DateTimeField holding a unix timestamp
|
||||||
|
diff = max(
|
||||||
|
0.0, float(self.start_time) - float(cast(Any, preview.start_time))
|
||||||
|
)
|
||||||
ffmpeg_cmd = [
|
ffmpeg_cmd = [
|
||||||
"/usr/lib/ffmpeg/8.0/bin/ffmpeg", # hardcode path for exports thumbnail due to missing libwebp support
|
"/usr/lib/ffmpeg/8.0/bin/ffmpeg", # hardcode path for exports thumbnail due to missing libwebp support
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
|
|||||||
+5
-2
@@ -3,8 +3,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
|
from collections.abc import Iterable
|
||||||
from multiprocessing.synchronize import Event as MpEvent
|
from multiprocessing.synchronize import Event as MpEvent
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
from peewee import SQL, Case, fn
|
from peewee import SQL, Case, fn
|
||||||
|
|
||||||
@@ -191,14 +193,15 @@ class StorageMaintainer(threading.Thread):
|
|||||||
|
|
||||||
stream_usages = {
|
stream_usages = {
|
||||||
row["stream_type"]: row["usage"] or 0
|
row["stream_type"]: row["usage"] or 0
|
||||||
for row in (
|
for row in cast(
|
||||||
|
Iterable[dict[str, Any]],
|
||||||
Recordings.select(
|
Recordings.select(
|
||||||
Recordings.stream_type,
|
Recordings.stream_type,
|
||||||
fn.SUM(Recordings.segment_size).alias("usage"),
|
fn.SUM(Recordings.segment_size).alias("usage"),
|
||||||
)
|
)
|
||||||
.where(Recordings.camera == camera, Recordings.segment_size != 0)
|
.where(Recordings.camera == camera, Recordings.segment_size != 0)
|
||||||
.group_by(Recordings.stream_type)
|
.group_by(Recordings.stream_type)
|
||||||
.dicts()
|
.dicts(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
stream_bandwidths = self.camera_storage_stats.get(camera, {}).get(
|
stream_bandwidths = self.camera_storage_stats.get(camera, {}).get(
|
||||||
|
|||||||
@@ -406,12 +406,12 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
tracked_obj.obj_data["sub_label"] = (sub_label, score)
|
tracked_obj.obj_data["sub_label"] = (sub_label, score)
|
||||||
|
|
||||||
if event:
|
if event:
|
||||||
event.sub_label = sub_label # type: ignore[assignment]
|
event.sub_label = sub_label
|
||||||
data = event.data
|
data = event.data
|
||||||
if sub_label is None:
|
if sub_label is None:
|
||||||
data["sub_label_score"] = None # type: ignore[index]
|
data["sub_label_score"] = None
|
||||||
elif score is not None:
|
elif score is not None:
|
||||||
data["sub_label_score"] = score # type: ignore[index]
|
data["sub_label_score"] = score
|
||||||
event.data = data
|
event.data = data
|
||||||
event.save()
|
event.save()
|
||||||
|
|
||||||
@@ -440,7 +440,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
objects_list = []
|
objects_list = []
|
||||||
sub_labels = set()
|
sub_labels = set()
|
||||||
events = Event.select(Event.id, Event.label, Event.sub_label).where(
|
events = Event.select(Event.id, Event.label, Event.sub_label).where(
|
||||||
Event.id.in_(detection_ids) # type: ignore[call-arg, misc]
|
Event.id.in_(detection_ids)
|
||||||
)
|
)
|
||||||
for det_event in events:
|
for det_event in events:
|
||||||
if det_event.sub_label:
|
if det_event.sub_label:
|
||||||
@@ -506,11 +506,11 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
|
|
||||||
if event:
|
if event:
|
||||||
data = event.data
|
data = event.data
|
||||||
data[field_name] = field_value # type: ignore[index]
|
data[field_name] = field_value
|
||||||
if field_value is None:
|
if field_value is None:
|
||||||
data[f"{field_name}_score"] = None # type: ignore[index]
|
data[f"{field_name}_score"] = None
|
||||||
elif score is not None:
|
elif score is not None:
|
||||||
data[f"{field_name}_score"] = score # type: ignore[index]
|
data[f"{field_name}_score"] = score
|
||||||
event.data = data
|
event.data = data
|
||||||
event.save()
|
event.save()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user