uiprotect 1.15.0__py3-none-any.whl → 1.17.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
@@ -185,12 +185,6 @@ class ProtectBaseObject(BaseModel):
185
185
  """
186
186
  return {}
187
187
 
188
- @classmethod
189
- @cache
190
- def _get_unifi_remaps_set(self) -> set[str]:
191
- """Helper method to get set of all child UFP objects."""
192
- return set(self._get_unifi_remaps())
193
-
194
188
  @classmethod
195
189
  @cache
196
190
  def _get_to_unifi_remaps(cls) -> dict[str, str]:
@@ -238,9 +232,9 @@ class ProtectBaseObject(BaseModel):
238
232
 
239
233
  @classmethod
240
234
  @cache
241
- def _get_protect_objs_set(cls) -> set[str]:
242
- """Helper method to get all child UFP objects"""
243
- return set(cls._get_protect_objs())
235
+ def _get_excluded_fields(cls) -> set[str]:
236
+ """Helper method to get all excluded fields for the current object."""
237
+ return set(cls._get_protect_objs()) | set(cls._get_protect_lists())
244
238
 
245
239
  @classmethod
246
240
  @cache
@@ -251,12 +245,6 @@ class ProtectBaseObject(BaseModel):
251
245
  assert cls._protect_lists is not None
252
246
  return cls._protect_lists
253
247
 
254
- @classmethod
255
- @cache
256
- def _get_protect_lists_set(cls) -> set[str]:
257
- """Helper method to get all child UFP objects"""
258
- return set(cls._get_protect_lists())
259
-
260
248
  @classmethod
261
249
  @cache
262
250
  def _get_protect_dicts(cls) -> dict[str, type[ProtectBaseObject]]:
@@ -266,12 +254,6 @@ class ProtectBaseObject(BaseModel):
266
254
  assert cls._protect_dicts is not None
267
255
  return cls._protect_dicts
268
256
 
269
- @classmethod
270
- @cache
271
- def _get_protect_dicts_set(cls) -> set[str]:
272
- """Helper method to get all child UFP objects"""
273
- return set(cls._get_protect_dicts())
274
-
275
257
  @classmethod
276
258
  def _clean_protect_obj(
277
259
  cls,
@@ -401,15 +383,12 @@ class ProtectBaseObject(BaseModel):
401
383
  if not isinstance(value, list):
402
384
  return value
403
385
 
404
- items: list[Any] = []
405
- for item in value:
406
- if isinstance(item, ProtectBaseObject):
407
- new_item = item.unifi_dict()
408
- else:
409
- new_item = klass.construct({}).unifi_dict(data=item) # type: ignore[arg-type]
410
- items.append(new_item)
411
-
412
- return items
386
+ return [
387
+ item.unifi_dict()
388
+ if isinstance(item, ProtectBaseObject)
389
+ else klass.construct({}).unifi_dict(data=item) # type: ignore[arg-type]
390
+ for item in value
391
+ ]
413
392
 
414
393
  def _unifi_dict_protect_obj_dict(
415
394
  self,
@@ -424,13 +403,10 @@ class ProtectBaseObject(BaseModel):
424
403
  if not isinstance(value, dict):
425
404
  return value
426
405
 
427
- items: dict[Any, Any] = {}
428
- for obj_key, obj in value.items():
429
- if isinstance(obj, ProtectBaseObject):
430
- obj = obj.unifi_dict()
431
- items[obj_key] = obj
432
-
433
- return items
406
+ return {
407
+ obj_key: obj.unifi_dict() if isinstance(obj, ProtectBaseObject) else obj
408
+ for obj_key, obj in value.items()
409
+ }
434
410
 
435
411
  def unifi_dict(
436
412
  self,
@@ -454,9 +430,7 @@ class ProtectBaseObject(BaseModel):
454
430
  """
455
431
  use_obj = False
456
432
  if data is None:
457
- excluded_fields = (
458
- self._get_protect_objs_set() | self._get_protect_lists_set()
459
- )
433
+ excluded_fields = self._get_excluded_fields()
460
434
  if exclude is not None:
461
435
  excluded_fields |= exclude
462
436
  data = self.dict(exclude=excluded_fields)
@@ -971,16 +945,13 @@ class ProtectAdoptableDeviceModel(ProtectDeviceModel):
971
945
  exclude: set[str] | None = None,
972
946
  ) -> dict[str, Any]:
973
947
  data = super().unifi_dict(data=data, exclude=exclude)
974
-
975
- if "wiredConnectionState" in data and data["wiredConnectionState"] is None:
976
- del data["wiredConnectionState"]
977
- if "wifiConnectionState" in data and data["wifiConnectionState"] is None:
978
- del data["wifiConnectionState"]
979
- if (
980
- "bluetoothConnectionState" in data
981
- and data["bluetoothConnectionState"] is None
948
+ for key in (
949
+ "wiredConnectionState",
950
+ "wifiConnectionState",
951
+ "bluetoothConnectionState",
982
952
  ):
983
- del data["bluetoothConnectionState"]
953
+ if key in data and data[key] is None:
954
+ del data[key]
984
955
  return data
985
956
 
986
957
  @classmethod
@@ -8,7 +8,6 @@ from collections.abc import Iterable
8
8
  from copy import deepcopy
9
9
  from dataclasses import dataclass
10
10
  from datetime import datetime
11
- from functools import cache
12
11
  from typing import TYPE_CHECKING, Any
13
12
 
14
13
  from aiohttp.client_exceptions import ServerDisconnectedError
@@ -220,11 +219,6 @@ class Bootstrap(ProtectBaseObject):
220
219
 
221
220
  return super().unifi_dict_to_dict(data)
222
221
 
223
- @classmethod
224
- @cache
225
- def _unifi_dict_remove_keys(cls) -> set[str]:
226
- return {"events", "captureWsStats", "macLookup", "idLookup"}
227
-
228
222
  def unifi_dict(
229
223
  self,
230
224
  data: dict[str, Any] | None = None,
@@ -232,7 +226,7 @@ class Bootstrap(ProtectBaseObject):
232
226
  ) -> dict[str, Any]:
233
227
  data = super().unifi_dict(data=data, exclude=exclude)
234
228
 
235
- for key in Bootstrap._unifi_dict_remove_keys():
229
+ for key in ("events", "captureWsStats", "macLookup", "idLookup"):
236
230
  if key in data:
237
231
  del data[key]
238
232
  for model_type in ModelType.bootstrap_models_types_set:
uiprotect/data/devices.py CHANGED
@@ -1062,27 +1062,21 @@ class Camera(ProtectMotionDeviceModel):
1062
1062
  ]
1063
1063
 
1064
1064
  data = super().unifi_dict(data=data, exclude=exclude)
1065
+ for key in (
1066
+ "lastRingEventId",
1067
+ "lastSmartDetect",
1068
+ "lastSmartAudioDetect",
1069
+ "lastSmartDetectEventId",
1070
+ "lastSmartAudioDetectEventId",
1071
+ "lastSmartDetects",
1072
+ "lastSmartAudioDetects",
1073
+ "lastSmartDetectEventIds",
1074
+ "lastSmartAudioDetectEventIds",
1075
+ "talkbackStream",
1076
+ ):
1077
+ if key in data:
1078
+ del data[key]
1065
1079
 
