uiprotect 3.1.9__py3-none-any.whl → 3.2.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 CHANGED
@@ -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, ClassVar, TypeVar
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
- unifi_objs = cls._get_protect_objs()
132
- has_unifi_objs = bool(unifi_objs)
133
- unifi_lists = cls._get_protect_lists()
134
- has_unifi_lists = bool(unifi_lists)
135
- unifi_dicts = cls._get_protect_dicts()
136
- has_unifi_dicts = bool(unifi_dicts)
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
- def _set_protect_subtypes(cls) -> None:
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
- cls._protect_objs = {}
201
- cls._protect_lists = {}
202
- cls._protect_dicts = {}
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
- cls._protect_lists[name] = field.type_
224
+ lists[name] = field.type_
209
225
  elif field.shape == SHAPE_DICT:
210
- cls._protect_dicts[name] = field.type_
226
+ dicts[name] = field.type_
211
227
  else:
212
- cls._protect_objs[name] = field.type_
228
+ objs[name] = field.type_
213
229
  except TypeError:
214
230
  pass
215
231
 
216
- @classmethod
217
- @cache
218
- def _get_protect_objs(cls) -> dict[str, type[ProtectBaseObject]]:
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
- return set(cls._get_protect_objs()) | set(cls._get_protect_lists())
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
- unifi_objs = cls._get_protect_objs()
331
- has_unifi_objs = bool(unifi_objs)
332
- unifi_lists = cls._get_protect_lists()
333
- has_unifi_lists = bool(unifi_lists)
334
- unifi_dicts = cls._get_protect_dicts()
335
- has_unifi_dicts = bool(unifi_dicts)
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,15 +424,24 @@ class ProtectBaseObject(BaseModel):
428
424
  data = self.dict(exclude=excluded_fields)
429
425
  use_obj = True
430
426
 
431
- for key, klass in self._get_protect_objs().items():
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
+ for key, klass in unifi_objs.items():
432
437
  if use_obj or key in data:
433
438
  data[key] = self._unifi_dict_protect_obj(data, key, use_obj, klass)
434
439
 
435
- for key, klass in self._get_protect_lists().items():
440
+ for key, klass in unifi_lists.items():
436
441
  if use_obj or key in data:
437
442
  data[key] = self._unifi_dict_protect_obj_list(data, key, use_obj, klass)
438
443
 
439
- for key in self._get_protect_dicts():
444
+ for key in unifi_dicts:
440
445
  if use_obj or key in data:
441
446
  data[key] = self._unifi_dict_protect_obj_dict(data, key, use_obj)
442
447
 
@@ -455,11 +460,14 @@ class ProtectBaseObject(BaseModel):
455
460
  The api client is injected into each dict for any child
456
461
  UFP objects that are detected.
457
462
  """
458
- unifi_objs = cls._get_protect_objs()
459
- has_unifi_objs = bool(unifi_objs)
460
- unifi_lists = cls._get_protect_lists()
461
- has_unifi_lists = bool(unifi_lists)
462
-
463
+ (
464
+ unifi_objs,
465
+ has_unifi_objs,
466
+ unifi_lists,
467
+ has_unifi_lists,
468
+ unifi_dicts,
469
+ has_unifi_dicts,
470
+ ) = cls._get_protect_model()
463
471
  api = cls._api
464
472
  _fields = cls.__fields__
465
473
  unifi_obj: ProtectBaseObject | None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 3.1.9
3
+ Version: 3.2.0
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -14,7 +14,7 @@ uiprotect/cli/nvr.py,sha256=TwxEg2XT8jXAbOqv6gc7KFXELKadeItEDYweSL4_-e8,4260
14
14
  uiprotect/cli/sensors.py,sha256=fQtcDJCVxs4VbAqcavgBy2ABiVxAW3GXtna6_XFBp2k,8153
15
15
  uiprotect/cli/viewers.py,sha256=2cyrp104ffIvgT0wYGIO0G35QMkEbFe7fSVqLwDXQYQ,2171
16
16
  uiprotect/data/__init__.py,sha256=OcfuJl2qXfHcj_mdnrHhzZ5tEIZrw8auziX5IE7dn-I,2938
17
- uiprotect/data/base.py,sha256=OefiljoofvG7Hp3cEp3DOabKDHW86qBXjiQnI_OUONg,35499
17
+ uiprotect/data/base.py,sha256=7V66U1DJdUIvDw6DhtPaOGBd6rZGzVD_84-tpTVSBLY,34963
18
18
  uiprotect/data/bootstrap.py,sha256=EWl8zWo3zSN7HWMTgcoWr3UI9WE62Mi6FJ33DTqWTII,21128
19
19
  uiprotect/data/convert.py,sha256=8h6Il_DhMkPRDPj9F_rA2UZIlTuchS3BQD24peKpk2A,2185
20
20
  uiprotect/data/devices.py,sha256=n2TVY0J-xhO7fXgrvC0hqsHjNc-B_DdySDKHOIKPeqs,110363
@@ -30,8 +30,8 @@ uiprotect/test_util/__init__.py,sha256=whiOUb5LfDLNT3AQG6ISiKtAqO2JnhCIdFavhWDK4
30
30
  uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
31
31
  uiprotect/utils.py,sha256=3SJFF8qs1Jz8t3mD8qwc1hFSocolFjdXI_v4yVlC7o4,20088
32
32
  uiprotect/websocket.py,sha256=D5DZrMzo434ecp8toNxOB5HM193kVwYw42yEcg99yMw,8029
33
- uiprotect-3.1.9.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
- uiprotect-3.1.9.dist-info/METADATA,sha256=Dwku5PiqpAAGuSE4lMNpd98ZEXU6aY0iwpiSpV4HMM8,10982
35
- uiprotect-3.1.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- uiprotect-3.1.9.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
- uiprotect-3.1.9.dist-info/RECORD,,
33
+ uiprotect-3.2.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
+ uiprotect-3.2.0.dist-info/METADATA,sha256=91rjXK4o3FasHP0kjLaGfvWki16MEQXoyZnxsZunYN8,10982
35
+ uiprotect-3.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ uiprotect-3.2.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
+ uiprotect-3.2.0.dist-info/RECORD,,