diff --git a/custom_components/grocy/__init__.py b/custom_components/grocy/__init__.py index 014eb48..c32d9ae 100644 --- a/custom_components/grocy/__init__.py +++ b/custom_components/grocy/__init__.py @@ -1,5 +1,4 @@ -""" -Custom integration to integrate Grocy with Home Assistant. +"""Custom integration to integrate Grocy with Home Assistant. For more details about this integration, please refer to https://github.com/custom-components/grocy @@ -7,7 +6,6 @@ from __future__ import annotations import logging -from typing import List from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -67,7 +65,7 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> return unloaded -async def _async_get_available_entities(grocy_data: GrocyData) -> List[str]: +async def _async_get_available_entities(grocy_data: GrocyData) -> list[str]: """Return a list of available entities based on enabled Grocy features.""" available_entities = [] grocy_config = await grocy_data.async_get_config() diff --git a/custom_components/grocy/binary_sensor.py b/custom_components/grocy/binary_sensor.py index c0becbc..7dada40 100644 --- a/custom_components/grocy/binary_sensor.py +++ b/custom_components/grocy/binary_sensor.py @@ -1,10 +1,10 @@ """Binary sensor platform for Grocy.""" from __future__ import annotations -import logging from collections.abc import Callable, Mapping from dataclasses import dataclass -from typing import Any, List +import logging +from typing import Any from homeassistant.components.binary_sensor import ( BinarySensorEntity, @@ -35,7 +35,7 @@ async def async_setup_entry( config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ): - """Setup binary sensor platform.""" + """Initialize binary sensor platform.""" coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN] entities = [] for description in BINARY_SENSORS: @@ -56,8 +56,8 @@ async def async_setup_entry( class GrocyBinarySensorEntityDescription(BinarySensorEntityDescription): """Grocy binary sensor entity description.""" - attributes_fn: Callable[[List[Any]], Mapping[str, Any] | None] = lambda _: None - exists_fn: Callable[[List[str]], bool] = lambda _: True + attributes_fn: Callable[[list[Any]], Mapping[str, Any] | None] = lambda _: None + exists_fn: Callable[[list[str]], bool] = lambda _: True entity_registry_enabled_default: bool = False diff --git a/custom_components/grocy/config_flow.py b/custom_components/grocy/config_flow.py index aabd540..97553f0 100644 --- a/custom_components/grocy/config_flow.py +++ b/custom_components/grocy/config_flow.py @@ -1,10 +1,11 @@ """Adds config flow for Grocy.""" -import logging from collections import OrderedDict +import logging +from pygrocy import Grocy import voluptuous as vol + from homeassistant import config_entries -from pygrocy import Grocy from .const import ( CONF_API_KEY, diff --git a/custom_components/grocy/coordinator.py b/custom_components/grocy/coordinator.py index 4aac982..1bd521e 100644 --- a/custom_components/grocy/coordinator.py +++ b/custom_components/grocy/coordinator.py @@ -2,12 +2,13 @@ from __future__ import annotations import logging -from typing import Any, Dict, List +from typing import Any + +from pygrocy import Grocy from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from pygrocy import Grocy from .const import ( CONF_API_KEY, @@ -23,7 +24,7 @@ _LOGGER = logging.getLogger(__name__) -class GrocyDataUpdateCoordinator(DataUpdateCoordinator[Dict[str, Any]]): +class GrocyDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Grocy data update coordinator.""" def __init__( @@ -50,8 +51,8 @@ def __init__( ) self.grocy_data = GrocyData(hass, self.grocy_api) - self.available_entities: List[str] = [] - self.entities: List[Entity] = [] + self.available_entities: list[str] = [] + self.entities: list[Entity] = [] async def _async_update_data(self) -> dict[str, Any]: """Fetch data.""" @@ -59,7 +60,7 @@ async def _async_update_data(self) -> dict[str, Any]: for entity in self.entities: if not entity.enabled: - _LOGGER.debug("Entity %s is disabled.", entity.entity_id) + _LOGGER.debug("Entity %s is disabled", entity.entity_id) continue try: diff --git a/custom_components/grocy/entity.py b/custom_components/grocy/entity.py index 06bbe4f..e7641bd 100644 --- a/custom_components/grocy/entity.py +++ b/custom_components/grocy/entity.py @@ -1,8 +1,8 @@ """Entity for Grocy.""" from __future__ import annotations -import json from collections.abc import Mapping +import json from typing import Any from homeassistant.config_entries import ConfigEntry diff --git a/custom_components/grocy/grocy_data.py b/custom_components/grocy/grocy_data.py index a4067cd..17cff96 100644 --- a/custom_components/grocy/grocy_data.py +++ b/custom_components/grocy/grocy_data.py @@ -1,16 +1,16 @@ """Communication with Grocy API.""" from __future__ import annotations -import logging from datetime import datetime, timedelta -from typing import List +import logging from aiohttp import hdrs, web +from pygrocy.data_models.battery import Battery + from homeassistant.components.http import HomeAssistantView from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession -from pygrocy.data_models.battery import Battery from .const import ( ATTR_BATTERIES, @@ -38,7 +38,7 @@ class GrocyData: """Handles communication and gets the data.""" - def __init__(self, hass, api): + def __init__(self, hass: HomeAssistant, api) -> None: # noqa: D107 """Initialize Grocy data.""" self.hass = hass self.api = api @@ -166,7 +166,7 @@ def wrapper(): return await self.hass.async_add_executor_job(wrapper) - async def async_update_batteries(self) -> List[Battery]: + async def async_update_batteries(self) -> list[Battery]: """Update batteries.""" def wrapper(): @@ -174,7 +174,7 @@ def wrapper(): return await self.hass.async_add_executor_job(wrapper) - async def async_update_overdue_batteries(self) -> List[Battery]: + async def async_update_overdue_batteries(self) -> list[Battery]: """Update overdue batteries.""" def wrapper(): @@ -187,7 +187,7 @@ def wrapper(): async def async_setup_endpoint_for_image_proxy( hass: HomeAssistant, config_entry: ConfigEntry ): - """Setup and register the image api for grocy images with HA.""" + """Do setup and register the image api for grocy images with HA.""" session = async_get_clientsession(hass) url = config_entry.get(CONF_URL) @@ -210,7 +210,7 @@ class GrocyPictureView(HomeAssistantView): url = "/api/grocy/{picture_type}/{filename}" name = "api:grocy:picture" - def __init__(self, session, base_url, api_key): + def __init__(self, session, base_url, api_key) -> None: # noqa: D107 self._session = session self._base_url = base_url self._api_key = api_key diff --git a/custom_components/grocy/helpers.py b/custom_components/grocy/helpers.py index c8d9bb0..b0c1a8e 100644 --- a/custom_components/grocy/helpers.py +++ b/custom_components/grocy/helpers.py @@ -2,13 +2,13 @@ from __future__ import annotations import base64 -from typing import Any, Dict, Tuple +from typing import Any from urllib.parse import urlparse from pygrocy.data_models.meal_items import MealPlanItem -def extract_base_url_and_path(url: str) -> Tuple[str, str]: +def extract_base_url_and_path(url: str) -> tuple[str, str]: """Extract the base url and path from a given URL.""" parsed_url = urlparse(url) @@ -18,7 +18,7 @@ def extract_base_url_and_path(url: str) -> Tuple[str, str]: class MealPlanItemWrapper: """Wrapper around the pygrocy MealPlanItem.""" - def __init__(self, meal_plan: MealPlanItem): + def __init__(self, meal_plan: MealPlanItem) -> None: # noqa: D107 self._meal_plan = meal_plan @property @@ -35,7 +35,7 @@ def picture_url(self) -> str | None: return f"/api/grocy/recipepictures/{str(b64name, 'utf-8')}" return None - def as_dict(self) -> Dict[str, Any]: + def as_dict(self) -> dict[str, Any]: """Return attributes for the pygrocy MealPlanItem object including picture URL.""" props = self.meal_plan.as_dict() props["picture_url"] = self.picture_url diff --git a/custom_components/grocy/sensor.py b/custom_components/grocy/sensor.py index de041fb..656a86a 100644 --- a/custom_components/grocy/sensor.py +++ b/custom_components/grocy/sensor.py @@ -1,10 +1,10 @@ """Sensor platform for Grocy.""" from __future__ import annotations -import logging from collections.abc import Callable, Mapping from dataclasses import dataclass -from typing import Any, List +import logging +from typing import Any from homeassistant.components.sensor import ( SensorEntity, @@ -41,7 +41,7 @@ async def async_setup_entry( config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ): - """Setup sensor platform.""" + """Do setup sensor platform.""" coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN] entities = [] for description in SENSORS: @@ -51,7 +51,7 @@ async def async_setup_entry( entities.append(entity) else: _LOGGER.debug( - "Entity description '%s' is not available.", + "Entity description '%s' is not available", description.key, ) @@ -62,8 +62,8 @@ async def async_setup_entry( class GrocySensorEntityDescription(SensorEntityDescription): """Grocy sensor entity description.""" - attributes_fn: Callable[[List[Any]], Mapping[str, Any] | None] = lambda _: None - exists_fn: Callable[[List[str]], bool] = lambda _: True + attributes_fn: Callable[[list[Any]], Mapping[str, Any] | None] = lambda _: None + exists_fn: Callable[[list[str]], bool] = lambda _: True entity_registry_enabled_default: bool = False diff --git a/custom_components/grocy/services.py b/custom_components/grocy/services.py index 30899e6..d6c9222 100644 --- a/custom_components/grocy/services.py +++ b/custom_components/grocy/services.py @@ -1,10 +1,11 @@ """Grocy services.""" from __future__ import annotations +from pygrocy import EntityType, TransactionType import voluptuous as vol + from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, ServiceCall -from pygrocy import EntityType, TransactionType from .const import ATTR_CHORES, ATTR_TASKS, DOMAIN from .coordinator import GrocyDataUpdateCoordinator @@ -145,7 +146,8 @@ async def async_setup_services( - hass: HomeAssistant, config_entry: ConfigEntry # pylint: disable=unused-argument + hass: HomeAssistant, + config_entry: ConfigEntry, # pylint: disable=unused-argument ) -> None: """Set up services for Grocy integration.""" coordinator: GrocyDataUpdateCoordinator = hass.data[DOMAIN] @@ -200,7 +202,7 @@ async def async_unload_services(hass: HomeAssistant) -> None: hass.services.async_remove(DOMAIN, service) -async def async_add_product_service(hass, coordinator, data): +async def async_add_product_service(hass: HomeAssistant, coordinator, data): """Add a product in Grocy.""" product_id = data[SERVICE_PRODUCT_ID] amount = data[SERVICE_AMOUNT] @@ -212,7 +214,7 @@ def wrapper(): await hass.async_add_executor_job(wrapper) -async def async_open_product_service(hass, coordinator, data): +async def async_open_product_service(hass: HomeAssistant, coordinator, data): """Open a product in Grocy.""" product_id = data[SERVICE_PRODUCT_ID] amount = data[SERVICE_AMOUNT] @@ -226,7 +228,7 @@ def wrapper(): await hass.async_add_executor_job(wrapper) -async def async_consume_product_service(hass, coordinator, data): +async def async_consume_product_service(hass: HomeAssistant, coordinator, data): """Consume a product in Grocy.""" product_id = data[SERVICE_PRODUCT_ID] amount = data[SERVICE_AMOUNT] @@ -251,7 +253,7 @@ def wrapper(): await hass.async_add_executor_job(wrapper) -async def async_execute_chore_service(hass, coordinator, data): +async def async_execute_chore_service(hass: HomeAssistant, coordinator, data): """Execute a chore in Grocy.""" chore_id = data[SERVICE_CHORE_ID] done_by = data.get(SERVICE_DONE_BY, "") @@ -264,7 +266,7 @@ def wrapper(): await _async_force_update_entity(coordinator, ATTR_CHORES) -async def async_complete_task_service(hass, coordinator, data): +async def async_complete_task_service(hass: HomeAssistant, coordinator, data): """Complete a task in Grocy.""" task_id = data[SERVICE_TASK_ID] @@ -275,7 +277,7 @@ def wrapper(): await _async_force_update_entity(coordinator, ATTR_TASKS) -async def async_add_generic_service(hass, coordinator, data): +async def async_add_generic_service(hass: HomeAssistant, coordinator, data): """Add a generic entity in Grocy.""" entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None) entity_type = EntityType.TASKS @@ -289,10 +291,10 @@ def wrapper(): coordinator.grocy_api.add_generic(entity_type, data) await hass.async_add_executor_job(wrapper) - await post_generic_refresh(coordinator, entity_type); + await _post_generic_refresh(coordinator, entity_type) -async def async_update_generic_service(hass, coordinator, data): +async def async_update_generic_service(hass: HomeAssistant, coordinator, data): """Update a generic entity in Grocy.""" entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None) entity_type = EntityType.TASKS @@ -308,10 +310,10 @@ def wrapper(): coordinator.grocy_api.update_generic(entity_type, object_id, data) await hass.async_add_executor_job(wrapper) - await post_generic_refresh(coordinator, entity_type); + await _post_generic_refresh(coordinator, entity_type) -async def async_delete_generic_service(hass, coordinator, data): +async def async_delete_generic_service(hass: HomeAssistant, coordinator, data): """Delete a generic entity in Grocy.""" entity_type_raw = data.get(SERVICE_ENTITY_TYPE, None) entity_type = EntityType.TASKS @@ -325,14 +327,15 @@ def wrapper(): coordinator.grocy_api.delete_generic(entity_type, object_id) await hass.async_add_executor_job(wrapper) - await post_generic_refresh(coordinator, entity_type); + await _post_generic_refresh(coordinator, entity_type) -async def post_generic_refresh(coordinator, entity_type): - if entity_type == "tasks" or entity_type == "chores": +async def _post_generic_refresh(coordinator, entity_type): + if entity_type in ("tasks", "chores"): await _async_force_update_entity(coordinator, entity_type) -async def async_consume_recipe_service(hass, coordinator, data): + +async def async_consume_recipe_service(hass: HomeAssistant, coordinator, data): """Consume a recipe in Grocy.""" recipe_id = data[SERVICE_RECIPE_ID] @@ -342,7 +345,7 @@ def wrapper(): await hass.async_add_executor_job(wrapper) -async def async_track_battery_service(hass, coordinator, data): +async def async_track_battery_service(hass: HomeAssistant, coordinator, data): """Track a battery in Grocy.""" battery_id = data[SERVICE_BATTERY_ID]