Add config entries to connection class (#16618)

This commit is contained in:
Paulus Schoutsen 2018-09-17 10:12:46 +02:00 committed by Pascal Vizeli
parent 3e0c6c176a
commit 201fd4afee
24 changed files with 104 additions and 63 deletions

View file

@ -35,4 +35,5 @@ async def _async_has_devices(hass):
config_entry_flow.register_discovery_flow(
DOMAIN, 'Google Cast', _async_has_devices)
DOMAIN, 'Google Cast', _async_has_devices,
config_entries.CONN_CLASS_LOCAL_PUSH)

View file

@ -54,6 +54,7 @@ class ConfigManagerEntryIndexView(HomeAssistantView):
'title': entry.title,
'source': entry.source,
'state': entry.state,
'connection_class': entry.connection_class,
} for entry in hass.config_entries.async_entries()])

View file

@ -2,7 +2,7 @@
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT
from homeassistant.helpers import aiohttp_client
@ -23,10 +23,11 @@ def configured_hosts(hass):
@config_entries.HANDLERS.register(DOMAIN)
class DeconzFlowHandler(data_entry_flow.FlowHandler):
class DeconzFlowHandler(config_entries.ConfigFlow):
"""Handle a deCONZ config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
def __init__(self):
"""Initialize the deCONZ config flow."""

View file

@ -1,7 +1,7 @@
"""Config flow to configure Google Hangouts."""
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import callback
@ -19,10 +19,11 @@ def configured_hangouts(hass):
@config_entries.HANDLERS.register(HANGOUTS_DOMAIN)
class HangoutsFlowHandler(data_entry_flow.FlowHandler):
class HangoutsFlowHandler(config_entries.ConfigFlow):
"""Config flow Google Hangouts."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
def __init__(self):
"""Initialize Google Hangouts config flow."""

View file

@ -1,7 +1,7 @@
"""Config flow to configure the HomematicIP Cloud component."""
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.core import callback
from .const import DOMAIN as HMIPC_DOMAIN
@ -18,10 +18,11 @@ def configured_haps(hass):
@config_entries.HANDLERS.register(HMIPC_DOMAIN)
class HomematicipCloudFlowHandler(data_entry_flow.FlowHandler):
class HomematicipCloudFlowHandler(config_entries.ConfigFlow):
"""Config flow for the HomematicIP Cloud component."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
def __init__(self):
"""Initialize HomematicIP Cloud config flow."""

View file

@ -6,7 +6,7 @@ import os
import async_timeout
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
@ -41,10 +41,11 @@ def _find_username_from_config(hass, filename):
@config_entries.HANDLERS.register(DOMAIN)
class HueFlowHandler(data_entry_flow.FlowHandler):
class HueFlowHandler(config_entries.ConfigFlow):
"""Handle a Hue config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
def __init__(self):
"""Initialize the Hue flow."""

View file

@ -293,4 +293,5 @@ class iOSIdentifyDeviceView(HomeAssistantView):
config_entry_flow.register_discovery_flow(
DOMAIN, 'Home Assistant iOS', lambda *_: True)
DOMAIN, 'Home Assistant iOS', lambda *_: True,
config_entries.CONN_CLASS_CLOUD_PUSH)

View file

@ -15,6 +15,7 @@ class FlowHandler(config_entries.ConfigFlow):
"""Handle a config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""

View file

@ -7,7 +7,7 @@ import os
import async_timeout
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.json import load_json
@ -49,10 +49,11 @@ class CodeInvalid(NestAuthError):
@config_entries.HANDLERS.register(DOMAIN)
class NestFlowHandler(data_entry_flow.FlowHandler):
class NestFlowHandler(config_entries.ConfigFlow):
"""Handle a Nest config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
def __init__(self):
"""Initialize the Nest config flow."""

View file