1066
- if "lastRingEventId" in data:
1067
- del data["lastRingEventId"]
1068
- if "lastSmartDetect" in data:
1069
- del data["lastSmartDetect"]
1070
- if "lastSmartAudioDetect" in data:
1071
- del data["lastSmartAudioDetect"]
1072
- if "lastSmartDetectEventId" in data:
1073
- del data["lastSmartDetectEventId"]
1074
- if "lastSmartAudioDetectEventId" in data:
1075
- del data["lastSmartAudioDetectEventId"]
1076
- if "lastSmartDetects" in data:
1077
- del data["lastSmartDetects"]
1078
- if "lastSmartAudioDetects" in data:
1079
- del data["lastSmartAudioDetects"]
1080
- if "lastSmartDetectEventIds" in data:
1081
- del data["lastSmartDetectEventIds"]
1082
- if "lastSmartAudioDetectEventIds" in data:
1083
- del data["lastSmartAudioDetectEventIds"]
1084
- if "talkbackStream" in data:
1085
- del data["talkbackStream"]
1086
1080
  if "lcdMessage" in data and data["lcdMessage"] is None:
1087
1081
  data["lcdMessage"] = {}
1088
1082
 
@@ -2820,18 +2814,15 @@ class Sensor(ProtectAdoptableDeviceModel):
2820
2814
  exclude: set[str] | None = None,
2821
2815
  ) -> dict[str, Any]:
2822
2816
  data = super().unifi_dict(data=data, exclude=exclude)
2823
-
2824
- if "lastMotionEventId" in data:
2825
- del data["lastMotionEventId"]
2826
- if "lastContactEventId" in data:
2827
- del data["lastContactEventId"]
2828
- if "lastValueEventId" in data:
2829
- del data["lastValueEventId"]
2830
- if "lastAlarmEventId" in data:
2831
- del data["lastAlarmEventId"]
2832
- if "extremeValueDetectedAt" in data:
2833
- del data["extremeValueDetectedAt"]
2834
-
2817
+ for key in (
2818
+ "lastMotionEventId",
2819
+ "lastContactEventId",
2820
+ "lastValueEventId",
2821
+ "lastAlarmEventId",
2822
+ "extremeValueDetectedAt",
2823
+ ):
2824
+ if key in data:
2825
+ del data[key]
2835
2826
  return data
2836
2827
 
2837
2828
  @property
uiprotect/data/nvr.py CHANGED
@@ -309,9 +309,9 @@ class Event(ProtectModelWithId):
309
309
 
310
310
  @classmethod
311
311
  def unifi_dict_to_dict(cls, data: dict[str, Any]) -> dict[str, Any]:
312
- for key in {"start", "end", "timestamp", "deletedAt"}.intersection(data):
313
- data[key] = convert_to_datetime(data[key])
314
-
312
+ for key in ("start", "end", "timestamp", "deletedAt"):
313
+ if key in data:
314
+ data[key] = convert_to_datetime(data[key])
315
315
  return super().unifi_dict_to_dict(data)
316
316
 
