From e60f9ca3928aef9f546a1ecd70fa525a306a1f5c Mon Sep 17 00:00:00 2001
From: Andrey <andrey-git@users.noreply.github.com>
Date: Fri, 13 Jul 2018 20:14:45 +0300
Subject: [PATCH] More typing (#15449)

## Description:

More typing improvements.

Switch to using `mypy.ini` for flexibility

Add `warn_return_any` check except in `homeassistant.util.yaml` that does typing hacks. Fix some type annotations as resulting from this check and ignore others were fixing is hard.

## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
---
 homeassistant/config.py    | 13 ++++++-------
 homeassistant/core.py      | 11 ++++++-----
 homeassistant/loader.py    |  2 +-
 homeassistant/remote.py    |  2 +-
 homeassistant/setup.py     |  6 +++---
 homeassistant/util/json.py |  2 +-
 mypy.ini                   | 11 +++++++++++
 tox.ini                    |  2 +-
 8 files changed, 30 insertions(+), 19 deletions(-)
 create mode 100644 mypy.ini

diff --git a/homeassistant/config.py b/homeassistant/config.py
index 48632ccab83..2afa943ee50 100644
--- a/homeassistant/config.py
+++ b/homeassistant/config.py
@@ -171,7 +171,8 @@ def get_default_config_dir() -> str:
     return os.path.join(data_dir, CONFIG_DIR_NAME)  # type: ignore
 
 
-def ensure_config_exists(config_dir: str, detect_location: bool = True) -> str:
+def ensure_config_exists(config_dir: str, detect_location: bool = True)\
+        -> Optional[str]:
     """Ensure a configuration file exists in given configuration directory.
 
     Creating a default one if needed.
@@ -187,7 +188,8 @@ def ensure_config_exists(config_dir: str, detect_location: bool = True) -> str:
     return config_path
 
 
-def create_default_config(config_dir, detect_location=True):
+def create_default_config(config_dir: str, detect_location=True)\
+        -> Optional[str]:
     """Create a default configuration file in given configuration directory.
 
     Return path to new config file if success, None if failed.
@@ -286,11 +288,8 @@ async def async_hass_config_yaml(hass):
     return conf
 
 
-def find_config_file(config_dir):
-    """Look in given directory for supported configuration files.
-
-    Async friendly.
-    """
+def find_config_file(config_dir: str) -> Optional[str]:
+    """Look in given directory for supported configuration files."""
     config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
 
     return config_path if os.path.isfile(config_path) else None
diff --git a/homeassistant/core.py b/homeassistant/core.py
index c7aa04910bd..8b534bf1731 100644
--- a/homeassistant/core.py
+++ b/homeassistant/core.py
@@ -106,7 +106,7 @@ class CoreState(enum.Enum):
 
     def __str__(self) -> str:
         """Return the event."""
-        return self.value
+        return self.value  # type: ignore
 
 
 class HomeAssistant(object):
@@ -137,7 +137,7 @@ class HomeAssistant(object):
         # This is a dictionary that any component can store any data on.
         self.data = {}
         self.state = CoreState.not_running
-        self.exit_code = None
+        self.exit_code = 0  # type: int
         self.config_entries = None
 
     @property
@@ -239,7 +239,7 @@ class HomeAssistant(object):
 
         target: target to call.
         """
-        task = self.loop.create_task(target)
+        task = self.loop.create_task(target)  # type: asyncio.tasks.Task
 
         if self._track_task:
             self._pending_tasks.append(task)
@@ -252,7 +252,8 @@ class HomeAssistant(object):
             target: Callable[..., Any],
             *args: Any) -> asyncio.Future:
         """Add an executor job from within the event loop."""
-        task = self.loop.run_in_executor(None, target, *args)
+        task = self.loop.run_in_executor(
+            None, target, *args)  # type: asyncio.Future
 
         # If a task is scheduled
         if self._track_task:
@@ -307,7 +308,7 @@ class HomeAssistant(object):
         """Stop Home Assistant and shuts down all threads."""
         fire_coroutine_threadsafe(self.async_stop(), self.loop)
 
-    async def async_stop(self, exit_code=0) -> None:
+    async def async_stop(self, exit_code: int = 0) -> None:
         """Stop Home Assistant and shuts down all threads.
 
         This method is a coroutine.
diff --git a/homeassistant/loader.py b/homeassistant/loader.py
index b22271d6eb5..52e6b1e7703 100644
--- a/homeassistant/loader.py
+++ b/homeassistant/loader.py
@@ -67,7 +67,7 @@ def get_component(hass, comp_or_platform) -> Optional[ModuleType]:
     Async friendly.
     """
     try:
-        return hass.data[DATA_KEY][comp_or_platform]
+        return hass.data[DATA_KEY][comp_or_platform]  # type: ignore
     except KeyError:
         pass
 
diff --git a/homeassistant/remote.py b/homeassistant/remote.py
index b3e5f417618..ae932b7d955 100644
--- a/homeassistant/remote.py
+++ b/homeassistant/remote.py
@@ -38,7 +38,7 @@ class APIStatus(enum.Enum):
 
     def __str__(self) -> str:
         """Return the state."""
-        return self.value
+        return self.value  # type: ignore
 
 
 class API(object):
diff --git a/homeassistant/setup.py b/homeassistant/setup.py
index 5398cfde963..478320dca27 100644
--- a/homeassistant/setup.py
+++ b/homeassistant/setup.py
@@ -26,7 +26,7 @@ SLOW_SETUP_WARNING = 10
 def setup_component(hass: core.HomeAssistant, domain: str,
                     config: Optional[Dict] = None) -> bool:
     """Set up a component and all its dependencies."""
-    return run_coroutine_threadsafe(
+    return run_coroutine_threadsafe(  # type: ignore
         async_setup_component(hass, domain, config), loop=hass.loop).result()
 
 
@@ -42,7 +42,7 @@ async def async_setup_component(hass: core.HomeAssistant, domain: str,
     setup_tasks = hass.data.get(DATA_SETUP)
 
     if setup_tasks is not None and domain in setup_tasks:
-        return await setup_tasks[domain]
+        return await setup_tasks[domain]  # type: ignore
 
     if config is None:
         config = {}
@@ -53,7 +53,7 @@ async def async_setup_component(hass: core.HomeAssistant, domain: str,
     task = setup_tasks[domain] = hass.async_create_task(
         _async_setup_component(hass, domain, config))
 
-    return await task
+    return await task  # type: ignore
 
 
 async def _async_process_dependencies(hass, config, name, dependencies):
diff --git a/homeassistant/util/json.py b/homeassistant/util/json.py
index 74feb779dcd..1029e58c118 100644
--- a/homeassistant/util/json.py
+++ b/homeassistant/util/json.py
@@ -25,7 +25,7 @@ def load_json(filename: str, default: Union[List, Dict, None] = None) \
     """
     try:
         with open(filename, encoding='utf-8') as fdesc:
-            return json.loads(fdesc.read())
+            return json.loads(fdesc.read())  # type: ignore
     except FileNotFoundError:
         # This is not a fatal error
         _LOGGER.debug('JSON file not found: %s', filename)
diff --git a/mypy.ini b/mypy.ini
new file mode 100644
index 00000000000..3970ea72d47
--- /dev/null
+++ b/mypy.ini
@@ -0,0 +1,11 @@
+[mypy]
+warn_redundant_casts = true
+warn_unused_configs = true
+ignore_missing_imports = true
+follow_imports = silent
+warn_unused_ignores = true
+warn_return_any = true
+
+[mypy-homeassistant.util.yaml]
+warn_return_any = false
+
diff --git a/tox.ini b/tox.ini
index 6e22f2a5e95..fb36ac6511a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -42,4 +42,4 @@ whitelist_externals=/bin/bash
 deps =
      -r{toxinidir}/requirements_test.txt
 commands =
-         /bin/bash -c 'mypy --ignore-missing-imports --follow-imports=silent --strict-optional --warn-unused-ignores homeassistant/*.py homeassistant/util/'
+         /bin/bash -c 'mypy homeassistant/*.py homeassistant/util/'
-- 
GitLab