Bump bring-api to 1.0.0 (#136657)

This commit is contained in:
Manu 2025-01-28 13:24:44 +01:00 committed by GitHub
parent 7f3e56eb58
commit fa4b93da2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 311 additions and 271 deletions

View File

@ -63,7 +63,8 @@ class BringConfigFlow(ConfigFlow, domain=DOMAIN):
): ):
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
return self.async_create_entry( return self.async_create_entry(
title=self.info.get("name") or user_input[CONF_EMAIL], data=user_input title=self.info.name or user_input[CONF_EMAIL],
data=user_input,
) )
return self.async_show_form( return self.async_show_form(

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -12,6 +13,7 @@ from bring_api import (
BringRequestException, BringRequestException,
) )
from bring_api.types import BringItemsResponse, BringList, BringUserSettingsResponse from bring_api.types import BringItemsResponse, BringList, BringUserSettingsResponse
from mashumaro.mixins.orjson import DataClassORJSONMixin
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL from homeassistant.const import CONF_EMAIL
@ -24,9 +26,13 @@ from .const import DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class BringData(BringList, BringItemsResponse): @dataclass(frozen=True)
class BringData(DataClassORJSONMixin):
"""Coordinator data class.""" """Coordinator data class."""
lst: BringList
content: BringItemsResponse
class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]): class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]):
"""A Bring Data Update Coordinator.""" """A Bring Data Update Coordinator."""
@ -67,11 +73,11 @@ class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]):
return self.data return self.data
list_dict: dict[str, BringData] = {} list_dict: dict[str, BringData] = {}
for lst in lists_response["lists"]: for lst in lists_response.lists:
if (ctx := set(self.async_contexts())) and lst["listUuid"] not in ctx: if (ctx := set(self.async_contexts())) and lst.listUuid not in ctx:
continue continue
try: try:
items = await self.bring.get_list(lst["listUuid"]) items = await self.bring.get_list(lst.listUuid)
except BringRequestException as e: except BringRequestException as e:
raise UpdateFailed( raise UpdateFailed(
"Unable to connect and retrieve data from bring" "Unable to connect and retrieve data from bring"
@ -79,7 +85,7 @@ class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]):
except BringParseException as e: except BringParseException as e:
raise UpdateFailed("Unable to parse response from bring") from e raise UpdateFailed("Unable to parse response from bring") from e
else: else:
list_dict[lst["listUuid"]] = BringData(**lst, **items) list_dict[lst.listUuid] = BringData(lst, items)
return list_dict return list_dict

View File

@ -2,15 +2,16 @@
from __future__ import annotations from __future__ import annotations
from typing import Any
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import BringConfigEntry from . import BringConfigEntry
from .coordinator import BringData
async def async_get_config_entry_diagnostics( async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: BringConfigEntry hass: HomeAssistant, config_entry: BringConfigEntry
) -> dict[str, BringData]: ) -> dict[str, Any]:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
return config_entry.runtime_data.data return {k: v.to_dict() for k, v in config_entry.runtime_data.data.items()}

View File

@ -20,13 +20,13 @@ class BringBaseEntity(CoordinatorEntity[BringDataUpdateCoordinator]):
bring_list: BringData, bring_list: BringData,
) -> None: ) -> None:
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(coordinator, bring_list["listUuid"]) super().__init__(coordinator, bring_list.lst.listUuid)
self._list_uuid = bring_list["listUuid"] self._list_uuid = bring_list.lst.listUuid
self.device_info = DeviceInfo( self.device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE, entry_type=DeviceEntryType.SERVICE,
name=bring_list["name"], name=bring_list.lst.name,
identifiers={ identifiers={
(DOMAIN, f"{coordinator.config_entry.unique_id}_{self._list_uuid}") (DOMAIN, f"{coordinator.config_entry.unique_id}_{self._list_uuid}")
}, },

View File

@ -7,5 +7,5 @@
"integration_type": "service", "integration_type": "service",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["bring_api"], "loggers": ["bring_api"],
"requirements": ["bring-api==0.9.1"] "requirements": ["bring-api==1.0.0"]
} }

View File

