Skip to content

Commit

Permalink
refactor: use internal self._api inside the object
Browse files Browse the repository at this point in the history
We should avoid the public self.api method inside the object since there
is no reason to check again as the objects themselves could not be created
if it was unset
  • Loading branch information
bdraco committed Jun 11, 2024
1 parent 2d715f9 commit 32a507c
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 105 deletions.
2 changes: 1 addition & 1 deletion src/uiprotect/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ async def get_devices(
objs: list[ProtectModel] = []

for obj_dict in await self.get_devices_raw(model_type):
obj = create_from_unifi_dict(obj_dict)
obj = create_from_unifi_dict(obj_dict, api=self)

if expected_type is not None and not isinstance(obj, expected_type):
raise NvrError(f"Unexpected model returned: {obj.model}")
Expand Down
39 changes: 22 additions & 17 deletions src/uiprotect/data/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class ProtectBaseObject(BaseModel):
* Provides `.unifi_dict` to convert object back into UFP JSON
"""

_api: ProtectApiClient | None = PrivateAttr(None)
_api: ProtectApiClient = PrivateAttr(...)

_protect_objs: ClassVar[dict[str, type[ProtectBaseObject]] | None] = None
_protect_lists: ClassVar[dict[str, type[ProtectBaseObject]] | None] = None
Expand All @@ -103,7 +103,8 @@ def __init__(self, api: ProtectApiClient | None = None, **data: Any) -> None:
Use the static method `.from_unifi_dict()` to create objects from UFP JSON data from then the main class constructor.
"""
super().__init__(**data)
self._api = api
if api is not None:
self._api = api

@classmethod
def from_unifi_dict(
Expand All @@ -125,7 +126,8 @@ def from_unifi_dict(
(cameras, users, etc.)
"""
data["api"] = api
if api is not None:
data["api"] = api
data = cls.unifi_dict_to_dict(data)

if is_debug():
Expand Down Expand Up @@ -161,7 +163,8 @@ def construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self:
}

obj = super().construct(_fields_set=_fields_set, **values)
obj._api = api
if api is not None:
obj._api = api

return obj

Expand Down Expand Up @@ -756,7 +759,9 @@ async def _save_device_changes(
if self.model is None:
raise BadRequest("Unknown model type")

if not self.api.bootstrap.auth_user.can(self.model, PermissionNode.WRITE, self):
if not self._api.bootstrap.auth_user.can(
self.model, PermissionNode.WRITE, self
):
if revert_on_fail:
self.revert_changes(data_before_changes)
raise NotAuthorized(f"Do not have write permission for obj: {self.id}")
Expand Down Expand Up @@ -811,11 +816,11 @@ async def emit_message(self, updated: dict[str, Any]) -> None:
data_frame.header = header
data_frame.data = updated

message = self.api.bootstrap.process_ws_packet(
message = self._api.bootstrap.process_ws_packet(
WSPacket(action_frame.packed + data_frame.packed),
)
if message is not None:
self.api.emit_message(message)
self._api.emit_message(message)


class ProtectDeviceModel(ProtectModelWithId):
Expand Down Expand Up @@ -977,7 +982,7 @@ def _get_unifi_remaps(cls) -> dict[str, str]:

async def _api_update(self, data: dict[str, Any]) -> None:
if self.model is not None:
return await self.api.update_device(self.model, self.id, data)
return await self._api.update_device(self.model, self.id, data)
return None

def unifi_dict(
Expand Down Expand Up @@ -1026,12 +1031,12 @@ def bridge(self) -> Bridge | None:
if self.bridge_id is None:
return None

return self.api.bootstrap.bridges[self.bridge_id]
return self._api.bootstrap.bridges[self.bridge_id]

Check warning on line 1034 in src/uiprotect/data/base.py

View check run for this annotation

Codecov / codecov/patch

src/uiprotect/data/base.py#L1034

Added line #L1034 was not covered by tests

@property
def protect_url(self) -> str:
"""UFP Web app URL for this device"""
return f"{self.api.base_url}/protect/devices/{self.id}"
return f"{self._api.base_url}/protect/devices/{self.id}"

@property
def is_adopted_by_us(self) -> bool:
Expand All @@ -1053,38 +1058,38 @@ def callback() -> None:
async def reboot(self) -> None:
"""Reboots an adopted device"""
if self.model is not None:
if not self.api.bootstrap.auth_user.can(
if not self._api.bootstrap.auth_user.can(
self.model,
PermissionNode.WRITE,
self,
):
raise NotAuthorized("Do not have permission to reboot device")
await self.api.reboot_device(self.model, self.id)
await self._api.reboot_device(self.model, self.id)

async def unadopt(self) -> None:
"""Unadopt/Unmanage adopted device"""
if not self.is_adopted_by_us:
raise BadRequest("Device is not adopted")

if self.model is not None:
if not self.api.bootstrap.auth_user.can(
if not self._api.bootstrap.auth_user.can(
self.model,
PermissionNode.DELETE,
self,
):
raise NotAuthorized("Do not have permission to unadopt devices")
await self.api.unadopt_device(self.model, self.id)
await self._api.unadopt_device(self.model, self.id)

Check warning on line 1081 in src/uiprotect/data/base.py

View check run for this annotation

Codecov / codecov/patch

src/uiprotect/data/base.py#L1081

Added line #L1081 was not covered by tests

async def adopt(self, name: str | None = None) -> None:
"""Adopts a device"""
if not self.can_adopt:
raise BadRequest("Device cannot be adopted")

if self.model is not None:
if not self.api.bootstrap.auth_user.can(self.model, PermissionNode.CREATE):
if not self._api.bootstrap.auth_user.can(self.model, PermissionNode.CREATE):
raise NotAuthorized("Do not have permission to adopt devices")

await self.api.adopt_device(self.model, self.id)
await self._api.adopt_device(self.model, self.id)

Check warning on line 1092 in src/uiprotect/data/base.py

View check run for this annotation

Codecov / codecov/patch

src/uiprotect/data/base.py#L1092

Added line #L1092 was not covered by tests
if name is not None:
await self.set_name(name)

Expand Down Expand Up @@ -1118,4 +1123,4 @@ def last_motion_event(self) -> Event | None:
if self.last_motion_event_id is None:
return None

return self.api.bootstrap.events.get(self.last_motion_event_id)
return self._api.bootstrap.events.get(self.last_motion_event_id)
8 changes: 4 additions & 4 deletions src/uiprotect/data/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def clear_ws_stats(self) -> None:

@property
def auth_user(self) -> User:
user: User = self.api.bootstrap.users[self.auth_user_id]
user: User = self._api.bootstrap.users[self.auth_user_id]
return user

@property
Expand Down Expand Up @@ -388,7 +388,7 @@ def _process_add_packet(
and obj.model.value in ModelType.bootstrap_models_set()
):
key = f"{obj.model.value}s"
if not self.api.ignore_unadopted or (
if not self._api.ignore_unadopted or (
obj.is_adopted and not obj.is_adopted_by_other
):
getattr(self, key)[obj.id] = obj
Expand Down Expand Up @@ -612,9 +612,9 @@ async def refresh_device(self, model_type: ModelType, device_id: str) -> None:
"""Refresh a device in the bootstrap."""
try:
if model_type == ModelType.NVR:
device: ProtectModelWithId = await self.api.get_nvr()
device: ProtectModelWithId = await self._api.get_nvr()

Check warning on line 615 in src/uiprotect/data/bootstrap.py

View check run for this annotation

Codecov / codecov/patch

src/uiprotect/data/bootstrap.py#L615

Added line #L615 was not covered by tests
else:
device = await self.api.get_device(model_type, device_id)
device = await self._api.get_device(model_type, device_id)

Check warning on line 617 in src/uiprotect/data/bootstrap.py

View check run for this annotation

Codecov / codecov/patch

src/uiprotect/data/bootstrap.py#L617

Added line #L617 was not covered by tests
except (
ValidationError,
TimeoutError,
Expand Down
Loading

0 comments on commit 32a507c

Please sign in to comment.