@ -4,7 +4,7 @@ from collections import OrderedDict
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.const import (
CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE)
@ -23,10 +23,11 @@ def configured_instances(hass):
@config_entries.HANDLERS.register(DOMAIN)
class OpenUvFlowHandler(data_entry_flow.FlowHandler):
class OpenUvFlowHandler(config_entries.ConfigFlow):
"""Handle an OpenUV config flow."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
def __init__(self):
"""Initialize the config flow."""

View file

@ -34,4 +34,5 @@ async def _async_has_devices(hass):
return await hass.async_add_executor_job(soco.discover)
config_entry_flow.register_discovery_flow(DOMAIN, 'Sonos', _async_has_devices)
config_entry_flow.register_discovery_flow(
DOMAIN, 'Sonos', _async_has_devices, config_entries.CONN_CLASS_LOCAL_PUSH)

View file

@ -3,7 +3,7 @@
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
from homeassistant.const import (
CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_ICON, CONF_RADIUS)
from homeassistant.core import callback
@ -20,7 +20,7 @@ def configured_zones(hass):
@config_entries.HANDLERS.register(DOMAIN)
class ZoneFlowHandler(data_entry_flow.FlowHandler):
class ZoneFlowHandler(config_entries.ConfigFlow):
"""Zone config flow."""
VERSION = 1

View file

@ -27,9 +27,10 @@ At a minimum, each config flow will have to define a version number and the
'user' step.
@config_entries.HANDLERS.register(DOMAIN)
class ExampleConfigFlow(data_entry_flow.FlowHandler):
class ExampleConfigFlow(config_entries.ConfigFlow):
VERSION = 1
CONNETION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
async def async_step_user(self, user_input=None):
@ -117,7 +118,7 @@ the flow from the config panel.
import logging
import uuid
from typing import Set, Optional, List # noqa pylint: disable=unused-import
from typing import Set, Optional, List, Dict # noqa pylint: disable=unused-import
from homeassistant import data_entry_flow
from homeassistant.core import callback, HomeAssistant
@ -170,15 +171,23 @@ DISCOVERY_SOURCES = (
EVENT_FLOW_DISCOVERED = 'config_entry_discovered'
CONN_CLASS_CLOUD_PUSH = 'cloud_push'
CONN_CLASS_CLOUD_POLL = 'cloud_poll'
CONN_CLASS_LOCAL_PUSH = 'local_push'
CONN_CLASS_LOCAL_POLL = 'local_poll'
CONN_CLASS_ASSUMED = 'assumed'
CONN_CLASS_UNKNOWN = 'unknown'
class ConfigEntry:
"""Hold a configuration entry."""
__slots__ = ('entry_id', 'version', 'domain', 'title', 'data', 'source',
'state')
'connection_class', 'state')
def __init__(self, version: str, domain: str, title: str, data: dict,
source: str, entry_id: Optional[str] = None,
source: str, connection_class: str,
entry_id: Optional[str] = None,
state: str = ENTRY_STATE_NOT_LOADED) -> None:
"""Initialize a config entry."""
# Unique id of the config entry
@ -199,6 +208,9 @@ class ConfigEntry:
# Source of the configuration (user, discovery, cloud)
self.source = source
# Connection class
self.connection_class = connection_class
# State of the entry (LOADED, NOT_LOADED)
self.state = state
@ -266,6 +278,7 @@ class ConfigEntry:
'title': self.title,
'data': self.data,
'source': self.source,
'connection_class': self.connection_class,
}
@ -352,7 +365,18 @@ class ConfigEntries:
self._entries = []
return
self._entries = [ConfigEntry(**entry) for entry in config['entries']]
self._entries = [
ConfigEntry(
version=entry['version'],
domain=entry['domain'],
entry_id=entry['entry_id'],
data=entry['data'],
source=entry['source'],
title=entry['title'],
# New in 0.79
connection_class=entry.get('connection_class',
CONN_CLASS_UNKNOWN))
for entry in config['entries']]
async def async_forward_entry_setup(self, entry, component):
"""Forward the setup of an entry to a different component.
@ -402,6 +426,7 @@ class ConfigEntries:
title=result['title'],
data=result['data'],
source=flow.context['source'],
connection_class=flow.CONNECTION_CLASS,
)
self._entries.append(entry)
self._async_schedule_save()
@ -469,6 +494,8 @@ async def _old_conf_migrator(old_config):
class ConfigFlow(data_entry_flow.FlowHandler):
"""Base class for config flows with some helpers."""
CONNECTION_CLASS = CONN_CLASS_UNKNOWN
@callback
def _async_current_entries(self):
"""Return current entries."""