@ -65,7 +65,7 @@ SENSOR_DESCRIPTIONS: tuple[BringSensorEntityDescription, ...] = (
translation_key=BringSensor.LIST_LANGUAGE, translation_key=BringSensor.LIST_LANGUAGE,
value_fn=( value_fn=(
lambda lst, settings: x.lower() lambda lst, settings: x.lower()
if (x := list_language(lst["listUuid"], settings)) if (x := list_language(lst.lst.listUuid, settings))
else None else None
), ),
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
@ -75,7 +75,7 @@ SENSOR_DESCRIPTIONS: tuple[BringSensorEntityDescription, ...] = (
BringSensorEntityDescription( BringSensorEntityDescription(
key=BringSensor.LIST_ACCESS, key=BringSensor.LIST_ACCESS,
translation_key=BringSensor.LIST_ACCESS, translation_key=BringSensor.LIST_ACCESS,
value_fn=lambda lst, _: lst["status"].lower(), value_fn=lambda lst, _: lst.content.status.value.lower(),
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
options=["registered", "shared", "invitation"], options=["registered", "shared", "invitation"],
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from itertools import chain
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import uuid import uuid
@ -59,7 +60,7 @@ async def async_setup_entry(
SERVICE_PUSH_NOTIFICATION, SERVICE_PUSH_NOTIFICATION,
{ {
vol.Required(ATTR_NOTIFICATION_TYPE): vol.All( vol.Required(ATTR_NOTIFICATION_TYPE): vol.All(
vol.Upper, cv.enum(BringNotificationType) vol.Upper, vol.Coerce(BringNotificationType)
), ),
vol.Optional(ATTR_ITEM_NAME): cv.string, vol.Optional(ATTR_ITEM_NAME): cv.string,
}, },
@ -92,21 +93,21 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
return [ return [
*( *(
TodoItem( TodoItem(
uid=item["uuid"], uid=item.uuid,
summary=item["itemId"], summary=item.itemId,
description=item["specification"] or "", description=item.specification,
status=TodoItemStatus.NEEDS_ACTION, status=TodoItemStatus.NEEDS_ACTION,
) )
for item in self.bring_list["purchase"] for item in self.bring_list.content.items.purchase
), ),
*( *(
TodoItem( TodoItem(
uid=item["uuid"], uid=item.uuid,
summary=item["itemId"], summary=item.itemId,
description=item["specification"] or "", description=item.specification,
status=TodoItemStatus.COMPLETED, status=TodoItemStatus.COMPLETED,
) )
for item in self.bring_list["recently"] for item in self.bring_list.content.items.recently
), ),
] ]
@ -119,7 +120,7 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
"""Add an item to the To-do list.""" """Add an item to the To-do list."""
try: try:
await self.coordinator.bring.save_item( await self.coordinator.bring.save_item(
self.bring_list["listUuid"], self._list_uuid,
item.summary or "", item.summary or "",
item.description or "", item.description or "",
str(uuid.uuid4()), str(uuid.uuid4()),
@ -154,26 +155,25 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
bring_list = self.bring_list bring_list = self.bring_list
bring_purchase_item = next( current_item = next(
(i for i in bring_list["purchase"] if i["uuid"] == item.uid), (
i
for i in chain(
bring_list.content.items.purchase, bring_list.content.items.recently
)
if i.uuid == item.uid
),
None, None,
) )
bring_recently_item = next(
(i for i in bring_list["recently"] if i["uuid"] == item.uid),
None,
)
current_item = bring_purchase_item or bring_recently_item
if TYPE_CHECKING: if TYPE_CHECKING:
assert item.uid assert item.uid
assert current_item assert current_item
if item.summary == current_item["itemId"]: if item.summary == current_item.itemId:
try: try:
await self.coordinator.bring.batch_update_list( await self.coordinator.bring.batch_update_list(
bring_list["listUuid"], self._list_uuid,
BringItem( BringItem(
itemId=item.summary or "", itemId=item.summary or "",
spec=item.description or "", spec=item.description or "",
@ -192,10 +192,10 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
else: else:
try: try:
await self.coordinator.bring.batch_update_list( await self.coordinator.bring.batch_update_list(
bring_list["listUuid"], self._list_uuid,
[ [
BringItem( BringItem(
itemId=current_item["itemId"], itemId=current_item.itemId,
spec=item.description or "", spec=item.description or "",
uuid=item.uid, uuid=item.uid,
operation=BringItemOperation.REMOVE, operation=BringItemOperation.REMOVE,
@ -225,7 +225,7 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
try: try:
await self.coordinator.bring.batch_update_list( await self.coordinator.bring.batch_update_list(
self.bring_list["listUuid"], self._list_uuid,
[ [
BringItem( BringItem(
itemId=uid, itemId=uid,

View File

@ -14,27 +14,25 @@ def list_language(
"""Get the lists language setting.""" """Get the lists language setting."""
try: try:
list_settings = next( list_settings = next(
filter( filter(lambda x: x.listUuid == list_uuid, user_settings.userlistsettings)
lambda x: x["listUuid"] == list_uuid,
user_settings["userlistsettings"],
)
) )
return next( return (
filter( next(
lambda x: x["key"] == "listArticleLanguage", filter(
list_settings["usersettings"], lambda x: x.key == "listArticleLanguage", list_settings.usersettings
)
) )
)["value"] ).value
except (StopIteration, KeyError): except StopIteration:
return None return None
def sum_attributes(bring_list: BringData, attribute: str) -> int: def sum_attributes(bring_list: BringData, attribute: str) -> int:
"""Count items with given attribute set.""" """Count items with given attribute set."""
return sum( return sum(
item["attributes"][0]["content"][attribute] getattr(item.attributes[0].content, attribute)
for item in bring_list["purchase"] for item in bring_list.content.items.purchase
if len(item.get("attributes", [])) if item.attributes
) )

2
requirements_all.txt generated
View File

@ -644,7 +644,7 @@ boto3==1.34.131
botocore==1.34.131 botocore==1.34.131
# homeassistant.components.bring # homeassistant.components.bring
bring-api==0.9.1 bring-api==1.0.0
# homeassistant.components.broadlink # homeassistant.components.broadlink
broadlink==0.19.0 broadlink==0.19.0

View File

@ -564,7 +564,7 @@ boschshcpy==0.2.91
botocore==1.34.131 botocore==1.34.131
# homeassistant.components.bring # homeassistant.components.bring
bring-api==0.9.1 bring-api==1.0.0
# homeassistant.components.broadlink # homeassistant.components.broadlink
broadlink==0.19.0 broadlink==0.19.0

View File

@ -1,17 +1,21 @@
"""Common fixtures for the Bring! tests.""" """Common fixtures for the Bring! tests."""
from collections.abc import Generator from collections.abc import Generator
from typing import cast
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
import uuid import uuid
from bring_api.types import BringAuthResponse from bring_api.types import (
BringAuthResponse,
BringItemsResponse,
BringListResponse,
BringUserSettingsResponse,
)
import pytest import pytest
from homeassistant.components.bring.const import DOMAIN from homeassistant.components.bring.const import DOMAIN
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from tests.common import MockConfigEntry, load_json_object_fixture from tests.common import MockConfigEntry, load_fixture
EMAIL = "test-email" EMAIL = "test-email"
PASSWORD = "test-password" PASSWORD = "test-password"
@ -44,11 +48,17 @@ def mock_bring_client() -> Generator[AsyncMock]:
client = mock_client.return_value client = mock_client.return_value
client.uuid = UUID client.uuid = UUID
client.mail = EMAIL client.mail = EMAIL
client.login.return_value = cast(BringAuthResponse, {"name": "Bring"}) client.login.return_value = BringAuthResponse.from_json(
client.load_lists.return_value = load_json_object_fixture("lists.json", DOMAIN) load_fixture("login.json", DOMAIN)
client.get_list.return_value = load_json_object_fixture("items.json", DOMAIN) )
client.get_all_user_settings.return_value = load_json_object_fixture( client.load_lists.return_value = BringListResponse.from_json(
"usersettings.json", DOMAIN load_fixture("lists.json", DOMAIN)
)
client.get_list.return_value = BringItemsResponse.from_json(
load_fixture("items.json", DOMAIN)
)
client.get_all_user_settings.return_value = BringUserSettingsResponse.from_json(
load_fixture("usersettings.json", DOMAIN)
) )
yield client yield client

View File

@ -1,44 +1,46 @@
{ {
"uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f", "uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f",
"status": "REGISTERED", "status": "REGISTERED",
"purchase": [ "items": {
{ "purchase": [
"uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de", {
"itemId": "Paprika", "uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de",
"specification": "Rot", "itemId": "Paprika",
"attributes": [ "specification": "Rot",
{ "attributes": [
"type": "PURCHASE_CONDITIONS", {
"content": { "type": "PURCHASE_CONDITIONS",
"urgent": true, "content": {
"convenient": true, "urgent": true,
"discounted": true "convenient": true,
"discounted": true
}
} }
} ]
] },
}, {
{ "uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e",
"uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e", "itemId": "Pouletbrüstli",
"itemId": "Pouletbrüstli", "specification": "Bio",
"specification": "Bio", "attributes": [
"attributes": [ {
{ "type": "PURCHASE_CONDITIONS",
"type": "PURCHASE_CONDITIONS", "content": {
"content": { "urgent": true,
"urgent": true, "convenient": true,
"convenient": true, "discounted": true
"discounted": true }
} }
} ]
] }
} ],
], "recently": [
"recently": [ {
{ "uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954",
"uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954", "itemId": "Ananas",
"itemId": "Ananas", "specification": "",
"specification": "", "attributes": []
"attributes": [] }
} ]
] }
} }

View File

@ -1,44 +1,46 @@
{ {
"uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f", "uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f",
"status": "INVITATION", "status": "INVITATION",
"purchase": [ "items": {
{ "purchase": [
"uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de", {
"itemId": "Paprika", "uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de",
"specification": "Rot", "itemId": "Paprika",
"attributes": [ "specification": "Rot",
{ "attributes": [
"type": "PURCHASE_CONDITIONS", {
"content": { "type": "PURCHASE_CONDITIONS",
"urgent": true, "content": {
"convenient": true, "urgent": true,
"discounted": true "convenient": true,
"discounted": true
}
} }
} ]
] },
}, {
{ "uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e",
"uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e", "itemId": "Pouletbrüstli",
"itemId": "Pouletbrüstli", "specification": "Bio",
"specification": "Bio", "attributes": [
"attributes": [ {
{ "type": "PURCHASE_CONDITIONS",
"type": "PURCHASE_CONDITIONS", "content": {
"content": { "urgent": true,
"urgent": true, "convenient": true,
"convenient": true, "discounted": true
"discounted": true }
} }
} ]
] }
} ],
], "recently": [
"recently": [ {
{ "uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954",
"uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954", "itemId": "Ananas",
"itemId": "Ananas", "specification": "",
"specification": "", "attributes": []
"attributes": [] }
} ]
] }
} }

View File

@ -1,44 +1,46 @@
{ {
"uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f", "uuid": "77a151f8-77c4-47a3-8295-c750a0e69d4f",
"status": "SHARED", "status": "SHARED",
"purchase": [ "items": {
{ "purchase": [
"uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de", {
"itemId": "Paprika", "uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de",
"specification": "Rot", "itemId": "Paprika",
"attributes": [ "specification": "Rot",
{ "attributes": [
"type": "PURCHASE_CONDITIONS", {
"content": { "type": "PURCHASE_CONDITIONS",
"urgent": true, "content": {
"convenient": true, "urgent": true,
"discounted": true "convenient": true,
"discounted": true
}
} }
} ]
] },
}, {
{ "uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e",
"uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e", "itemId": "Pouletbrüstli",
"itemId": "Pouletbrüstli", "specification": "Bio",
"specification": "Bio", "attributes": [
"attributes": [ {
{ "type": "PURCHASE_CONDITIONS",
"type": "PURCHASE_CONDITIONS", "content": {
"content": { "urgent": true,
"urgent": true, "convenient": true,
"convenient": true, "discounted": true
"discounted": true }
} }
} ]
] }
} ],
], "recently": [
"recently": [ {
{ "uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954",
"uuid": "fc8db30a-647e-4e6c-9d71-3b85d6a2d954", "itemId": "Ananas",
"itemId": "Ananas", "specification": "",
"specification": "", "attributes": []
"attributes": [] }
} ]
] }
} }

View File

@ -0,0 +1,12 @@
{
"uuid": "4d717571-174a-4bc1-ab24-929c7227ca43",
"publicUuid": "9a21fdfc-63a4-441a-afc1-ef3030605a9d",
"email": "test-email",
"name": "Bring",
"photoPath": "",
"bringListUUID": "e542eef6-dba7-4c31-a52c-29e6ab9d83a5",
"access_token": "ACCESS_TOKEN",
"refresh_token": "REFRESH_TOKEN",
"token_type": "Bearer",
"expires_in": 604799
}

View File

@ -2,100 +2,112 @@
# name: test_diagnostics # name: test_diagnostics
dict({ dict({
'b4776778-7f6c-496e-951b-92a35d3db0dd': dict({ 'b4776778-7f6c-496e-951b-92a35d3db0dd': dict({
'listUuid': 'b4776778-7f6c-496e-951b-92a35d3db0dd', 'content': dict({
'name': 'Baumarkt', 'items': dict({
'purchase': list([ 'purchase': list([
dict({
'attributes': list([
dict({ dict({
'content': dict({ 'attributes': list([
'convenient': True, dict({
'discounted': True, 'content': dict({
'urgent': True, 'convenient': True,
}), 'discounted': True,
'type': 'PURCHASE_CONDITIONS', 'urgent': True,
}),
'type': 'PURCHASE_CONDITIONS',
}),
]),
'itemId': 'Paprika',
'specification': 'Rot',
'uuid': 'b5d0790b-5f32-4d5c-91da-e29066f167de',
}),
dict({
'attributes': list([
dict({
'content': dict({
'convenient': True,
'discounted': True,
'urgent': True,
}),
'type': 'PURCHASE_CONDITIONS',
}),
]),
'itemId': 'Pouletbrüstli',
'specification': 'Bio',
'uuid': '72d370ab-d8ca-4e41-b956-91df94795b4e',
}), }),
]), ]),
'itemId': 'Paprika', 'recently': list([
'specification': 'Rot',
'uuid': 'b5d0790b-5f32-4d5c-91da-e29066f167de',
}),
dict({
'attributes': list([
dict({ dict({
'content': dict({ 'attributes': list([
'convenient': True, ]),
'discounted': True, 'itemId': 'Ananas',
'urgent': True, 'specification': '',
}), 'uuid': 'fc8db30a-647e-4e6c-9d71-3b85d6a2d954',
'type': 'PURCHASE_CONDITIONS',
}), }),
]), ]),
'itemId': 'Pouletbrüstli',
'specification': 'Bio',
'uuid': '72d370ab-d8ca-4e41-b956-91df94795b4e',
}), }),
]), 'status': 'REGISTERED',
'recently': list([ 'uuid': '77a151f8-77c4-47a3-8295-c750a0e69d4f',
dict({ }),
'attributes': list([ 'lst': dict({
]), 'listUuid': 'b4776778-7f6c-496e-951b-92a35d3db0dd',
'itemId': 'Ananas', 'name': 'Baumarkt',
'specification': '', 'theme': 'ch.publisheria.bring.theme.home',
'uuid': 'fc8db30a-647e-4e6c-9d71-3b85d6a2d954', }),
}),
]),
'status': 'REGISTERED',
'theme': 'ch.publisheria.bring.theme.home',
'uuid': '77a151f8-77c4-47a3-8295-c750a0e69d4f',
}), }),
'e542eef6-dba7-4c31-a52c-29e6ab9d83a5': dict({ 'e542eef6-dba7-4c31-a52c-29e6ab9d83a5': dict({
'listUuid': 'e542eef6-dba7-4c31-a52c-29e6ab9d83a5', 'content': dict({
'name': 'Einkauf', 'items': dict({
'purchase': list([ 'purchase': list([
dict({
'attributes': list([
dict({ dict({
'content': dict({ 'attributes': list([
'convenient': True, dict({
'discounted': True, 'content': dict({
'urgent': True, 'convenient': True,
}), 'discounted': True,
'type': 'PURCHASE_CONDITIONS', 'urgent': True,
}),
'type': 'PURCHASE_CONDITIONS',
}),
]),
'itemId': 'Paprika',
'specification': 'Rot',
'uuid': 'b5d0790b-5f32-4d5c-91da-e29066f167de',
}),
dict({
'attributes': list([
dict({
'content': dict({
'convenient': True,
'discounted': True,
'urgent': True,
}),
'type': 'PURCHASE_CONDITIONS',
}),
]),
'itemId': 'Pouletbrüstli',
'specification': 'Bio',
'uuid': '72d370ab-d8ca-4e41-b956-91df94795b4e',
}), }),
]), ]),
'itemId': 'Paprika', 'recently': list([
'specification': 'Rot',
'uuid': 'b5d0790b-5f32-4d5c-91da-e29066f167de',
}),
dict({
'attributes': list([
dict({ dict({
'content': dict({ 'attributes': list([
'convenient': True, ]),
'discounted': True, 'itemId': 'Ananas',
'urgent': True, 'specification': '',
}), 'uuid': 'fc8db30a-647e-4e6c-9d71-3b85d6a2d954',
'type': 'PURCHASE_CONDITIONS',
}), }),
]), ]),
'itemId': 'Pouletbrüstli',
'specification': 'Bio',
'uuid': '72d370ab-d8ca-4e41-b956-91df94795b4e',
}), }),
]), 'status': 'REGISTERED',
'recently': list([ 'uuid': '77a151f8-77c4-47a3-8295-c750a0e69d4f',
dict({ }),
'attributes': list([ 'lst': dict({
]), 'listUuid': 'e542eef6-dba7-4c31-a52c-29e6ab9d83a5',
'itemId': 'Ananas', 'name': 'Einkauf',
'specification': '', 'theme': 'ch.publisheria.bring.theme.home',
'uuid': 'fc8db30a-647e-4e6c-9d71-3b85d6a2d954', }),
}),
]),
'status': 'REGISTERED',
'theme': 'ch.publisheria.bring.theme.home',
'uuid': '77a151f8-77c4-47a3-8295-c750a0e69d4f',
}), }),
}) })
# --- # ---

View File

@ -3,6 +3,7 @@
from collections.abc import Generator from collections.abc import Generator
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from bring_api import BringItemsResponse
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -12,7 +13,7 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, load_json_object_fixture, snapshot_platform from tests.common import MockConfigEntry, load_fixture, snapshot_platform
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -62,10 +63,9 @@ async def test_list_access_states(
) -> None: ) -> None:
"""Snapshot test states of list access sensor.""" """Snapshot test states of list access sensor."""
mock_bring_client.get_list.return_value = load_json_object_fixture( mock_bring_client.get_list.return_value = BringItemsResponse.from_json(
f"{fixture}.json", DOMAIN load_fixture(f"{fixture}.json", DOMAIN)
) )
bring_config_entry.add_to_hass(hass) bring_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(bring_config_entry.entry_id) await hass.config_entries.async_setup(bring_config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -1,15 +1,13 @@
"""Test for utility functions of the Bring! integration.""" """Test for utility functions of the Bring! integration."""
from typing import cast from bring_api import BringItemsResponse, BringListResponse, BringUserSettingsResponse
from bring_api import BringUserSettingsResponse
import pytest import pytest
from homeassistant.components.bring.const import DOMAIN from homeassistant.components.bring.const import DOMAIN
from homeassistant.components.bring.coordinator import BringData from homeassistant.components.bring.coordinator import BringData
from homeassistant.components.bring.util import list_language, sum_attributes from homeassistant.components.bring.util import list_language, sum_attributes
from tests.common import load_json_object_fixture from tests.common import load_fixture
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -17,7 +15,7 @@ from tests.common import load_json_object_fixture
[ [
("e542eef6-dba7-4c31-a52c-29e6ab9d83a5", "de-DE"), ("e542eef6-dba7-4c31-a52c-29e6ab9d83a5", "de-DE"),
("b4776778-7f6c-496e-951b-92a35d3db0dd", "en-US"), ("b4776778-7f6c-496e-951b-92a35d3db0dd", "en-US"),
("00000000-0000-0000-0000-00000000", None), ("00000000-0000-0000-0000-000000000000", None),
], ],
) )
def test_list_language(list_uuid: str, expected: str | None) -> None: def test_list_language(list_uuid: str, expected: str | None) -> None:
@ -25,10 +23,7 @@ def test_list_language(list_uuid: str, expected: str | None) -> None:
result = list_language( result = list_language(
list_uuid, list_uuid,
cast( BringUserSettingsResponse.from_json(load_fixture("usersettings.json", DOMAIN)),
BringUserSettingsResponse,
load_json_object_fixture("usersettings.json", DOMAIN),
),
) )
assert result == expected assert result == expected
@ -44,12 +39,11 @@ def test_list_language(list_uuid: str, expected: str | None) -> None:
) )
def test_sum_attributes(attribute: str, expected: int) -> None: def test_sum_attributes(attribute: str, expected: int) -> None:
"""Test function sum_attributes.""" """Test function sum_attributes."""
items = BringItemsResponse.from_json(load_fixture("items.json", DOMAIN))
lst = BringListResponse.from_json(load_fixture("lists.json", DOMAIN))
result = sum_attributes( result = sum_attributes(
cast( BringData(lst.lists[0], items),
BringData,
load_json_object_fixture("items.json", DOMAIN),
),
attribute, attribute,
) )