Bring back typing check. Meanwhile just for homeassistant/*.py (#14410)
* Bring back typing check. Meanwhile just for homeassistant/.py * Change follow-imports to silent. Add a few more checks.
This commit is contained in:
parent
70af7e5fad
commit
7aec098a05
11 changed files with 41 additions and 30 deletions
|
@ -10,8 +10,8 @@ matrix:
|
|||
env: TOXENV=lint
|
||||
- python: "3.5.3"
|
||||
env: TOXENV=pylint
|
||||
# - python: "3.5"
|
||||
# env: TOXENV=typing
|
||||
- python: "3.5.3"
|
||||
env: TOXENV=typing
|
||||
- python: "3.5.3"
|
||||
env: TOXENV=py35
|
||||
- python: "3.6"
|
||||
|
|
|
@ -8,7 +8,8 @@ import subprocess
|
|||
import sys
|
||||
import threading
|
||||
|
||||
from typing import Optional, List
|
||||
from typing import Optional, List, Dict, Any # noqa #pylint: disable=unused-import
|
||||
|
||||
|
||||
from homeassistant import monkey_patch
|
||||
from homeassistant.const import (
|
||||
|
@ -259,7 +260,7 @@ def setup_and_run_hass(config_dir: str,
|
|||
config = {
|
||||
'frontend': {},
|
||||
'demo': {}
|
||||
}
|
||||
} # type: Dict[str, Any]
|
||||
hass = bootstrap.from_config_dict(
|
||||
config, config_dir=config_dir, verbose=args.verbose,
|
||||
skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days,
|
||||
|
|
|
@ -35,7 +35,7 @@ ACCESS_TOKEN_EXPIRATION = timedelta(minutes=30)
|
|||
DATA_REQS = 'auth_reqs_processed'
|
||||
|
||||
|
||||
def generate_secret(entropy=32):
|
||||
def generate_secret(entropy: int = 32) -> str:
|
||||
"""Generate a secret.
|
||||
|
||||
Backport of secrets.token_hex from Python 3.6
|
||||
|
|
|
@ -278,7 +278,8 @@ def async_enable_logging(hass: core.HomeAssistant,
|
|||
|
||||
if log_rotate_days:
|
||||
err_handler = logging.handlers.TimedRotatingFileHandler(
|
||||
err_log_path, when='midnight', backupCount=log_rotate_days)
|
||||
err_log_path, when='midnight',
|
||||
backupCount=log_rotate_days) # type: logging.FileHandler
|
||||
else:
|
||||
err_handler = logging.FileHandler(
|
||||
err_log_path, mode='w', delay=True)
|
||||
|
@ -297,7 +298,7 @@ def async_enable_logging(hass: core.HomeAssistant,
|
|||
EVENT_HOMEASSISTANT_CLOSE, async_stop_async_handler)
|
||||
|
||||
logger = logging.getLogger('')
|
||||
logger.addHandler(async_handler)
|
||||
logger.addHandler(async_handler) # type: ignore
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
# Save the log file location for access by other components.
|
||||
|
|
|
@ -7,7 +7,7 @@ import os
|
|||
import re
|
||||
import shutil
|
||||
# pylint: disable=unused-import
|
||||
from typing import Any, List, Tuple # NOQA
|
||||
from typing import Any, List, Tuple, Optional # NOQA
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
@ -60,7 +60,7 @@ DEFAULT_CORE_CONFIG = (
|
|||
(CONF_TIME_ZONE, 'UTC', 'time_zone', 'Pick yours from here: http://en.wiki'
|
||||
'pedia.org/wiki/List_of_tz_database_time_zones'),
|
||||
(CONF_CUSTOMIZE, '!include customize.yaml', None, 'Customization file'),
|
||||
) # type: Tuple[Tuple[str, Any, Any, str], ...]
|
||||
) # type: Tuple[Tuple[str, Any, Any, Optional[str]], ...]
|
||||
DEFAULT_CONFIG = """
|
||||
# Show links to resources in log and frontend
|
||||
introduction:
|
||||
|
@ -167,7 +167,7 @@ def get_default_config_dir() -> str:
|
|||
"""Put together the default configuration directory based on the OS."""
|
||||
data_dir = os.getenv('APPDATA') if os.name == "nt" \
|
||||
else os.path.expanduser('~')
|
||||
return os.path.join(data_dir, CONFIG_DIR_NAME)
|
||||
return os.path.join(data_dir, CONFIG_DIR_NAME) # type: ignore
|
||||
|
||||
|
||||
def ensure_config_exists(config_dir: str, detect_location: bool = True) -> str:
|
||||
|
|
|
@ -17,7 +17,7 @@ import threading
|
|||
from time import monotonic
|
||||
|
||||
from types import MappingProxyType
|
||||
from typing import Optional, Any, Callable, List # NOQA
|
||||
from typing import Optional, Any, Callable, List, TypeVar, Dict # NOQA
|
||||
|
||||
from async_timeout import timeout
|
||||
import voluptuous as vol
|
||||
|
@ -41,6 +41,8 @@ import homeassistant.util.dt as dt_util
|
|||
import homeassistant.util.location as location
|
||||
from homeassistant.util.unit_system import UnitSystem, METRIC_SYSTEM # NOQA
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
DOMAIN = 'homeassistant'
|
||||
|
||||
# How long we wait for the result of a service call
|
||||
|
@ -70,16 +72,15 @@ def valid_state(state: str) -> bool:
|
|||
return len(state) < 256
|
||||
|
||||
|
||||
def callback(func: Callable[..., None]) -> Callable[..., None]:
|
||||
def callback(func: Callable[..., T]) -> Callable[..., T]:
|
||||
"""Annotation to mark method as safe to call from within the event loop."""
|
||||
# pylint: disable=protected-access
|
||||
func._hass_callback = True
|
||||
setattr(func, '_hass_callback', True)
|
||||
return func
|
||||
|
||||
|
||||
def is_callback(func: Callable[..., Any]) -> bool:
|
||||
"""Check if function is safe to be called in the event loop."""
|
||||
return '_hass_callback' in getattr(func, '__dict__', {})
|
||||
return getattr(func, '_hass_callback', False) is True
|
||||
|
||||
|
||||
@callback
|
||||
|
@ -136,13 +137,14 @@ class HomeAssistant(object):
|
|||
self.data = {}
|
||||
self.state = CoreState.not_running
|
||||
self.exit_code = None
|
||||
self.config_entries = None
|
||||
|
||||
@property
|
||||
def is_running(self) -> bool:
|
||||
"""Return if Home Assistant is running."""
|
||||
return self.state in (CoreState.starting, CoreState.running)
|
||||
|
||||
def start(self) -> None:
|
||||
def start(self) -> int:
|
||||
"""Start home assistant."""
|
||||
# Register the async start
|
||||
fire_coroutine_threadsafe(self.async_start(), self.loop)
|
||||
|
@ -152,13 +154,13 @@ class HomeAssistant(object):
|
|||
# Block until stopped
|
||||
_LOGGER.info("Starting Home Assistant core loop")
|
||||
self.loop.run_forever()
|
||||
return self.exit_code
|
||||
except KeyboardInterrupt:
|
||||
self.loop.call_soon_threadsafe(
|
||||
self.loop.create_task, self.async_stop())
|
||||
self.loop.run_forever()
|
||||
finally:
|
||||
self.loop.close()
|
||||
return self.exit_code
|
||||
|
||||
async def async_start(self):
|
||||
"""Finalize startup from inside the event loop.
|
||||
|
@ -200,7 +202,10 @@ class HomeAssistant(object):
|
|||
self.loop.call_soon_threadsafe(self.async_add_job, target, *args)
|
||||
|
||||
@callback
|
||||
def async_add_job(self, target: Callable[..., None], *args: Any) -> None:
|
||||
def async_add_job(
|
||||
self,
|
||||
target: Callable[..., Any],
|
||||
*args: Any) -> Optional[asyncio.tasks.Task]:
|
||||
"""Add a job from within the eventloop.
|
||||
|
||||
This method must be run in the event loop.
|
||||
|
@ -354,7 +359,7 @@ class EventBus(object):
|
|||
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize a new event bus."""
|
||||
self._listeners = {}
|
||||
self._listeners = {} # type: Dict[str, List[Callable]]
|
||||
self._hass = hass
|
||||
|
||||
@callback
|
||||
|
@ -1039,7 +1044,7 @@ class Config(object):
|
|||
# List of allowed external dirs to access
|
||||
self.whitelist_external_dirs = set()
|
||||
|
||||
def distance(self: object, lat: float, lon: float) -> float:
|
||||
def distance(self, lat: float, lon: float) -> float:
|
||||
"""Calculate distance from Home Assistant.
|
||||
|
||||
Async friendly.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""The exceptions used by Home Assistant."""
|
||||
import jinja2
|
||||
|
||||
|
||||
class HomeAssistantError(Exception):
|
||||
|
@ -22,7 +23,7 @@ class NoEntitySpecifiedError(HomeAssistantError):
|
|||
class TemplateError(HomeAssistantError):
|
||||
"""Error during template rendering."""
|
||||
|
||||
def __init__(self, exception):
|
||||
def __init__(self, exception: jinja2.TemplateError) -> None:
|
||||
"""Init the error."""
|
||||
super().__init__('{}: {}'.format(exception.__class__.__name__,
|
||||
exception))
|
||||
|
|
|
@ -93,7 +93,7 @@ def get_component(hass, comp_or_platform) -> Optional[ModuleType]:
|
|||
# This prevents that when only
|
||||
# custom_components/switch/some_platform.py exists,
|
||||
# the import custom_components.switch would succeed.
|
||||
if module.__spec__.origin == 'namespace':
|
||||
if module.__spec__ and module.__spec__.origin == 'namespace':
|
||||
continue
|
||||
|
||||
_LOGGER.info("Loaded %s from %s", comp_or_platform, path)
|
||||
|
|
|
@ -139,10 +139,11 @@ async def _async_setup_component(hass: core.HomeAssistant,
|
|||
|
||||
try:
|
||||
if hasattr(component, 'async_setup'):
|
||||
result = await component.async_setup(hass, processed_config)
|
||||
result = await component.async_setup( # type: ignore
|
||||
hass, processed_config)
|
||||
else:
|
||||
result = await hass.async_add_job(
|
||||
component.setup, hass, processed_config)
|
||||
component.setup, hass, processed_config) # type: ignore
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Error during setup of component %s", domain)
|
||||
async_notify_setup_error(hass, domain, True)
|
||||
|
@ -165,14 +166,15 @@ async def _async_setup_component(hass: core.HomeAssistant,
|
|||
for entry in hass.config_entries.async_entries(domain):
|
||||
await entry.async_setup(hass, component=component)
|
||||
|
||||
hass.config.components.add(component.DOMAIN)
|
||||
hass.config.components.add(component.DOMAIN) # type: ignore
|
||||
|
||||
# Cleanup
|
||||
if domain in hass.data[DATA_SETUP]:
|
||||
hass.data[DATA_SETUP].pop(domain)
|
||||
|
||||
hass.bus.async_fire(
|
||||
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}
|
||||
EVENT_COMPONENT_LOADED,
|
||||
{ATTR_COMPONENT: component.DOMAIN} # type: ignore
|
||||
)
|
||||
|
||||
return True
|
||||
|
|
|
@ -24,7 +24,7 @@ logging.basicConfig(level=logging.INFO)
|
|||
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
|
||||
|
||||
|
||||
def test_real(func):
|
||||
def check_real(func):
|
||||
"""Force a function to require a keyword _test_real to be passed in."""
|
||||
@functools.wraps(func)
|
||||
def guard_func(*args, **kwargs):
|
||||
|
@ -40,8 +40,8 @@ def test_real(func):
|
|||
|
||||
|
||||
# Guard a few functions that would make network connections
|
||||
location.detect_location_info = test_real(location.detect_location_info)
|
||||
location.elevation = test_real(location.elevation)
|
||||
location.detect_location_info = check_real(location.detect_location_info)
|
||||
location.elevation = check_real(location.elevation)
|
||||
util.get_local_ip = lambda: '127.0.0.1'
|
||||
|
||||
|
||||
|
|
3
tox.ini
3
tox.ini
|
@ -38,7 +38,8 @@ commands =
|
|||
|
||||
[testenv:typing]
|
||||
basepython = {env:PYTHON3_PATH:python3}
|
||||
whitelist_externals=/bin/bash
|
||||
deps =
|
||||
-r{toxinidir}/requirements_test.txt
|
||||
commands =
|
||||
mypy --ignore-missing-imports --follow-imports=skip homeassistant
|
||||
/bin/bash -c 'mypy --ignore-missing-imports --follow-imports=silent homeassistant/*.py'
|
||||
|
|
Loading…
Add table
Reference in a new issue