From ee6f969c2a4675ccedd04afda36f841bb652b99b Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:56:34 +0100 Subject: [PATCH] Add type hints to ps4 media player (#89236) --- homeassistant/components/ps4/media_player.py | 94 ++++++++++++-------- 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/ps4/media_player.py b/homeassistant/components/ps4/media_player.py index 3e6a15df340..8799aad65d4 100644 --- a/homeassistant/components/ps4/media_player.py +++ b/homeassistant/components/ps4/media_player.py @@ -2,6 +2,7 @@ import asyncio from contextlib import suppress import logging +from typing import Any, cast from pyps4_2ndscreen.errors import NotReady, PSDataIncomplete from pyps4_2ndscreen.media_art import TYPE_APP as PS_TYPE_APP @@ -27,6 +28,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.util.json import JsonObjectType from . import format_unique_id, load_games, save_games from .const import ( @@ -52,12 +54,12 @@ async def async_setup_entry( ) -> None: """Set up PS4 from a config entry.""" config = config_entry - creds = config.data[CONF_TOKEN] + creds: str = config.data[CONF_TOKEN] device_list = [] for device in config.data["devices"]: - host = device[CONF_HOST] - region = device[CONF_REGION] - name = device[CONF_NAME] + host: str = device[CONF_HOST] + region: str = device[CONF_REGION] + name: str = device[CONF_NAME] ps4 = pyps4.Ps4Async(host, creds, device_name=DEFAULT_ALIAS) device_list.append(PS4Device(config, name, host, region, ps4, creds)) async_add_entities(device_list, update_before_add=True) @@ -75,7 +77,15 @@ class PS4Device(MediaPlayerEntity): | MediaPlayerEntityFeature.SELECT_SOURCE ) - def __init__(self, config, name, host, region, ps4, creds): + def __init__( + self, + config: ConfigEntry, + name: str, + host: str, + region: str, + ps4: pyps4.Ps4Async, + creds: str, + ) -> None: """Initialize the ps4 device.""" self._entry_id = config.entry_id self._ps4 = ps4 @@ -83,30 +93,30 @@ class PS4Device(MediaPlayerEntity): self._attr_name = name self._region = region self._creds = creds - self._media_image = None - self._games = {} + self._media_image: str | None = None + self._games: JsonObjectType = {} self._retry = 0 self._disconnected = False @callback - def status_callback(self): + def status_callback(self) -> None: """Handle status callback. Parse status.""" self._parse_status() self.async_write_ha_state() @callback - def subscribe_to_protocol(self): + def subscribe_to_protocol(self) -> None: """Notify protocol to callback with update changes.""" self.hass.data[PS4_DATA].protocol.add_callback(self._ps4, self.status_callback) @callback - def unsubscribe_to_protocol(self): + def unsubscribe_to_protocol(self) -> None: """Notify protocol to remove callback.""" self.hass.data[PS4_DATA].protocol.remove_callback( self._ps4, self.status_callback ) - def check_region(self): + def check_region(self) -> None: """Display logger msg if region is deprecated.""" # Non-Breaking although data returned may be inaccurate. if self._region in deprecated_regions: @@ -151,10 +161,11 @@ class PS4Device(MediaPlayerEntity): self._parse_status() - def _parse_status(self): + def _parse_status(self) -> None: """Parse status.""" - if (status := self._ps4.status) is not None: - self._games = load_games(self.hass, self.unique_id) + status: dict[str, Any] | None = self._ps4.status + if status is not None: + self._games = load_games(self.hass, cast(str, self.unique_id)) if self._games: self.get_source_list() @@ -193,28 +204,30 @@ class PS4Device(MediaPlayerEntity): def _use_saved(self) -> bool: """Return True, Set media attrs if data is locked.""" if self.media_content_id in self._games: - store = self._games[self.media_content_id] + store = cast(JsonObjectType, self._games[self.media_content_id]) # If locked get attributes from file. if store.get(ATTR_LOCKED): - self._attr_media_title = store.get(ATTR_MEDIA_TITLE) + self._attr_media_title = cast(str | None, store.get(ATTR_MEDIA_TITLE)) self._attr_source = self._attr_media_title - self._media_image = store.get(ATTR_MEDIA_IMAGE_URL) - self._attr_media_content_type = store.get(ATTR_MEDIA_CONTENT_TYPE) + self._media_image = cast(str | None, store.get(ATTR_MEDIA_IMAGE_URL)) + self._attr_media_content_type = cast( + str | None, store.get(ATTR_MEDIA_CONTENT_TYPE) + ) return True return False - def idle(self): + def idle(self) -> None: """Set states for state idle.""" self.reset_title() self._attr_state = MediaPlayerState.IDLE - def state_standby(self): + def state_standby(self) -> None: """Set states for state standby.""" self.reset_title() self._attr_state = MediaPlayerState.STANDBY - def state_unknown(self): + def state_unknown(self) -> None: """Set states for state unknown.""" self.reset_title() self._attr_state = None @@ -223,14 +236,14 @@ class PS4Device(MediaPlayerEntity): self._disconnected = True self._retry = 0 - def reset_title(self): + def reset_title(self) -> None: """Update if there is no title.""" self._attr_media_title = None self._attr_media_content_id = None self._attr_media_content_type = None self._attr_source = None - async def async_get_title_data(self, title_id, name): + async def async_get_title_data(self, title_id: str, name: str) -> None: """Get PS Store Data.""" app_name = None @@ -272,10 +285,10 @@ class PS4Device(MediaPlayerEntity): await self.hass.async_add_executor_job(self.update_list) self.async_write_ha_state() - def update_list(self): + def update_list(self) -> None: """Update Game List, Correct data if different.""" if self.media_content_id in self._games: - store = self._games[self.media_content_id] + store = cast(JsonObjectType, self._games[self.media_content_id]) if ( store.get(ATTR_MEDIA_TITLE) != self.media_title @@ -290,7 +303,7 @@ class PS4Device(MediaPlayerEntity): self._media_image, self._attr_media_content_type, ) - self._games = load_games(self.hass, self.unique_id) + self._games = load_games(self.hass, cast(str, self.unique_id)) self.get_source_list() @@ -298,14 +311,22 @@ class PS4Device(MediaPlayerEntity): """Parse data entry and update source list.""" games = [] for data in self._games.values(): - games.append(data[ATTR_MEDIA_TITLE]) + data = cast(JsonObjectType, data) + games.append(cast(str, data[ATTR_MEDIA_TITLE])) self._attr_source_list = sorted(games) - def add_games(self, title_id, app_name, image, g_type, is_locked=False): + def add_games( + self, + title_id: str | None, + app_name: str | None, + image: str | None, + g_type: str | None, + is_locked: bool = False, + ) -> None: """Add games to list.""" games = self._games if title_id is not None and title_id not in games: - game = { + game: JsonObjectType = { title_id: { ATTR_MEDIA_TITLE: app_name, ATTR_MEDIA_IMAGE_URL: image, @@ -314,9 +335,9 @@ class PS4Device(MediaPlayerEntity): } } games.update(game) - save_games(self.hass, games, self.unique_id) + save_games(self.hass, games, cast(str, self.unique_id)) - async def async_get_device_info(self, status): + async def async_get_device_info(self, status: dict[str, Any] | None) -> None: """Set device info for registry.""" # If cannot get status on startup, assume info from registry. if status is None: @@ -362,7 +383,7 @@ class PS4Device(MediaPlayerEntity): self.hass.data[PS4_DATA].devices.remove(self) @property - def entity_picture(self): + def entity_picture(self) -> str | None: """Return picture.""" if ( self.state == MediaPlayerState.PLAYING @@ -376,7 +397,7 @@ class PS4Device(MediaPlayerEntity): return None @property - def media_image_url(self): + def media_image_url(self) -> str | None: """Image url of current playing media.""" if self.media_content_id is None: return None @@ -405,7 +426,8 @@ class PS4Device(MediaPlayerEntity): async def async_select_source(self, source: str) -> None: """Select input source.""" for title_id, data in self._games.items(): - game = data[ATTR_MEDIA_TITLE] + data = cast(JsonObjectType, data) + game = cast(str, data[ATTR_MEDIA_TITLE]) if ( source.lower().encode(encoding="utf-8") == game.lower().encode(encoding="utf-8") @@ -421,10 +443,10 @@ class PS4Device(MediaPlayerEntity): _LOGGER.warning("Could not start title. '%s' is not in source list", source) return - async def async_send_command(self, command): + async def async_send_command(self, command: str) -> None: """Send Button Command.""" await self.async_send_remote_control(command) - async def async_send_remote_control(self, command): + async def async_send_remote_control(self, command: str) -> None: """Send RC command.""" await self._ps4.remote_control(command)