View file

@ -1,26 +1,28 @@
"""Helpers for data entry flows for config entries."""
from functools import partial
from homeassistant.core import callback
from homeassistant import config_entries, data_entry_flow
from homeassistant import config_entries
def register_discovery_flow(domain, title, discovery_function):
def register_discovery_flow(domain, title, discovery_function,
connection_class):
"""Register flow for discovered integrations that not require auth."""
config_entries.HANDLERS.register(domain)(
partial(DiscoveryFlowHandler, domain, title, discovery_function))
partial(DiscoveryFlowHandler, domain, title, discovery_function,
connection_class))
class DiscoveryFlowHandler(data_entry_flow.FlowHandler):
class DiscoveryFlowHandler(config_entries.ConfigFlow):
"""Handle a discovery config flow."""
VERSION = 1
def __init__(self, domain, title, discovery_function):
def __init__(self, domain, title, discovery_function, connection_class):
"""Initialize the discovery config flow."""
self._domain = domain
self._title = title
self._discovery_function = discovery_function
self.CONNECTION_CLASS = connection_class # pylint: disable=C0103
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
@ -83,15 +85,3 @@ class DiscoveryFlowHandler(data_entry_flow.FlowHandler):
title=self._title,
data={},
)
@callback
def _async_current_entries(self):
"""Return current entries."""
return self.hass.config_entries.async_entries(self._domain)
@callback
def _async_in_progress(self):
"""Return other in progress flows for current domain."""
return [flw for flw in self.hass.config_entries.flow.async_progress()
if flw['handler'] == self._domain and
flw['flow_id'] != self.flow_id]

View file

@ -550,14 +550,16 @@ class MockConfigEntry(config_entries.ConfigEntry):
def __init__(self, *, domain='test', data=None, version=0, entry_id=None,
source=config_entries.SOURCE_USER, title='Mock Title',
state=None):
state=None,
connection_class=config_entries.CONN_CLASS_UNKNOWN):
"""Initialize a mock config entry."""
kwargs = {
'entry_id': entry_id or 'mock-id',
'domain': domain,
'data': data or {},
'version': version,
'title': title
'title': title,
'connection_class': connection_class,
}
if source is not None:
kwargs['source'] = source

View file

@ -42,7 +42,8 @@ async def setup_bridge(hass, data, allow_clip_sensor=True):
hass.data[deconz.DATA_DECONZ_ID] = {}
config_entry = config_entries.ConfigEntry(
1, deconz.DOMAIN, 'Mock Title',
{'host': 'mock-host', 'allow_clip_sensor': allow_clip_sensor}, 'test')
{'host': 'mock-host', 'allow_clip_sensor': allow_clip_sensor}, 'test',
config_entries.CONN_CLASS_LOCAL_PUSH)
await hass.config_entries.async_forward_entry_setup(
config_entry, 'binary_sensor')
# To flush out the service call to update the group

View file

