From 4a4ec7b864c3199d3f04c3d2636e1213bd8594a1 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Wed, 4 Aug 2021 00:03:53 +0000 Subject: [PATCH 01/10] init --- custom_components/hacs/enums.py | 7 ++ custom_components/hacs/operational/setup.py | 104 +++++++++++++----- .../hacs/operational/setup_actions/sensor.py | 25 ----- 3 files changed, 84 insertions(+), 52 deletions(-) delete mode 100644 custom_components/hacs/operational/setup_actions/sensor.py diff --git a/custom_components/hacs/enums.py b/custom_components/hacs/enums.py index af8a6a05e02..590513636fd 100644 --- a/custom_components/hacs/enums.py +++ b/custom_components/hacs/enums.py @@ -3,6 +3,11 @@ from enum import Enum +class ConfigurationMode(str, Enum): + YAML = "yaml" + UI = "flow" + + class HacsCategory(str, Enum): APPDAEMON = "appdaemon" INTEGRATION = "integration" @@ -35,6 +40,8 @@ class HacsSetupTask(str, Enum): WEBSOCKET = "WebSocket API" FRONTEND = "Frontend" SENSOR = "Sensor" + RESTORE = "Restore" + SCHEDULE = "Scheduled startup tasks" HACS_REPO = "Hacs Repository" CATEGORIES = "Additional categories" CLEAR_STORAGE = "Clear storage" diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index 7bc4536c0d7..a4369b25c54 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -7,6 +7,8 @@ from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError from homeassistant.helpers.aiohttp_client import async_create_clientsession from homeassistant.helpers.event import async_call_later +from homeassistant.helpers import discovery +from homeassistant.util.decorator import Registry from custom_components.hacs.const import ( DOMAIN, @@ -14,7 +16,14 @@ INTEGRATION_VERSION, STARTUP, ) -from custom_components.hacs.enums import HacsDisabledReason, HacsStage, LovelaceMode +from custom_components.hacs.enums import ( + HacsDisabledReason, + HacsSetupTask, + HacsStage, + LovelaceMode, + ConfigurationMode, +) +from custom_components.hacs.base import HacsBase from custom_components.hacs.hacsbase.configuration import Configuration from custom_components.hacs.hacsbase.data import HacsData from custom_components.hacs.helpers.functions.constrains import check_constrains @@ -32,7 +41,6 @@ from custom_components.hacs.operational.setup_actions.load_hacs_repository import ( async_load_hacs_repository, ) -from custom_components.hacs.operational.setup_actions.sensor import async_add_sensor from custom_components.hacs.operational.setup_actions.websocket_api import ( async_setup_hacs_websockt_api, ) @@ -43,6 +51,8 @@ except ImportError: from homeassistant.components.lovelace.system_health import system_health_info +SETUP_TASKS = Registry() + async def _async_common_setup(hass): """Common setup stages.""" @@ -68,7 +78,7 @@ async def async_setup_entry(hass, config_entry): hacs.configuration = Configuration.from_dict( config_entry.data, config_entry.options ) - hacs.configuration.config_type = "flow" + hacs.configuration.config_type = ConfigurationMode.UI hacs.configuration.config_entry = config_entry return await async_startup_wrapper_for_config_entry() @@ -79,13 +89,13 @@ async def async_setup(hass, config): hacs = get_hacs() if DOMAIN not in config: return True - if hacs.configuration and hacs.configuration.config_type == "flow": + if hacs.configuration and hacs.configuration.config_type == ConfigurationMode.UI: return True await _async_common_setup(hass) hacs.configuration = Configuration.from_dict(config[DOMAIN]) - hacs.configuration.config_type = "yaml" + hacs.configuration.config_type = ConfigurationMode.YAML await async_startup_wrapper_for_yaml() return True @@ -129,15 +139,17 @@ async def async_hacs_startup(): lovelace_info = await system_health_info(hacs.hass) except (TypeError, KeyError, HomeAssistantError): # If this happens, the users YAML is not valid, we assume YAML mode - lovelace_info = {"mode": "yaml"} + lovelace_info = {"mode": LovelaceMode.YAML} hacs.log.debug(f"Configuration type: {hacs.configuration.config_type}") hacs.version = INTEGRATION_VERSION hacs.log.info(STARTUP) hacs.core.config_path = hacs.hass.config.path() hacs.system.ha_version = HAVERSION - hacs.system.lovelace_mode = lovelace_info.get("mode", "yaml") - hacs.core.lovelace_mode = LovelaceMode(lovelace_info.get("mode", "yaml")) + hacs.system.lovelace_mode = LovelaceMode( + lovelace_info.get("mode", LovelaceMode.YAML) + ) + hacs.core.lovelace_mode = LovelaceMode(lovelace_info.get("mode", LovelaceMode.YAML)) # Setup websocket API await async_setup_hacs_websockt_api() @@ -177,42 +189,80 @@ async def async_hacs_startup(): # Check HACS Constrains if not await hacs.hass.async_add_executor_job(check_constrains): - if hacs.configuration.config_type == "flow": + if hacs.configuration.config_type == ConfigurationMode.UI: if hacs.configuration.config_entry is not None: await async_remove_entry(hacs.hass, hacs.configuration.config_entry) hacs.disable(HacsDisabledReason.CONSTRAINS) return False - # Load HACS + for task, name in ( + (async_load_hacs, HacsSetupTask.HACS_REPO), + (async_storrage_restore, HacsSetupTask.RESTORE), + (async_schedule_startup_tasks, HacsSetupTask.SCHEDULE), + (async_setup_sensor, HacsSetupTask.SENSOR), + ): + hacs.log.info("Setup task '%s' started", name) + start_time = datetime.now() + result = await task(hacs) + time_elapsed = datetime.now() - start_time + hacs.log.debug( + "Setup task '%s' completed with result '%s' in '%f' seconds", + name, + result, + time_elapsed.total_seconds(), + ) + if result is False: + return False + + # Mischief managed! + await hacs.async_set_stage(HacsStage.WAITING) + hacs.log.info( + "Setup complete, waiting for Home Assistant before startup tasks starts" + ) + return True + + +async def async_schedule_startup_tasks(hacs: HacsBase): + """Schedule startup tasks.""" + if hacs.hass.state == CoreState.running: + async_call_later(hacs.hass, 5, hacs.startup_tasks) + else: + hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, hacs.startup_tasks) + + +async def async_load_hacs(hacs: HacsBase): + """Load HACS.""" if not await async_load_hacs_repository(): - if hacs.configuration.config_type == "flow": + if hacs.configuration.config_type == ConfigurationMode.UI: if hacs.configuration.config_entry is not None: await async_remove_entry(hacs.hass, hacs.configuration.config_entry) hacs.disable(HacsDisabledReason.LOAD_HACS) return False - # Restore from storefiles + +async def async_storrage_restore(hacs: HacsBase): + """Setup storrage restore.""" if not await hacs.data.restore(): hacs_repo = hacs.get_by_name("hacs/integration") hacs_repo.pending_restart = True - if hacs.configuration.config_type == "flow": + if hacs.configuration.config_type == ConfigurationMode.UI: if hacs.configuration.config_entry is not None: await async_remove_entry(hacs.hass, hacs.configuration.config_entry) hacs.disable(HacsDisabledReason.RESTORE) return False - # Setup startup tasks - if hacs.hass.state == CoreState.running: - async_call_later(hacs.hass, 5, hacs.startup_tasks) - else: - hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, hacs.startup_tasks) - # Set up sensor - await async_add_sensor() - - # Mischief managed! - await hacs.async_set_stage(HacsStage.WAITING) - hacs.log.info( - "Setup complete, waiting for Home Assistant before startup tasks starts" - ) - return True +async def async_setup_sensor(hacs: HacsBase): + """Setup HACS sensor.""" + if hacs.configuration.config_type == ConfigurationMode.YAML: + hacs.hass.async_create_task( + discovery.async_load_platform( + hacs.hass, "sensor", DOMAIN, {}, hacs.configuration.config + ) + ) + else: + hacs.hass.async_add_job( + hacs.hass.config_entries.async_forward_entry_setup( + hacs.configuration.config_entry, "sensor" + ) + ) diff --git a/custom_components/hacs/operational/setup_actions/sensor.py b/custom_components/hacs/operational/setup_actions/sensor.py deleted file mode 100644 index 13be265cf42..00000000000 --- a/custom_components/hacs/operational/setup_actions/sensor.py +++ /dev/null @@ -1,25 +0,0 @@ -""""Starting setup task: Sensor".""" -from homeassistant.helpers import discovery - -from custom_components.hacs.const import DOMAIN -from custom_components.hacs.share import get_hacs - -from ...enums import HacsSetupTask - - -async def async_add_sensor(): - """Async wrapper for add sensor""" - hacs = get_hacs() - hacs.log.info("Setup task %s", HacsSetupTask.SENSOR) - if hacs.configuration.config_type == "yaml": - hacs.hass.async_create_task( - discovery.async_load_platform( - hacs.hass, "sensor", DOMAIN, {}, hacs.configuration.config - ) - ) - else: - hacs.hass.async_add_job( - hacs.hass.config_entries.async_forward_entry_setup( - hacs.configuration.config_entry, "sensor" - ) - ) From 56a6a418ed204c417b319b51685f8a1038e5ea53 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Wed, 4 Aug 2021 00:06:37 +0000 Subject: [PATCH 02/10] clean --- custom_components/hacs/operational/setup.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index a4369b25c54..b5bc9497c4d 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -8,7 +8,6 @@ from homeassistant.helpers.aiohttp_client import async_create_clientsession from homeassistant.helpers.event import async_call_later from homeassistant.helpers import discovery -from homeassistant.util.decorator import Registry from custom_components.hacs.const import ( DOMAIN, @@ -46,12 +45,7 @@ ) from custom_components.hacs.share import get_hacs -try: - from homeassistant.components.lovelace import system_health_info -except ImportError: - from homeassistant.components.lovelace.system_health import system_health_info - -SETUP_TASKS = Registry() +from homeassistant.components.lovelace.system_health import system_health_info async def _async_common_setup(hass): From 5d20f99f135eaca0a02271bf611ccd9d04b0c594 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Wed, 4 Aug 2021 00:07:21 +0000 Subject: [PATCH 03/10] return --- custom_components/hacs/operational/setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index b5bc9497c4d..bd0512c537d 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -254,9 +254,9 @@ async def async_setup_sensor(hacs: HacsBase): hacs.hass, "sensor", DOMAIN, {}, hacs.configuration.config ) ) - else: - hacs.hass.async_add_job( - hacs.hass.config_entries.async_forward_entry_setup( - hacs.configuration.config_entry, "sensor" - ) + return + hacs.hass.async_add_job( + hacs.hass.config_entries.async_forward_entry_setup( + hacs.configuration.config_entry, "sensor" ) + ) From e4671178edd2dcaa5543b82ca30d7e5df74425df Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Sun, 8 Aug 2021 13:28:17 +0000 Subject: [PATCH 04/10] Remove broken test --- .../setup_actions/test_sensor_setup.py | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 tests/operational/setup_actions/test_sensor_setup.py diff --git a/tests/operational/setup_actions/test_sensor_setup.py b/tests/operational/setup_actions/test_sensor_setup.py deleted file mode 100644 index 28b84c54737..00000000000 --- a/tests/operational/setup_actions/test_sensor_setup.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest -from homeassistant.config_entries import ConfigEntries, ConfigEntry - -from custom_components.hacs.operational.setup_actions.sensor import async_add_sensor - - -@pytest.mark.asyncio -async def test_async_add_sensor_ui(hacs, hass): - hass.data["custom_components"] = None - hass.config_entries = ConfigEntries(hass, {"hacs": {}}) - hacs.configuration.config_entry = ConfigEntry( - 1, - "hacs", - "hacs", - {}, - "user", - {}, - ) - hacs.configuration.config = {"key": "value"} - await async_add_sensor() - - -@pytest.mark.asyncio -async def test_async_add_sensor_yaml(hacs): - hacs.configuration.config = {"key": "value"} - - hacs.configuration.config_type = "yaml" - await async_add_sensor() From 80620a4b34d14ff23055c4a7ec8a3eb32b952465 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Sun, 8 Aug 2021 14:08:55 +0000 Subject: [PATCH 05/10] Add base manager structure --- custom_components/hacs/base.py | 64 ++++++++++++++++++- custom_components/hacs/operational/setup.py | 11 +++- custom_components/hacs/setup/__init__.py | 1 + custom_components/hacs/setup/const.py | 0 .../hacs/setup/entries/__init.__.py | 0 custom_components/hacs/setup/entries/base.py | 6 ++ custom_components/hacs/setup/manager.py | 7 ++ custom_components/hacs/utils/modules.py | 16 +++++ 8 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 custom_components/hacs/setup/__init__.py create mode 100644 custom_components/hacs/setup/const.py create mode 100644 custom_components/hacs/setup/entries/__init.__.py create mode 100644 custom_components/hacs/setup/entries/base.py create mode 100644 custom_components/hacs/setup/manager.py create mode 100644 custom_components/hacs/utils/modules.py diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index 8e91ea35eea..fae0ed8dda6 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -1,7 +1,11 @@ """Base HACS class.""" +from __future__ import annotations +from dataclasses import dataclass +import asyncio import logging -from typing import List, Optional, TYPE_CHECKING +from typing import Any, List, Optional, TYPE_CHECKING import pathlib +from importlib import import_module import attr from aiogithubapi.github import AIOGitHubAPI @@ -14,9 +18,11 @@ from .models.core import HacsCore from .models.frontend import HacsFrontend from .models.system import HacsSystem +from .utils.modules import get_modules if TYPE_CHECKING: from .helpers.classes.repository import HacsRepository + from .setup.manager import HacsSetupManager class HacsCommon: @@ -38,6 +44,13 @@ class HacsStatus: upgrading_all: bool = False +@dataclass +class HacsManagers: + """HacsManagers.""" + + setup: HacsSetupManager | None + + @attr.s class HacsBaseAttributes: """Base HACS class.""" @@ -58,6 +71,8 @@ class HacsBaseAttributes: system: HacsSystem = attr.ib(HacsSystem) repositories: List["HacsRepository"] = [] + manager: HacsManagers | None = None + @attr.s class HacsBase(HacsBaseAttributes): @@ -139,3 +154,50 @@ def enable(self) -> None: self.system.disabled = False self.system.disabled_reason = None self.log.info("HACS is enabled") + + +class HacsCommonManager(HacsBase): + """Hacs common manager.""" + + def __init__(self) -> None: + """Initialize the setup manager class.""" + self._entries: dict[str, Any] = {} + + @property + def all_entries(self) -> list[Any]: + """Return all list of all checks.""" + return list(self._entries.values()) + + async def async_load(self): + """Load all tasks.""" + package = f"{__package__}.tasks" + modules = get_modules(__file__) + + async def _load_module(module: str): + entry_module = import_module(f"{package}.{module}") + if entry := await entry_module.async_setup(): + self._entries[entry.slug] = entry + + await asyncio.gather(*[_load_module(module) for module in modules]) + self.log.info( + "Loaded %s setup entries (%s)", len(self.all_entries), self.all_entries + ) + + def get(self, slug: str) -> Any | None: + """Return a element from the entries.""" + return self._entries.get(slug) + + @property + def stages(self) -> tuple[HacsStage]: + """Return all valid stages for the entry.""" + return () + + async def async_execute(self) -> None: + """Execute the the execute methods of each entry if the stage matches.""" + await asyncio.gather( + *[ + module.execute() + for module in self.all_entries + if self.system.stage in module.stages or not module.stages + ] + ) diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index bd0512c537d..e1b09c01617 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -22,7 +22,7 @@ LovelaceMode, ConfigurationMode, ) -from custom_components.hacs.base import HacsBase +from custom_components.hacs.base import HacsBase, HacsManagers from custom_components.hacs.hacsbase.configuration import Configuration from custom_components.hacs.hacsbase.data import HacsData from custom_components.hacs.helpers.functions.constrains import check_constrains @@ -45,6 +45,8 @@ ) from custom_components.hacs.share import get_hacs +from ..setup.manager import HacsSetupManager + from homeassistant.components.lovelace.system_health import system_health_info @@ -54,6 +56,13 @@ async def _async_common_setup(hass): hacs.hass = hass hacs.system.running = True hacs.session = async_create_clientsession(hass) + hacs.manager = HacsManagers() + + # Define all managers + hacs.manager.setup = HacsSetupManager() + + # Load all managers + hacs.manager.setup.async_load() async def async_setup_entry(hass, config_entry): diff --git a/custom_components/hacs/setup/__init__.py b/custom_components/hacs/setup/__init__.py new file mode 100644 index 00000000000..76ad976e125 --- /dev/null +++ b/custom_components/hacs/setup/__init__.py @@ -0,0 +1 @@ +"""HACS setup module.""" diff --git a/custom_components/hacs/setup/const.py b/custom_components/hacs/setup/const.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/custom_components/hacs/setup/entries/__init.__.py b/custom_components/hacs/setup/entries/__init.__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/custom_components/hacs/setup/entries/base.py b/custom_components/hacs/setup/entries/base.py new file mode 100644 index 00000000000..d606b6407a3 --- /dev/null +++ b/custom_components/hacs/setup/entries/base.py @@ -0,0 +1,6 @@ +""""Hacs base setup task.""" +from custom_components.hacs.base import HacsBase + + +class HacsSetuptTaskBase(HacsBase): + """"Hacs base setup task.""" diff --git a/custom_components/hacs/setup/manager.py b/custom_components/hacs/setup/manager.py new file mode 100644 index 00000000000..3454327904f --- /dev/null +++ b/custom_components/hacs/setup/manager.py @@ -0,0 +1,7 @@ +"""HACS setup module.""" + +from ..base import HacsCommonManager + + +class HacsSetupManager(HacsCommonManager): + """Hacs Setup manager.""" diff --git a/custom_components/hacs/utils/modules.py b/custom_components/hacs/utils/modules.py new file mode 100644 index 00000000000..920447dd064 --- /dev/null +++ b/custom_components/hacs/utils/modules.py @@ -0,0 +1,16 @@ +"""HACS/util/modules.""" +from pathlib import Path +from functools import lru_cache + + +@lru_cache(maxsize=None) +def get_modules(manager_path: str, folder: str = "entries") -> list[str]: + """Retrun a list of modules inside a directory""" + ignore_files = ("base.py", "__init__.py", "manager.py") + module_files = Path(manager_path).parent.joinpath(folder) + + return [ + module.stem + for module in module_files.glob("*.py") + if module.name not in ignore_files + ] From befb12265c2e30722937300b3db1a9dec2224398 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Sun, 8 Aug 2021 14:15:22 +0000 Subject: [PATCH 06/10] move --- custom_components/hacs/base.py | 8 +++++--- .../hacs/{setup/entries => managers}/__init.__.py | 0 custom_components/hacs/{setup => managers}/const.py | 0 .../hacs/{setup/manager.py => managers/setup.py} | 5 +++-- .../hacs/{setup => managers/setup_entries}/__init__.py | 0 .../hacs/managers/setup_entries/setup/__init.__.py | 0 .../entries => managers/setup_entries/setup}/base.py | 0 custom_components/hacs/operational/setup.py | 2 +- 8 files changed, 9 insertions(+), 6 deletions(-) rename custom_components/hacs/{setup/entries => managers}/__init.__.py (100%) rename custom_components/hacs/{setup => managers}/const.py (100%) rename custom_components/hacs/{setup/manager.py => managers/setup.py} (51%) rename custom_components/hacs/{setup => managers/setup_entries}/__init__.py (100%) create mode 100644 custom_components/hacs/managers/setup_entries/setup/__init.__.py rename custom_components/hacs/{setup/entries => managers/setup_entries/setup}/base.py (100%) diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index fae0ed8dda6..1d0176f6ebf 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -22,7 +22,7 @@ if TYPE_CHECKING: from .helpers.classes.repository import HacsRepository - from .setup.manager import HacsSetupManager + from .managers.setup import HacsSetupManager class HacsCommon: @@ -159,6 +159,8 @@ def enable(self) -> None: class HacsCommonManager(HacsBase): """Hacs common manager.""" + entries_loaction: str = "" + def __init__(self) -> None: """Initialize the setup manager class.""" self._entries: dict[str, Any] = {} @@ -170,8 +172,8 @@ def all_entries(self) -> list[Any]: async def async_load(self): """Load all tasks.""" - package = f"{__package__}.tasks" - modules = get_modules(__file__) + package = f"{__package__}.{self.entries_loaction}" + modules = get_modules(__file__, self.entries_loaction) async def _load_module(module: str): entry_module = import_module(f"{package}.{module}") diff --git a/custom_components/hacs/setup/entries/__init.__.py b/custom_components/hacs/managers/__init.__.py similarity index 100% rename from custom_components/hacs/setup/entries/__init.__.py rename to custom_components/hacs/managers/__init.__.py diff --git a/custom_components/hacs/setup/const.py b/custom_components/hacs/managers/const.py similarity index 100% rename from custom_components/hacs/setup/const.py rename to custom_components/hacs/managers/const.py diff --git a/custom_components/hacs/setup/manager.py b/custom_components/hacs/managers/setup.py similarity index 51% rename from custom_components/hacs/setup/manager.py rename to custom_components/hacs/managers/setup.py index 3454327904f..2c470d3efc5 100644 --- a/custom_components/hacs/setup/manager.py +++ b/custom_components/hacs/managers/setup.py @@ -1,7 +1,8 @@ """HACS setup module.""" - -from ..base import HacsCommonManager +from custom_components.hacs.base import HacsCommonManager class HacsSetupManager(HacsCommonManager): """Hacs Setup manager.""" + + entries_loaction = "setup_entries" diff --git a/custom_components/hacs/setup/__init__.py b/custom_components/hacs/managers/setup_entries/__init__.py similarity index 100% rename from custom_components/hacs/setup/__init__.py rename to custom_components/hacs/managers/setup_entries/__init__.py diff --git a/custom_components/hacs/managers/setup_entries/setup/__init.__.py b/custom_components/hacs/managers/setup_entries/setup/__init.__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/custom_components/hacs/setup/entries/base.py b/custom_components/hacs/managers/setup_entries/setup/base.py similarity index 100% rename from custom_components/hacs/setup/entries/base.py rename to custom_components/hacs/managers/setup_entries/setup/base.py diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index e1b09c01617..abdc5fb1f3d 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -45,7 +45,7 @@ ) from custom_components.hacs.share import get_hacs -from ..setup.manager import HacsSetupManager +from ..managers.setup import HacsSetupManager from homeassistant.components.lovelace.system_health import system_health_info From 20d492348ab77b4d01d8358f2cf62de57d4c5b61 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Sun, 8 Aug 2021 14:38:36 +0000 Subject: [PATCH 07/10] add task manager --- custom_components/hacs/base.py | 67 ++----------------- custom_components/hacs/managers/setup.py | 8 --- .../hacs/managers/setup_entries/__init__.py | 1 - custom_components/hacs/operational/setup.py | 13 +--- .../__init.__.py => task/__init__.py} | 0 .../hacs/{managers => task}/const.py | 0 custom_components/hacs/task/manager.py | 55 +++++++++++++++ .../setup => task/tasks}/__init.__.py | 0 .../setup => task/tasks}/base.py | 4 +- 9 files changed, 64 insertions(+), 84 deletions(-) delete mode 100644 custom_components/hacs/managers/setup.py delete mode 100644 custom_components/hacs/managers/setup_entries/__init__.py rename custom_components/hacs/{managers/__init.__.py => task/__init__.py} (100%) rename custom_components/hacs/{managers => task}/const.py (100%) create mode 100644 custom_components/hacs/task/manager.py rename custom_components/hacs/{managers/setup_entries/setup => task/tasks}/__init.__.py (100%) rename custom_components/hacs/{managers/setup_entries/setup => task/tasks}/base.py (53%) diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index 1d0176f6ebf..fb42d1b7250 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -1,11 +1,9 @@ """Base HACS class.""" from __future__ import annotations -from dataclasses import dataclass -import asyncio + import logging -from typing import Any, List, Optional, TYPE_CHECKING +from typing import List, Optional, TYPE_CHECKING import pathlib -from importlib import import_module import attr from aiogithubapi.github import AIOGitHubAPI @@ -18,11 +16,10 @@ from .models.core import HacsCore from .models.frontend import HacsFrontend from .models.system import HacsSystem -from .utils.modules import get_modules if TYPE_CHECKING: from .helpers.classes.repository import HacsRepository - from .managers.setup import HacsSetupManager + from .task.manager import HacsTaskManager class HacsCommon: @@ -44,13 +41,6 @@ class HacsStatus: upgrading_all: bool = False -@dataclass -class HacsManagers: - """HacsManagers.""" - - setup: HacsSetupManager | None - - @attr.s class HacsBaseAttributes: """Base HACS class.""" @@ -71,7 +61,7 @@ class HacsBaseAttributes: system: HacsSystem = attr.ib(HacsSystem) repositories: List["HacsRepository"] = [] - manager: HacsManagers | None = None + task: HacsTaskManager | None = None @attr.s @@ -154,52 +144,3 @@ def enable(self) -> None: self.system.disabled = False self.system.disabled_reason = None self.log.info("HACS is enabled") - - -class HacsCommonManager(HacsBase): - """Hacs common manager.""" - - entries_loaction: str = "" - - def __init__(self) -> None: - """Initialize the setup manager class.""" - self._entries: dict[str, Any] = {} - - @property - def all_entries(self) -> list[Any]: - """Return all list of all checks.""" - return list(self._entries.values()) - - async def async_load(self): - """Load all tasks.""" - package = f"{__package__}.{self.entries_loaction}" - modules = get_modules(__file__, self.entries_loaction) - - async def _load_module(module: str): - entry_module = import_module(f"{package}.{module}") - if entry := await entry_module.async_setup(): - self._entries[entry.slug] = entry - - await asyncio.gather(*[_load_module(module) for module in modules]) - self.log.info( - "Loaded %s setup entries (%s)", len(self.all_entries), self.all_entries - ) - - def get(self, slug: str) -> Any | None: - """Return a element from the entries.""" - return self._entries.get(slug) - - @property - def stages(self) -> tuple[HacsStage]: - """Return all valid stages for the entry.""" - return () - - async def async_execute(self) -> None: - """Execute the the execute methods of each entry if the stage matches.""" - await asyncio.gather( - *[ - module.execute() - for module in self.all_entries - if self.system.stage in module.stages or not module.stages - ] - ) diff --git a/custom_components/hacs/managers/setup.py b/custom_components/hacs/managers/setup.py deleted file mode 100644 index 2c470d3efc5..00000000000 --- a/custom_components/hacs/managers/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -"""HACS setup module.""" -from custom_components.hacs.base import HacsCommonManager - - -class HacsSetupManager(HacsCommonManager): - """Hacs Setup manager.""" - - entries_loaction = "setup_entries" diff --git a/custom_components/hacs/managers/setup_entries/__init__.py b/custom_components/hacs/managers/setup_entries/__init__.py deleted file mode 100644 index 76ad976e125..00000000000 --- a/custom_components/hacs/managers/setup_entries/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""HACS setup module.""" diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index abdc5fb1f3d..3296aab7cf5 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -1,4 +1,5 @@ """Setup HACS.""" +from custom_components.hacs.task.manager import HacsTaskManager from datetime import datetime from aiogithubapi import AIOGitHubAPIException, GitHub from homeassistant.const import EVENT_HOMEASSISTANT_STARTED @@ -22,7 +23,7 @@ LovelaceMode, ConfigurationMode, ) -from custom_components.hacs.base import HacsBase, HacsManagers +from custom_components.hacs.base import HacsBase from custom_components.hacs.hacsbase.configuration import Configuration from custom_components.hacs.hacsbase.data import HacsData from custom_components.hacs.helpers.functions.constrains import check_constrains @@ -45,8 +46,6 @@ ) from custom_components.hacs.share import get_hacs -from ..managers.setup import HacsSetupManager - from homeassistant.components.lovelace.system_health import system_health_info @@ -56,13 +55,7 @@ async def _async_common_setup(hass): hacs.hass = hass hacs.system.running = True hacs.session = async_create_clientsession(hass) - hacs.manager = HacsManagers() - - # Define all managers - hacs.manager.setup = HacsSetupManager() - - # Load all managers - hacs.manager.setup.async_load() + hacs.tasks = HacsTaskManager() async def async_setup_entry(hass, config_entry): diff --git a/custom_components/hacs/managers/__init.__.py b/custom_components/hacs/task/__init__.py similarity index 100% rename from custom_components/hacs/managers/__init.__.py rename to custom_components/hacs/task/__init__.py diff --git a/custom_components/hacs/managers/const.py b/custom_components/hacs/task/const.py similarity index 100% rename from custom_components/hacs/managers/const.py rename to custom_components/hacs/task/const.py diff --git a/custom_components/hacs/task/manager.py b/custom_components/hacs/task/manager.py new file mode 100644 index 00000000000..29218ff06b4 --- /dev/null +++ b/custom_components/hacs/task/manager.py @@ -0,0 +1,55 @@ +"""Hacs task manager.""" +from __future__ import annotations +import asyncio +from pathlib import Path +from importlib import import_module + +from custom_components.hacs.task.tasks.base import HacsTaskBase +from custom_components.hacs.base import HacsBase + + +class HacsTaskManager(HacsBase): + """Hacs task manager.""" + + entries_loaction: str = "" + + def __init__(self) -> None: + """Initialize the setup manager class.""" + self.__tasks: dict[str, HacsTaskBase] = {} + + @property + def all_tasks(self) -> list[HacsTaskBase]: + """Return all list of all checks.""" + return list(self.__tasks.values()) + + async def async_load(self): + """Load all tasks.""" + package = f"{__package__}.{self.entries_loaction}" + task_files = Path(__file__).parent.joinpath("tasks") + task_modules = ( + module.stem + for module in task_files.glob("*.py") + if module.name not in ("base.py", "__init__.py", "manager.py") + ) + + async def _load_module(module: str): + task_module = import_module(f"{package}.{module}") + if task := await task_module.async_setup(): + self.__tasks[task.slug] = task + + await asyncio.gather(*[_load_module(task) for task in task_modules]) + self.log.info("Loaded %s tasks", len(self.all_tasks)) + + def get(self, slug: str) -> HacsTaskBase | None: + """Return a task.""" + return self.__tasks.get(slug) + + async def async_execute(self) -> None: + """Execute the the execute methods of each task if the stage matches.""" + await asyncio.gather( + *[ + task.execute() + for task in self.all_tasks + if self.system.stage in task.stages or not task.stages + ] + ) diff --git a/custom_components/hacs/managers/setup_entries/setup/__init.__.py b/custom_components/hacs/task/tasks/__init.__.py similarity index 100% rename from custom_components/hacs/managers/setup_entries/setup/__init.__.py rename to custom_components/hacs/task/tasks/__init.__.py diff --git a/custom_components/hacs/managers/setup_entries/setup/base.py b/custom_components/hacs/task/tasks/base.py similarity index 53% rename from custom_components/hacs/managers/setup_entries/setup/base.py rename to custom_components/hacs/task/tasks/base.py index d606b6407a3..5895ec7b5ca 100644 --- a/custom_components/hacs/managers/setup_entries/setup/base.py +++ b/custom_components/hacs/task/tasks/base.py @@ -2,5 +2,5 @@ from custom_components.hacs.base import HacsBase -class HacsSetuptTaskBase(HacsBase): - """"Hacs base setup task.""" +class HacsTaskBase(HacsBase): + """"Hacs task base.""" From 6cb46e8f8911e6594f6c33ec9d74dd95f5ca353b Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Mon, 9 Aug 2021 17:13:30 +0000 Subject: [PATCH 08/10] add HacsTaskHelloWorld --- custom_components/hacs/operational/setup.py | 5 ++ custom_components/hacs/task/const.py | 12 +++ custom_components/hacs/task/manager.py | 26 ++++--- .../task/tasks/{__init.__.py => __init__.py} | 0 custom_components/hacs/task/tasks/base.py | 75 +++++++++++++++++++ .../hacs/task/tasks/hello_world.py | 14 ++++ 6 files changed, 120 insertions(+), 12 deletions(-) rename custom_components/hacs/task/tasks/{__init.__.py => __init__.py} (100%) create mode 100644 custom_components/hacs/task/tasks/hello_world.py diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py index 3296aab7cf5..5c5358d25b0 100644 --- a/custom_components/hacs/operational/setup.py +++ b/custom_components/hacs/operational/setup.py @@ -57,6 +57,11 @@ async def _async_common_setup(hass): hacs.session = async_create_clientsession(hass) hacs.tasks = HacsTaskManager() + await hacs.tasks.async_load() + + test = hacs.tasks.get("hello_world") + await test.execute() + async def async_setup_entry(hass, config_entry): """Set up this integration using UI.""" diff --git a/custom_components/hacs/task/const.py b/custom_components/hacs/task/const.py index e69de29bb2d..a1578471db6 100644 --- a/custom_components/hacs/task/const.py +++ b/custom_components/hacs/task/const.py @@ -0,0 +1,12 @@ +"""Constants for tasks.""" +from enum import Enum + + +class HacsTaskType(str, Enum): + """HacsTaskType""" + + RUNTIME = "runtime" + EVENT = "event" + SCHEDULE = "schedule" + MANUAL = "manual" + BASE = "base" diff --git a/custom_components/hacs/task/manager.py b/custom_components/hacs/task/manager.py index 29218ff06b4..f8d5dc28743 100644 --- a/custom_components/hacs/task/manager.py +++ b/custom_components/hacs/task/manager.py @@ -1,30 +1,30 @@ """Hacs task manager.""" from __future__ import annotations + import asyncio -from pathlib import Path from importlib import import_module +from pathlib import Path -from custom_components.hacs.task.tasks.base import HacsTaskBase from custom_components.hacs.base import HacsBase +from custom_components.hacs.task.const import HacsTaskType +from custom_components.hacs.task.tasks.base import HacsTaskBase class HacsTaskManager(HacsBase): """Hacs task manager.""" - entries_loaction: str = "" - def __init__(self) -> None: """Initialize the setup manager class.""" self.__tasks: dict[str, HacsTaskBase] = {} @property - def all_tasks(self) -> list[HacsTaskBase]: - """Return all list of all checks.""" + def tasks(self) -> list[HacsTaskBase]: + """Return all list of all tasks.""" return list(self.__tasks.values()) async def async_load(self): """Load all tasks.""" - package = f"{__package__}.{self.entries_loaction}" + package = f"{__package__}.tasks" task_files = Path(__file__).parent.joinpath("tasks") task_modules = ( module.stem @@ -38,18 +38,20 @@ async def _load_module(module: str): self.__tasks[task.slug] = task await asyncio.gather(*[_load_module(task) for task in task_modules]) - self.log.info("Loaded %s tasks", len(self.all_tasks)) + self.log.info("Loaded %s tasks", len(self.tasks)) def get(self, slug: str) -> HacsTaskBase | None: """Return a task.""" return self.__tasks.get(slug) - async def async_execute(self) -> None: - """Execute the the execute methods of each task if the stage matches.""" + async def async_execute_runtume_tasks(self) -> None: + """Execute the the execute methods of each runtime task if the stage matches.""" await asyncio.gather( *[ task.execute() - for task in self.all_tasks - if self.system.stage in task.stages or not task.stages + for task in self.tasks + if task.type == HacsTaskType.RUNTIME + and self.system.stage in task.stages + or not task.stages ] ) diff --git a/custom_components/hacs/task/tasks/__init.__.py b/custom_components/hacs/task/tasks/__init__.py similarity index 100% rename from custom_components/hacs/task/tasks/__init.__.py rename to custom_components/hacs/task/tasks/__init__.py diff --git a/custom_components/hacs/task/tasks/base.py b/custom_components/hacs/task/tasks/base.py index 5895ec7b5ca..32a3159198f 100644 --- a/custom_components/hacs/task/tasks/base.py +++ b/custom_components/hacs/task/tasks/base.py @@ -1,6 +1,81 @@ """"Hacs base setup task.""" +# pylint: disable=abstract-method +from __future__ import annotations + +from abc import abstractmethod +from datetime import timedelta + from custom_components.hacs.base import HacsBase +from custom_components.hacs.enums import HacsStage +from custom_components.hacs.task.const import HacsTaskType class HacsTaskBase(HacsBase): """"Hacs task base.""" + + @property + def type(self) -> HacsTaskType: + """Return the task type.""" + raise HacsTaskType.BASE + + @property + def slug(self) -> str: + """Return the check slug.""" + return self.__class__.__module__.rsplit(".", maxsplit=1)[-1] + + async def execute(self): + """Execute the task.""" + raise NotImplementedError + + +class HacsTaskEventBase(HacsTaskBase): + """"HacsTaskEventBase.""" + + @property + def type(self) -> HacsTaskType: + """Return the task type.""" + return HacsTaskType.EVENT + + @property + @abstractmethod + def event(self) -> str: + """Return the event to listen to.""" + raise NotImplementedError + + +class HacsTaskScheduleBase(HacsTaskBase): + """"HacsTaskScheduleBase.""" + + @property + def type(self) -> HacsTaskType: + """Return the task type.""" + return HacsTaskType.SCHEDULE + + @property + @abstractmethod + def schedule(self) -> timedelta: + """Return the schedule.""" + raise NotImplementedError + + +class HacsTaskManualBase(HacsTaskBase): + """"HacsTaskManualBase.""" + + @property + def type(self) -> HacsTaskType: + """Return the task type.""" + return HacsTaskType.MANUAL + + +class HacsTaskRuntimeBase(HacsTaskBase): + """"HacsTaskRuntimeBase.""" + + @property + def type(self) -> HacsTaskType: + """Return the task type.""" + return HacsTaskType.RUNTIME + + @property + def stages(self) -> list[HacsStage]: + """Return a list of valid stages when this task can run.""" + return [] diff --git a/custom_components/hacs/task/tasks/hello_world.py b/custom_components/hacs/task/tasks/hello_world.py new file mode 100644 index 00000000000..0ae9fb91c33 --- /dev/null +++ b/custom_components/hacs/task/tasks/hello_world.py @@ -0,0 +1,14 @@ +""""Hacs base setup task.""" +from .base import HacsTaskManualBase + + +async def async_setup(): + """Set up this task.""" + return HacsTaskHelloWorld() + + +class HacsTaskHelloWorld(HacsTaskManualBase): + """"Hacs task base.""" + + async def execute(self): + self.log.error("Hello World!") From 31e1b44151ae8bfa1764dbee2fe424b191a82c96 Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Mon, 9 Aug 2021 17:54:28 +0000 Subject: [PATCH 09/10] broken --- custom_components/hacs/base.py | 36 ++++++++++---- custom_components/hacs/share.py | 47 ++++++++++++++----- custom_components/hacs/task/tasks/base.py | 2 + .../hacs/task/tasks/hello_world.py | 3 ++ custom_components/hacs/utils/bind_hacs.py | 7 +++ custom_components/hacs/utils/modules.py | 16 ------- tests/conftest.py | 1 - 7 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 custom_components/hacs/utils/bind_hacs.py delete mode 100644 custom_components/hacs/utils/modules.py diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index fb42d1b7250..fd56d6c94bb 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -1,6 +1,6 @@ """Base HACS class.""" from __future__ import annotations - +from dataclasses import dataclass, field import logging from typing import List, Optional, TYPE_CHECKING import pathlib @@ -22,15 +22,17 @@ from .task.manager import HacsTaskManager +@dataclass class HacsCommon: """Common for HACS.""" - categories: List = [] - default: List = [] - installed: List = [] - skip: List = [] + categories: list[str] = field(default_factory=list) + default: list[str] = field(default_factory=list) + installed: list[str] = field(default_factory=list) + skip: list[str] = field(default_factory=list) +@dataclass class HacsStatus: """HacsStatus.""" @@ -59,15 +61,33 @@ class HacsBaseAttributes: frontend: HacsFrontend = attr.ib(HacsFrontend) log: logging.Logger = getLogger() system: HacsSystem = attr.ib(HacsSystem) - repositories: List["HacsRepository"] = [] + repositories: list[HacsRepository] = [] task: HacsTaskManager | None = None -@attr.s -class HacsBase(HacsBaseAttributes): +class HacsBase: """Base HACS class.""" + def __init__(self) -> None: + self._default: Optional[AIOGitHubAPIRepository] + self._github: Optional[AIOGitHubAPI] + self._hass: Optional[HomeAssistant] + self._configuration: Optional[Configuration] + self._repository: Optional[AIOGitHubAPIRepository] + self._stage: HacsStage = HacsStage.SETUP + self._common: Optional[HacsCommon] + + self.core: HacsCore = attr.ib(HacsCore) + self.common: HacsCommon = attr.ib(HacsCommon) + self.status: HacsStatus = attr.ib(HacsStatus) + self.frontend: HacsFrontend = attr.ib(HacsFrontend) + self.log: logging.Logger = getLogger() + self.system: HacsSystem = attr.ib(HacsSystem) + self.repositories: list[HacsRepository] = [] + + self.task: HacsTaskManager | None = None + @property def stage(self) -> HacsStage: """Returns a HacsStage object.""" diff --git a/custom_components/hacs/share.py b/custom_components/hacs/share.py index a3665c2b664..949caf43b56 100644 --- a/custom_components/hacs/share.py +++ b/custom_components/hacs/share.py @@ -1,7 +1,24 @@ """Shared HACS elements.""" +from __future__ import annotations + +from dataclasses import dataclass + import os +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .base import HacsBase + from .hacsbase.hacs import Hacs + from .operational.factory import HacsTaskFactory + + +@dataclass +class HacsShare: + """HacsShare""" + + hacs: Hacs | None = None + factory: HacsTaskFactory | None = None -from .base import HacsBase SHARE = { "hacs": None, @@ -13,26 +30,32 @@ def get_hacs() -> HacsBase: - if SHARE["hacs"] is None: - from custom_components.hacs.hacsbase.hacs import Hacs as Legacy + """Return a HACS object.""" + if (hacs := HacsShare.hacs) is not None: + return hacs - _hacs = Legacy() + from .hacsbase.hacs import Hacs # pylint: disable=import-outside-toplevel - if not "PYTEST" in os.environ and "GITHUB_ACTION" in os.environ: - _hacs.system.action = True + SHARE["hacs"] = HacsShare.hacs = hacs = Hacs() - SHARE["hacs"] = _hacs + if not "PYTEST" in os.environ and "GITHUB_ACTION" in os.environ: + hacs.system.action = True - return SHARE["hacs"] + return hacs def get_factory(): - if SHARE["factory"] is None: - from custom_components.hacs.operational.factory import HacsTaskFactory + """Return a HacsTaskFactory object.""" + if (factory := HacsShare.factory) is not None: + return factory + + from .operational.factory import ( # pylint: disable=import-outside-toplevel + HacsTaskFactory, + ) - SHARE["factory"] = HacsTaskFactory() + SHARE["factory"] = HacsShare.factory = factory = HacsTaskFactory() - return SHARE["factory"] + return factory def get_queue(): diff --git a/custom_components/hacs/task/tasks/base.py b/custom_components/hacs/task/tasks/base.py index 32a3159198f..66f9a6e471d 100644 --- a/custom_components/hacs/task/tasks/base.py +++ b/custom_components/hacs/task/tasks/base.py @@ -8,8 +8,10 @@ from custom_components.hacs.base import HacsBase from custom_components.hacs.enums import HacsStage from custom_components.hacs.task.const import HacsTaskType +from custom_components.hacs.utils.bind_hacs import bind_hacs +@bind_hacs class HacsTaskBase(HacsBase): """"Hacs task base.""" diff --git a/custom_components/hacs/task/tasks/hello_world.py b/custom_components/hacs/task/tasks/hello_world.py index 0ae9fb91c33..b986227a7f0 100644 --- a/custom_components/hacs/task/tasks/hello_world.py +++ b/custom_components/hacs/task/tasks/hello_world.py @@ -1,4 +1,5 @@ """"Hacs base setup task.""" +from custom_components.hacs.utils.bind_hacs import bind_hacs from .base import HacsTaskManualBase @@ -7,8 +8,10 @@ async def async_setup(): return HacsTaskHelloWorld() +@bind_hacs class HacsTaskHelloWorld(HacsTaskManualBase): """"Hacs task base.""" async def execute(self): self.log.error("Hello World!") + self.log.error(self.__hacs) diff --git a/custom_components/hacs/utils/bind_hacs.py b/custom_components/hacs/utils/bind_hacs.py new file mode 100644 index 00000000000..bfec34d0380 --- /dev/null +++ b/custom_components/hacs/utils/bind_hacs.py @@ -0,0 +1,7 @@ +"""Bind HACS to classes.""" +from ..share import get_hacs + + +def bind_hacs(cls): + cls.__hacs = get_hacs() + return cls \ No newline at end of file diff --git a/custom_components/hacs/utils/modules.py b/custom_components/hacs/utils/modules.py deleted file mode 100644 index 920447dd064..00000000000 --- a/custom_components/hacs/utils/modules.py +++ /dev/null @@ -1,16 +0,0 @@ -"""HACS/util/modules.""" -from pathlib import Path -from functools import lru_cache - - -@lru_cache(maxsize=None) -def get_modules(manager_path: str, folder: str = "entries") -> list[str]: - """Retrun a list of modules inside a directory""" - ignore_files = ("base.py", "__init__.py", "manager.py") - module_files = Path(manager_path).parent.joinpath(folder) - - return [ - module.stem - for module in module_files.glob("*.py") - if module.name not in ignore_files - ] diff --git a/tests/conftest.py b/tests/conftest.py index d96e6b4a8c1..57891c06eb7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -94,7 +94,6 @@ def hacs(hass): hacs_obj.configuration.token = TOKEN hacs_obj.core.config_path = hass.config.path() hacs_obj.system.action = False - SHARE["hacs"] = hacs_obj yield hacs_obj From f6de7e215899e8de0b0ebbb86b9238518bf629fb Mon Sep 17 00:00:00 2001 From: Ludeeus Date: Sun, 15 Aug 2021 08:26:19 +0000 Subject: [PATCH 10/10] changes --- custom_components/hacs/base.py | 142 ++++++------------ custom_components/hacs/share.py | 40 +++++ .../hacs/task/tasks/hello_world.py | 2 +- 3 files changed, 87 insertions(+), 97 deletions(-) diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index fd56d6c94bb..2c911101125 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -1,6 +1,6 @@ """Base HACS class.""" from __future__ import annotations -from dataclasses import dataclass, field + import logging from typing import List, Optional, TYPE_CHECKING import pathlib @@ -22,17 +22,15 @@ from .task.manager import HacsTaskManager -@dataclass class HacsCommon: """Common for HACS.""" - categories: list[str] = field(default_factory=list) - default: list[str] = field(default_factory=list) - installed: list[str] = field(default_factory=list) - skip: list[str] = field(default_factory=list) + categories: List = [] + default: List = [] + installed: List = [] + skip: List = [] -@dataclass class HacsStatus: """HacsStatus.""" @@ -47,112 +45,44 @@ class HacsStatus: class HacsBaseAttributes: """Base HACS class.""" - _default: Optional[AIOGitHubAPIRepository] - _github: Optional[AIOGitHubAPI] - _hass: Optional[HomeAssistant] - _configuration: Optional[Configuration] - _repository: Optional[AIOGitHubAPIRepository] - _stage: HacsStage = HacsStage.SETUP - _common: Optional[HacsCommon] - - core: HacsCore = attr.ib(HacsCore) - common: HacsCommon = attr.ib(HacsCommon) - status: HacsStatus = attr.ib(HacsStatus) - frontend: HacsFrontend = attr.ib(HacsFrontend) - log: logging.Logger = getLogger() - system: HacsSystem = attr.ib(HacsSystem) - repositories: list[HacsRepository] = [] + default: Optional[AIOGitHubAPIRepository] + github: Optional[AIOGitHubAPI] + + repositories: List["HacsRepository"] = [] task: HacsTaskManager | None = None -class HacsBase: +class Hacs: """Base HACS class.""" def __init__(self) -> None: - self._default: Optional[AIOGitHubAPIRepository] - self._github: Optional[AIOGitHubAPI] - self._hass: Optional[HomeAssistant] - self._configuration: Optional[Configuration] - self._repository: Optional[AIOGitHubAPIRepository] - self._stage: HacsStage = HacsStage.SETUP - self._common: Optional[HacsCommon] - - self.core: HacsCore = attr.ib(HacsCore) - self.common: HacsCommon = attr.ib(HacsCommon) - self.status: HacsStatus = attr.ib(HacsStatus) - self.frontend: HacsFrontend = attr.ib(HacsFrontend) + """Initialize.""" + self.common: HacsCommon = HacsCommon() + self.configuration: Configuration = Configuration() + self.core: HacsCore = HacsCore() + self.default: AIOGitHubAPIRepository | None = None + self.frontend: HacsFrontend = HacsFrontend() + self.github: AIOGitHubAPI | None = None + self.hass: HomeAssistant | None = None + self.integration_dir = pathlib.Path(__file__).parent self.log: logging.Logger = getLogger() - self.system: HacsSystem = attr.ib(HacsSystem) - self.repositories: list[HacsRepository] = [] + self.repository: AIOGitHubAPIRepository | None = None + self.status: HacsStatus = HacsStatus() + self.system: HacsSystem = HacsSystem() - self.task: HacsTaskManager | None = None + self._stage: HacsStage = HacsStage.SETUP @property def stage(self) -> HacsStage: - """Returns a HacsStage object.""" + """Returns the current stage.""" return self._stage @stage.setter - def stage(self, value: HacsStage) -> None: - """Set the value for the stage property.""" + def stage(self, value: Configuration) -> None: + """Set the current stage.""" self._stage = value - @property - def github(self) -> Optional[AIOGitHubAPI]: - """Returns a AIOGitHubAPI object.""" - return self._github - - @github.setter - def github(self, value: AIOGitHubAPI) -> None: - """Set the value for the github property.""" - self._github = value - - @property - def repository(self) -> Optional[AIOGitHubAPIRepository]: - """Returns a AIOGitHubAPIRepository object representing hacs/integration.""" - return self._repository - - @repository.setter - def repository(self, value: AIOGitHubAPIRepository) -> None: - """Set the value for the repository property.""" - self._repository = value - - @property - def default(self) -> Optional[AIOGitHubAPIRepository]: - """Returns a AIOGitHubAPIRepository object representing hacs/default.""" - return self._default - - @default.setter - def default(self, value: AIOGitHubAPIRepository) -> None: - """Set the value for the default property.""" - self._default = value - - @property - def hass(self) -> Optional[HomeAssistant]: - """Returns a HomeAssistant object.""" - return self._hass - - @hass.setter - def hass(self, value: HomeAssistant) -> None: - """Set the value for the default property.""" - self._hass = value - - @property - def configuration(self) -> Optional[Configuration]: - """Returns a Configuration object.""" - return self._configuration - - @configuration.setter - def configuration(self, value: Configuration) -> None: - """Set the value for the default property.""" - self._configuration = value - - @property - def integration_dir(self) -> pathlib.Path: - """Return the HACS integration dir.""" - return pathlib.Path(__file__).parent - def disable(self, reason: HacsDisabledReason) -> None: """Disable HACS.""" self.system.disabled = True @@ -164,3 +94,23 @@ def enable(self) -> None: self.system.disabled = False self.system.disabled_reason = None self.log.info("HACS is enabled") + + +class HacsBase(Hacs): + """Hacs Baseclass""" + + __hacs: Hacs + + common: HacsCommon = __hacs.common + configuration: Configuration = Configuration() + core: HacsCore = HacsCore() + default: AIOGitHubAPIRepository | None = None + frontend: HacsFrontend = __hacs.frontend + github: AIOGitHubAPI | None = __hacs.github + hass: HomeAssistant | None = __hacs.hass + integration_dir = pathlib.Path(__file__).parent + log: logging.Logger = __hacs.log + repository: AIOGitHubAPIRepository = __hacs.repository + stage: HacsStage = __hacs.stage + status: HacsStatus = HacsStatus() + system: HacsSystem = HacsSystem() diff --git a/custom_components/hacs/share.py b/custom_components/hacs/share.py index 949caf43b56..3d53a185b45 100644 --- a/custom_components/hacs/share.py +++ b/custom_components/hacs/share.py @@ -29,6 +29,26 @@ class HacsShare: } +class HacsBaseclass(Hacs): + """Hacs Baseclass""" + + _hacs: get_hacs() + + common: HacsCommon = __hacs.common + configuration: Configuration = Configuration() + core: HacsCore = HacsCore() + default: AIOGitHubAPIRepository | None = None + frontend: HacsFrontend = __hacs.frontend + github: AIOGitHubAPI | None = __hacs.github + hass: HomeAssistant | None = __hacs.hass + integration_dir = pathlib.Path(__file__).parent + log: logging.Logger = __hacs.log + repository: AIOGitHubAPIRepository = __hacs.repository + stage: HacsStage = __hacs.stage + status: HacsStatus = HacsStatus() + system: HacsSystem = HacsSystem() + + def get_hacs() -> HacsBase: """Return a HACS object.""" if (hacs := HacsShare.hacs) is not None: @@ -89,3 +109,23 @@ def get_removed(repository): def list_removed_repositories(): return SHARE["removed_repositories"] + + +class HacsBaseClass(Hacs): + """Hacs Baseclass""" + + _hacs: get_hacs() + + common: HacsCommon = _hacs.common + configuration: Configuration = Configuration() + core: HacsCore = HacsCore() + default: AIOGitHubAPIRepository | None = None + frontend: HacsFrontend = __hacs.frontend + github: AIOGitHubAPI | None = __hacs.github + hass: HomeAssistant | None = __hacs.hass + integration_dir = pathlib.Path(__file__).parent + log: logging.Logger = __hacs.log + repository: AIOGitHubAPIRepository = __hacs.repository + stage: HacsStage = __hacs.stage + status: HacsStatus = HacsStatus() + system: HacsSystem = HacsSystem() \ No newline at end of file diff --git a/custom_components/hacs/task/tasks/hello_world.py b/custom_components/hacs/task/tasks/hello_world.py index b986227a7f0..4e552a4be07 100644 --- a/custom_components/hacs/task/tasks/hello_world.py +++ b/custom_components/hacs/task/tasks/hello_world.py @@ -14,4 +14,4 @@ class HacsTaskHelloWorld(HacsTaskManualBase): async def execute(self): self.log.error("Hello World!") - self.log.error(self.__hacs) + self.log.error(self.hass)