Type check all helpers (#25373)
* Type check all helpers, add inline exclusions for work in progress * Remove unused Script._template_cache * Add some missing type hints * Remove unneeded type: ignore * Type hint fixes * Mypy assistance tweaks * Don't look for None in deprecated config "at most once" check * Avoid None name slugify attempt when generating entity id * Avoid None state store attempt on entity remove
This commit is contained in:
parent
0653f57fb4
commit
d64f1e767c
19 changed files with 119 additions and 69 deletions
|
@ -1,6 +1,6 @@
|
|||
"""Helper to check the configuration file."""
|
||||
from collections import OrderedDict, namedtuple
|
||||
# from typing import Dict, List, Sequence
|
||||
from typing import List
|
||||
|
||||
import attr
|
||||
import voluptuous as vol
|
||||
|
@ -17,6 +17,9 @@ import homeassistant.util.yaml.loader as yaml_loader
|
|||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-warn-return-any
|
||||
|
||||
CheckConfigError = namedtuple(
|
||||
'CheckConfigError', "message domain config")
|
||||
|
||||
|
@ -25,7 +28,8 @@ CheckConfigError = namedtuple(
|
|||
class HomeAssistantConfig(OrderedDict):
|
||||
"""Configuration result with errors attribute."""
|
||||
|
||||
errors = attr.ib(default=attr.Factory(list))
|
||||
errors = attr.ib(
|
||||
default=attr.Factory(list)) # type: List[CheckConfigError]
|
||||
|
||||
def add_error(self, message, domain=None, config=None):
|
||||
"""Add a single error."""
|
||||
|
@ -114,9 +118,10 @@ async def async_check_ha_config_file(hass: HomeAssistant) -> \
|
|||
result.add_error("Component not found: {}".format(domain))
|
||||
continue
|
||||
|
||||
if hasattr(component, 'CONFIG_SCHEMA'):
|
||||
config_schema = getattr(component, 'CONFIG_SCHEMA', None)
|
||||
if config_schema is not None:
|
||||
try:
|
||||
config = component.CONFIG_SCHEMA(config)
|
||||
config = config_schema(config)
|
||||
result[domain] = config[domain]
|
||||
except vol.Invalid as ex:
|
||||
_comp_error(ex, domain, config)
|
||||
|
@ -133,8 +138,7 @@ async def async_check_ha_config_file(hass: HomeAssistant) -> \
|
|||
for p_name, p_config in config_per_platform(config, domain):
|
||||
# Validate component specific platform schema
|
||||
try:
|
||||
p_validated = component_platform_schema( # type: ignore
|
||||
p_config)
|
||||
p_validated = component_platform_schema(p_config)
|
||||
except vol.Invalid as ex:
|
||||
_comp_error(ex, domain, config)
|
||||
continue
|
||||
|
@ -163,9 +167,10 @@ async def async_check_ha_config_file(hass: HomeAssistant) -> \
|
|||
continue
|
||||
|
||||
# Validate platform specific schema
|
||||
if hasattr(platform, 'PLATFORM_SCHEMA'):
|
||||
platform_schema = getattr(platform, 'PLATFORM_SCHEMA', None)
|
||||
if platform_schema is not None:
|
||||
try:
|
||||
p_validated = platform.PLATFORM_SCHEMA(p_validated)
|
||||
p_validated = platform_schema(p_validated)
|
||||
except vol.Invalid as ex:
|
||||
_comp_error(
|
||||
ex, '{}.{}'.format(domain, p_name), p_validated)
|
||||
|
|
|
@ -4,6 +4,8 @@ from functools import partial
|
|||
from homeassistant import config_entries
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-defs
|
||||
|
||||
def register_discovery_flow(domain, title, discovery_function,
|
||||
connection_class):
|
||||
"""Register flow for discovered integrations that not require auth."""
|
||||
|
|
|
@ -27,6 +27,9 @@ from homeassistant.exceptions import TemplateError
|
|||
from homeassistant.helpers.logging import KeywordStyleAdapter
|
||||
from homeassistant.util import slugify as util_slugify
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs, no-warn-return-any
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
TIME_PERIOD_ERROR = "offset {} should be format 'HH:MM' or 'HH:MM:SS'"
|
||||
|
@ -92,7 +95,8 @@ def boolean(value: Any) -> bool:
|
|||
if value in ('0', 'false', 'no', 'off', 'disable'):
|
||||
return False
|
||||
elif isinstance(value, Number):
|
||||
return value != 0
|
||||
# type ignore: https://github.com/python/mypy/issues/3186
|
||||
return value != 0 # type: ignore
|
||||
raise vol.Invalid('invalid boolean value {}'.format(value))
|
||||
|
||||
|
||||
|
@ -161,7 +165,7 @@ def isdir(value: Any) -> str:
|
|||
return dir_in
|
||||
|
||||
|
||||
def ensure_list(value: Union[T, Sequence[T]]) -> Sequence[T]:
|
||||
def ensure_list(value: Union[T, Sequence[T], None]) -> Sequence[T]:
|
||||
"""Wrap value in list if it is not one."""
|
||||
if value is None:
|
||||
return []
|
||||
|
@ -556,7 +560,8 @@ def deprecated(key: str,
|
|||
else:
|
||||
# Unclear when it is None, but it happens, so let's guard.
|
||||
# https://github.com/home-assistant/home-assistant/issues/24982
|
||||
module_name = __name__
|
||||
# type ignore/unreachable: https://github.com/python/typeshed/pull/3137
|
||||
module_name = __name__ # type: ignore
|
||||
|
||||
if replacement_key and invalidation_version:
|
||||
warning = ("The '{key}' option (with value '{value}') is"
|
||||
|
@ -606,13 +611,15 @@ def deprecated(key: str,
|
|||
config.pop(key)
|
||||
else:
|
||||
value = default
|
||||
if (replacement_key
|
||||
and (replacement_key not in config
|
||||
or default == config.get(replacement_key))
|
||||
and value is not None):
|
||||
config[replacement_key] = value
|
||||
keys = [key]
|
||||
if replacement_key:
|
||||
keys.append(replacement_key)
|
||||
if value is not None and (
|
||||
replacement_key not in config or
|
||||
default == config.get(replacement_key)):
|
||||
config[replacement_key] = value
|
||||
|
||||
return has_at_most_one_key(key, replacement_key)(config)
|
||||
return has_at_most_one_key(*keys)(config)
|
||||
|
||||
return validator
|
||||
|
||||
|
@ -739,7 +746,7 @@ CONDITION_SCHEMA = vol.Any(
|
|||
ZONE_CONDITION_SCHEMA,
|
||||
AND_CONDITION_SCHEMA,
|
||||
OR_CONDITION_SCHEMA,
|
||||
)
|
||||
) # type: vol.Schema
|
||||
|
||||
_SCRIPT_DELAY_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_ALIAS): string,
|
||||
|
|
|
@ -7,6 +7,8 @@ from homeassistant.components.http import HomeAssistantView
|
|||
from homeassistant.components.http.data_validator import RequestDataValidator
|
||||
|
||||
|
||||
# mypy: allow-untyped-calls, allow-untyped-defs
|
||||
|
||||
class _BaseFlowManagerView(HomeAssistantView):
|
||||
"""Foundation for flow manager views."""
|
||||
|
||||
|
|
|
@ -12,6 +12,10 @@ from homeassistant.loader import bind_hass
|
|||
|
||||
from .typing import HomeAssistantType
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs, no-warn-return-any
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_UNDEF = object()
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ from homeassistant.exceptions import HomeAssistantError
|
|||
from homeassistant.loader import DEPENDENCY_BLACKLIST
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
EVENT_LOAD_PLATFORM = 'load_platform.{}'
|
||||
ATTR_PLATFORM = 'platform'
|
||||
|
||||
|
|
|
@ -10,14 +10,19 @@ from homeassistant.const import (
|
|||
ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON,
|
||||
STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES, ATTR_DEVICE_CLASS)
|
||||
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_registry import (
|
||||
EVENT_ENTITY_REGISTRY_UPDATED, RegistryEntry)
|
||||
from homeassistant.core import HomeAssistant, callback, CALLBACK_TYPE
|
||||
from homeassistant.config import DATA_CUSTOMIZE
|
||||
from homeassistant.exceptions import NoEntitySpecifiedError
|
||||
from homeassistant.util import ensure_unique_string, slugify
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-defs, no-check-untyped-defs
|
||||
# mypy: no-warn-return-any
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SLOW_UPDATE_WARNING = 10
|
||||
|
||||
|
@ -34,7 +39,7 @@ def generate_entity_id(entity_id_format: str, name: Optional[str],
|
|||
current_ids, hass
|
||||
).result()
|
||||
|
||||
name = (slugify(name) or slugify(DEVICE_DEFAULT_NAME)).lower()
|
||||
name = (slugify(name or "") or slugify(DEVICE_DEFAULT_NAME)).lower()
|
||||
|
||||
return ensure_unique_string(
|
||||
entity_id_format.format(name), current_ids)
|
||||
|
@ -80,10 +85,10 @@ class Entity:
|
|||
parallel_updates = None
|
||||
|
||||
# Entry in the entity registry
|
||||
registry_entry = None
|
||||
registry_entry = None # type: Optional[RegistryEntry]
|
||||
|
||||
# Hold list for functions to call on remove.
|
||||
_on_remove = None
|
||||
_on_remove = None # type: Optional[List[CALLBACK_TYPE]]
|
||||
|
||||
# Context
|
||||
_context = None
|
||||
|
@ -98,7 +103,7 @@ class Entity:
|
|||
return True
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
def unique_id(self) -> Optional[str]:
|
||||
"""Return a unique ID."""
|
||||
return None
|
||||
|
||||
|
@ -137,7 +142,7 @@ class Entity:
|
|||
return None
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
return None
|
||||
|
||||
|
@ -181,7 +186,7 @@ class Entity:
|
|||
return False
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
def supported_features(self) -> Optional[int]:
|
||||
"""Flag supported features."""
|
||||
return None
|
||||
|
||||
|
@ -386,7 +391,7 @@ class Entity:
|
|||
self.parallel_updates.release()
|
||||
|
||||
@callback
|
||||
def async_on_remove(self, func):
|
||||
def async_on_remove(self, func: CALLBACK_TYPE) -> None:
|
||||
"""Add a function to call when entity removed."""
|
||||
if self._on_remove is None:
|
||||
self._on_remove = []
|
||||
|
@ -421,6 +426,7 @@ class Entity:
|
|||
Not to be extended by integrations.
|
||||
"""
|
||||
if self.registry_entry is not None:
|
||||
assert self.hass is not None
|
||||
self.async_on_remove(self.hass.bus.async_listen(
|
||||
EVENT_ENTITY_REGISTRY_UPDATED, self._async_registry_updated))
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ from homeassistant.loader import bind_hass, async_get_integration
|
|||
from homeassistant.util import slugify
|
||||
from .entity_platform import EntityPlatform
|
||||
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
|
||||
DATA_INSTANCES = 'entity_components'
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ from homeassistant.util.async_ import (
|
|||
|
||||
from .event import async_track_time_interval, async_call_later
|
||||
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
SLOW_SETUP_WARNING = 10
|
||||
SLOW_SETUP_MAX_WAIT = 60
|
||||
PLATFORM_NOT_READY_RETRIES = 10
|
||||
|
|
|
@ -23,6 +23,10 @@ from homeassistant.util.yaml import load_yaml
|
|||
|
||||
from .typing import HomeAssistantType
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs, no-warn-return-any
|
||||
|
||||
PATH_REGISTRY = 'entity_registry.yaml'
|
||||
DATA_REGISTRY = 'entity_registry'
|
||||
EVENT_ENTITY_REGISTRY_UPDATED = 'entity_registry_updated'
|
||||
|
@ -48,7 +52,8 @@ class RegistryEntry:
|
|||
config_entry_id = attr.ib(type=str, default=None)
|
||||
disabled_by = attr.ib(
|
||||
type=str, default=None,
|
||||
validator=attr.validators.in_((DISABLED_HASS, DISABLED_USER, None)))
|
||||
validator=attr.validators.in_((DISABLED_HASS, DISABLED_USER, None))
|
||||
) # type: Optional[str]
|
||||
domain = attr.ib(type=str, init=False, repr=False)
|
||||
|
||||
@domain.default
|
||||
|
|
|
@ -7,13 +7,16 @@ import attr
|
|||
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.helpers.sun import get_astral_event_next
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant, callback, CALLBACK_TYPE
|
||||
from homeassistant.const import (
|
||||
ATTR_NOW, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL,
|
||||
SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET, EVENT_CORE_CONFIG_UPDATE)
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs, no-warn-return-any
|
||||
# PyLint does not like the use of threaded_listener_factory
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
|
@ -172,7 +175,7 @@ track_same_state = threaded_listener_factory(async_track_same_state)
|
|||
|
||||
@callback
|
||||
@bind_hass
|
||||
def async_track_point_in_time(hass, action, point_in_time):
|
||||
def async_track_point_in_time(hass, action, point_in_time) -> CALLBACK_TYPE:
|
||||
"""Add a listener that fires once after a specific point in time."""
|
||||
utc_point_in_time = dt_util.as_utc(point_in_time)
|
||||
|
||||
|
@ -190,7 +193,8 @@ track_point_in_time = threaded_listener_factory(async_track_point_in_time)
|
|||
|
||||
@callback
|
||||
@bind_hass
|
||||
def async_track_point_in_utc_time(hass, action, point_in_time):
|
||||
def async_track_point_in_utc_time(
|
||||
hass, action, point_in_time) -> CALLBACK_TYPE:
|
||||
"""Add a listener that fires once after a specific point in UTC time."""
|
||||
# Ensure point_in_time is UTC
|
||||
point_in_time = dt_util.as_utc(point_in_time)
|
||||
|
|
|
@ -3,6 +3,8 @@ import inspect
|
|||
import logging
|
||||
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
class KeywordMessage:
|
||||
"""
|
||||
Represents a logging message with keyword arguments.
|
||||
|
|
|
@ -15,6 +15,10 @@ from homeassistant.exceptions import HomeAssistantError
|
|||
from homeassistant.helpers.json import JSONEncoder
|
||||
from homeassistant.helpers.storage import Store # noqa pylint_disable=unused-import
|
||||
|
||||
|
||||
# mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs
|
||||
# mypy: no-warn-return-any
|
||||
|
||||
DATA_RESTORE_STATE_TASK = 'restore_state_task'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -182,8 +186,8 @@ class RestoreStateData():
|
|||
# we're going to serialize it to JSON and then re-load it.
|
||||
if state is not None:
|
||||
state = State.from_dict(_encode_complex(state.as_dict()))
|
||||
|
||||
self.last_states[entity_id] = StoredState(state, dt_util.utcnow())
|
||||
if state is not None:
|
||||
self.last_states[entity_id] = StoredState(state, dt_util.utcnow())
|
||||
|
||||
self.entity_ids.remove(entity_id)
|
||||
|
||||
|
@ -219,6 +223,7 @@ class RestoreEntity(Entity):
|
|||
|
||||
async def async_internal_added_to_hass(self) -> None:
|
||||
"""Register this entity as a restorable entity."""
|
||||
assert self.hass is not None
|
||||
_, data = await asyncio.gather(
|
||||
super().async_internal_added_to_hass(),
|
||||
RestoreStateData.async_get_instance(self.hass),
|
||||
|
@ -227,6 +232,7 @@ class RestoreEntity(Entity):
|
|||
|
||||
async def async_internal_will_remove_from_hass(self) -> None:
|
||||
"""Run when entity will be removed from hass."""
|
||||
assert self.hass is not None
|
||||
_, data = await asyncio.gather(
|
||||
super().async_internal_will_remove_from_hass(),
|
||||
RestoreStateData.async_get_instance(self.hass),
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
import logging
|
||||
from contextlib import suppress
|
||||
from datetime import datetime
|
||||
from itertools import islice
|
||||
from typing import Optional, Sequence
|
||||
from typing import Optional, Sequence, Callable, Dict, List, Set, Tuple
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import HomeAssistant, Context, callback
|
||||
from homeassistant.core import HomeAssistant, Context, callback, CALLBACK_TYPE
|
||||
from homeassistant.const import CONF_CONDITION, CONF_TIMEOUT
|
||||
from homeassistant import exceptions
|
||||
from homeassistant.helpers import (
|
||||
|
@ -20,6 +21,10 @@ import homeassistant.util.dt as date_util
|
|||
from homeassistant.util.async_ import (
|
||||
run_coroutine_threadsafe, run_callback_threadsafe)
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_ALIAS = 'alias'
|
||||
|
@ -76,7 +81,8 @@ class _SuspendScript(Exception):
|
|||
class Script():
|
||||
"""Representation of a script."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, sequence, name: str = None,
|
||||
def __init__(self, hass: HomeAssistant, sequence,
|
||||
name: Optional[str] = None,
|
||||
change_listener=None) -> None:
|
||||
"""Initialize the script."""
|
||||
self.hass = hass
|
||||
|
@ -85,14 +91,13 @@ class Script():
|
|||
self.name = name
|
||||
self._change_listener = change_listener
|
||||
self._cur = -1
|
||||
self._exception_step = None
|
||||
self._exception_step = None # type: Optional[int]
|
||||
self.last_action = None
|
||||
self.last_triggered = None
|
||||
self.last_triggered = None # type: Optional[datetime]
|
||||
self.can_cancel = any(CONF_DELAY in action or CONF_WAIT_TEMPLATE
|
||||
in action for action in self.sequence)
|
||||
self._async_listener = []
|
||||
self._template_cache = {}
|
||||
self._config_cache = {}
|
||||
self._async_listener = [] # type: List[CALLBACK_TYPE]
|
||||
self._config_cache = {} # type: Dict[Set[Tuple], Callable[..., bool]]
|
||||
self._actions = {
|
||||
ACTION_DELAY: self._async_delay,
|
||||
ACTION_WAIT_TEMPLATE: self._async_wait_template,
|
||||
|
|
|
@ -19,6 +19,9 @@ import homeassistant.helpers.config_validation as cv
|
|||
from homeassistant.util.async_ import run_coroutine_threadsafe
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
CONF_SERVICE = 'service'
|
||||
CONF_SERVICE_TEMPLATE = 'service_template'
|
||||
CONF_SERVICE_ENTITY_ID = 'entity_id'
|
||||
|
|
|
@ -3,7 +3,7 @@ import asyncio
|
|||
from json import JSONEncoder
|
||||
import logging
|
||||
import os
|
||||
from typing import Dict, List, Optional, Callable, Union
|
||||
from typing import Dict, List, Optional, Callable, Union, Any, Type
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import callback
|
||||
|
@ -11,6 +11,10 @@ from homeassistant.loader import bind_hass
|
|||
from homeassistant.util import json as json_util
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-warn-return-any
|
||||
|
||||
STORAGE_DIR = '.storage'
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -48,17 +52,17 @@ class Store:
|
|||
"""Class to help storing data."""
|
||||
|
||||
def __init__(self, hass, version: int, key: str, private: bool = False, *,
|
||||
encoder: JSONEncoder = None):
|
||||
encoder: Optional[Type[JSONEncoder]] = None):
|
||||
"""Initialize storage class."""
|
||||
self.version = version
|
||||
self.key = key
|
||||
self.hass = hass
|
||||
self._private = private
|
||||
self._data = None
|
||||
self._data = None # type: Optional[Dict[str, Any]]
|
||||
self._unsub_delay_listener = None
|
||||
self._unsub_stop_listener = None
|
||||
self._write_lock = asyncio.Lock()
|
||||
self._load_task = None
|
||||
self._load_task = None # type: Optional[asyncio.Future]
|
||||
self._encoder = encoder
|
||||
|
||||
@property
|
||||
|
|
|
@ -12,7 +12,7 @@ from typing import Iterable
|
|||
import jinja2
|
||||
from jinja2 import contextfilter, contextfunction
|
||||
from jinja2.sandbox import ImmutableSandboxedEnvironment
|
||||
from jinja2.utils import Namespace
|
||||
from jinja2.utils import Namespace # type: ignore
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_UNIT_OF_MEASUREMENT,
|
||||
|
@ -26,6 +26,10 @@ from homeassistant.loader import bind_hass
|
|||
from homeassistant.util import convert, dt as dt_util, location as loc_util
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
|
||||
|
||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||
# mypy: no-check-untyped-defs, no-warn-return-any
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_SENTINEL = object()
|
||||
DATE_STR_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
@ -192,14 +196,13 @@ class Template:
|
|||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
if self._compiled is None:
|
||||
self._ensure_compiled()
|
||||
compiled = self._compiled or self._ensure_compiled()
|
||||
|
||||
if variables is not None:
|
||||
kwargs.update(variables)
|
||||
|
||||
try:
|
||||
return self._compiled.render(kwargs).strip()
|
||||
return compiled.render(kwargs).strip()
|
||||
except jinja2.TemplateError as err:
|
||||
raise TemplateError(err)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""JSON utility functions."""
|
||||
import logging
|
||||
from typing import Union, List, Dict, Optional
|
||||
from typing import Union, List, Dict, Optional, Type
|
||||
|
||||
import json
|
||||
import os
|
||||
|
@ -42,7 +42,7 @@ def load_json(filename: str, default: Union[List, Dict, None] = None) \
|
|||
|
||||
def save_json(filename: str, data: Union[List, Dict],
|
||||
private: bool = False, *,
|
||||
encoder: Optional[json.JSONEncoder] = None) -> None:
|
||||
encoder: Optional[Type[json.JSONEncoder]] = None) -> None:
|
||||
"""Save JSON data to a file.
|
||||
|
||||
Returns True on success.
|
||||
|
|
19
mypyrc
19
mypyrc
|
@ -1,21 +1,4 @@
|
|||
homeassistant/*.py
|
||||
homeassistant/auth/
|
||||
homeassistant/helpers/
|
||||
homeassistant/util/
|
||||
homeassistant/helpers/__init__.py
|
||||
homeassistant/helpers/aiohttp_client.py
|
||||
homeassistant/helpers/area_registry.py
|
||||
homeassistant/helpers/condition.py
|
||||
homeassistant/helpers/deprecation.py
|
||||
homeassistant/helpers/dispatcher.py
|
||||
homeassistant/helpers/entity_values.py
|
||||
homeassistant/helpers/entityfilter.py
|
||||
homeassistant/helpers/icon.py
|
||||
homeassistant/helpers/intent.py
|
||||
homeassistant/helpers/json.py
|
||||
homeassistant/helpers/location.py
|
||||
homeassistant/helpers/signal.py
|
||||
homeassistant/helpers/state.py
|
||||
homeassistant/helpers/sun.py
|
||||
homeassistant/helpers/temperature.py
|
||||
homeassistant/helpers/translation.py
|
||||
homeassistant/helpers/typing.py
|
||||
|
|
Loading…
Add table
Reference in a new issue