317
317
  def unifi_dict(
@@ -47,6 +47,8 @@ class WSSubscriptionMessage:
47
47
 
48
48
 
49
49
  class BaseWSPacketFrame:
50
+ UNPACK_FORMAT = struct.Struct("!bbbbi")
51
+
50
52
  data: Any
51
53
  position: int = 0
52
54
  header: WSPacketFrameHeader | None = None
@@ -89,7 +91,7 @@ class BaseWSPacketFrame:
89
91
  i: payload_size
90
92
  """
91
93
  header_end = position + WS_HEADER_SIZE
92
-
94
+ payload_size: int
93
95
  try:
94
96
  (
95
97
  packet_type,
@@ -97,8 +99,7 @@ class BaseWSPacketFrame:
97
99
  deflated,
98
100
  unknown,
99
101
  payload_size,
100
- ) = struct.unpack(
101
- "!bbbbi",
102
+ ) = BaseWSPacketFrame.UNPACK_FORMAT.unpack(
102
103
  data[position:header_end],
103
104
  )
104
105
  except struct.error as e:
@@ -117,9 +118,9 @@ class BaseWSPacketFrame:
117
118
  unknown=unknown,
118
119
  payload_size=payload_size,
119
120
  )
120
- frame.length = WS_HEADER_SIZE + frame.header.payload_size
121
- frame.is_deflated = bool(frame.header.deflated)
122
- frame_end = header_end + frame.header.payload_size
121
+ frame.length = WS_HEADER_SIZE + payload_size
122
+ frame.is_deflated = bool(deflated)
123
+ frame_end = header_end + payload_size
123
124
  frame.set_data_from_binary(data[header_end:frame_end])
124
125
 
125
126
  return frame
@@ -188,11 +189,10 @@ class WSPacket:
188
189
  self._raw = data
189
190
 
190
191
  def decode(self) -> None:
191
- self._action_frame = WSRawPacketFrame.from_binary(self._raw)
192
- self._data_frame = WSRawPacketFrame.from_binary(
193
- self._raw,
194
- self._action_frame.length,
195
- )
192
+ data = self._raw
193
+ self._action_frame = WSRawPacketFrame.from_binary(data)
194
+ length = self._action_frame.length
195
+ self._data_frame = WSRawPacketFrame.from_binary(data, length)
196
196
 
197
197
  @cached_property
198
198
  def action_frame(self) -> BaseWSPacketFrame:
@@ -202,6 +202,7 @@ class WSPacket:
202
202
  if self._action_frame is None:
203
203
  raise WSDecodeError("Packet unexpectedly not decoded")
204
204
 
205
+ self.__dict__["data_frame"] = self._data_frame
205
206
  return self._action_frame
206
207
 
207
208
  @cached_property
@@ -212,6 +213,7 @@ class WSPacket:
212
213
  if self._data_frame is None:
213
214
  raise WSDecodeError("Packet unexpectedly not decoded")
214
215
 
216
+ self.__dict__["action_frame"] = self._action_frame
215
217
  return self._data_frame
216
218
 
217
219
  @property
uiprotect/utils.py CHANGED
@@ -17,7 +17,7 @@ from copy import deepcopy
17
17
  from datetime import datetime, timedelta, timezone, tzinfo
18
18
  from decimal import Decimal
19
19
  from enum import Enum
20
- from functools import lru_cache
20
+ from functools import cache, lru_cache
21
21
  from hashlib import sha224
22
22
  from http.cookies import Morsel
23
23
  from inspect import isclass
@@ -96,22 +96,20 @@ IP_TYPES = {
96
96
  Union[IPv6Address, IPv4Address, None],
97
97
  }
98
98
 
99
- if sys.version_info[:2] < (3, 11):
100
- pass
101
- else:
102
- pass
103
-
104
99
 
105
100
  def set_debug() -> None:
106
101
  """Sets ENV variable for UFP_DEBUG to on (True)"""
107
102
  os.environ[DEBUG_ENV] = str(True)
103
+ is_debug.cache_clear()
108
104
 
109
105
 
110
106
  def set_no_debug() -> None:
111
107
  """Sets ENV variable for UFP_DEBUG to off (False)"""
112
108
  os.environ[DEBUG_ENV] = str(False)
109
+ is_debug.cache_clear()
113
110
 
114
111
 
112
+ @cache
115
113
  def is_debug() -> bool:
116
114
  """Returns if debug ENV is on (True)"""
117
115
  return os.environ.get(DEBUG_ENV) == str(True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uiprotect
3
- Version: 1.15.0
3
+ Version: 1.17.0
4
4
  Summary: Python API for Unifi Protect (Unofficial)
5
5
  Home-page: https://github.com/uilibs/uiprotect
6
6
  License: MIT
@@ -14,24 +14,24 @@ 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=OWKeMWk7n5VaHF_meTt2Ykw7H9zx6U47u-P2vLNDWzE,36627
18
- uiprotect/data/bootstrap.py,sha256=copw7uL_YIthNH-PraSoqg5vL-UpGrt95zKy1FpHn5w,21881
17
+ uiprotect/data/base.py,sha256=q5lpNJ4keAQ4oDjalwg9eL3kaVzEapfwtcTzZZlrN_M,35691
18
+ uiprotect/data/bootstrap.py,sha256=epMt3lRNCp4mu_gkyjV12Ec62snB1FUOP_obVIsWp-w,21723
19
19
  uiprotect/data/convert.py,sha256=8h6Il_DhMkPRDPj9F_rA2UZIlTuchS3BQD24peKpk2A,2185
20
- uiprotect/data/devices.py,sha256=Nq3bOko5PFf5LvEBoD4JV8kmbq50laRdh3VHMWX7t-0,111809
21
- uiprotect/data/nvr.py,sha256=XC4NO1c_Mom-hIpzj9ksKFcgKbHd6ToqWjkgzxJ1PJY,47636
20
+ uiprotect/data/devices.py,sha256=yJ9lOgl0MbesSs4m0GZF0T28MtR_EYdzyvAkK6NGIBY,111217
21
+ uiprotect/data/nvr.py,sha256=zCEAI-rKLEpp9P63QDvJi0hGRsuv-PWGssgHw1POYeQ,47648
22
22
  uiprotect/data/types.py,sha256=8z8jIoMlfDre7Op1JAN45PLZdAE-4i3gDPSo2uymqu4,17996
23
23
  uiprotect/data/user.py,sha256=Wb-ZWSwIJbyUbfVuENtUYbuW-uftHNDcoMH85dvEjkw,7071
24
- uiprotect/data/websocket.py,sha256=XgDS-cZMD6Fdc6bHrD0pJ_dEf_G3ZTKlP4FNzEXCYso,6305
24
+ uiprotect/data/websocket.py,sha256=EW9wdvX2yQanuGtWXmpMh29FSSJKjeZYQYM7zciQqE4,6453
25
25
  uiprotect/exceptions.py,sha256=kgn0cRM6lTtgLza09SDa3ZiX6ue1QqHCOogQ4qu6KTQ,965
26
26
  uiprotect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  uiprotect/release_cache.json,sha256=NamnSFy78hOWY0DPO87J9ELFCAN6NnVquv8gQO75ZG4,386
28
28
  uiprotect/stream.py,sha256=McV3XymKyjn-1uV5jdQHcpaDjqLS4zWyMASQ8ubcyb4,4924
29
29
  uiprotect/test_util/__init__.py,sha256=d2g7afa0LSdixQ0kjEDYwafDFME_UlW2LzxpamZ2BC0,18556
30
30
  uiprotect/test_util/anonymize.py,sha256=f-8ijU-_y9r-uAbhIPn0f0I6hzJpAkvJzc8UpWihObI,8478
31
- uiprotect/utils.py,sha256=6OLY8hNiCzk418PjJJIlFW7jjPzVt1vxBKEzBSqMeTk,18418
31
+ uiprotect/utils.py,sha256=kVRJwvHP683Sjhi2pnxwCwbaRl_uMQ2qFYSvt9kpfoU,18426
32
32
  uiprotect/websocket.py,sha256=JHI_2EZeRPqPyQopsBZS0dr3tu0HaTiqeLazfBXhW_8,7339
33
- uiprotect-1.15.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
- uiprotect-1.15.0.dist-info/METADATA,sha256=vGRfaDV2IzMD9WNxZ2Z9VDsSEwsegr1hJJET3YvBa5E,10985
35
- uiprotect-1.15.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- uiprotect-1.15.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
- uiprotect-1.15.0.dist-info/RECORD,,
33
+ uiprotect-1.17.0.dist-info/LICENSE,sha256=INx18jhdbVXMEiiBANeKEbrbz57ckgzxk5uutmmcxGk,1111
34
+ uiprotect-1.17.0.dist-info/METADATA,sha256=W-mtu1rojIcy5qyYoNn1zH3ZXJgwuWbVDmrPz2bBV58,10985
35
+ uiprotect-1.17.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ uiprotect-1.17.0.dist-info/entry_points.txt,sha256=J78AUTPrTTxgI3s7SVgrmGqDP7piX2wuuEORzhDdVRA,47
37
+ uiprotect-1.17.0.dist-info/RECORD,,