uiprotect 7.21.0__py3-none-any.whl → 7.22.0__py3-none-any.whl
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/data/base.py +6 -8
- uiprotect/data/types.py +28 -18
- uiprotect/test_util/anonymize.py +2 -3
- uiprotect/utils.py +6 -10
- {uiprotect-7.21.0.dist-info → uiprotect-7.22.0.dist-info}/METADATA +5 -4
- {uiprotect-7.21.0.dist-info → uiprotect-7.22.0.dist-info}/RECORD +9 -9
- {uiprotect-7.21.0.dist-info → uiprotect-7.22.0.dist-info}/WHEEL +1 -1
- {uiprotect-7.21.0.dist-info → uiprotect-7.22.0.dist-info}/entry_points.txt +0 -0
- {uiprotect-7.21.0.dist-info → uiprotect-7.22.0.dist-info/licenses}/LICENSE +0 -0
uiprotect/data/base.py
CHANGED
|
@@ -27,14 +27,12 @@ from ..utils import (
|
|
|
27
27
|
to_snake_case,
|
|
28
28
|
)
|
|
29
29
|
from .types import (
|
|
30
|
-
SHAPE_DICT_V1,
|
|
31
|
-
SHAPE_LIST_V1,
|
|
32
30
|
ModelType,
|
|
33
31
|
PercentFloat,
|
|
34
32
|
PermissionNode,
|
|
35
33
|
ProtectWSPayloadFormat,
|
|
36
34
|
StateType,
|
|
37
|
-
|
|
35
|
+
get_field_type,
|
|
38
36
|
)
|
|
39
37
|
from .websocket import (
|
|
40
38
|
WSJSONPacketFrame,
|
|
@@ -223,11 +221,11 @@ class ProtectBaseObject(BaseModel):
|
|
|
223
221
|
|
|
224
222
|
for name, field in cls.model_fields.items():
|
|
225
223
|
try:
|
|
226
|
-
|
|
224
|
+
origin, type_ = get_field_type(field.annotation) # type: ignore[arg-type]
|
|
227
225
|
if _is_protect_base_object(type_):
|
|
228
|
-
if
|
|
226
|
+
if origin is list:
|
|
229
227
|
lists[name] = type_
|
|
230
|
-
elif
|
|
228
|
+
elif origin is dict:
|
|
231
229
|
dicts[name] = type_
|
|
232
230
|
else:
|
|
233
231
|
objs[name] = type_
|
|
@@ -489,8 +487,8 @@ class ProtectBaseObject(BaseModel):
|
|
|
489
487
|
has_unifi_objs,
|
|
490
488
|
unifi_lists,
|
|
491
489
|
has_unifi_lists,
|
|
492
|
-
|
|
493
|
-
|
|
490
|
+
_unifi_dicts,
|
|
491
|
+
_has_unifi_dicts,
|
|
494
492
|
) = self._get_protect_model()
|
|
495
493
|
api = self._api
|
|
496
494
|
_fields = self.__class__.model_fields
|
uiprotect/data/types.py
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import enum
|
|
4
|
-
|
|
4
|
+
import types
|
|
5
|
+
from collections.abc import Callable, Coroutine, Sequence
|
|
5
6
|
from functools import cache, lru_cache
|
|
6
|
-
from typing import Annotated, Any, Literal, TypeVar, Union
|
|
7
|
+
from typing import Annotated, Any, Literal, TypeVar, Union, get_args, get_origin
|
|
7
8
|
|
|
8
9
|
from packaging.version import Version as BaseVersion
|
|
9
10
|
from pydantic import BaseModel, Field
|
|
10
11
|
from pydantic.types import StringConstraints
|
|
11
|
-
from pydantic.v1.config import BaseConfig as BaseConfigV1
|
|
12
|
-
from pydantic.v1.fields import SHAPE_DICT as SHAPE_DICT_V1 # noqa: F401
|
|
13
|
-
from pydantic.v1.fields import SHAPE_LIST as SHAPE_LIST_V1 # noqa: F401
|
|
14
|
-
from pydantic.v1.fields import SHAPE_SET as SHAPE_SET_V1 # noqa: F401
|
|
15
|
-
from pydantic.v1.fields import ModelField as ModelFieldV1
|
|
16
12
|
from pydantic_extra_types.color import Color # noqa: F401
|
|
17
13
|
|
|
18
14
|
from .._compat import cached_property
|
|
@@ -21,20 +17,34 @@ KT = TypeVar("KT")
|
|
|
21
17
|
VT = TypeVar("VT")
|
|
22
18
|
|
|
23
19
|
|
|
24
|
-
class _BaseConfigV1(BaseConfigV1):
|
|
25
|
-
arbitrary_types_allowed = True
|
|
26
|
-
validate_assignment = True
|
|
27
|
-
|
|
28
|
-
|
|
29
20
|
@lru_cache(maxsize=512)
|
|
30
|
-
def
|
|
31
|
-
"""Extract the type from
|
|
21
|
+
def get_field_type(annotation: type[Any] | None) -> tuple[type | None, Any]:
|
|
22
|
+
"""Extract the origin and type from an annotation."""
|
|
32
23
|
if annotation is None:
|
|
33
24
|
raise ValueError("Type annotation cannot be None")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
|
|
25
|
+
origin = get_origin(annotation)
|
|
26
|
+
args: Sequence[Any]
|
|
27
|
+
if origin in (list, set):
|
|
28
|
+
if not (args := get_args(annotation)):
|
|
29
|
+
raise ValueError(f"Unable to determine args of type: {annotation}")
|
|
30
|
+
return origin, args[0]
|
|
31
|
+
if origin is dict:
|
|
32
|
+
if not (args := get_args(annotation)):
|
|
33
|
+
raise ValueError(f"Unable to determine args of type: {annotation}")
|
|
34
|
+
return origin, args[1]
|
|
35
|
+
if origin is Annotated:
|
|
36
|
+
if not (args := get_args(annotation)):
|
|
37
|
+
raise ValueError(f"Unable to determine args of type: {annotation}")
|
|
38
|
+
return None, args[0]
|
|
39
|
+
if origin is Union or origin is types.UnionType:
|
|
40
|
+
if not (args := get_args(annotation)):
|
|
41
|
+
raise ValueError(f"Unable to determine args of type: {annotation}")
|
|
42
|
+
args = [get_field_type(arg) for arg in args]
|
|
43
|
+
if len(args) == 2 and type(None) in list(zip(*args, strict=False))[1]:
|
|
44
|
+
# Strip '| None' type from Union
|
|
45
|
+
return next(arg for arg in args if arg[1] is not type(None))
|
|
46
|
+
return None, annotation
|
|
47
|
+
return origin, annotation
|
|
38
48
|
|
|
39
49
|
|
|
40
50
|
DEFAULT = "DEFAULT_VALUE"
|
uiprotect/test_util/anonymize.py
CHANGED
|
@@ -3,11 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
import secrets
|
|
4
4
|
import string
|
|
5
5
|
import uuid
|
|
6
|
+
import warnings
|
|
6
7
|
from typing import Any
|
|
7
8
|
from urllib.parse import urlparse
|
|
8
9
|
|
|
9
|
-
import typer
|
|
10
|
-
|
|
11
10
|
from ..data import ModelType
|
|
12
11
|
|
|
13
12
|
object_id_mapping: dict[str, str] = {}
|
|
@@ -111,7 +110,7 @@ def anonymize_dict(obj: dict[str, Any], name: str | None = None) -> dict[str, An
|
|
|
111
110
|
if obj["modelKey"] in [m.value for m in ModelType]:
|
|
112
111
|
obj_type = ModelType(obj["modelKey"])
|
|
113
112
|
else:
|
|
114
|
-
|
|
113
|
+
warnings.warn(f"Unknown modelKey: {obj['modelKey']}", stacklevel=2)
|
|
115
114
|
|
|
116
115
|
if obj_type == ModelType.USER:
|
|
117
116
|
return anonymize_user(obj)
|
uiprotect/utils.py
CHANGED
|
@@ -32,15 +32,12 @@ from aiohttp import ClientResponse
|
|
|
32
32
|
from pydantic.fields import FieldInfo
|
|
33
33
|
|
|
34
34
|
from .data.types import (
|
|
35
|
-
SHAPE_DICT_V1,
|
|
36
|
-
SHAPE_LIST_V1,
|
|
37
|
-
SHAPE_SET_V1,
|
|
38
35
|
Color,
|
|
39
36
|
SmartDetectAudioType,
|
|
40
37
|
SmartDetectObjectType,
|
|
41
38
|
Version,
|
|
42
39
|
VideoMode,
|
|
43
|
-
|
|
40
|
+
get_field_type,
|
|
44
41
|
)
|
|
45
42
|
from .exceptions import NvrError
|
|
46
43
|
|
|
@@ -208,22 +205,21 @@ def to_camel_case(name: str) -> str:
|
|
|
208
205
|
|
|
209
206
|
|
|
210
207
|
_EMPTY_UUID = UUID("0" * 32)
|
|
211
|
-
_SHAPE_TYPES = {SHAPE_DICT_V1, SHAPE_SET_V1, SHAPE_LIST_V1}
|
|
212
208
|
|
|
213
209
|
|
|
214
210
|
def convert_unifi_data(value: Any, field: FieldInfo) -> Any:
|
|
215
211
|
"""Converts value from UFP data into pydantic field class"""
|
|
216
|
-
|
|
212
|
+
origin, type_ = get_field_type(field.annotation) # type: ignore[arg-type]
|
|
217
213
|
|
|
218
214
|
if type_ is Any:
|
|
219
215
|
return value
|
|
220
216
|
|
|
221
|
-
if
|
|
222
|
-
if
|
|
217
|
+
if origin is not None:
|
|
218
|
+
if origin is list and isinstance(value, list):
|
|
223
219
|
return [convert_unifi_data(v, field) for v in value]
|
|
224
|
-
if
|
|
220
|
+
if origin is set and isinstance(value, list):
|
|
225
221
|
return {convert_unifi_data(v, field) for v in value}
|
|
226
|
-
if
|
|
222
|
+
if origin is dict and isinstance(value, dict):
|
|
227
223
|
return {k: convert_unifi_data(v, field) for k, v in value.items()}
|
|
228
224
|
|
|
229
225
|
if value is not None:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: uiprotect
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.22.0
|
|
4
4
|
Summary: Python API for Unifi Protect (Unofficial)
|
|
5
|
-
License: MIT
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Author: UI Protect Maintainers
|
|
7
8
|
Author-email: ui@koston.org
|
|
8
9
|
Requires-Python: >=3.10
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
11
|
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Natural Language :: English
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
20
|
Classifier: Topic :: Software Development :: Build Tools
|
|
20
21
|
Classifier: Topic :: Software Development :: Libraries
|
|
21
22
|
Requires-Dist: aiofiles (>=24)
|
|
@@ -16,12 +16,12 @@ uiprotect/cli/nvr.py,sha256=TwxEg2XT8jXAbOqv6gc7KFXELKadeItEDYweSL4_-e8,4260
|
|
|
16
16
|
uiprotect/cli/sensors.py,sha256=crz_R52X7EFKQtBgL2QzacThExOOoN5NubERQuw5jpk,8119
|
|
17
17
|
uiprotect/cli/viewers.py,sha256=IgJpOzwdo9HVs55Osf3uC5d0raeU19WFIW-RfrnnOug,2137
|
|
18
18
|
uiprotect/data/__init__.py,sha256=audwJBjxRiYdNPeYlP6iofFIOq3gyQzh6VpDsOCM2dQ,2964
|
|
19
|
-
uiprotect/data/base.py,sha256=
|
|
19
|
+
uiprotect/data/base.py,sha256=siz-EA41JMeyqMsqOsELys9rsmYZdTlDmhS-80iY_O8,35342
|
|
20
20
|
uiprotect/data/bootstrap.py,sha256=arnmmQOfVp9HHSKbKicgl-quA1kT7C6Ub0Ca_n_XgDE,23548
|
|
21
21
|
uiprotect/data/convert.py,sha256=xEN878_hm0HZZCVYGwJSxcSp2as9zpkvsemVIibReOA,2628
|
|
22
22
|
uiprotect/data/devices.py,sha256=QLgMpTt3ui-8hj6PR75UthVUtbZWyM7tomHkuDhu0wQ,117507
|
|
23
23
|
uiprotect/data/nvr.py,sha256=HnknmMmUxe1aPA0PHJZSiEwpvo1phtHBp3wXsU6v_iI,46681
|
|
24
|
-
uiprotect/data/types.py,sha256=
|
|
24
|
+
uiprotect/data/types.py,sha256=szB5vOzLaiJm0o3Lhdtaoawq54kNtiOFMWKjfSVuy4o,19869
|
|
25
25
|
uiprotect/data/user.py,sha256=Del5LUmt5uCfAQMI9-kl_GaKm085oTLjxmcCrlEKXxc,10526
|
|
26
26
|
uiprotect/data/websocket.py,sha256=m4EV1Qfh08eKOihy70ycViYgEQpeNSGZQJWdtGIYJDA,6791
|
|
27
27
|
uiprotect/exceptions.py,sha256=kgn0cRM6lTtgLza09SDa3ZiX6ue1QqHCOogQ4qu6KTQ,965
|
|
@@ -29,11 +29,11 @@ uiprotect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
29
29
|
uiprotect/release_cache.json,sha256=NamnSFy78hOWY0DPO87J9ELFCAN6NnVquv8gQO75ZG4,386
|
|
30
30
|
uiprotect/stream.py,sha256=ls65vMOXF4IlJ5axewFITfhcaTh_ihaFeCkCTfhy0Nk,5168
|
|
31
31
|
uiprotect/test_util/__init__.py,sha256=O22HGFX5Mb0j9LPzO48tm4ZqZTqGVBHo0jnye2FdT_I,19803
|
|
32
|
-
uiprotect/test_util/anonymize.py,sha256=
|
|
33
|
-
uiprotect/utils.py,sha256=
|
|
32
|
+
uiprotect/test_util/anonymize.py,sha256=3YG56B6bJcjrfZLWPfmPNlePr88NTvftTvigvPEMxks,8483
|
|
33
|
+
uiprotect/utils.py,sha256=BjQCia7PZyG6ES8PH-SYRIMja2ldm_ClojkCOB9iGak,20599
|
|
34
34
|
uiprotect/websocket.py,sha256=BedfEVLWhiTP5Il4ULerw2cUNGlr2OLyb_91QOh3iSs,8176
|
|
35
|
-
uiprotect-7.
|
|
36
|
-
uiprotect-7.
|
|
37
|
-
uiprotect-7.
|
|
38
|
-
uiprotect-7.
|
|
39
|
-
uiprotect-7.
|
|
35
|
+
uiprotect-7.22.0.dist-info/METADATA,sha256=snSZUY5Zzp9F_gaIW4gZQk8CVysNvKFkOPxL33u-yjE,11200
|
|
36
|
+
uiprotect-7.22.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
37
|
+
uiprotect-7.22.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
|
|
38
|
+
uiprotect-7.22.0.dist-info/licenses/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
|
|
39
|
+
uiprotect-7.22.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|