@ -9,7 +9,6 @@ import voluptuous as vol
from homeassistant import config_entries as core_ce
from homeassistant.config_entries import HANDLERS
from homeassistant.data_entry_flow import FlowHandler
from homeassistant.setup import async_setup_component
from homeassistant.components.config import config_entries
from homeassistant.loader import set_component
@ -37,13 +36,15 @@ def test_get_entries(hass, client):
MockConfigEntry(
domain='comp',
title='Test 1',
source='bla'
source='bla',
connection_class=core_ce.CONN_CLASS_LOCAL_POLL,
).add_to_hass(hass)
MockConfigEntry(
domain='comp2',
title='Test 2',
source='bla2',
state=core_ce.ENTRY_STATE_LOADED,
connection_class=core_ce.CONN_CLASS_ASSUMED,
).add_to_hass(hass)
resp = yield from client.get('/api/config/config_entries/entry')
assert resp.status == 200
@ -55,13 +56,15 @@ def test_get_entries(hass, client):
'domain': 'comp',
'title': 'Test 1',
'source': 'bla',
'state': 'not_loaded'
'state': 'not_loaded',
'connection_class': 'local_poll',
},
{
'domain': 'comp2',
'title': 'Test 2',
'source': 'bla2',
'state': 'loaded',
'connection_class': 'assumed',
},
]
@ -100,7 +103,7 @@ def test_available_flows(hass, client):
@asyncio.coroutine
def test_initialize_flow(hass, client):
"""Test we can initialize a flow."""
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
@asyncio.coroutine
def async_step_user(self, user_input=None):
schema = OrderedDict()
@ -155,7 +158,7 @@ def test_initialize_flow(hass, client):
@asyncio.coroutine
def test_abort(hass, client):
"""Test a flow that aborts."""
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
@asyncio.coroutine
def async_step_user(self, user_input=None):
return self.async_abort(reason='bla')
@ -181,7 +184,7 @@ def test_create_account(hass, client):
hass, 'test',
MockModule('test', async_setup_entry=mock_coro_func(True)))
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
VERSION = 1
@asyncio.coroutine
@ -213,7 +216,7 @@ def test_two_step_flow(hass, client):
hass, 'test',
MockModule('test', async_setup_entry=mock_coro_func(True)))
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
VERSION = 1
@asyncio.coroutine
@ -269,7 +272,7 @@ def test_two_step_flow(hass, client):
@asyncio.coroutine
def test_get_progress_index(hass, client):
"""Test querying for the flows that are in progress."""
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
VERSION = 5
@asyncio.coroutine
@ -301,7 +304,7 @@ def test_get_progress_index(hass, client):
@asyncio.coroutine
def test_get_progress_flow(hass, client):
"""Test we can query the API for same result as we get from init a flow."""
class TestFlow(FlowHandler):
class TestFlow(core_ce.ConfigFlow):
@asyncio.coroutine
def async_step_user(self, user_input=None):
schema = OrderedDict()

View file

@ -64,7 +64,7 @@ async def setup_bridge(hass, data, allow_deconz_groups=True):
config_entry = config_entries.ConfigEntry(
1, deconz.DOMAIN, 'Mock Title',
{'host': 'mock-host', 'allow_deconz_groups': allow_deconz_groups},
'test')
'test', config_entries.CONN_CLASS_LOCAL_PUSH)
await hass.config_entries.async_forward_entry_setup(config_entry, 'light')
# To flush out the service call to update the group
await hass.async_block_till_done()

View file

@ -199,7 +199,7 @@ async def setup_bridge(hass, mock_bridge):
hass.data[hue.DOMAIN] = {'mock-host': mock_bridge}
config_entry = config_entries.ConfigEntry(1, hue.DOMAIN, 'Mock Title', {
'host': 'mock-host'
}, 'test')
}, 'test', config_entries.CONN_CLASS_LOCAL_POLL)
await hass.config_entries.async_forward_entry_setup(config_entry, 'light')
# To flush out the service call to update the group
await hass.async_block_till_done()

View file

