mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-23 15:09:22 +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:
@@ -1,12 +1,10 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AppTimelineHourlyQueryParameters(BaseModel):
|
||||
cameras: Optional[str] = "all"
|
||||
labels: Optional[str] = "all"
|
||||
after: Optional[float] = None
|
||||
before: Optional[float] = None
|
||||
limit: Optional[int] = 200
|
||||
timezone: Optional[str] = "utc"
|
||||
cameras: str | None = "all"
|
||||
labels: str | None = "all"
|
||||
after: float | None = None
|
||||
before: float | None = None
|
||||
limit: int | None = 200
|
||||
timezone: str | None = "utc"
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
DEFAULT_TIME_RANGE = "00:00,24:00"
|
||||
|
||||
|
||||
class EventsQueryParams(BaseModel):
|
||||
camera: Optional[str] = "all"
|
||||
cameras: Optional[str] = "all"
|
||||
label: Optional[str] = "all"
|
||||
labels: Optional[str] = "all"
|
||||
sub_label: Optional[str] = "all"
|
||||
sub_labels: Optional[str] = "all"
|
||||
attributes: Optional[str] = "all"
|
||||
zone: Optional[str] = "all"
|
||||
zones: Optional[str] = "all"
|
||||
limit: Optional[int] = 100
|
||||
after: Optional[float] = None
|
||||
before: Optional[float] = None
|
||||
time_range: Optional[str] = DEFAULT_TIME_RANGE
|
||||
has_clip: Optional[int] = None
|
||||
has_snapshot: Optional[int] = None
|
||||
in_progress: Optional[int] = None
|
||||
include_thumbnails: Optional[int] = Field(
|
||||
camera: str | None = "all"
|
||||
cameras: str | None = "all"
|
||||
label: str | None = "all"
|
||||
labels: str | None = "all"
|
||||
sub_label: str | None = "all"
|
||||
sub_labels: str | None = "all"
|
||||
attributes: str | None = "all"
|
||||
zone: str | None = "all"
|
||||
zones: str | None = "all"
|
||||
limit: int | None = 100
|
||||
after: float | None = None
|
||||
before: float | None = None
|
||||
time_range: str | None = DEFAULT_TIME_RANGE
|
||||
has_clip: int | None = None
|
||||
has_snapshot: int | None = None
|
||||
in_progress: int | None = None
|
||||
include_thumbnails: int | None = Field(
|
||||
1,
|
||||
description=(
|
||||
"Deprecated. Thumbnail data is no longer included in the response. "
|
||||
@@ -30,25 +28,25 @@ class EventsQueryParams(BaseModel):
|
||||
),
|
||||
deprecated=True,
|
||||
)
|
||||
favorites: Optional[int] = None
|
||||
min_score: Optional[float] = None
|
||||
max_score: Optional[float] = None
|
||||
min_speed: Optional[float] = None
|
||||
max_speed: Optional[float] = None
|
||||
recognized_license_plate: Optional[str] = "all"
|
||||
is_submitted: Optional[int] = None
|
||||
min_length: Optional[float] = None
|
||||
max_length: Optional[float] = None
|
||||
event_id: Optional[str] = None
|
||||
sort: Optional[str] = None
|
||||
timezone: Optional[str] = "utc"
|
||||
favorites: int | None = None
|
||||
min_score: float | None = None
|
||||
max_score: float | None = None
|
||||
min_speed: float | None = None
|
||||
max_speed: float | None = None
|
||||
recognized_license_plate: str | None = "all"
|
||||
is_submitted: int | None = None
|
||||
min_length: float | None = None
|
||||
max_length: float | None = None
|
||||
event_id: str | None = None
|
||||
sort: str | None = None
|
||||
timezone: str | None = "utc"
|
||||
|
||||
|
||||
class EventsSearchQueryParams(BaseModel):
|
||||
query: Optional[str] = None
|
||||
event_id: Optional[str] = None
|
||||
search_type: Optional[str] = "thumbnail"
|
||||
include_thumbnails: Optional[int] = Field(
|
||||
query: str | None = None
|
||||
event_id: str | None = None
|
||||
search_type: str | None = "thumbnail"
|
||||
include_thumbnails: int | None = Field(
|
||||
1,
|
||||
description=(
|
||||
"Deprecated. Thumbnail data is no longer included in the response. "
|
||||
@@ -56,28 +54,28 @@ class EventsSearchQueryParams(BaseModel):
|
||||
),
|
||||
deprecated=True,
|
||||
)
|
||||
limit: Optional[int] = 50
|
||||
cameras: Optional[str] = "all"
|
||||
labels: Optional[str] = "all"
|
||||
sub_labels: Optional[str] = "all"
|
||||
attributes: Optional[str] = "all"
|
||||
zones: Optional[str] = "all"
|
||||
after: Optional[float] = None
|
||||
before: Optional[float] = None
|
||||
time_range: Optional[str] = DEFAULT_TIME_RANGE
|
||||
has_clip: Optional[bool] = None
|
||||
has_snapshot: Optional[bool] = None
|
||||
is_submitted: Optional[bool] = None
|
||||
timezone: Optional[str] = "utc"
|
||||
min_score: Optional[float] = None
|
||||
max_score: Optional[float] = None
|
||||
min_speed: Optional[float] = None
|
||||
max_speed: Optional[float] = None
|
||||
recognized_license_plate: Optional[str] = "all"
|
||||
sort: Optional[str] = None
|
||||
limit: int | None = 50
|
||||
cameras: str | None = "all"
|
||||
labels: str | None = "all"
|
||||
sub_labels: str | None = "all"
|
||||
attributes: str | None = "all"
|
||||
zones: str | None = "all"
|
||||
after: float | None = None
|
||||
before: float | None = None
|
||||
time_range: str | None = DEFAULT_TIME_RANGE
|
||||
has_clip: bool | None = None
|
||||
has_snapshot: bool | None = None
|
||||
is_submitted: bool | None = None
|
||||
timezone: str | None = "utc"
|
||||
min_score: float | None = None
|
||||
max_score: float | None = None
|
||||
min_speed: float | None = None
|
||||
max_speed: float | None = None
|
||||
recognized_license_plate: str | None = "all"
|
||||
sort: str | None = None
|
||||
|
||||
|
||||
class EventsSummaryQueryParams(BaseModel):
|
||||
timezone: Optional[str] = "utc"
|
||||
has_clip: Optional[int] = None
|
||||
has_snapshot: Optional[int] = None
|
||||
timezone: str | None = "utc"
|
||||
has_clip: int | None = None
|
||||
has_snapshot: int | None = None
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -17,33 +16,33 @@ class Extension(str, Enum):
|
||||
|
||||
|
||||
class MediaLatestFrameQueryParams(BaseModel):
|
||||
bbox: Optional[int] = None
|
||||
timestamp: Optional[int] = None
|
||||
zones: Optional[int] = None
|
||||
mask: Optional[int] = None
|
||||
motion: Optional[int] = None
|
||||
paths: Optional[int] = None
|
||||
regions: Optional[int] = None
|
||||
quality: Optional[int] = 70
|
||||
height: Optional[int] = None
|
||||
store: Optional[int] = None
|
||||
bbox: int | None = None
|
||||
timestamp: int | None = None
|
||||
zones: int | None = None
|
||||
mask: int | None = None
|
||||
motion: int | None = None
|
||||
paths: int | None = None
|
||||
regions: int | None = None
|
||||
quality: int | None = 70
|
||||
height: int | None = None
|
||||
store: int | None = None
|
||||
|
||||
|
||||
class MediaEventsSnapshotQueryParams(BaseModel):
|
||||
download: Optional[bool] = False
|
||||
timestamp: Optional[int] = None
|
||||
bbox: Optional[int] = None
|
||||
crop: Optional[int] = None
|
||||
height: Optional[int] = None
|
||||
quality: Optional[int] = None
|
||||
download: bool | None = False
|
||||
timestamp: int | None = None
|
||||
bbox: int | None = None
|
||||
crop: int | None = None
|
||||
height: int | None = None
|
||||
quality: int | None = None
|
||||
|
||||
|
||||
class MediaMjpegFeedQueryParams(BaseModel):
|
||||
fps: int = 3
|
||||
height: int = 360
|
||||
bbox: Optional[int] = None
|
||||
timestamp: Optional[int] = None
|
||||
zones: Optional[int] = None
|
||||
mask: Optional[int] = None
|
||||
motion: Optional[int] = None
|
||||
regions: Optional[int] = None
|
||||
bbox: int | None = None
|
||||
timestamp: int | None = None
|
||||
zones: int | None = None
|
||||
mask: int | None = None
|
||||
motion: int | None = None
|
||||
regions: int | None = None
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
from typing import Optional, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic.json_schema import SkipJsonSchema
|
||||
|
||||
|
||||
class MediaRecordingsSummaryQueryParams(BaseModel):
|
||||
timezone: str = "utc"
|
||||
cameras: Optional[str] = "all"
|
||||
cameras: str | None = "all"
|
||||
|
||||
|
||||
class MediaRecordingsAvailabilityQueryParams(BaseModel):
|
||||
cameras: str = "all"
|
||||
before: Union[float, SkipJsonSchema[None]] = None
|
||||
after: Union[float, SkipJsonSchema[None]] = None
|
||||
before: float | SkipJsonSchema[None] = None
|
||||
after: float | SkipJsonSchema[None] = None
|
||||
scale: int = 30
|
||||
|
||||
|
||||
class RecordingsDeleteQueryParams(BaseModel):
|
||||
keep: Optional[str] = None
|
||||
cameras: Optional[str] = "all"
|
||||
keep: str | None = None
|
||||
cameras: str | None = "all"
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from frigate.events.types import RegenerateDescriptionEnum
|
||||
|
||||
|
||||
class RegenerateQueryParameters(BaseModel):
|
||||
source: Optional[RegenerateDescriptionEnum] = RegenerateDescriptionEnum.thumbnails
|
||||
force: Optional[bool] = Field(
|
||||
source: RegenerateDescriptionEnum | None = RegenerateDescriptionEnum.thumbnails
|
||||
force: bool | None = Field(
|
||||
default=False,
|
||||
description="Force (re)generating the description even if GenAI is disabled for this camera.",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic.json_schema import SkipJsonSchema
|
||||
|
||||
@@ -10,11 +8,11 @@ class ReviewQueryParams(BaseModel):
|
||||
cameras: str = "all"
|
||||
labels: str = "all"
|
||||
zones: str = "all"
|
||||
reviewed: Union[int, SkipJsonSchema[None]] = None
|
||||
limit: Union[int, SkipJsonSchema[None]] = None
|
||||
severity: Union[SeverityEnum, SkipJsonSchema[None]] = None
|
||||
before: Union[float, SkipJsonSchema[None]] = None
|
||||
after: Union[float, SkipJsonSchema[None]] = None
|
||||
reviewed: int | SkipJsonSchema[None] = None
|
||||
limit: int | SkipJsonSchema[None] = None
|
||||
severity: SeverityEnum | SkipJsonSchema[None] = None
|
||||
before: float | SkipJsonSchema[None] = None
|
||||
after: float | SkipJsonSchema[None] = None
|
||||
|
||||
|
||||
class ReviewSummaryQueryParams(BaseModel):
|
||||
@@ -26,6 +24,6 @@ class ReviewSummaryQueryParams(BaseModel):
|
||||
|
||||
class ReviewActivityMotionQueryParams(BaseModel):
|
||||
cameras: str = "all"
|
||||
before: Union[float, SkipJsonSchema[None]] = None
|
||||
after: Union[float, SkipJsonSchema[None]] = None
|
||||
before: float | SkipJsonSchema[None] = None
|
||||
after: float | SkipJsonSchema[None] = None
|
||||
scale: int = 30
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -8,26 +8,26 @@ from frigate.config import GenAIProviderEnum
|
||||
class AppConfigSetBody(BaseModel):
|
||||
requires_restart: int = 1
|
||||
update_topic: str | None = None
|
||||
config_data: Optional[Dict[str, Any]] = None
|
||||
config_data: dict[str, Any] | None = None
|
||||
skip_save: bool = False
|
||||
|
||||
|
||||
class GenAIProbeBody(BaseModel):
|
||||
provider: GenAIProviderEnum
|
||||
api_key: Optional[str] = None
|
||||
base_url: Optional[str] = None
|
||||
provider_options: Dict[str, Any] = Field(default_factory=dict)
|
||||
api_key: str | None = None
|
||||
base_url: str | None = None
|
||||
provider_options: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AppPutPasswordBody(BaseModel):
|
||||
password: str
|
||||
old_password: Optional[str] = None
|
||||
old_password: str | None = None
|
||||
|
||||
|
||||
class AppPostUsersBody(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
role: Optional[str] = "viewer"
|
||||
role: str | None = "viewer"
|
||||
|
||||
|
||||
class AppPostLoginBody(BaseModel):
|
||||
@@ -47,7 +47,7 @@ class MediaSyncBody(BaseModel):
|
||||
dry_run: bool = Field(
|
||||
default=True, description="If True, only report orphans without deleting them"
|
||||
)
|
||||
media_types: List[str] = Field(
|
||||
media_types: list[str] = Field(
|
||||
default=["all"],
|
||||
description="Types of media to sync: 'all', 'event_snapshots', 'event_thumbnails', 'review_thumbnails', 'previews', 'exports', 'recordings'",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
|
||||
MAX_BATCH_EXPORT_ITEMS = 50
|
||||
@@ -9,18 +7,18 @@ class BatchExportItem(BaseModel):
|
||||
camera: str = Field(title="Camera name")
|
||||
start_time: float = Field(title="Start time")
|
||||
end_time: float = Field(title="End time")
|
||||
image_path: Optional[str] = Field(
|
||||
image_path: str | None = Field(
|
||||
default=None,
|
||||
title="Existing thumbnail path",
|
||||
description="Optional existing image to use as the export thumbnail",
|
||||
)
|
||||
friendly_name: Optional[str] = Field(
|
||||
friendly_name: str | None = Field(
|
||||
default=None,
|
||||
title="Friendly name",
|
||||
max_length=256,
|
||||
description="Optional friendly name for this specific export item",
|
||||
)
|
||||
client_item_id: Optional[str] = Field(
|
||||
client_item_id: str | None = Field(
|
||||
default=None,
|
||||
title="Client item ID",
|
||||
max_length=128,
|
||||
@@ -29,13 +27,13 @@ class BatchExportItem(BaseModel):
|
||||
|
||||
|
||||
class BatchExportBody(BaseModel):
|
||||
items: List[BatchExportItem] = Field(
|
||||
items: list[BatchExportItem] = Field(
|
||||
title="Items",
|
||||
min_length=1,
|
||||
max_length=MAX_BATCH_EXPORT_ITEMS,
|
||||
description="List of export items. Each item has its own camera and time range.",
|
||||
)
|
||||
export_case_id: Optional[str] = Field(
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
title="Export case ID",
|
||||
max_length=30,
|
||||
@@ -44,13 +42,13 @@ class BatchExportBody(BaseModel):
|
||||
"existing case is temporarily admin-only until case-level ACLs exist."
|
||||
),
|
||||
)
|
||||
new_case_name: Optional[str] = Field(
|
||||
new_case_name: str | None = Field(
|
||||
default=None,
|
||||
title="New case name",
|
||||
max_length=100,
|
||||
description="Name of a new export case to create when export_case_id is omitted",
|
||||
)
|
||||
new_case_description: Optional[str] = Field(
|
||||
new_case_description: str | None = Field(
|
||||
default=None,
|
||||
title="New case description",
|
||||
description="Optional description for a newly created export case",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Chat API request models."""
|
||||
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -11,7 +11,7 @@ class ChatMessage(BaseModel):
|
||||
role: str = Field(
|
||||
description="Message role: 'user', 'assistant', 'system', or 'tool'"
|
||||
)
|
||||
content: Optional[Any] = Field(
|
||||
content: Any | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Message content. Usually a string, but may be a multimodal content "
|
||||
@@ -19,13 +19,13 @@ class ChatMessage(BaseModel):
|
||||
"request tool calls."
|
||||
),
|
||||
)
|
||||
tool_call_id: Optional[str] = Field(
|
||||
tool_call_id: str | None = Field(
|
||||
default=None, description="For tool messages, the ID of the tool call"
|
||||
)
|
||||
name: Optional[str] = Field(
|
||||
name: str | None = Field(
|
||||
default=None, description="For tool messages, the tool name"
|
||||
)
|
||||
tool_calls: Optional[list[dict[str, Any]]] = Field(
|
||||
tool_calls: list[dict[str, Any]] | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"For assistant messages replayed from prior turns, the OpenAI-format "
|
||||
@@ -52,7 +52,7 @@ class ChatCompletionRequest(BaseModel):
|
||||
default=False,
|
||||
description="If true, stream the final assistant response in the body as newline-delimited JSON.",
|
||||
)
|
||||
enable_thinking: Optional[bool] = Field(
|
||||
enable_thinking: bool | None = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"Per-request thinking toggle. None means use the provider default. "
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -12,14 +10,14 @@ class AudioTranscriptionBody(BaseModel):
|
||||
|
||||
|
||||
class DeleteFaceImagesBody(BaseModel):
|
||||
ids: List[str] = Field(
|
||||
ids: list[str] = Field(
|
||||
description="List of image filenames to delete from the face folder"
|
||||
)
|
||||
|
||||
|
||||
class GenerateStateExamplesBody(BaseModel):
|
||||
model_name: str = Field(description="Name of the classification model")
|
||||
cameras: Dict[str, Tuple[float, float, float, float]] = Field(
|
||||
cameras: dict[str, tuple[float, float, float, float]] = Field(
|
||||
description="Dictionary mapping camera names to normalized crop coordinates in [x1, y1, x2, y2] format (values 0-1)"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from frigate.config.classification import TriggerType
|
||||
@@ -7,49 +5,47 @@ from frigate.config.classification import TriggerType
|
||||
|
||||
class EventsSubLabelBody(BaseModel):
|
||||
subLabel: str = Field(title="Sub label", max_length=100)
|
||||
subLabelScore: Optional[float] = Field(
|
||||
subLabelScore: float | None = Field(
|
||||
title="Score for sub label", default=None, gt=0.0, le=1.0
|
||||
)
|
||||
camera: Optional[str] = Field(
|
||||
title="Camera this object is detected on.", default=None
|
||||
)
|
||||
camera: str | None = Field(title="Camera this object is detected on.", default=None)
|
||||
|
||||
|
||||
class EventsLPRBody(BaseModel):
|
||||
recognizedLicensePlate: str = Field(
|
||||
title="Recognized License Plate", max_length=100
|
||||
)
|
||||
recognizedLicensePlateScore: Optional[float] = Field(
|
||||
recognizedLicensePlateScore: float | None = Field(
|
||||
title="Score for recognized license plate", default=None, gt=0.0, le=1.0
|
||||
)
|
||||
|
||||
|
||||
class EventsAttributesBody(BaseModel):
|
||||
attributes: List[str] = Field(
|
||||
attributes: list[str] = Field(
|
||||
title="Selected classification attributes for the event",
|
||||
default_factory=list,
|
||||
)
|
||||
|
||||
|
||||
class EventsDescriptionBody(BaseModel):
|
||||
description: Union[str, None] = Field(title="The description of the event")
|
||||
description: str | None = Field(title="The description of the event")
|
||||
|
||||
|
||||
class EventsCreateBody(BaseModel):
|
||||
sub_label: Optional[str] = None
|
||||
score: Optional[float] = 0
|
||||
duration: Optional[int] = 30
|
||||
include_recording: Optional[bool] = True
|
||||
draw: Optional[dict] = {}
|
||||
pre_capture: Optional[int] = None
|
||||
sub_label: str | None = None
|
||||
score: float | None = 0
|
||||
duration: int | None = 30
|
||||
include_recording: bool | None = True
|
||||
draw: dict | None = {}
|
||||
pre_capture: int | None = None
|
||||
|
||||
|
||||
class EventsEndBody(BaseModel):
|
||||
end_time: Optional[float] = None
|
||||
end_time: float | None = None
|
||||
|
||||
|
||||
class EventsDeleteBody(BaseModel):
|
||||
event_ids: List[str] = Field(title="The event IDs to delete")
|
||||
event_ids: list[str] = Field(title="The event IDs to delete")
|
||||
|
||||
|
||||
class SubmitPlusBody(BaseModel):
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Request bodies for bulk export operations."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field, conlist, constr
|
||||
|
||||
|
||||
@@ -17,7 +15,7 @@ class ExportBulkReassignBody(BaseModel):
|
||||
|
||||
# List of export IDs with at least one element and each element with at least one char
|
||||
ids: conlist(constr(min_length=1), min_length=1)
|
||||
export_case_id: Optional[str] = Field(
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
max_length=30,
|
||||
description="Case ID to assign to, or null to unassign from current case",
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -7,7 +5,7 @@ class ExportCaseCreateBody(BaseModel):
|
||||
"""Request body for creating a new export case."""
|
||||
|
||||
name: str = Field(max_length=100, description="Friendly name of the export case")
|
||||
description: Optional[str] = Field(
|
||||
description: str | None = Field(
|
||||
default=None, description="Optional description of the export case"
|
||||
)
|
||||
|
||||
@@ -15,11 +13,11 @@ class ExportCaseCreateBody(BaseModel):
|
||||
class ExportCaseUpdateBody(BaseModel):
|
||||
"""Request body for updating an existing export case."""
|
||||
|
||||
name: Optional[str] = Field(
|
||||
name: str | None = Field(
|
||||
default=None,
|
||||
max_length=100,
|
||||
description="Updated friendly name of the export case",
|
||||
)
|
||||
description: Optional[str] = Field(
|
||||
description: str | None = Field(
|
||||
default=None, description="Updated description of the export case"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic.json_schema import SkipJsonSchema
|
||||
|
||||
@@ -13,15 +11,15 @@ class ExportRecordingsBody(BaseModel):
|
||||
source: PlaybackSourceEnum = Field(
|
||||
default=PlaybackSourceEnum.recordings, title="Playback source"
|
||||
)
|
||||
name: Optional[str] = Field(title="Friendly name", default=None, max_length=256)
|
||||
image_path: Union[str, SkipJsonSchema[None]] = None
|
||||
export_case_id: Optional[str] = Field(
|
||||
name: str | None = Field(title="Friendly name", default=None, max_length=256)
|
||||
image_path: str | SkipJsonSchema[None] = None
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
title="Export case ID",
|
||||
max_length=30,
|
||||
description="ID of the export case to assign this export to",
|
||||
)
|
||||
chapters: Optional[ChaptersEnum] = Field(
|
||||
chapters: ChaptersEnum | None = Field(
|
||||
default=None,
|
||||
title="Chapter mode",
|
||||
description=(
|
||||
@@ -36,19 +34,19 @@ class ExportRecordingsCustomBody(BaseModel):
|
||||
default=PlaybackSourceEnum.recordings, title="Playback source"
|
||||
)
|
||||
name: str = Field(title="Friendly name", default=None, max_length=256)
|
||||
image_path: Union[str, SkipJsonSchema[None]] = None
|
||||
export_case_id: Optional[str] = Field(
|
||||
image_path: str | SkipJsonSchema[None] = None
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
title="Export case ID",
|
||||
max_length=30,
|
||||
description="ID of the export case to assign this export to",
|
||||
)
|
||||
ffmpeg_input_args: Optional[str] = Field(
|
||||
ffmpeg_input_args: str | None = Field(
|
||||
default=None,
|
||||
title="FFmpeg input arguments",
|
||||
description="Custom FFmpeg input arguments. If not provided, defaults to timelapse input args.",
|
||||
)
|
||||
ffmpeg_output_args: Optional[str] = Field(
|
||||
ffmpeg_output_args: str | None = Field(
|
||||
default=None,
|
||||
title="FFmpeg output arguments",
|
||||
description="Custom FFmpeg output arguments. If not provided, defaults to timelapse output args.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Chat API response models."""
|
||||
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -17,14 +17,14 @@ class ChatMessageResponse(BaseModel):
|
||||
"""A message in the chat response."""
|
||||
|
||||
role: str = Field(description="Message role")
|
||||
content: Optional[str] = Field(
|
||||
content: str | None = Field(
|
||||
default=None, description="Message content (None if tool calls present)"
|
||||
)
|
||||
reasoning: Optional[str] = Field(
|
||||
reasoning: str | None = Field(
|
||||
default=None,
|
||||
description="Separated reasoning/thinking trace if the model emitted one",
|
||||
)
|
||||
tool_calls: Optional[list[ToolCallInvocation]] = Field(
|
||||
tool_calls: list[ToolCallInvocation] | None = Field(
|
||||
default=None, description="Tool calls if LLM wants to call tools"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, RootModel
|
||||
|
||||
|
||||
class FacesResponse(RootModel[Dict[str, List[str]]]):
|
||||
class FacesResponse(RootModel[dict[str, list[str]]]):
|
||||
"""Response model for the get_faces endpoint.
|
||||
|
||||
Returns a mapping of face names to lists of image filenames.
|
||||
@@ -17,7 +15,7 @@ class FacesResponse(RootModel[Dict[str, List[str]]]):
|
||||
}
|
||||
"""
|
||||
|
||||
root: Dict[str, List[str]] = Field(
|
||||
root: dict[str, list[str]] = Field(
|
||||
default_factory=dict,
|
||||
description="Dictionary mapping face names to lists of image filenames",
|
||||
)
|
||||
@@ -30,9 +28,9 @@ class FaceRecognitionResponse(BaseModel):
|
||||
"""
|
||||
|
||||
success: bool = Field(description="Whether the face recognition was successful")
|
||||
score: Optional[float] = Field(
|
||||
score: float | None = Field(
|
||||
default=None, description="Confidence score of the recognition (0-1)"
|
||||
)
|
||||
face_name: Optional[str] = Field(
|
||||
face_name: str | None = Field(
|
||||
default=None, description="The recognized face name if successful"
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
@@ -6,20 +6,20 @@ from pydantic import BaseModel, ConfigDict
|
||||
class EventResponse(BaseModel):
|
||||
id: str
|
||||
label: str
|
||||
sub_label: Optional[str]
|
||||
sub_label: str | None
|
||||
camera: str
|
||||
start_time: float
|
||||
end_time: Optional[float]
|
||||
false_positive: Optional[bool]
|
||||
end_time: float | None
|
||||
false_positive: bool | None
|
||||
zones: list[str]
|
||||
thumbnail: Optional[str]
|
||||
thumbnail: str | None
|
||||
has_clip: bool
|
||||
has_snapshot: bool
|
||||
retain_indefinitely: bool
|
||||
plus_id: Optional[str]
|
||||
model_hash: Optional[str]
|
||||
detector_type: Optional[str]
|
||||
model_type: Optional[str]
|
||||
plus_id: str | None
|
||||
model_hash: str | None
|
||||
detector_type: str | None
|
||||
model_type: str | None
|
||||
data: dict[str, Any]
|
||||
|
||||
model_config = ConfigDict(protected_namespaces=())
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -8,7 +6,7 @@ class ExportCaseModel(BaseModel):
|
||||
|
||||
id: str = Field(description="Unique identifier for the export case")
|
||||
name: str = Field(description="Friendly name of the export case")
|
||||
description: Optional[str] = Field(
|
||||
description: str | None = Field(
|
||||
default=None, description="Optional description of the export case"
|
||||
)
|
||||
created_at: float = Field(
|
||||
@@ -19,4 +17,4 @@ class ExportCaseModel(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
ExportCasesResponse = List[ExportCaseModel]
|
||||
ExportCasesResponse = list[ExportCaseModel]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -15,7 +15,7 @@ class ExportModel(BaseModel):
|
||||
in_progress: bool = Field(
|
||||
description="Whether the export is currently being processed"
|
||||
)
|
||||
export_case_id: Optional[str] = Field(
|
||||
export_case_id: str | None = Field(
|
||||
default=None, description="ID of the export case this export belongs to"
|
||||
)
|
||||
|
||||
@@ -25,10 +25,10 @@ class StartExportResponse(BaseModel):
|
||||
|
||||
success: bool = Field(description="Whether the export was started successfully")
|
||||
message: str = Field(description="Status or error message")
|
||||
export_id: Optional[str] = Field(
|
||||
export_id: str | None = Field(
|
||||
default=None, description="The export ID if successfully started"
|
||||
)
|
||||
status: Optional[str] = Field(
|
||||
status: str | None = Field(
|
||||
default=None,
|
||||
description="Queue status for the export job",
|
||||
)
|
||||
@@ -38,24 +38,24 @@ class BatchExportResultModel(BaseModel):
|
||||
"""Per-item result for a batch export request."""
|
||||
|
||||
camera: str = Field(description="Camera name for this export attempt")
|
||||
export_id: Optional[str] = Field(
|
||||
export_id: str | None = Field(
|
||||
default=None,
|
||||
description="The export ID when the export was successfully queued",
|
||||
)
|
||||
success: bool = Field(description="Whether the export was successfully queued")
|
||||
status: Optional[str] = Field(
|
||||
status: str | None = Field(
|
||||
default=None,
|
||||
description="Queue status for this camera export",
|
||||
)
|
||||
error: Optional[str] = Field(
|
||||
error: str | None = Field(
|
||||
default=None,
|
||||
description="Validation or queueing error for this item, if any",
|
||||
)
|
||||
item_index: Optional[int] = Field(
|
||||
item_index: int | None = Field(
|
||||
default=None,
|
||||
description="Zero-based index of this result within the request items list",
|
||||
)
|
||||
client_item_id: Optional[str] = Field(
|
||||
client_item_id: str | None = Field(
|
||||
default=None,
|
||||
description="Opaque client-supplied item identifier echoed from the request",
|
||||
)
|
||||
@@ -64,12 +64,12 @@ class BatchExportResultModel(BaseModel):
|
||||
class BatchExportResponse(BaseModel):
|
||||
"""Response model for starting an export batch."""
|
||||
|
||||
export_case_id: Optional[str] = Field(
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
description="Export case ID associated with the batch",
|
||||
)
|
||||
export_ids: List[str] = Field(description="Export IDs successfully queued")
|
||||
results: List[BatchExportResultModel] = Field(
|
||||
export_ids: list[str] = Field(description="Export IDs successfully queued")
|
||||
results: list[BatchExportResultModel] = Field(
|
||||
description="Per-item batch export results"
|
||||
)
|
||||
|
||||
@@ -81,29 +81,29 @@ class ExportJobModel(BaseModel):
|
||||
job_type: str = Field(description="Job type")
|
||||
status: str = Field(description="Current job status")
|
||||
camera: str = Field(description="Camera associated with this export job")
|
||||
name: Optional[str] = Field(
|
||||
name: str | None = Field(
|
||||
default=None,
|
||||
description="Friendly name for the export",
|
||||
)
|
||||
export_case_id: Optional[str] = Field(
|
||||
export_case_id: str | None = Field(
|
||||
default=None,
|
||||
description="ID of the export case this export belongs to",
|
||||
)
|
||||
request_start_time: float = Field(description="Requested export start time")
|
||||
request_end_time: float = Field(description="Requested export end time")
|
||||
start_time: Optional[float] = Field(
|
||||
start_time: float | None = Field(
|
||||
default=None,
|
||||
description="Unix timestamp when execution started",
|
||||
)
|
||||
end_time: Optional[float] = Field(
|
||||
end_time: float | None = Field(
|
||||
default=None,
|
||||
description="Unix timestamp when execution completed",
|
||||
)
|
||||
error_message: Optional[str] = Field(
|
||||
error_message: str | None = Field(
|
||||
default=None,
|
||||
description="Error message for failed jobs",
|
||||
)
|
||||
results: Optional[dict[str, Any]] = Field(
|
||||
results: dict[str, Any] | None = Field(
|
||||
default=None,
|
||||
description="Result metadata for completed jobs",
|
||||
)
|
||||
@@ -117,7 +117,7 @@ class ExportJobModel(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
ExportJobsResponse = List[ExportJobModel]
|
||||
ExportJobsResponse = list[ExportJobModel]
|
||||
|
||||
|
||||
ExportsResponse = List[ExportModel]
|
||||
ExportsResponse = list[ExportModel]
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -13,5 +11,5 @@ class PreviewModel(BaseModel):
|
||||
end: float = Field(description="Unix timestamp when the preview ends")
|
||||
|
||||
|
||||
PreviewsResponse = List[PreviewModel]
|
||||
PreviewFramesResponse = List[str]
|
||||
PreviewsResponse = list[PreviewModel]
|
||||
PreviewFramesResponse = list[str]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import datetime
|
||||
from typing import Dict
|
||||
|
||||
from pydantic import BaseModel, Json
|
||||
|
||||
@@ -34,7 +33,7 @@ class DayReview(BaseModel):
|
||||
|
||||
class ReviewSummaryResponse(BaseModel):
|
||||
last24Hours: Last24HoursReview
|
||||
root: Dict[str, DayReview]
|
||||
root: dict[str, DayReview]
|
||||
|
||||
|
||||
class ReviewActivityMotionResponse(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user