uiprotect 4.2.0__tar.gz → 5.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of uiprotect might be problematic. Click here for more details.
- {uiprotect-4.2.0 → uiprotect-5.1.0}/PKG-INFO +1 -1
- {uiprotect-4.2.0 → uiprotect-5.1.0}/pyproject.toml +5 -4
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/__init__.py +0 -2
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/devices.py +10 -11
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/test_util/__init__.py +1 -1
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/utils.py +4 -11
- {uiprotect-4.2.0 → uiprotect-5.1.0}/LICENSE +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/README.md +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/__main__.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/api.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/__init__.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/backup.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/base.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/cameras.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/chimes.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/doorlocks.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/events.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/lights.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/liveviews.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/nvr.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/sensors.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/cli/viewers.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/__init__.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/base.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/bootstrap.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/convert.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/nvr.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/types.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/user.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/data/websocket.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/exceptions.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/py.typed +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/release_cache.json +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/stream.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/test_util/anonymize.py +0 -0
- {uiprotect-4.2.0 → uiprotect-5.1.0}/src/uiprotect/websocket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "uiprotect"
|
|
3
|
-
version = "
|
|
3
|
+
version = "5.1.0"
|
|
4
4
|
description = "Python API for Unifi Protect (Unofficial)"
|
|
5
5
|
authors = ["UI Protect Maintainers <ui@koston.org>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -48,8 +48,8 @@ typer = ">=0.12.3"
|
|
|
48
48
|
convertertools = ">=0.5.0"
|
|
49
49
|
|
|
50
50
|
[tool.poetry.group.dev.dependencies]
|
|
51
|
-
pytest = "
|
|
52
|
-
pytest-cov = "
|
|
51
|
+
pytest = ">=7,<9"
|
|
52
|
+
pytest-cov = ">=3,<6"
|
|
53
53
|
aiosqlite = ">=0.20.0"
|
|
54
54
|
asttokens = "^2.4.1"
|
|
55
55
|
pytest-asyncio = "^0.23.7"
|
|
@@ -57,7 +57,7 @@ pytest-benchmark = "^4.0.0"
|
|
|
57
57
|
pytest-sugar = "^1.0.0"
|
|
58
58
|
pytest-timeout = "^2.3.1"
|
|
59
59
|
pytest-xdist = "^3.6.1"
|
|
60
|
-
types-aiofiles = "
|
|
60
|
+
types-aiofiles = ">=23.2.0.20240403,<25.0.0.0"
|
|
61
61
|
types-dateparser = "^1.2.0.20240420"
|
|
62
62
|
mypy = "^1.10.0"
|
|
63
63
|
|
|
@@ -146,6 +146,7 @@ ignore = [
|
|
|
146
146
|
"D106", # Missing docstring in public nested class
|
|
147
147
|
"UP007", # typer needs Optional syntax
|
|
148
148
|
"UP038", # Use `X | Y` in `isinstance` is slower
|
|
149
|
+
"S603", # check for execution of untrusted input
|
|
149
150
|
]
|
|
150
151
|
select = [
|
|
151
152
|
"B", # flake8-bugbear
|
|
@@ -7,7 +7,6 @@ from .exceptions import Invalid, NotAuthorized, NvrError
|
|
|
7
7
|
from .utils import (
|
|
8
8
|
get_nested_attr,
|
|
9
9
|
get_nested_attr_as_bool,
|
|
10
|
-
get_top_level_attr,
|
|
11
10
|
get_top_level_attr_as_bool,
|
|
12
11
|
make_enabled_getter,
|
|
13
12
|
make_required_getter,
|
|
@@ -21,7 +20,6 @@ __all__ = [
|
|
|
21
20
|
"ProtectApiClient",
|
|
22
21
|
"get_nested_attr",
|
|
23
22
|
"get_nested_attr_as_bool",
|
|
24
|
-
"get_top_level_attr",
|
|
25
23
|
"get_top_level_attr_as_bool",
|
|
26
24
|
"make_value_getter",
|
|
27
25
|
"make_enabled_getter",
|
|
@@ -1134,11 +1134,9 @@ class Camera(ProtectMotionDeviceModel):
|
|
|
1134
1134
|
smart_type: SmartDetectObjectType,
|
|
1135
1135
|
) -> Event | None:
|
|
1136
1136
|
"""Get the last smart detect event for given type."""
|
|
1137
|
-
event_id
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
return self._api.bootstrap.events.get(event_id)
|
|
1137
|
+
if event_id := self.last_smart_detect_event_ids.get(smart_type):
|
|
1138
|
+
return self._api.bootstrap.events.get(event_id)
|
|
1139
|
+
return None
|
|
1142
1140
|
|
|
1143
1141
|
@property
|
|
1144
1142
|
def last_smart_audio_detect_event(self) -> Event | None:
|
|
@@ -1222,19 +1220,20 @@ class Camera(ProtectMotionDeviceModel):
|
|
|
1222
1220
|
"""Get active smart detection types."""
|
|
1223
1221
|
if self.use_global:
|
|
1224
1222
|
return set(self.smart_detect_settings.object_types).intersection(
|
|
1225
|
-
self.feature_flags.smart_detect_types
|
|
1223
|
+
self.feature_flags.smart_detect_types
|
|
1226
1224
|
)
|
|
1227
1225
|
return set(self.smart_detect_settings.object_types)
|
|
1228
1226
|
|
|
1229
1227
|
@property
|
|
1230
1228
|
def active_audio_detect_types(self) -> set[SmartDetectAudioType]:
|
|
1231
1229
|
"""Get active audio detection types."""
|
|
1230
|
+
if not (enabled_audio_types := self.smart_detect_settings.audio_types):
|
|
1231
|
+
return set()
|
|
1232
1232
|
if self.use_global:
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
)
|
|
1236
|
-
|
|
1237
|
-
return set(self.smart_detect_settings.audio_types or [])
|
|
1233
|
+
if not (feature_audio_types := self.feature_flags.smart_detect_audio_types):
|
|
1234
|
+
return set()
|
|
1235
|
+
return set(feature_audio_types).intersection(enabled_audio_types)
|
|
1236
|
+
return set(enabled_audio_types)
|
|
1238
1237
|
|
|
1239
1238
|
@property
|
|
1240
1239
|
def is_motion_detection_on(self) -> bool:
|
|
@@ -359,7 +359,7 @@ class SampleDataGenerator:
|
|
|
359
359
|
length = int((motion_event["end"] - motion_event["start"]) / 1000)
|
|
360
360
|
if self.anonymize:
|
|
361
361
|
run(
|
|
362
|
-
split(
|
|
362
|
+
split(
|
|
363
363
|
BLANK_VIDEO_CMD.format(
|
|
364
364
|
length=length,
|
|
365
365
|
filename=self.output_folder / f"{filename}.mp4",
|
|
@@ -634,7 +634,7 @@ def get_nested_attr(attrs: tuple[str, ...], obj: Any) -> Any:
|
|
|
634
634
|
for key in attrs:
|
|
635
635
|
if (value := getattr(value, key, _SENTINEL)) is _SENTINEL:
|
|
636
636
|
return None
|
|
637
|
-
return value
|
|
637
|
+
return value
|
|
638
638
|
|
|
639
639
|
|
|
640
640
|
def get_nested_attr_as_bool(attrs: tuple[str, ...], obj: Any) -> bool:
|
|
@@ -643,25 +643,18 @@ def get_nested_attr_as_bool(attrs: tuple[str, ...], obj: Any) -> bool:
|
|
|
643
643
|
for key in attrs:
|
|
644
644
|
if (value := getattr(value, key, _SENTINEL)) is _SENTINEL:
|
|
645
645
|
return False
|
|
646
|
-
return bool(value
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
def get_top_level_attr(attr: str, obj: Any) -> Any:
|
|
650
|
-
"""Fetch a top level attribute."""
|
|
651
|
-
value = getattr(obj, attr)
|
|
652
|
-
return value.value if isinstance(value, Enum) else value
|
|
646
|
+
return bool(value)
|
|
653
647
|
|
|
654
648
|
|
|
655
649
|
def get_top_level_attr_as_bool(attr: str, obj: Any) -> Any:
|
|
656
650
|
"""Fetch a top level attribute as a bool."""
|
|
657
|
-
|
|
658
|
-
return bool(value.value if isinstance(value, Enum) else value)
|
|
651
|
+
return bool(getattr(obj, attr))
|
|
659
652
|
|
|
660
653
|
|
|
661
654
|
def make_value_getter(ufp_value: str) -> Callable[[T], Any]:
|
|
662
655
|
"""Return a function to get a value from a Protect device."""
|
|
663
656
|
if "." not in ufp_value:
|
|
664
|
-
return
|
|
657
|
+
return attrgetter(ufp_value)
|
|
665
658
|
return partial(get_nested_attr, tuple(ufp_value.split(".")))
|
|
666
659
|
|
|
667
660
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|