@ -36,7 +36,8 @@ async def setup_bridge(hass, data):
hass.data[deconz.DATA_DECONZ_UNSUB] = []
hass.data[deconz.DATA_DECONZ_ID] = {}
config_entry = config_entries.ConfigEntry(
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test',
config_entries.CONN_CLASS_LOCAL_PUSH)
await hass.config_entries.async_forward_entry_setup(config_entry, 'scene')
# To flush out the service call to update the group
await hass.async_block_till_done()

View file

@ -58,7 +58,8 @@ async def setup_bridge(hass, data, allow_clip_sensor=True):
hass.data[deconz.DATA_DECONZ_ID] = {}
config_entry = config_entries.ConfigEntry(
1, deconz.DOMAIN, 'Mock Title',
{'host': 'mock-host', 'allow_clip_sensor': allow_clip_sensor}, 'test')
{'host': 'mock-host', 'allow_clip_sensor': allow_clip_sensor}, 'test',
config_entries.CONN_CLASS_LOCAL_PUSH)
await hass.config_entries.async_forward_entry_setup(config_entry, 'sensor')
# To flush out the service call to update the group
await hass.async_block_till_done()

View file

@ -54,7 +54,8 @@ async def setup_bridge(hass, data):
hass.data[deconz.DATA_DECONZ_UNSUB] = []
hass.data[deconz.DATA_DECONZ_ID] = {}
config_entry = config_entries.ConfigEntry(
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test',
config_entries.CONN_CLASS_LOCAL_PUSH)
await hass.config_entries.async_forward_entry_setup(config_entry, 'switch')
# To flush out the service call to update the group
await hass.async_block_till_done()

View file

@ -21,7 +21,8 @@ def flow_conf(hass):
with patch.dict(config_entries.HANDLERS):
config_entry_flow.register_discovery_flow(
'test', 'Test', has_discovered_devices)
'test', 'Test', has_discovered_devices,
config_entries.CONN_CLASS_LOCAL_POLL)
yield handler_conf

View file

@ -103,7 +103,7 @@ def test_add_entry_calls_setup_entry(hass, manager):
hass, 'comp',
MockModule('comp', async_setup_entry=mock_setup_entry))
class TestFlow(data_entry_flow.FlowHandler):
class TestFlow(config_entries.ConfigFlow):
VERSION = 1
@ -159,8 +159,9 @@ async def test_saving_and_loading(hass):
hass, 'test',
MockModule('test', async_setup_entry=lambda *args: mock_coro(True)))
class TestFlow(data_entry_flow.FlowHandler):
class TestFlow(config_entries.ConfigFlow):
VERSION = 5
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
@asyncio.coroutine
def async_step_user(self, user_input=None):
@ -175,8 +176,9 @@ async def test_saving_and_loading(hass):
await hass.config_entries.flow.async_init(
'test', context={'source': config_entries.SOURCE_USER})
class Test2Flow(data_entry_flow.FlowHandler):
class Test2Flow(config_entries.ConfigFlow):
VERSION = 3
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
@asyncio.coroutine
def async_step_user(self, user_input=None):
@ -209,6 +211,7 @@ async def test_saving_and_loading(hass):
assert orig.title == loaded.title
assert orig.data == loaded.data
assert orig.source == loaded.source
assert orig.connection_class == loaded.connection_class
async def test_forward_entry_sets_up_component(hass):
@ -252,7 +255,7 @@ async def test_discovery_notification(hass):
loader.set_component(hass, 'test', MockModule('test'))
await async_setup_component(hass, 'persistent_notification', {})
class TestFlow(data_entry_flow.FlowHandler):
class TestFlow(config_entries.ConfigFlow):
VERSION = 5
async def async_step_discovery(self, user_input=None):
@ -289,7 +292,7 @@ async def test_discovery_notification_not_created(hass):
loader.set_component(hass, 'test', MockModule('test'))
await async_setup_component(hass, 'persistent_notification', {})
class TestFlow(data_entry_flow.FlowHandler):
class TestFlow(config_entries.ConfigFlow):
VERSION = 5
async def async_step_discovery(self, user_input=None):