Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: optimize update_from_dict #75

Merged
merged 7 commits into from
Jun 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 36 additions & 60 deletions src/uiprotect/data/base.py
Original file line number Diff line number Diff line change
@@ -485,68 +485,44 @@

return new_data

def _inject_api(
self,
data: dict[str, Any],
api: ProtectApiClient | None,
) -> dict[str, Any]:
data["api"] = api
unifi_objs_sets = self._get_protect_objs_set()
has_unifi_objs = bool(unifi_objs_sets)
unifi_lists_sets = self._get_protect_lists_set()
has_unifi_lists = bool(unifi_lists_sets)
unifi_dicts_sets = self._get_protect_dicts_set()
has_unifi_dicts = bool(unifi_dicts_sets)
for key, value in data.items():
if has_unifi_objs and key in unifi_objs_sets and isinstance(value, dict):
value["api"] = api
elif (
has_unifi_lists and key in unifi_lists_sets and isinstance(value, list)
):
for item in value:
if isinstance(item, dict):
item["api"] = api
elif (
has_unifi_dicts and key in unifi_dicts_sets and isinstance(value, dict)
):
for item in value.values():
if isinstance(item, dict):
item["api"] = api
def update_from_dict(cls: ProtectObject, data: dict[str, Any]) -> ProtectObject:
"""
Updates current object from a cleaned UFP JSON dict.

return data
The api client is injected into each dict for any child
UFP objects that are detected.
"""
unifi_objs = cls._get_protect_objs()
has_unifi_objs = bool(unifi_objs)
unifi_lists = cls._get_protect_lists()
has_unifi_lists = bool(unifi_lists)

def update_from_dict(self: ProtectObject, data: dict[str, Any]) -> ProtectObject:
"""Updates current object from a cleaned UFP JSON dict"""
data_set = set(data)
for key in self._get_protect_objs_set().intersection(data_set):
unifi_obj: Any | None = getattr(self, key)
if unifi_obj is not None and isinstance(unifi_obj, ProtectBaseObject):
item = data.pop(key)
if item is not None:
item = unifi_obj.update_from_dict(item)
setattr(self, key, item)

data = self._inject_api(data, self._api)
unifi_lists = self._get_protect_lists()
for key in self._get_protect_lists_set().intersection(data_set):
if not isinstance(data[key], list):
continue
klass = unifi_lists[key]
new_items = []
for item in data.pop(key):
if item is not None and isinstance(item, ProtectBaseObject):
new_items.append(item)
elif isinstance(item, dict):
new_items.append(klass(**item))
setattr(self, key, new_items)

# Always injected above
del data["api"]

for key in data:
setattr(self, key, convert_unifi_data(data[key], self.__fields__[key]))

return self
api = cls._api
_fields = cls.__fields__
unifi_obj: ProtectBaseObject | None
if "api" in data:
del data["api"]

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

Codecov / codecov/patch

src/uiprotect/data/base.py#L504

Added line #L504 was not covered by tests
value: Any

for key, item in data.items():
if has_unifi_objs and key in unifi_objs and isinstance(item, dict):
if (unifi_obj := getattr(cls, key)) is not None:
value = unifi_obj.update_from_dict(item)
else:
value = None

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

Codecov / codecov/patch

src/uiprotect/data/base.py#L512

Added line #L512 was not covered by tests
elif has_unifi_lists and key in unifi_lists and isinstance(item, list):
klass = unifi_lists[key]

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

Codecov / codecov/patch

src/uiprotect/data/base.py#L514

Added line #L514 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line where a new instance of a class is created inside a list comprehension was not covered by tests. This is a crucial part of the functionality as it involves data transformation and API injection. It is recommended to add unit tests to cover this scenario to ensure that the creation and initialization of objects in lists are handled correctly.

Would you like assistance in writing these unit tests?

Tools
GitHub Check: codecov/patch

[warning] 515-515: src/uiprotect/data/base.py#L515
Added line #L515 was not covered by tests

value = [
klass(**i, api=api) if isinstance(i, dict) else i
for i in item
if i is not None and isinstance(i, (dict, ProtectBaseObject))
]
else:
value = convert_unifi_data(item, _fields[key])

setattr(cls, key, value)

return cls

def dict_with_excludes(self) -> dict[str, Any]:
"""Returns a dict of the current object without any UFP objects converted to dicts."""
Loading