From 7ff23506fe33af647a48a0c4d681cdbc835dca01 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 9 Sep 2022 08:57:14 +0200 Subject: [PATCH] Use new enums in cast (#77946) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- homeassistant/components/cast/__init__.py | 6 +- homeassistant/components/cast/media_player.py | 57 +++++++++---------- homeassistant/components/lovelace/cast.py | 20 ++++--- homeassistant/components/plex/cast.py | 9 ++- pylint/plugins/hass_enforce_type_hints.py | 4 +- tests/components/lovelace/test_cast.py | 11 ++-- 6 files changed, 55 insertions(+), 52 deletions(-) diff --git a/homeassistant/components/cast/__init__.py b/homeassistant/components/cast/__init__.py index 63f0693b01a..467678ba82b 100644 --- a/homeassistant/components/cast/__init__.py +++ b/homeassistant/components/cast/__init__.py @@ -7,7 +7,7 @@ from typing import Protocol from pychromecast import Chromecast import voluptuous as vol -from homeassistant.components.media_player import BrowseMedia +from homeassistant.components.media_player import BrowseMedia, MediaType from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant @@ -74,7 +74,7 @@ class CastProtocol(Protocol): async def async_browse_media( self, hass: HomeAssistant, - media_content_type: str, + media_content_type: MediaType | str, media_content_id: str, cast_type: str, ) -> BrowseMedia | None: @@ -88,7 +88,7 @@ class CastProtocol(Protocol): hass: HomeAssistant, cast_entity_id: str, chromecast: Chromecast, - media_type: str, + media_type: MediaType | str, media_id: str, ) -> bool: """Play media. diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 75d3de06856..edd8e0331d9 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -7,7 +7,7 @@ from contextlib import suppress from datetime import datetime import json import logging -from typing import Any +from typing import TYPE_CHECKING, Any import pychromecast from pychromecast.controllers.homeassistant import HomeAssistantController @@ -29,29 +29,21 @@ import yarl from homeassistant.components import media_source, zeroconf from homeassistant.components.media_player import ( + ATTR_MEDIA_EXTRA, BrowseError, BrowseMedia, + MediaClass, MediaPlayerDeviceClass, MediaPlayerEntity, MediaPlayerEntityFeature, + MediaPlayerState, + MediaType, async_process_play_media_url, ) -from homeassistant.components.media_player.const import ( - ATTR_MEDIA_EXTRA, - MEDIA_CLASS_DIRECTORY, - MEDIA_TYPE_MOVIE, - MEDIA_TYPE_MUSIC, - MEDIA_TYPE_TVSHOW, -) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CAST_APP_ID_HOMEASSISTANT_LOVELACE, EVENT_HOMEASSISTANT_STOP, - STATE_BUFFERING, - STATE_IDLE, - STATE_OFF, - STATE_PAUSED, - STATE_PLAYING, ) from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError @@ -83,6 +75,9 @@ from .helpers import ( parse_playlist, ) +if TYPE_CHECKING: + from . import CastProtocol + _LOGGER = logging.getLogger(__name__) APP_IDS_UNRELIABLE_MEDIA_INFO = ("Netflix",) @@ -590,7 +585,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): return BrowseMedia( title="Cast", - media_class=MEDIA_CLASS_DIRECTORY, + media_class=MediaClass.DIRECTORY, media_content_id="", media_content_type="", can_play=False, @@ -599,7 +594,9 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): ) async def async_browse_media( - self, media_content_type: str | None = None, media_content_id: str | None = None + self, + media_content_type: MediaType | str | None = None, + media_content_id: str | None = None, ) -> BrowseMedia: """Implement the websocket media browsing helper.""" content_filter = None @@ -619,6 +616,8 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): if media_content_id is None: return await self._async_root_payload(content_filter) + platform: CastProtocol + assert media_content_type is not None for platform in self.hass.data[CAST_DOMAIN]["cast_platform"].values(): browse_media = await platform.async_browse_media( self.hass, @@ -634,7 +633,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): ) async def async_play_media( - self, media_type: str, media_id: str, **kwargs: Any + self, media_type: MediaType | str, media_id: str, **kwargs: Any ) -> None: """Play a piece of media.""" chromecast = self._get_chromecast() @@ -774,27 +773,27 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): return (media_status, media_status_received) @property - def state(self) -> str | None: + def state(self) -> MediaPlayerState | None: """Return the state of the player.""" # The lovelace app loops media to prevent timing out, don't show that if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: - return STATE_PLAYING + return MediaPlayerState.PLAYING if (media_status := self._media_status()[0]) is not None: if media_status.player_state == MEDIA_PLAYER_STATE_PLAYING: - return STATE_PLAYING + return MediaPlayerState.PLAYING if media_status.player_state == MEDIA_PLAYER_STATE_BUFFERING: - return STATE_BUFFERING + return MediaPlayerState.BUFFERING if media_status.player_is_paused: - return STATE_PAUSED + return MediaPlayerState.PAUSED if media_status.player_is_idle: - return STATE_IDLE + return MediaPlayerState.IDLE if self.app_id is not None and self.app_id != pychromecast.IDLE_APP_ID: if self.app_id in APP_IDS_UNRELIABLE_MEDIA_INFO: # Some apps don't report media status, show the player as playing - return STATE_PLAYING - return STATE_IDLE + return MediaPlayerState.PLAYING + return MediaPlayerState.IDLE if self._chromecast is not None and self._chromecast.is_idle: - return STATE_OFF + return MediaPlayerState.OFF return None @property @@ -807,7 +806,7 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): return media_status.content_id if media_status else None @property - def media_content_type(self) -> str | None: + def media_content_type(self) -> MediaType | None: """Content type of current playing media.""" # The lovelace app loops media to prevent timing out, don't show that if self.app_id == CAST_APP_ID_HOMEASSISTANT_LOVELACE: @@ -815,11 +814,11 @@ class CastMediaPlayerEntity(CastDevice, MediaPlayerEntity): if (media_status := self._media_status()[0]) is None: return None if media_status.media_is_tvshow: - return MEDIA_TYPE_TVSHOW + return MediaType.TVSHOW if media_status.media_is_movie: - return MEDIA_TYPE_MOVIE + return MediaType.MOVIE if media_status.media_is_musictrack: - return MEDIA_TYPE_MUSIC + return MediaType.MUSIC return None @property diff --git a/homeassistant/components/lovelace/cast.py b/homeassistant/components/lovelace/cast.py index bd06d142bd3..73645e66ddb 100644 --- a/homeassistant/components/lovelace/cast.py +++ b/homeassistant/components/lovelace/cast.py @@ -12,8 +12,12 @@ from homeassistant.components.cast.home_assistant_cast import ( NO_URL_AVAILABLE_ERROR, SERVICE_SHOW_VIEW, ) -from homeassistant.components.media_player import BrowseError, BrowseMedia -from homeassistant.components.media_player.const import MEDIA_CLASS_APP +from homeassistant.components.media_player import ( + BrowseError, + BrowseMedia, + MediaClass, + MediaType, +) from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError @@ -34,7 +38,7 @@ async def async_get_media_browser_root_object( return [ BrowseMedia( title="Dashboards", - media_class=MEDIA_CLASS_APP, + media_class=MediaClass.APP, media_content_id="", media_content_type=DOMAIN, thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png", @@ -46,7 +50,7 @@ async def async_get_media_browser_root_object( async def async_browse_media( hass: HomeAssistant, - media_content_type: str, + media_content_type: MediaType | str, media_content_id: str, cast_type: str, ) -> BrowseMedia | None: @@ -64,7 +68,7 @@ async def async_browse_media( children = [ BrowseMedia( title="Default", - media_class=MEDIA_CLASS_APP, + media_class=MediaClass.APP, media_content_id=DEFAULT_DASHBOARD, media_content_type=DOMAIN, thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png", @@ -96,7 +100,7 @@ async def async_browse_media( children.append( BrowseMedia( title=view["title"], - media_class=MEDIA_CLASS_APP, + media_class=MediaClass.APP, media_content_id=f'{info["url_path"]}/{view["path"]}', media_content_type=DOMAIN, thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png", @@ -114,7 +118,7 @@ async def async_play_media( hass: HomeAssistant, cast_entity_id: str, chromecast: Chromecast, - media_type: str, + media_type: MediaType | str, media_id: str, ) -> bool: """Play media.""" @@ -195,7 +199,7 @@ def _item_from_info(info: dict) -> BrowseMedia: """Convert dashboard info to browse item.""" return BrowseMedia( title=info["title"], - media_class=MEDIA_CLASS_APP, + media_class=MediaClass.APP, media_content_id=info["url_path"], media_content_type=DOMAIN, thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png", diff --git a/homeassistant/components/plex/cast.py b/homeassistant/components/plex/cast.py index c85b6ee3a78..720875bec6b 100644 --- a/homeassistant/components/plex/cast.py +++ b/homeassistant/components/plex/cast.py @@ -5,8 +5,7 @@ from pychromecast import Chromecast from pychromecast.controllers.plex import PlexController from homeassistant.components.cast.const import DOMAIN as CAST_DOMAIN -from homeassistant.components.media_player import BrowseMedia -from homeassistant.components.media_player.const import MEDIA_CLASS_APP +from homeassistant.components.media_player import BrowseMedia, MediaClass, MediaType from homeassistant.core import HomeAssistant from . import async_browse_media as async_browse_plex_media, is_plex_media_id @@ -20,7 +19,7 @@ async def async_get_media_browser_root_object( return [ BrowseMedia( title="Plex", - media_class=MEDIA_CLASS_APP, + media_class=MediaClass.APP, media_content_id="", media_content_type="plex", thumbnail="https://brands.home-assistant.io/_/plex/logo.png", @@ -32,7 +31,7 @@ async def async_get_media_browser_root_object( async def async_browse_media( hass: HomeAssistant, - media_content_type: str, + media_content_type: MediaType | str, media_content_id: str, cast_type: str, ) -> BrowseMedia | None: @@ -61,7 +60,7 @@ async def async_play_media( hass: HomeAssistant, cast_entity_id: str, chromecast: Chromecast, - media_type: str, + media_type: MediaType | str, media_id: str, ) -> bool: """Play media.""" diff --git a/pylint/plugins/hass_enforce_type_hints.py b/pylint/plugins/hass_enforce_type_hints.py index 379c19b044d..1cfb36f9398 100644 --- a/pylint/plugins/hass_enforce_type_hints.py +++ b/pylint/plugins/hass_enforce_type_hints.py @@ -203,7 +203,7 @@ _FUNCTION_MATCH: dict[str, list[TypeHintMatch]] = { function_name="async_browse_media", arg_types={ 0: "HomeAssistant", - 1: "str", + 1: "MediaType | str", 2: "str", 3: "str", }, @@ -215,7 +215,7 @@ _FUNCTION_MATCH: dict[str, list[TypeHintMatch]] = { 0: "HomeAssistant", 1: "str", 2: "Chromecast", - 3: "str", + 3: "MediaType | str", 4: "str", }, return_type="bool", diff --git a/tests/components/lovelace/test_cast.py b/tests/components/lovelace/test_cast.py index 6f6035b54b6..4945a2cab83 100644 --- a/tests/components/lovelace/test_cast.py +++ b/tests/components/lovelace/test_cast.py @@ -5,6 +5,7 @@ from unittest.mock import patch import pytest from homeassistant.components.lovelace import cast as lovelace_cast +from homeassistant.components.media_player import MediaClass from homeassistant.config import async_process_ha_core_config from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component @@ -71,7 +72,7 @@ async def test_root_object(hass): assert len(root) == 1 item = root[0] assert item.title == "Dashboards" - assert item.media_class == lovelace_cast.MEDIA_CLASS_APP + assert item.media_class == MediaClass.APP assert item.media_content_id == "" assert item.media_content_type == lovelace_cast.DOMAIN assert item.thumbnail == "https://brands.home-assistant.io/_/lovelace/logo.png" @@ -106,7 +107,7 @@ async def test_browse_media(hass, mock_yaml_dashboard, mock_https_url): child_1 = top_level_items.children[0] assert child_1.title == "Default" - assert child_1.media_class == lovelace_cast.MEDIA_CLASS_APP + assert child_1.media_class == MediaClass.APP assert child_1.media_content_id == lovelace_cast.DEFAULT_DASHBOARD assert child_1.media_content_type == lovelace_cast.DOMAIN assert child_1.thumbnail == "https://brands.home-assistant.io/_/lovelace/logo.png" @@ -115,7 +116,7 @@ async def test_browse_media(hass, mock_yaml_dashboard, mock_https_url): child_2 = top_level_items.children[1] assert child_2.title == "YAML Title" - assert child_2.media_class == lovelace_cast.MEDIA_CLASS_APP + assert child_2.media_class == MediaClass.APP assert child_2.media_content_id == "yaml-with-views" assert child_2.media_content_type == lovelace_cast.DOMAIN assert child_2.thumbnail == "https://brands.home-assistant.io/_/lovelace/logo.png" @@ -130,7 +131,7 @@ async def test_browse_media(hass, mock_yaml_dashboard, mock_https_url): grandchild_1 = child_2.children[0] assert grandchild_1.title == "Hello" - assert grandchild_1.media_class == lovelace_cast.MEDIA_CLASS_APP + assert grandchild_1.media_class == MediaClass.APP assert grandchild_1.media_content_id == "yaml-with-views/0" assert grandchild_1.media_content_type == lovelace_cast.DOMAIN assert ( @@ -141,7 +142,7 @@ async def test_browse_media(hass, mock_yaml_dashboard, mock_https_url): grandchild_2 = child_2.children[1] assert grandchild_2.title == "second-view" - assert grandchild_2.media_class == lovelace_cast.MEDIA_CLASS_APP + assert grandchild_2.media_class == MediaClass.APP assert grandchild_2.media_content_id == "yaml-with-views/second-view" assert grandchild_2.media_content_type == lovelace_cast.DOMAIN assert (