Refactor StorageJSON to keep loaded_integrations a set until its converted to JSON (#5793)

* Refactor StorageJSON to keep loaded_integrations a set until its converted to a dict

after #5792 we will be checking loaded_integrations often. ESPHome
core keep uses a set, but it would get converted to a list when
passed through StorageJSON. Keep it a set until its needed to
be read/write to JSON so we do not have to linear searches on it
since they have a time complexity of O(n) vs O(1)

* legacy
This commit is contained in:
J. Nick Koston 2023-11-19 21:31:00 -06:00 committed by GitHub
parent cd9bf29df1
commit 2aaee81313
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 54 deletions

View file

@ -285,7 +285,7 @@ class DashboardEntry:
"name": self.name,
"friendly_name": self.friendly_name,
"configuration": self.filename,
"loaded_integrations": self.loaded_integrations,
"loaded_integrations": sorted(self.loaded_integrations),
"deployed_version": self.update_old,
"current_version": self.update_new,
"path": self.path,
@ -381,7 +381,7 @@ class DashboardEntry:
return const.__version__
@property
def loaded_integrations(self) -> list[str]:
def loaded_integrations(self) -> set[str]:
if self.storage is None:
return []
return self.storage.loaded_integrations

View file

@ -1,21 +1,15 @@
from __future__ import annotations
import binascii
import codecs
from datetime import datetime
import json
import logging
import os
from typing import Optional
from datetime import datetime
from esphome import const
from esphome.const import CONF_DISABLED, CONF_MDNS
from esphome.core import CORE
from esphome.helpers import write_file_if_changed
from esphome.const import (
CONF_MDNS,
CONF_DISABLED,
)
from esphome.types import CoreType
_LOGGER = logging.getLogger(__name__)
@ -40,48 +34,47 @@ def trash_storage_path() -> str:
class StorageJSON:
def __init__(
self,
storage_version,
name,
friendly_name,
comment,
esphome_version,
src_version,
address,
web_port,
target_platform,
build_path,
firmware_bin_path,
loaded_integrations,
no_mdns,
):
storage_version: int,
name: str,
friendly_name: str,
comment: str,
esphome_version: str,
src_version: int | None,
address: str,
web_port: int | None,
target_platform: str,
build_path: str,
firmware_bin_path: str,
loaded_integrations: set[str],
no_mdns: bool,
) -> None:
# Version of the storage JSON schema
assert storage_version is None or isinstance(storage_version, int)
self.storage_version: int = storage_version
self.storage_version = storage_version
# The name of the node
self.name: str = name
self.name = name
# The friendly name of the node
self.friendly_name: str = friendly_name
self.friendly_name = friendly_name
# The comment of the node
self.comment: str = comment
self.comment = comment
# The esphome version this was compiled with
self.esphome_version: str = esphome_version
self.esphome_version = esphome_version
# The version of the file in src/main.cpp - Used to migrate the file
assert src_version is None or isinstance(src_version, int)
self.src_version: int = src_version
self.src_version = src_version
# Address of the ESP, for example livingroom.local or a static IP
self.address: str = address
self.address = address
# Web server port of the ESP, for example 80
assert web_port is None or isinstance(web_port, int)
self.web_port: int = web_port
self.web_port = web_port
# The type of hardware in use, like "ESP32", "ESP32C3", "ESP8266", etc.
self.target_platform: str = target_platform
self.target_platform = target_platform
# The absolute path to the platformio project
self.build_path: str = build_path
self.build_path = build_path
# The absolute path to the firmware binary
self.firmware_bin_path: str = firmware_bin_path
# A list of strings of names of loaded integrations
self.loaded_integrations: list[str] = loaded_integrations
self.loaded_integrations.sort()
self.firmware_bin_path = firmware_bin_path
# A set of strings of names of loaded integrations
self.loaded_integrations = loaded_integrations
# Is mDNS disabled
self.no_mdns = no_mdns
@ -98,7 +91,7 @@ class StorageJSON:
"esp_platform": self.target_platform,
"build_path": self.build_path,
"firmware_bin_path": self.firmware_bin_path,
"loaded_integrations": self.loaded_integrations,
"loaded_integrations": sorted(self.loaded_integrations),
"no_mdns": self.no_mdns,
}
@ -109,9 +102,7 @@ class StorageJSON:
write_file_if_changed(path, self.to_json())
@staticmethod
def from_esphome_core(
esph: CoreType, old: Optional["StorageJSON"]
) -> "StorageJSON":
def from_esphome_core(esph: CoreType, old: StorageJSON | None) -> StorageJSON:
hardware = esph.target_platform.upper()
if esph.is_esp32:
from esphome.components import esp32
@ -129,7 +120,7 @@ class StorageJSON:
target_platform=hardware,
build_path=esph.build_path,
firmware_bin_path=esph.firmware_bin,
loaded_integrations=list(esph.loaded_integrations),
loaded_integrations=esph.loaded_integrations,
no_mdns=(
CONF_MDNS in esph.config
and CONF_DISABLED in esph.config[CONF_MDNS]
@ -140,7 +131,7 @@ class StorageJSON:
@staticmethod
def from_wizard(
name: str, friendly_name: str, address: str, platform: str
) -> "StorageJSON":
) -> StorageJSON:
return StorageJSON(
storage_version=1,
name=name,
@ -153,12 +144,12 @@ class StorageJSON:
target_platform=platform,
build_path=None,
firmware_bin_path=None,
loaded_integrations=[],
loaded_integrations=set(),
no_mdns=False,
)
@staticmethod
def _load_impl(path: str) -> Optional["StorageJSON"]:
def _load_impl(path: str) -> StorageJSON | None:
with codecs.open(path, "r", encoding="utf-8") as f_handle:
storage = json.load(f_handle)
storage_version = storage["storage_version"]
@ -174,7 +165,7 @@ class StorageJSON:
esp_platform = storage.get("esp_platform")
build_path = storage.get("build_path")
firmware_bin_path = storage.get("firmware_bin_path")
loaded_integrations = storage.get("loaded_integrations", [])
loaded_integrations = set(storage.get("loaded_integrations", []))
no_mdns = storage.get("no_mdns", False)
return StorageJSON(
storage_version,
@ -193,7 +184,7 @@ class StorageJSON:
)
@staticmethod
def load(path: str) -> Optional["StorageJSON"]:
def load(path: str) -> StorageJSON | None:
try:
return StorageJSON._load_impl(path)
except Exception: # pylint: disable=broad-except
@ -215,7 +206,7 @@ class EsphomeStorageJSON:
# The last time ESPHome checked for an update as an isoformat encoded str
self.last_update_check_str: str = last_update_check
# Cache of the version gotten in the last version check
self.remote_version: Optional[str] = remote_version
self.remote_version: str | None = remote_version
def as_dict(self) -> dict:
return {
@ -226,7 +217,7 @@ class EsphomeStorageJSON:
}
@property
def last_update_check(self) -> Optional[datetime]:
def last_update_check(self) -> datetime | None:
try:
return datetime.strptime(self.last_update_check_str, "%Y-%m-%dT%H:%M:%S")
except Exception: # pylint: disable=broad-except
@ -243,7 +234,7 @@ class EsphomeStorageJSON:
write_file_if_changed(path, self.to_json())
@staticmethod
def _load_impl(path: str) -> Optional["EsphomeStorageJSON"]:
def _load_impl(path: str) -> EsphomeStorageJSON | None:
with codecs.open(path, "r", encoding="utf-8") as f_handle:
storage = json.load(f_handle)
storage_version = storage["storage_version"]
@ -255,14 +246,14 @@ class EsphomeStorageJSON:
)
@staticmethod
def load(path: str) -> Optional["EsphomeStorageJSON"]:
def load(path: str) -> EsphomeStorageJSON | None:
try:
return EsphomeStorageJSON._load_impl(path)
except Exception: # pylint: disable=broad-except
return None
@staticmethod
def get_default() -> "EsphomeStorageJSON":
def get_default() -> EsphomeStorageJSON:
return EsphomeStorageJSON(
storage_version=1,
cookie_secret=binascii.hexlify(os.urandom(64)).decode(),