uiprotect 3.1.9__tar.gz → 3.3.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-3.1.9 → uiprotect-3.3.0}/PKG-INFO +1 -1
- {uiprotect-3.1.9 → uiprotect-3.3.0}/pyproject.toml +1 -1
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/base.py +80 -67
- {uiprotect-3.1.9 → uiprotect-3.3.0}/LICENSE +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/README.md +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/__init__.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/__main__.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/api.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/__init__.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/backup.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/base.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/cameras.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/chimes.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/doorlocks.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/events.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/lights.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/liveviews.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/nvr.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/sensors.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/cli/viewers.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/__init__.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/bootstrap.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/convert.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/devices.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/nvr.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/types.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/user.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/data/websocket.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/exceptions.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/py.typed +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/release_cache.json +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/stream.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/test_util/__init__.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/test_util/anonymize.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/utils.py +0 -0
- {uiprotect-3.1.9 → uiprotect-3.3.0}/src/uiprotect/websocket.py +0 -0
|
@@ -8,7 +8,7 @@ from collections.abc import Callable
|
|
|
8
8
|
from datetime import datetime, timedelta
|
|
9
9
|
from functools import cache, cached_property
|
|
10
10
|
from ipaddress import IPv4Address
|
|
11
|
-
from typing import TYPE_CHECKING, Any,
|
|
11
|
+
from typing import TYPE_CHECKING, Any, NamedTuple, TypeVar
|
|
12
12
|
from uuid import UUID
|
|
13
13
|
|
|
14
14
|
from pydantic.v1 import BaseModel
|
|
@@ -65,6 +65,23 @@ def _is_protect_base_object(cls: type) -> bool:
|
|
|
65
65
|
return issubclass(cls, ProtectBaseObject)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
class _ProtectModelObjects(NamedTuple):
|
|
69
|
+
"""
|
|
70
|
+
Class to track all child of UFP objects.
|
|
71
|
+
|
|
72
|
+
objs are UFP objects
|
|
73
|
+
lists are lists of UFP objects
|
|
74
|
+
dicts are dicts of UFP objects
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
objs: dict[str, type[ProtectBaseObject]]
|
|
78
|
+
has_objs: bool
|
|
79
|
+
lists: dict[str, type[ProtectBaseObject]]
|
|
80
|
+
has_lists: bool
|
|
81
|
+
dicts: dict[str, type[ProtectBaseObject]]
|
|
82
|
+
has_dicts: bool
|
|
83
|
+
|
|
84
|
+
|
|
68
85
|
class ProtectBaseObject(BaseModel):
|
|
69
86
|
"""
|
|
70
87
|
Base class for building Python objects from UniFi Protect JSON.
|
|
@@ -76,10 +93,6 @@ class ProtectBaseObject(BaseModel):
|
|
|
76
93
|
|
|
77
94
|
_api: ProtectApiClient = PrivateAttr(None)
|
|
78
95
|
|
|
79
|
-
_protect_objs: ClassVar[dict[str, type[ProtectBaseObject]] | None] = None
|
|
80
|
-
_protect_lists: ClassVar[dict[str, type[ProtectBaseObject]] | None] = None
|
|
81
|
-
_protect_dicts: ClassVar[dict[str, type[ProtectBaseObject]] | None] = None
|
|
82
|
-
|
|
83
96
|
class Config:
|
|
84
97
|
arbitrary_types_allowed = True
|
|
85
98
|
validate_assignment = True
|
|
@@ -128,12 +141,14 @@ class ProtectBaseObject(BaseModel):
|
|
|
128
141
|
@classmethod
|
|
129
142
|
def construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self:
|
|
130
143
|
api: ProtectApiClient | None = values.pop("api", None)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
(
|
|
145
|
+
unifi_objs,
|
|
146
|
+
has_unifi_objs,
|
|
147
|
+
unifi_lists,
|
|
148
|
+
has_unifi_lists,
|
|
149
|
+
unifi_dicts,
|
|
150
|
+
has_unifi_dicts,
|
|
151
|
+
) = cls._get_protect_model()
|
|
137
152
|
for key, value in values.items():
|
|
138
153
|
if has_unifi_objs and key in unifi_objs and isinstance(value, dict):
|
|
139
154
|
values[key] = unifi_objs[key].construct(**value)
|
|
@@ -195,56 +210,35 @@ class ProtectBaseObject(BaseModel):
|
|
|
195
210
|
}
|
|
196
211
|
|
|
197
212
|
@classmethod
|
|
198
|
-
|
|
213
|
+
@cache
|
|
214
|
+
def _get_protect_model(cls) -> _ProtectModelObjects:
|
|
199
215
|
"""Helper method to detect attrs of current class that are UFP Objects themselves"""
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
216
|
+
objs: dict[str, type[ProtectBaseObject]] = {}
|
|
217
|
+
lists: dict[str, type[ProtectBaseObject]] = {}
|
|
218
|
+
dicts: dict[str, type[ProtectBaseObject]] = {}
|
|
203
219
|
|
|
204
220
|
for name, field in cls.__fields__.items():
|
|
205
221
|
try:
|
|
206
222
|
if _is_protect_base_object(field.type_):
|
|
207
223
|
if field.shape == SHAPE_LIST:
|
|
208
|
-
|
|
224
|
+
lists[name] = field.type_
|
|
209
225
|
elif field.shape == SHAPE_DICT:
|
|
210
|
-
|
|
226
|
+
dicts[name] = field.type_
|
|
211
227
|
else:
|
|
212
|
-
|
|
228
|
+
objs[name] = field.type_
|
|
213
229
|
except TypeError:
|
|
214
230
|
pass
|
|
215
231
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"""Helper method to get all child UFP objects"""
|
|
220
|
-
if cls._protect_objs is None:
|
|
221
|
-
cls._set_protect_subtypes()
|
|
222
|
-
assert cls._protect_objs is not None
|
|
223
|
-
return cls._protect_objs
|
|
232
|
+
return _ProtectModelObjects(
|
|
233
|
+
objs, bool(objs), lists, bool(lists), dicts, bool(dicts)
|
|
234
|
+
)
|
|
224
235
|
|
|
225
236
|
@classmethod
|
|
226
237
|
@cache
|
|
227
238
|
def _get_excluded_fields(cls) -> set[str]:
|
|
228
239
|
"""Helper method to get all excluded fields for the current object."""
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@classmethod
|
|
232
|
-
@cache
|
|
233
|
-
def _get_protect_lists(cls) -> dict[str, type[ProtectBaseObject]]:
|
|
234
|
-
"""Helper method to get all child of UFP objects (lists)"""
|
|
235
|
-
if cls._protect_lists is None:
|
|
236
|
-
cls._set_protect_subtypes()
|
|
237
|
-
assert cls._protect_lists is not None
|
|
238
|
-
return cls._protect_lists
|
|
239
|
-
|
|
240
|
-
@classmethod
|
|
241
|
-
@cache
|
|
242
|
-
def _get_protect_dicts(cls) -> dict[str, type[ProtectBaseObject]]:
|
|
243
|
-
"""Helper method to get all child of UFP objects (dicts)"""
|
|
244
|
-
if cls._protect_dicts is None:
|
|
245
|
-
cls._set_protect_subtypes()
|
|
246
|
-
assert cls._protect_dicts is not None
|
|
247
|
-
return cls._protect_dicts
|
|
240
|
+
protect_model = cls._get_protect_model()
|
|
241
|
+
return set(protect_model.objs) | set(protect_model.lists)
|
|
248
242
|
|
|
249
243
|
@classmethod
|
|
250
244
|
def _clean_protect_obj(
|
|
@@ -327,12 +321,14 @@ class ProtectBaseObject(BaseModel):
|
|
|
327
321
|
return data
|
|
328
322
|
|
|
329
323
|
# clean child UFP objs
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
324
|
+
(
|
|
325
|
+
unifi_objs,
|
|
326
|
+
has_unifi_objs,
|
|
327
|
+
unifi_lists,
|
|
328
|
+
has_unifi_lists,
|
|
329
|
+
unifi_dicts,
|
|
330
|
+
has_unifi_dicts,
|
|
331
|
+
) = cls._get_protect_model()
|
|
336
332
|
for key, value in data.items():
|
|
337
333
|
if has_unifi_objs and key in unifi_objs:
|
|
338
334
|
data[key] = cls._clean_protect_obj(value, unifi_objs[key], api)
|
|
@@ -428,17 +424,31 @@ class ProtectBaseObject(BaseModel):
|
|
|
428
424
|
data = self.dict(exclude=excluded_fields)
|
|
429
425
|
use_obj = True
|
|
430
426
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
427
|
+
(
|
|
428
|
+
unifi_objs,
|
|
429
|
+
has_unifi_objs,
|
|
430
|
+
unifi_lists,
|
|
431
|
+
has_unifi_lists,
|
|
432
|
+
unifi_dicts,
|
|
433
|
+
has_unifi_dicts,
|
|
434
|
+
) = self._get_protect_model()
|
|
435
|
+
|
|
436
|
+
if has_unifi_objs:
|
|
437
|
+
for key, klass in unifi_objs.items():
|
|
438
|
+
if use_obj or key in data:
|
|
439
|
+
data[key] = self._unifi_dict_protect_obj(data, key, use_obj, klass)
|
|
440
|
+
|
|
441
|
+
if has_unifi_lists:
|
|
442
|
+
for key, klass in unifi_lists.items():
|
|
443
|
+
if use_obj or key in data:
|
|
444
|
+
data[key] = self._unifi_dict_protect_obj_list(
|
|
445
|
+
data, key, use_obj, klass
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
if has_unifi_dicts:
|
|
449
|
+
for key in unifi_dicts:
|
|
450
|
+
if use_obj or key in data:
|
|
451
|
+
data[key] = self._unifi_dict_protect_obj_dict(data, key, use_obj)
|
|
442
452
|
|
|
443
453
|
# all child objects have been serialized correctly do not do it twice
|
|
444
454
|
new_data: dict[str, Any] = serialize_unifi_obj(data, levels=2)
|
|
@@ -455,11 +465,14 @@ class ProtectBaseObject(BaseModel):
|
|
|
455
465
|
The api client is injected into each dict for any child
|
|
456
466
|
UFP objects that are detected.
|
|
457
467
|
"""
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
468
|
+
(
|
|
469
|
+
unifi_objs,
|
|
470
|
+
has_unifi_objs,
|
|
471
|
+
unifi_lists,
|
|
472
|
+
has_unifi_lists,
|
|
473
|
+
unifi_dicts,
|
|
474
|
+
has_unifi_dicts,
|
|
475
|
+
) = cls._get_protect_model()
|
|
463
476
|
api = cls._api
|
|
464
477
|
_fields = cls.__fields__
|
|
465
478
|
unifi_obj: ProtectBaseObject | None
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|