mirror of
https://github.com/esphome/esphome.git
synced 2024-11-24 07:58:09 +01:00
Bump python min to 3.9 (#3871)
This commit is contained in:
parent
c3a8972550
commit
d220d41182
25 changed files with 130 additions and 147 deletions
|
@ -30,4 +30,4 @@ repos:
|
|||
rev: v3.0.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py38-plus]
|
||||
args: [--py39-plus]
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
|
@ -200,7 +199,7 @@ async def esp8266_pin_to_code(config):
|
|||
@coroutine_with_priority(-999.0)
|
||||
async def add_pin_initial_states_array():
|
||||
# Add includes at the very end, so that they override everything
|
||||
initial_states: List[PinInitialState] = CORE.data[KEY_ESP8266][
|
||||
initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][
|
||||
KEY_PIN_INITIAL_STATES
|
||||
]
|
||||
initial_modes_s = ", ".join(str(x.mode) for x in initial_states)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, List
|
||||
from typing import Any
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
|
@ -349,7 +349,7 @@ def _spi_extra_validate(config):
|
|||
class MethodDescriptor:
|
||||
method_schema: Any
|
||||
to_code: Any
|
||||
supported_chips: List[str]
|
||||
supported_chips: list[str]
|
||||
extra_validate: Any = None
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from typing import List
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
|
@ -60,7 +59,7 @@ SELECT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).e
|
|||
)
|
||||
|
||||
|
||||
async def setup_select_core_(var, config, *, options: List[str]):
|
||||
async def setup_select_core_(var, config, *, options: list[str]):
|
||||
await setup_entity(var, config)
|
||||
|
||||
cg.add(var.traits.set_options(options))
|
||||
|
@ -76,14 +75,14 @@ async def setup_select_core_(var, config, *, options: List[str]):
|
|||
await mqtt.register_mqtt_component(mqtt_, config)
|
||||
|
||||
|
||||
async def register_select(var, config, *, options: List[str]):
|
||||
async def register_select(var, config, *, options: list[str]):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
var = cg.Pvariable(config[CONF_ID], var)
|
||||
cg.add(cg.App.register_select(var))
|
||||
await setup_select_core_(var, config, options=options)
|
||||
|
||||
|
||||
async def new_select(config, *, options: List[str]):
|
||||
async def new_select(config, *, options: list[str]):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await register_select(var, config, options=options)
|
||||
return var
|
||||
|
|
|
@ -23,7 +23,7 @@ from esphome.core import CORE, EsphomeError
|
|||
from esphome.helpers import indent
|
||||
from esphome.util import safe_print, OrderedDict
|
||||
|
||||
from typing import List, Optional, Tuple, Union
|
||||
from typing import Optional, Union
|
||||
from esphome.loader import get_component, get_platform, ComponentManifest
|
||||
from esphome.yaml_util import is_secret, ESPHomeDataBase, ESPForceValue
|
||||
from esphome.voluptuous_schema import ExtraKeysInvalid
|
||||
|
@ -50,10 +50,10 @@ def iter_components(config):
|
|||
yield p_name, platform, p_config
|
||||
|
||||
|
||||
ConfigPath = List[Union[str, int]]
|
||||
ConfigPath = list[Union[str, int]]
|
||||
|
||||
|
||||
def _path_begins_with(path, other): # type: (ConfigPath, ConfigPath) -> bool
|
||||
def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool:
|
||||
if len(path) < len(other):
|
||||
return False
|
||||
return path[: len(other)] == other
|
||||
|
@ -67,7 +67,7 @@ class _ValidationStepTask:
|
|||
self.step = step
|
||||
|
||||
@property
|
||||
def _cmp_tuple(self) -> Tuple[float, int]:
|
||||
def _cmp_tuple(self) -> tuple[float, int]:
|
||||
return (-self.priority, self.id_number)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
@ -84,21 +84,20 @@ class Config(OrderedDict, fv.FinalValidateConfig):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
# A list of voluptuous errors
|
||||
self.errors = [] # type: List[vol.Invalid]
|
||||
self.errors: list[vol.Invalid] = []
|
||||
# A list of paths that should be fully outputted
|
||||
# The values will be the paths to all "domain", for example (['logger'], 'logger')
|
||||
# or (['sensor', 'ultrasonic'], 'sensor.ultrasonic')
|
||||
self.output_paths = [] # type: List[Tuple[ConfigPath, str]]
|
||||
self.output_paths: list[tuple[ConfigPath, str]] = []
|
||||
# A list of components ids with the config path
|
||||
self.declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
|
||||
self.declare_ids: list[tuple[core.ID, ConfigPath]] = []
|
||||
self._data = {}
|
||||
# Store pending validation tasks (in heap order)
|
||||
self._validation_tasks: List[_ValidationStepTask] = []
|
||||
self._validation_tasks: list[_ValidationStepTask] = []
|
||||
# ID to ensure stable order for keys with equal priority
|
||||
self._validation_tasks_id = 0
|
||||
|
||||
def add_error(self, error):
|
||||
# type: (vol.Invalid) -> None
|
||||
def add_error(self, error: vol.Invalid) -> None:
|
||||
if isinstance(error, vol.MultipleInvalid):
|
||||
for err in error.errors:
|
||||
self.add_error(err)
|
||||
|
@ -132,20 +131,16 @@ class Config(OrderedDict, fv.FinalValidateConfig):
|
|||
e.prepend(path)
|
||||
self.add_error(e)
|
||||
|
||||
def add_str_error(self, message, path):
|
||||
# type: (str, ConfigPath) -> None
|
||||
def add_str_error(self, message: str, path: ConfigPath) -> None:
|
||||
self.add_error(vol.Invalid(message, path))
|
||||
|
||||
def add_output_path(self, path, domain):
|
||||
# type: (ConfigPath, str) -> None
|
||||
def add_output_path(self, path: ConfigPath, domain: str) -> None:
|
||||
self.output_paths.append((path, domain))
|
||||
|
||||
def remove_output_path(self, path, domain):
|
||||
# type: (ConfigPath, str) -> None
|
||||
def remove_output_path(self, path: ConfigPath, domain: str) -> None:
|
||||
self.output_paths.remove((path, domain))
|
||||
|
||||
def is_in_error_path(self, path):
|
||||
# type: (ConfigPath) -> bool
|
||||
def is_in_error_path(self, path: ConfigPath) -> bool:
|
||||
for err in self.errors:
|
||||
if _path_begins_with(err.path, path):
|
||||
return True
|
||||
|
@ -157,16 +152,16 @@ class Config(OrderedDict, fv.FinalValidateConfig):
|
|||
conf = conf[key]
|
||||
conf[path[-1]] = value
|
||||
|
||||
def get_error_for_path(self, path):
|
||||
# type: (ConfigPath) -> Optional[vol.Invalid]
|
||||
def get_error_for_path(self, path: ConfigPath) -> Optional[vol.Invalid]:
|
||||
for err in self.errors:
|
||||
if self.get_deepest_path(err.path) == path:
|
||||
self.errors.remove(err)
|
||||
return err
|
||||
return None
|
||||
|
||||
def get_deepest_document_range_for_path(self, path, get_key=False):
|
||||
# type: (ConfigPath, bool) -> Optional[ESPHomeDataBase]
|
||||
def get_deepest_document_range_for_path(
|
||||
self, path: ConfigPath, get_key: bool = False
|
||||
) -> Optional[ESPHomeDataBase]:
|
||||
data = self
|
||||
doc_range = None
|
||||
for index, path_item in enumerate(path):
|
||||
|
@ -207,8 +202,7 @@ class Config(OrderedDict, fv.FinalValidateConfig):
|
|||
return {}
|
||||
return data
|
||||
|
||||
def get_deepest_path(self, path):
|
||||
# type: (ConfigPath) -> ConfigPath
|
||||
def get_deepest_path(self, path: ConfigPath) -> ConfigPath:
|
||||
"""Return the path that is the deepest reachable by following path."""
|
||||
data = self
|
||||
part = []
|
||||
|
@ -532,7 +526,7 @@ class IDPassValidationStep(ConfigValidationStep):
|
|||
# because the component that did not validate doesn't have any IDs set
|
||||
return
|
||||
|
||||
searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
|
||||
searching_ids: list[tuple[core.ID, ConfigPath]] = []
|
||||
for id, path in iter_ids(result):
|
||||
if id.is_declaration:
|
||||
if id.id is not None:
|
||||
|
@ -780,8 +774,7 @@ def _get_parent_name(path, config):
|
|||
return path[-1]
|
||||
|
||||
|
||||
def _format_vol_invalid(ex, config):
|
||||
# type: (vol.Invalid, Config) -> str
|
||||
def _format_vol_invalid(ex: vol.Invalid, config: Config) -> str:
|
||||
message = ""
|
||||
|
||||
paren = _get_parent_name(ex.path[:-1], config)
|
||||
|
@ -862,8 +855,9 @@ def _print_on_next_line(obj):
|
|||
return False
|
||||
|
||||
|
||||
def dump_dict(config, path, at_root=True):
|
||||
# type: (Config, ConfigPath, bool) -> Tuple[str, bool]
|
||||
def dump_dict(
|
||||
config: Config, path: ConfigPath, at_root: bool = True
|
||||
) -> tuple[str, bool]:
|
||||
conf = config.get_nested_item(path)
|
||||
ret = ""
|
||||
multiline = False
|
||||
|
|
|
@ -5,8 +5,7 @@ from esphome.core import CORE
|
|||
from esphome.helpers import read_file
|
||||
|
||||
|
||||
def read_config_file(path):
|
||||
# type: (str) -> str
|
||||
def read_config_file(path: str) -> str:
|
||||
if CORE.vscode and (
|
||||
not CORE.ace or os.path.abspath(path) == os.path.abspath(CORE.config_path)
|
||||
):
|
||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
|||
import math
|
||||
import os
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
from esphome.const import (
|
||||
CONF_COMMENT,
|
||||
|
@ -469,19 +469,19 @@ class EsphomeCore:
|
|||
# Task counter for pending tasks
|
||||
self.task_counter = 0
|
||||
# The variable cache, for each ID this holds a MockObj of the variable obj
|
||||
self.variables: Dict[str, "MockObj"] = {}
|
||||
self.variables: dict[str, "MockObj"] = {}
|
||||
# A list of statements that go in the main setup() block
|
||||
self.main_statements: List["Statement"] = []
|
||||
self.main_statements: list["Statement"] = []
|
||||
# A list of statements to insert in the global block (includes and global variables)
|
||||
self.global_statements: List["Statement"] = []
|
||||
self.global_statements: list["Statement"] = []
|
||||
# A set of platformio libraries to add to the project
|
||||
self.libraries: List[Library] = []
|
||||
self.libraries: list[Library] = []
|
||||
# A set of build flags to set in the platformio project
|
||||
self.build_flags: Set[str] = set()
|
||||
self.build_flags: set[str] = set()
|
||||
# A set of defines to set for the compile process in esphome/core/defines.h
|
||||
self.defines: Set["Define"] = set()
|
||||
self.defines: set["Define"] = set()
|
||||
# A map of all platformio options to apply
|
||||
self.platformio_options: Dict[str, Union[str, List[str]]] = {}
|
||||
self.platformio_options: dict[str, Union[str, list[str]]] = {}
|
||||
# A set of strings of names of loaded integrations, used to find namespace ID conflicts
|
||||
self.loaded_integrations = set()
|
||||
# A set of component IDs to track what Component subclasses are declared
|
||||
|
@ -701,7 +701,7 @@ class EsphomeCore:
|
|||
_LOGGER.debug("Adding define: %s", define)
|
||||
return define
|
||||
|
||||
def add_platformio_option(self, key: str, value: Union[str, List[str]]) -> None:
|
||||
def add_platformio_option(self, key: str, value: Union[str, list[str]]) -> None:
|
||||
new_val = value
|
||||
old_val = self.platformio_options.get(key)
|
||||
if isinstance(old_val, list):
|
||||
|
@ -734,7 +734,7 @@ class EsphomeCore:
|
|||
_LOGGER.debug("Waiting for variable %s", id)
|
||||
yield
|
||||
|
||||
async def get_variable_with_full_id(self, id: ID) -> Tuple[ID, "MockObj"]:
|
||||
async def get_variable_with_full_id(self, id: ID) -> tuple[ID, "MockObj"]:
|
||||
if not isinstance(id, ID):
|
||||
raise ValueError(f"ID {id!r} must be of type ID!")
|
||||
return await _FakeAwaitable(self._get_variable_with_full_id_generator(id))
|
||||
|
|
|
@ -48,7 +48,8 @@ import heapq
|
|||
import inspect
|
||||
import logging
|
||||
import types
|
||||
from typing import Any, Awaitable, Callable, Generator, Iterator, List, Tuple
|
||||
from typing import Any, Callable
|
||||
from collections.abc import Awaitable, Generator, Iterator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -177,7 +178,7 @@ class _Task:
|
|||
return _Task(priority, self.id_number, self.iterator, self.original_function)
|
||||
|
||||
@property
|
||||
def _cmp_tuple(self) -> Tuple[float, int]:
|
||||
def _cmp_tuple(self) -> tuple[float, int]:
|
||||
return (-self.priority, self.id_number)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
@ -194,7 +195,7 @@ class FakeEventLoop:
|
|||
"""Emulate an asyncio EventLoop to run some registered coroutine jobs in sequence."""
|
||||
|
||||
def __init__(self):
|
||||
self._pending_tasks: List[_Task] = []
|
||||
self._pending_tasks: list[_Task] = []
|
||||
self._task_counter = 0
|
||||
|
||||
def add_job(self, func, *args, **kwargs):
|
||||
|
|
|
@ -8,14 +8,10 @@ from esphome.yaml_util import ESPHomeDataBase
|
|||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Generator,
|
||||
List,
|
||||
Optional,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
Sequence,
|
||||
)
|
||||
from collections.abc import Generator, Sequence
|
||||
|
||||
from esphome.core import ( # noqa
|
||||
CORE,
|
||||
|
@ -54,9 +50,9 @@ SafeExpType = Union[
|
|||
int,
|
||||
float,
|
||||
TimePeriod,
|
||||
Type[bool],
|
||||
Type[int],
|
||||
Type[float],
|
||||
type[bool],
|
||||
type[int],
|
||||
type[float],
|
||||
Sequence[Any],
|
||||
]
|
||||
|
||||
|
@ -150,7 +146,7 @@ class CallExpression(Expression):
|
|||
class StructInitializer(Expression):
|
||||
__slots__ = ("base", "args")
|
||||
|
||||
def __init__(self, base: Expression, *args: Tuple[str, Optional[SafeExpType]]):
|
||||
def __init__(self, base: Expression, *args: tuple[str, Optional[SafeExpType]]):
|
||||
self.base = base
|
||||
# TODO: args is always a Tuple, is this check required?
|
||||
if not isinstance(args, OrderedDict):
|
||||
|
@ -210,7 +206,7 @@ class ParameterListExpression(Expression):
|
|||
__slots__ = ("parameters",)
|
||||
|
||||
def __init__(
|
||||
self, *parameters: Union[ParameterExpression, Tuple[SafeExpType, str]]
|
||||
self, *parameters: Union[ParameterExpression, tuple[SafeExpType, str]]
|
||||
):
|
||||
self.parameters = []
|
||||
for parameter in parameters:
|
||||
|
@ -629,7 +625,7 @@ def add_define(name: str, value: SafeExpType = None):
|
|||
CORE.add_define(Define(name, safe_exp(value)))
|
||||
|
||||
|
||||
def add_platformio_option(key: str, value: Union[str, List[str]]):
|
||||
def add_platformio_option(key: str, value: Union[str, list[str]]):
|
||||
CORE.add_platformio_option(key, value)
|
||||
|
||||
|
||||
|
@ -646,7 +642,7 @@ async def get_variable(id_: ID) -> "MockObj":
|
|||
return await CORE.get_variable(id_)
|
||||
|
||||
|
||||
async def get_variable_with_full_id(id_: ID) -> Tuple[ID, "MockObj"]:
|
||||
async def get_variable_with_full_id(id_: ID) -> tuple[ID, "MockObj"]:
|
||||
"""
|
||||
Wait for the given ID to be defined in the code generation and
|
||||
return it as a MockObj.
|
||||
|
@ -661,7 +657,7 @@ async def get_variable_with_full_id(id_: ID) -> Tuple[ID, "MockObj"]:
|
|||
|
||||
async def process_lambda(
|
||||
value: Lambda,
|
||||
parameters: List[Tuple[SafeExpType, str]],
|
||||
parameters: list[tuple[SafeExpType, str]],
|
||||
capture: str = "=",
|
||||
return_type: SafeExpType = None,
|
||||
) -> Generator[LambdaExpression, None, None]:
|
||||
|
@ -715,7 +711,7 @@ def is_template(value):
|
|||
|
||||
async def templatable(
|
||||
value: Any,
|
||||
args: List[Tuple[SafeExpType, str]],
|
||||
args: list[tuple[SafeExpType, str]],
|
||||
output_type: Optional[SafeExpType],
|
||||
to_exp: Any = None,
|
||||
):
|
||||
|
@ -763,7 +759,7 @@ class MockObj(Expression):
|
|||
attr = attr[1:]
|
||||
return MockObj(f"{self.base}{self.op}{attr}", next_op)
|
||||
|
||||
def __call__(self, *args): # type: (SafeExpType) -> MockObj
|
||||
def __call__(self, *args: SafeExpType) -> "MockObj":
|
||||
call = CallExpression(self.base, *args)
|
||||
return MockObj(call, self.op)
|
||||
|
||||
|
|
|
@ -107,8 +107,9 @@ async def setup_entity(var, config):
|
|||
add(var.set_entity_category(config[CONF_ENTITY_CATEGORY]))
|
||||
|
||||
|
||||
def extract_registry_entry_config(registry, full_config):
|
||||
# type: (Registry, ConfigType) -> RegistryEntry
|
||||
def extract_registry_entry_config(
|
||||
registry: Registry, full_config: ConfigType
|
||||
) -> RegistryEntry:
|
||||
key, config = next((k, v) for k, v in full_config.items() if k in registry)
|
||||
return registry[key], config
|
||||
|
||||
|
|
|
@ -522,7 +522,7 @@ class DashboardEntry:
|
|||
return os.path.basename(self.path)
|
||||
|
||||
@property
|
||||
def storage(self): # type: () -> Optional[StorageJSON]
|
||||
def storage(self) -> Optional[StorageJSON]:
|
||||
if not self._loaded_storage:
|
||||
self._storage = StorageJSON.load(
|
||||
ext_storage_path(settings.config_dir, self.filename)
|
||||
|
@ -817,7 +817,7 @@ class UndoDeleteRequestHandler(BaseHandler):
|
|||
shutil.move(os.path.join(trash_path, configuration), config_file)
|
||||
|
||||
|
||||
PING_RESULT = {} # type: dict
|
||||
PING_RESULT: dict = {}
|
||||
IMPORT_RESULT = {}
|
||||
STOP_EVENT = threading.Event()
|
||||
PING_REQUEST = threading.Event()
|
||||
|
@ -933,7 +933,7 @@ def get_static_path(*args):
|
|||
return os.path.join(get_base_frontend_path(), "static", *args)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
@functools.cache
|
||||
def get_static_file_url(name):
|
||||
base = f"./static/{name}"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Any
|
||||
from typing import Any
|
||||
import contextvars
|
||||
|
||||
from esphome.types import ConfigFragmentType, ID, ConfigPathType
|
||||
|
@ -9,7 +9,7 @@ import esphome.config_validation as cv
|
|||
class FinalValidateConfig(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def data(self) -> Dict[str, Any]:
|
||||
def data(self) -> dict[str, Any]:
|
||||
"""A dictionary that can be used by post validation functions to store
|
||||
global data during the validation phase. Each component should store its
|
||||
data under a unique key
|
||||
|
|
|
@ -40,7 +40,7 @@ def indent(text, padding=" "):
|
|||
|
||||
# From https://stackoverflow.com/a/14945195/8924614
|
||||
def cpp_string_escape(string, encoding="utf-8"):
|
||||
def _should_escape(byte): # type: (int) -> bool
|
||||
def _should_escape(byte: int) -> bool:
|
||||
if not 32 <= byte < 127:
|
||||
return True
|
||||
if byte in (ord("\\"), ord('"')):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import logging
|
||||
from typing import Callable, List, Optional, Any, ContextManager
|
||||
from typing import Callable, Optional, Any, ContextManager
|
||||
from types import ModuleType
|
||||
import importlib
|
||||
import importlib.util
|
||||
|
@ -62,19 +62,19 @@ class ComponentManifest:
|
|||
return getattr(self.module, "to_code", None)
|
||||
|
||||
@property
|
||||
def dependencies(self) -> List[str]:
|
||||
def dependencies(self) -> list[str]:
|
||||
return getattr(self.module, "DEPENDENCIES", [])
|
||||
|
||||
@property
|
||||
def conflicts_with(self) -> List[str]:
|
||||
def conflicts_with(self) -> list[str]:
|
||||
return getattr(self.module, "CONFLICTS_WITH", [])
|
||||
|
||||
@property
|
||||
def auto_load(self) -> List[str]:
|
||||
def auto_load(self) -> list[str]:
|
||||
return getattr(self.module, "AUTO_LOAD", [])
|
||||
|
||||
@property
|
||||
def codeowners(self) -> List[str]:
|
||||
def codeowners(self) -> list[str]:
|
||||
return getattr(self.module, "CODEOWNERS", [])
|
||||
|
||||
@property
|
||||
|
@ -87,7 +87,7 @@ class ComponentManifest:
|
|||
return getattr(self.module, "FINAL_VALIDATE_SCHEMA", None)
|
||||
|
||||
@property
|
||||
def resources(self) -> List[FileResource]:
|
||||
def resources(self) -> list[FileResource]:
|
||||
"""Return a list of all file resources defined in the package of this component.
|
||||
|
||||
This will return all cpp source files that are located in the same folder as the
|
||||
|
@ -106,7 +106,7 @@ class ComponentManifest:
|
|||
|
||||
class ComponentMetaFinder(importlib.abc.MetaPathFinder):
|
||||
def __init__(
|
||||
self, components_path: Path, allowed_components: Optional[List[str]] = None
|
||||
self, components_path: Path, allowed_components: Optional[list[str]] = None
|
||||
) -> None:
|
||||
self._allowed_components = allowed_components
|
||||
self._finders = []
|
||||
|
@ -117,7 +117,7 @@ class ComponentMetaFinder(importlib.abc.MetaPathFinder):
|
|||
continue
|
||||
self._finders.append(finder)
|
||||
|
||||
def find_spec(self, fullname: str, path: Optional[List[str]], target=None):
|
||||
def find_spec(self, fullname: str, path: Optional[list[str]], target=None):
|
||||
if not fullname.startswith("esphome.components."):
|
||||
return None
|
||||
parts = fullname.split(".")
|
||||
|
@ -144,7 +144,7 @@ def clear_component_meta_finders():
|
|||
|
||||
|
||||
def install_meta_finder(
|
||||
components_path: Path, allowed_components: Optional[List[str]] = None
|
||||
components_path: Path, allowed_components: Optional[list[str]] = None
|
||||
):
|
||||
sys.meta_path.insert(0, ComponentMetaFinder(components_path, allowed_components))
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from dataclasses import dataclass
|
||||
import json
|
||||
from typing import List, Union
|
||||
from typing import Union
|
||||
from pathlib import Path
|
||||
|
||||
import logging
|
||||
|
@ -310,7 +310,7 @@ class IDEData:
|
|||
return str(Path(self.firmware_elf_path).with_suffix(".bin"))
|
||||
|
||||
@property
|
||||
def extra_flash_images(self) -> List[FlashImage]:
|
||||
def extra_flash_images(self) -> list[FlashImage]:
|
||||
return [
|
||||
FlashImage(path=entry["path"], offset=entry["offset"])
|
||||
for entry in self.raw["extra"]["flash_images"]
|
||||
|
|
|
@ -4,7 +4,7 @@ from datetime import datetime
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Optional, List
|
||||
from typing import Optional
|
||||
|
||||
from esphome import const
|
||||
from esphome.core import CORE
|
||||
|
@ -15,19 +15,19 @@ from esphome.types import CoreType
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def storage_path(): # type: () -> str
|
||||
def storage_path() -> str:
|
||||
return CORE.relative_internal_path(f"{CORE.config_filename}.json")
|
||||
|
||||
|
||||
def ext_storage_path(base_path, config_filename): # type: (str, str) -> str
|
||||
def ext_storage_path(base_path: str, config_filename: str) -> str:
|
||||
return os.path.join(base_path, ".esphome", f"{config_filename}.json")
|
||||
|
||||
|
||||
def esphome_storage_path(base_path): # type: (str) -> str
|
||||
def esphome_storage_path(base_path: str) -> str:
|
||||
return os.path.join(base_path, ".esphome", "esphome.json")
|
||||
|
||||
|
||||
def trash_storage_path(base_path): # type: (str) -> str
|
||||
def trash_storage_path(base_path: str) -> str:
|
||||
return os.path.join(base_path, ".esphome", "trash")
|
||||
|
||||
|
||||
|
@ -49,29 +49,29 @@ class StorageJSON:
|
|||
):
|
||||
# Version of the storage JSON schema
|
||||
assert storage_version is None or isinstance(storage_version, int)
|
||||
self.storage_version = storage_version # type: int
|
||||
self.storage_version: int = storage_version
|
||||
# The name of the node
|
||||
self.name = name # type: str
|
||||
self.name: str = name
|
||||
# The comment of the node
|
||||
self.comment = comment # type: str
|
||||
self.comment: str = comment
|
||||
# The esphome version this was compiled with
|
||||
self.esphome_version = esphome_version # type: str
|
||||
self.esphome_version: str = 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 = src_version # type: int
|
||||
self.src_version: int = src_version
|
||||
# Address of the ESP, for example livingroom.local or a static IP
|
||||
self.address = address # type: str
|
||||
self.address: str = address
|
||||
# Web server port of the ESP, for example 80
|
||||
assert web_port is None or isinstance(web_port, int)
|
||||
self.web_port = web_port # type: int
|
||||
self.web_port: int = web_port
|
||||
# The type of hardware in use, like "ESP32", "ESP32C3", "ESP8266", etc.
|
||||
self.target_platform = target_platform # type: str
|
||||
self.target_platform: str = target_platform
|
||||
# The absolute path to the platformio project
|
||||
self.build_path = build_path # type: str
|
||||
self.build_path: str = build_path
|
||||
# The absolute path to the firmware binary
|
||||
self.firmware_bin_path = firmware_bin_path # type: str
|
||||
self.firmware_bin_path: str = firmware_bin_path
|
||||
# A list of strings of names of loaded integrations
|
||||
self.loaded_integrations = loaded_integrations # type: List[str]
|
||||
self.loaded_integrations: list[str] = loaded_integrations
|
||||
self.loaded_integrations.sort()
|
||||
|
||||
def as_dict(self):
|
||||
|
@ -97,8 +97,8 @@ class StorageJSON:
|
|||
|
||||
@staticmethod
|
||||
def from_esphome_core(
|
||||
esph, old
|
||||
): # type: (CoreType, Optional[StorageJSON]) -> StorageJSON
|
||||
esph: CoreType, old: Optional["StorageJSON"]
|
||||
) -> "StorageJSON":
|
||||
hardware = esph.target_platform.upper()
|
||||
if esph.is_esp32:
|
||||
from esphome.components import esp32
|
||||
|
@ -135,7 +135,7 @@ class StorageJSON:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def _load_impl(path): # type: (str) -> Optional[StorageJSON]
|
||||
def _load_impl(path: str) -> Optional["StorageJSON"]:
|
||||
with codecs.open(path, "r", encoding="utf-8") as f_handle:
|
||||
storage = json.load(f_handle)
|
||||
storage_version = storage["storage_version"]
|
||||
|
@ -166,13 +166,13 @@ class StorageJSON:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def load(path): # type: (str) -> Optional[StorageJSON]
|
||||
def load(path: str) -> Optional["StorageJSON"]:
|
||||
try:
|
||||
return StorageJSON._load_impl(path)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return None
|
||||
|
||||
def __eq__(self, o): # type: (Any) -> bool
|
||||
def __eq__(self, o) -> bool:
|
||||
return isinstance(o, StorageJSON) and self.as_dict() == o.as_dict()
|
||||
|
||||
|
||||
|
@ -182,15 +182,15 @@ class EsphomeStorageJSON:
|
|||
):
|
||||
# Version of the storage JSON schema
|
||||
assert storage_version is None or isinstance(storage_version, int)
|
||||
self.storage_version = storage_version # type: int
|
||||
self.storage_version: int = storage_version
|
||||
# The cookie secret for the dashboard
|
||||
self.cookie_secret = cookie_secret # type: str
|
||||
self.cookie_secret: str = cookie_secret
|
||||
# The last time ESPHome checked for an update as an isoformat encoded str
|
||||
self.last_update_check_str = last_update_check # type: str
|
||||
self.last_update_check_str: str = last_update_check
|
||||
# Cache of the version gotten in the last version check
|
||||
self.remote_version = remote_version # type: Optional[str]
|
||||
self.remote_version: Optional[str] = remote_version
|
||||
|
||||
def as_dict(self): # type: () -> dict
|
||||
def as_dict(self) -> dict:
|
||||
return {
|
||||
"storage_version": self.storage_version,
|
||||
"cookie_secret": self.cookie_secret,
|
||||
|
@ -199,24 +199,24 @@ class EsphomeStorageJSON:
|
|||
}
|
||||
|
||||
@property
|
||||
def last_update_check(self): # type: () -> Optional[datetime]
|
||||
def last_update_check(self) -> Optional[datetime]:
|
||||
try:
|
||||
return datetime.strptime(self.last_update_check_str, "%Y-%m-%dT%H:%M:%S")
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return None
|
||||
|
||||
@last_update_check.setter
|
||||
def last_update_check(self, new): # type: (datetime) -> None
|
||||
def last_update_check(self, new: datetime) -> None:
|
||||
self.last_update_check_str = new.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
|
||||
def to_json(self): # type: () -> dict
|
||||
def to_json(self) -> dict:
|
||||
return f"{json.dumps(self.as_dict(), indent=2)}\n"
|
||||
|
||||
def save(self, path): # type: (str) -> None
|
||||
def save(self, path: str) -> None:
|
||||
write_file_if_changed(path, self.to_json())
|
||||
|
||||
@staticmethod
|
||||
def _load_impl(path): # type: (str) -> Optional[EsphomeStorageJSON]
|
||||
def _load_impl(path: str) -> Optional["EsphomeStorageJSON"]:
|
||||
with codecs.open(path, "r", encoding="utf-8") as f_handle:
|
||||
storage = json.load(f_handle)
|
||||
storage_version = storage["storage_version"]
|
||||
|
@ -228,14 +228,14 @@ class EsphomeStorageJSON:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def load(path): # type: (str) -> Optional[EsphomeStorageJSON]
|
||||
def load(path: str) -> Optional["EsphomeStorageJSON"]:
|
||||
try:
|
||||
return EsphomeStorageJSON._load_impl(path)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_default(): # type: () -> EsphomeStorageJSON
|
||||
def get_default() -> "EsphomeStorageJSON":
|
||||
return EsphomeStorageJSON(
|
||||
storage_version=1,
|
||||
cookie_secret=binascii.hexlify(os.urandom(64)).decode(),
|
||||
|
@ -243,5 +243,5 @@ class EsphomeStorageJSON:
|
|||
remote_version=None,
|
||||
)
|
||||
|
||||
def __eq__(self, o): # type: (Any) -> bool
|
||||
def __eq__(self, o) -> bool:
|
||||
return isinstance(o, EsphomeStorageJSON) and self.as_dict() == o.as_dict()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""This helper module tracks commonly used types in the esphome python codebase."""
|
||||
from typing import Dict, Union, List
|
||||
from typing import Union
|
||||
|
||||
from esphome.core import ID, Lambda, EsphomeCore
|
||||
|
||||
|
@ -8,11 +8,11 @@ ConfigFragmentType = Union[
|
|||
int,
|
||||
float,
|
||||
None,
|
||||
Dict[Union[str, int], "ConfigFragmentType"],
|
||||
List["ConfigFragmentType"],
|
||||
dict[Union[str, int], "ConfigFragmentType"],
|
||||
list["ConfigFragmentType"],
|
||||
ID,
|
||||
Lambda,
|
||||
]
|
||||
ConfigType = Dict[str, ConfigFragmentType]
|
||||
ConfigType = dict[str, ConfigFragmentType]
|
||||
CoreType = EsphomeCore
|
||||
ConfigPathType = Union[str, int]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import typing
|
||||
from typing import Union, List
|
||||
from typing import Union
|
||||
|
||||
import collections
|
||||
import io
|
||||
|
@ -242,7 +241,7 @@ def is_dev_esphome_version():
|
|||
return "dev" in const.__version__
|
||||
|
||||
|
||||
def parse_esphome_version() -> typing.Tuple[int, int, int]:
|
||||
def parse_esphome_version() -> tuple[int, int, int]:
|
||||
match = re.match(r"^(\d+).(\d+).(\d+)(-dev\d*|b\d*)?$", const.__version__)
|
||||
if match is None:
|
||||
raise ValueError(f"Failed to parse ESPHome version '{const.__version__}'")
|
||||
|
@ -282,7 +281,7 @@ class SerialPort:
|
|||
|
||||
|
||||
# from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py
|
||||
def get_serial_ports() -> List[SerialPort]:
|
||||
def get_serial_ports() -> list[SerialPort]:
|
||||
from serial.tools.list_ports import comports
|
||||
|
||||
result = []
|
||||
|
|
|
@ -10,15 +10,13 @@ import esphome.config_validation as cv
|
|||
from typing import Optional
|
||||
|
||||
|
||||
def _get_invalid_range(res, invalid):
|
||||
# type: (Config, cv.Invalid) -> Optional[DocumentRange]
|
||||
def _get_invalid_range(res: Config, invalid: cv.Invalid) -> Optional[DocumentRange]:
|
||||
return res.get_deepest_document_range_for_path(
|
||||
invalid.path, invalid.error_message == "extra keys not allowed"
|
||||
)
|
||||
|
||||
|
||||
def _dump_range(range):
|
||||
# type: (Optional[DocumentRange]) -> Optional[dict]
|
||||
def _dump_range(range: Optional[DocumentRange]) -> Optional[dict]:
|
||||
if range is None:
|
||||
return None
|
||||
return {
|
||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
|||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Union
|
||||
from typing import Union
|
||||
|
||||
from esphome.config import iter_components
|
||||
from esphome.const import (
|
||||
|
@ -98,7 +98,7 @@ def replace_file_content(text, pattern, repl):
|
|||
return content_new, count
|
||||
|
||||
|
||||
def storage_should_clean(old, new): # type: (StorageJSON, StorageJSON) -> bool
|
||||
def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool:
|
||||
if old is None:
|
||||
return True
|
||||
|
||||
|
@ -123,7 +123,7 @@ def update_storage_json():
|
|||
new.save(path)
|
||||
|
||||
|
||||
def format_ini(data: Dict[str, Union[str, List[str]]]) -> str:
|
||||
def format_ini(data: dict[str, Union[str, list[str]]]) -> str:
|
||||
content = ""
|
||||
for key, value in sorted(data.items()):
|
||||
if isinstance(value, list):
|
||||
|
@ -226,7 +226,7 @@ the custom_components folder or the external_components feature.
|
|||
|
||||
|
||||
def copy_src_tree():
|
||||
source_files: List[loader.FileResource] = []
|
||||
source_files: list[loader.FileResource] = []
|
||||
for _, component, _ in iter_components(CORE.config):
|
||||
source_files += component.resources
|
||||
source_files_map = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import socket
|
||||
import threading
|
||||
import time
|
||||
from typing import Dict, Optional
|
||||
from typing import Optional
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
@ -71,12 +71,12 @@ class DashboardStatus(threading.Thread):
|
|||
threading.Thread.__init__(self)
|
||||
self.zc = zc
|
||||
self.query_hosts: set[str] = set()
|
||||
self.key_to_host: Dict[str, str] = {}
|
||||
self.key_to_host: dict[str, str] = {}
|
||||
self.stop_event = threading.Event()
|
||||
self.query_event = threading.Event()
|
||||
self.on_update = on_update
|
||||
|
||||
def request_query(self, hosts: Dict[str, str]) -> None:
|
||||
def request_query(self, hosts: dict[str, str]) -> None:
|
||||
self.query_hosts = set(hosts.values())
|
||||
self.key_to_host = hosts
|
||||
self.query_event.set()
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[tool.black]
|
||||
target-version = ["py36", "py37", "py38"]
|
||||
target-version = ["py39", "py310"]
|
||||
exclude = 'generated'
|
||||
|
|
|
@ -109,7 +109,7 @@ def main():
|
|||
print_error(file_, linno, msg)
|
||||
errors += 1
|
||||
|
||||
PYUPGRADE_TARGET = "--py38-plus"
|
||||
PYUPGRADE_TARGET = "--py39-plus"
|
||||
cmd = ["pyupgrade", PYUPGRADE_TARGET] + files
|
||||
print()
|
||||
print("Running pyupgrade...")
|
||||
|
|
2
setup.py
2
setup.py
|
@ -74,7 +74,7 @@ setup(
|
|||
zip_safe=False,
|
||||
platforms="any",
|
||||
test_suite="tests",
|
||||
python_requires=">=3.8,<4.0",
|
||||
python_requires=">=3.9.0",
|
||||
install_requires=REQUIRES,
|
||||
keywords=["home", "automation"],
|
||||
entry_points={"console_scripts": ["esphome = esphome.__main__:main"]},
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
from typing import Text
|
||||
|
||||
import hypothesis.strategies._internal.core as st
|
||||
from hypothesis.strategies._internal.strategies import SearchStrategy
|
||||
|
||||
|
||||
@st.defines_strategy(force_reusable_values=True)
|
||||
def mac_addr_strings():
|
||||
# type: () -> SearchStrategy[Text]
|
||||
def mac_addr_strings() -> SearchStrategy[str]:
|
||||
"""A strategy for MAC address strings.
|
||||
|
||||
This consists of six strings representing integers [0..255],
|
||||
|
|
Loading…
Reference in a new issue