Move imports to top (#24108)

This commit is contained in:
Andrew Sayre 2019-05-26 06:47:11 -05:00 committed by Pascal Vizeli
parent 25505dc1d4
commit 0194905e97
4 changed files with 54 additions and 58 deletions

View File

@ -4,6 +4,7 @@ from datetime import timedelta
import logging
from typing import Dict
from pyheos import CommandError, Heos, const as heos_const
import voluptuous as vol
from homeassistant.components.media_player.const import (
@ -57,7 +58,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType):
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
"""Initialize config entry which represents the HEOS controller."""
from pyheos import Heos, CommandError
host = entry.data[CONF_HOST]
# Setting all_progress_events=False ensures that we only receive a
# media position update upon start of playback or when media changes
@ -137,16 +137,15 @@ class ControllerManager:
async def connect_listeners(self):
"""Subscribe to events of interest."""
from pyheos import const
self._device_registry, self._entity_registry = await asyncio.gather(
self._hass.helpers.device_registry.async_get_registry(),
self._hass.helpers.entity_registry.async_get_registry())
# Handle controller events
self._signals.append(self.controller.dispatcher.connect(
const.SIGNAL_CONTROLLER_EVENT, self._controller_event))
heos_const.SIGNAL_CONTROLLER_EVENT, self._controller_event))
# Handle connection-related events
self._signals.append(self.controller.dispatcher.connect(
const.SIGNAL_HEOS_EVENT, self._heos_event))
heos_const.SIGNAL_HEOS_EVENT, self._heos_event))
async def disconnect(self):
"""Disconnect subscriptions."""
@ -158,21 +157,19 @@ class ControllerManager:
async def _controller_event(self, event, data):
"""Handle controller event."""
from pyheos import const
if event == const.EVENT_PLAYERS_CHANGED:
self.update_ids(data[const.DATA_MAPPED_IDS])
if event == heos_const.EVENT_PLAYERS_CHANGED:
self.update_ids(data[heos_const.DATA_MAPPED_IDS])
# Update players
self._hass.helpers.dispatcher.async_dispatcher_send(
SIGNAL_HEOS_UPDATED)
async def _heos_event(self, event):
"""Handle connection event."""
from pyheos import CommandError, const
if event == const.EVENT_CONNECTED:
if event == heos_const.EVENT_CONNECTED:
try:
# Retrieve latest players and refresh status
data = await self.controller.load_players()
self.update_ids(data[const.DATA_MAPPED_IDS])
self.update_ids(data[heos_const.DATA_MAPPED_IDS])
except (CommandError, asyncio.TimeoutError, ConnectionError) as ex:
_LOGGER.error("Unable to refresh players: %s", ex)
# Update players
@ -241,9 +238,8 @@ class SourceManager:
def get_current_source(self, now_playing_media):
"""Determine current source from now playing media."""
from pyheos import const
# Match input by input_name:media_id
if now_playing_media.source_id == const.MUSIC_SOURCE_AUX_INPUT:
if now_playing_media.source_id == heos_const.MUSIC_SOURCE_AUX_INPUT:
return next((input_source.name for input_source in self.inputs
if input_source.input_name ==
now_playing_media.media_id), None)
@ -260,8 +256,6 @@ class SourceManager:
physical event therefore throttle it. Retrieving sources immediately
after the event may fail so retry.
"""
from pyheos import CommandError, const
@Throttle(MIN_UPDATE_SOURCES)
async def get_sources():
retry_attempts = 0
@ -286,9 +280,9 @@ class SourceManager:
return
async def update_sources(event, data=None):
if event in (const.EVENT_SOURCES_CHANGED,
const.EVENT_USER_CHANGED,
const.EVENT_CONNECTED):
if event in (heos_const.EVENT_SOURCES_CHANGED,
heos_const.EVENT_USER_CHANGED,
heos_const.EVENT_CONNECTED):
sources = await get_sources()
# If throttled, it will return None
if sources:
@ -300,6 +294,6 @@ class SourceManager:
SIGNAL_HEOS_UPDATED)
controller.dispatcher.connect(
const.SIGNAL_CONTROLLER_EVENT, update_sources)
heos_const.SIGNAL_CONTROLLER_EVENT, update_sources)
controller.dispatcher.connect(
const.SIGNAL_HEOS_EVENT, update_sources)
heos_const.SIGNAL_HEOS_EVENT, update_sources)

View File

@ -1,6 +1,7 @@
"""Config flow to configure Heos."""
import asyncio
from pyheos import Heos
import voluptuous as vol
from homeassistant import config_entries
@ -44,7 +45,6 @@ class HeosFlowHandler(config_entries.ConfigFlow):
async def async_step_user(self, user_input=None):
"""Obtain host and validate connection."""
from pyheos import Heos
self.hass.data.setdefault(DATA_DISCOVERED_HOSTS, {})
# Only a single entry is needed for all devices
if self._async_current_entries():

View File

@ -5,6 +5,8 @@ import logging
from operator import ior
from typing import Sequence
from pyheos import CommandError, const as heos_const
from homeassistant.components.media_player import MediaPlayerDevice
from homeassistant.components.media_player.const import (
ATTR_MEDIA_ENQUEUE, DOMAIN, MEDIA_TYPE_MUSIC, MEDIA_TYPE_PLAYLIST,
@ -25,6 +27,20 @@ BASE_SUPPORTED_FEATURES = SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \
SUPPORT_SHUFFLE_SET | SUPPORT_SELECT_SOURCE | \
SUPPORT_PLAY_MEDIA
PLAY_STATE_TO_STATE = {
heos_const.PLAY_STATE_PLAY: STATE_PLAYING,
heos_const.PLAY_STATE_STOP: STATE_IDLE,
heos_const.PLAY_STATE_PAUSE: STATE_PAUSED
}
CONTROL_TO_SUPPORT = {
heos_const.CONTROL_PLAY: SUPPORT_PLAY,
heos_const.CONTROL_PAUSE: SUPPORT_PAUSE,
heos_const.CONTROL_STOP: SUPPORT_STOP,
heos_const.CONTROL_PLAY_PREVIOUS: SUPPORT_PREVIOUS_TRACK,
heos_const.CONTROL_PLAY_NEXT: SUPPORT_NEXT_TRACK
}
_LOGGER = logging.getLogger(__name__)
@ -47,7 +63,6 @@ def log_command_error(command: str):
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
from pyheos import CommandError
try:
await func(*args, **kwargs)
except (CommandError, asyncio.TimeoutError, ConnectionError,
@ -62,31 +77,17 @@ class HeosMediaPlayer(MediaPlayerDevice):
def __init__(self, player):
"""Initialize."""
from pyheos import const
self._media_position_updated_at = None
self._player = player
self._signals = []
self._supported_features = BASE_SUPPORTED_FEATURES
self._source_manager = None
self._play_state_to_state = {
const.PLAY_STATE_PLAY: STATE_PLAYING,
const.PLAY_STATE_STOP: STATE_IDLE,
const.PLAY_STATE_PAUSE: STATE_PAUSED
}
self._control_to_support = {
const.CONTROL_PLAY: SUPPORT_PLAY,
const.CONTROL_PAUSE: SUPPORT_PAUSE,
const.CONTROL_STOP: SUPPORT_STOP,
const.CONTROL_PLAY_PREVIOUS: SUPPORT_PREVIOUS_TRACK,
const.CONTROL_PLAY_NEXT: SUPPORT_NEXT_TRACK
}
async def _player_update(self, player_id, event):
"""Handle player attribute updated."""
from pyheos import const
if self._player.player_id != player_id:
return
if event == const.EVENT_PLAYER_NOW_PLAYING_PROGRESS:
if event == heos_const.EVENT_PLAYER_NOW_PLAYING_PROGRESS:
self._media_position_updated_at = utcnow()
await self.async_update_ha_state(True)
@ -96,11 +97,10 @@ class HeosMediaPlayer(MediaPlayerDevice):
async def async_added_to_hass(self):
"""Device added to hass."""
from pyheos import const
self._source_manager = self.hass.data[HEOS_DOMAIN][DATA_SOURCE_MANAGER]
# Update state when attributes of the player change
self._signals.append(self._player.heos.dispatcher.connect(
const.SIGNAL_PLAYER_EVENT, self._player_update))
heos_const.SIGNAL_PLAYER_EVENT, self._player_update))
# Update state when heos changes
self._signals.append(
self.hass.helpers.dispatcher.async_dispatcher_connect(
@ -163,14 +163,13 @@ class HeosMediaPlayer(MediaPlayerDevice):
return
if media_type == MEDIA_TYPE_PLAYLIST:
from pyheos import const
playlists = await self._player.heos.get_playlists()
playlist = next((p for p in playlists if p.name == media_id), None)
if not playlist:
raise ValueError("Invalid playlist '{}'".format(media_id))
add_queue_option = const.ADD_QUEUE_ADD_TO_END \
add_queue_option = heos_const.ADD_QUEUE_ADD_TO_END \
if kwargs.get(ATTR_MEDIA_ENQUEUE) \
else const.ADD_QUEUE_REPLACE_AND_PLAY
else heos_const.ADD_QUEUE_REPLACE_AND_PLAY
await self._player.add_to_queue(playlist, add_queue_option)
return
@ -208,7 +207,7 @@ class HeosMediaPlayer(MediaPlayerDevice):
async def async_update(self):
"""Update supported features of the player."""
controls = self._player.now_playing_media.supported_controls
current_support = [self._control_to_support[control]
current_support = [CONTROL_TO_SUPPORT[control]
for control in controls]
self._supported_features = reduce(ior, current_support,
BASE_SUPPORTED_FEATURES)
@ -343,7 +342,7 @@ class HeosMediaPlayer(MediaPlayerDevice):
@property
def state(self) -> str:
"""State of the player."""
return self._play_state_to_state[self._player.state]
return PLAY_STATE_TO_STATE[self._player.state]
@property
def supported_features(self) -> int:

View File

@ -2,7 +2,7 @@
from typing import Dict, Sequence
from asynctest.mock import Mock, patch as patch
from pyheos import Dispatcher, HeosPlayer, HeosSource, InputSource, const
from pyheos import Dispatcher, Heos, HeosPlayer, HeosSource, InputSource, const
import pytest
from homeassistant.components.heos import DOMAIN
@ -22,20 +22,23 @@ def config_entry_fixture():
def controller_fixture(
players, favorites, input_sources, playlists, change_data, dispatcher):
"""Create a mock Heos controller fixture."""
with patch("pyheos.Heos", autospec=True) as mock:
mock_heos = mock.return_value
for player in players.values():
player.heos = mock_heos
mock_heos.dispatcher = dispatcher
mock_heos.get_players.return_value = players
mock_heos.players = players
mock_heos.get_favorites.return_value = favorites
mock_heos.get_input_sources.return_value = input_sources
mock_heos.get_playlists.return_value = playlists
mock_heos.load_players.return_value = change_data
mock_heos.is_signed_in = True
mock_heos.signed_in_username = "user@user.com"
mock_heos.connection_state = const.STATE_CONNECTED
mock_heos = Mock(Heos)
for player in players.values():
player.heos = mock_heos
mock_heos.dispatcher = dispatcher
mock_heos.get_players.return_value = players
mock_heos.players = players
mock_heos.get_favorites.return_value = favorites
mock_heos.get_input_sources.return_value = input_sources
mock_heos.get_playlists.return_value = playlists
mock_heos.load_players.return_value = change_data
mock_heos.is_signed_in = True
mock_heos.signed_in_username = "user@user.com"
mock_heos.connection_state = const.STATE_CONNECTED
mock = Mock(return_value=mock_heos)
with patch("homeassistant.components.heos.Heos", new=mock), \
patch("homeassistant.components.heos.config_flow.Heos", new=mock):
yield mock_heos