Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/dev' into evo_test_failure
Browse files Browse the repository at this point in the history
  • Loading branch information
zxdavb committed Oct 4, 2024
2 parents a8488fb + d9b0771 commit deb6a70
Show file tree
Hide file tree
Showing 36 changed files with 615 additions and 155 deletions.
4 changes: 2 additions & 2 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -1389,8 +1389,8 @@ build.json @home-assistant/supervisor
/tests/components/spotify/ @frenck @joostlek
/homeassistant/components/sql/ @gjohansson-ST @dougiteixeira
/tests/components/sql/ @gjohansson-ST @dougiteixeira
/homeassistant/components/squeezebox/ @rajlaud
/tests/components/squeezebox/ @rajlaud
/homeassistant/components/squeezebox/ @rajlaud @pssc @peteS-UK
/tests/components/squeezebox/ @rajlaud @pssc @peteS-UK
/homeassistant/components/srp_energy/ @briglx
/tests/components/srp_energy/ @briglx
/homeassistant/components/starline/ @anonym-tsk
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,15 @@
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass
from homeassistant.util import dt as dt_util
from homeassistant.util.hass_dict import HassKey

from . import indieauth, login_flow, mfa_setup_flow

DOMAIN = "auth"

type StoreResultType = Callable[[str, Credentials], str]
type RetrieveResultType = Callable[[str, str], Credentials | None]

DATA_STORE: HassKey[StoreResultType] = HassKey(DOMAIN)
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)

DELETE_CURRENT_TOKEN_DELAY = 2
Expand All @@ -177,14 +178,14 @@ def create_auth_code(
hass: HomeAssistant, client_id: str, credential: Credentials
) -> str:
"""Create an authorization code to fetch tokens."""
return cast(StoreResultType, hass.data[DOMAIN])(client_id, credential)
return hass.data[DATA_STORE](client_id, credential)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Component to allow users to login."""
store_result, retrieve_result = _create_auth_code_store()

hass.data[DOMAIN] = store_result
hass.data[DATA_STORE] = store_result

hass.http.register_view(TokenView(retrieve_result))
hass.http.register_view(RevokeTokenView())
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/auth/mfa_setup_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.util.hass_dict import HassKey

WS_TYPE_SETUP_MFA = "auth/setup_mfa"
SCHEMA_WS_SETUP_MFA = vol.All(
Expand All @@ -31,7 +32,7 @@
{vol.Required("type"): WS_TYPE_DEPOSE_MFA, vol.Required("mfa_module_id"): str}
)

DATA_SETUP_FLOW_MGR = "auth_mfa_setup_flow_manager"
DATA_SETUP_FLOW_MGR: HassKey[MfaFlowManager] = HassKey("auth_mfa_setup_flow_manager")

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -89,7 +90,7 @@ def websocket_setup_mfa(

async def async_setup_flow(msg: dict[str, Any]) -> None:
"""Return a setup flow for mfa auth module."""
flow_manager: MfaFlowManager = hass.data[DATA_SETUP_FLOW_MGR]
flow_manager = hass.data[DATA_SETUP_FLOW_MGR]

if (flow_id := msg.get("flow_id")) is not None:
result = await flow_manager.async_configure(flow_id, msg.get("user_input"))
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/backup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN, LOGGER
from .const import DATA_MANAGER, DOMAIN, LOGGER
from .http import async_register_http_views
from .manager import BackupManager
from .websocket import async_register_websocket_handlers
Expand All @@ -16,7 +16,7 @@
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Backup integration."""
backup_manager = BackupManager(hass)
hass.data[DOMAIN] = backup_manager
hass.data[DATA_MANAGER] = backup_manager

with_hassio = is_hassio(hass)

Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/backup/const.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
"""Constants for the Backup integration."""

from __future__ import annotations

from logging import getLogger
from typing import TYPE_CHECKING

from homeassistant.util.hass_dict import HassKey

if TYPE_CHECKING:
from .manager import BackupManager

DOMAIN = "backup"
DATA_MANAGER: HassKey[BackupManager] = HassKey(DOMAIN)
LOGGER = getLogger(__package__)

EXCLUDE_FROM_BACKUP = [
Expand Down
15 changes: 6 additions & 9 deletions homeassistant/components/backup/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback

from .const import DOMAIN, LOGGER
from .manager import BackupManager
from .const import DATA_MANAGER, LOGGER


@callback
Expand All @@ -33,7 +32,7 @@ async def handle_info(
msg: dict[str, Any],
) -> None:
"""List all stored backups."""
manager: BackupManager = hass.data[DOMAIN]
manager = hass.data[DATA_MANAGER]
backups = await manager.get_backups()
connection.send_result(
msg["id"],
Expand All @@ -58,8 +57,7 @@ async def handle_remove(
msg: dict[str, Any],
) -> None:
"""Remove a backup."""
manager: BackupManager = hass.data[DOMAIN]
await manager.remove_backup(msg["slug"])
await hass.data[DATA_MANAGER].remove_backup(msg["slug"])
connection.send_result(msg["id"])


Expand All @@ -72,8 +70,7 @@ async def handle_create(
msg: dict[str, Any],
) -> None:
"""Generate a backup."""
manager: BackupManager = hass.data[DOMAIN]
backup = await manager.generate_backup()
backup = await hass.data[DATA_MANAGER].generate_backup()
connection.send_result(msg["id"], backup)


Expand All @@ -86,7 +83,7 @@ async def handle_backup_start(
msg: dict[str, Any],
) -> None:
"""Backup start notification."""
manager: BackupManager = hass.data[DOMAIN]
manager = hass.data[DATA_MANAGER]
manager.backing_up = True
LOGGER.debug("Backup start notification")

Expand All @@ -108,7 +105,7 @@ async def handle_backup_end(
msg: dict[str, Any],
) -> None:
"""Backup end notification."""
manager: BackupManager = hass.data[DOMAIN]
manager = hass.data[DATA_MANAGER]
manager.backing_up = False
LOGGER.debug("Backup end notification")

Expand Down
7 changes: 6 additions & 1 deletion homeassistant/components/blueprint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@
from .const import CONF_USE_BLUEPRINT, DOMAIN # noqa: F401
from .errors import ( # noqa: F401
BlueprintException,
BlueprintInUse,
BlueprintWithNameException,
FailedToLoad,
InvalidBlueprint,
InvalidBlueprintInputs,
MissingInput,
)
from .models import Blueprint, BlueprintInputs, DomainBlueprints # noqa: F401
from .schemas import BLUEPRINT_SCHEMA, is_blueprint_instance_config # noqa: F401
from .schemas import ( # noqa: F401
BLUEPRINT_INSTANCE_FIELDS,
BLUEPRINT_SCHEMA,
is_blueprint_instance_config,
)

CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/cast/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/cast",
"iot_class": "local_polling",
"loggers": ["casttube", "pychromecast"],
"requirements": ["PyChromecast==14.0.2"],
"requirements": ["PyChromecast==14.0.1"],
"zeroconf": ["_googlecast._tcp.local."]
}
30 changes: 8 additions & 22 deletions homeassistant/components/jellyfin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@

from .client_wrapper import CannotConnect, InvalidAuth, create_client, validate_input
from .const import CONF_CLIENT_DEVICE_ID, DOMAIN, PLATFORMS
from .coordinator import JellyfinDataUpdateCoordinator, SessionsDataUpdateCoordinator
from .models import JellyfinData
from .coordinator import JellyfinDataUpdateCoordinator

type JellyfinConfigEntry = ConfigEntry[JellyfinData]
type JellyfinConfigEntry = ConfigEntry[JellyfinDataUpdateCoordinator]


async def async_setup_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) -> bool:
Expand All @@ -36,20 +35,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) ->

server_info: dict[str, Any] = connect_result["Servers"][0]

coordinators: dict[str, JellyfinDataUpdateCoordinator[Any]] = {
"sessions": SessionsDataUpdateCoordinator(
hass, client, server_info, entry.data[CONF_CLIENT_DEVICE_ID], user_id
),
}
coordinator = JellyfinDataUpdateCoordinator(hass, client, server_info, user_id)

for coordinator in coordinators.values():
await coordinator.async_config_entry_first_refresh()
await coordinator.async_config_entry_first_refresh()

entry.runtime_data = JellyfinData(
client_device_id=entry.data[CONF_CLIENT_DEVICE_ID],
jellyfin_client=client,
coordinators=coordinators,
)
entry.runtime_data = coordinator
entry.async_on_unload(client.stop)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

Expand All @@ -58,19 +49,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) ->

async def async_unload_entry(hass: HomeAssistant, entry: JellyfinConfigEntry) -> bool:
"""Unload a config entry."""
unloaded = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unloaded:
entry.runtime_data.jellyfin_client.stop()

return unloaded
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)


async def async_remove_config_entry_device(
hass: HomeAssistant, config_entry: JellyfinConfigEntry, device_entry: dr.DeviceEntry
) -> bool:
"""Remove device from a config entry."""
data = config_entry.runtime_data
coordinator = data.coordinators["sessions"]
coordinator = config_entry.runtime_data

return not device_entry.identifiers.intersection(
(
Expand Down
36 changes: 9 additions & 27 deletions homeassistant/components/jellyfin/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,28 @@

from __future__ import annotations

from abc import ABC, abstractmethod
from datetime import timedelta
from typing import Any, TypeVar
from typing import Any

from jellyfin_apiclient_python import JellyfinClient

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import DOMAIN, LOGGER, USER_APP_NAME
from .const import CONF_CLIENT_DEVICE_ID, DOMAIN, LOGGER, USER_APP_NAME

JellyfinDataT = TypeVar(
"JellyfinDataT",
bound=dict[str, dict[str, Any]] | dict[str, Any],
)


class JellyfinDataUpdateCoordinator(DataUpdateCoordinator[JellyfinDataT], ABC):
class JellyfinDataUpdateCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]):
"""Data update coordinator for the Jellyfin integration."""

config_entry: ConfigEntry

def __init__(
self,
hass: HomeAssistant,
api_client: JellyfinClient,
system_info: dict[str, Any],
client_device_id: str,
user_id: str,
) -> None:
"""Initialize the coordinator."""
Expand All @@ -37,32 +33,18 @@ def __init__(
name=DOMAIN,
update_interval=timedelta(seconds=10),
)
self.api_client: JellyfinClient = api_client
self.api_client = api_client
self.server_id: str = system_info["Id"]
self.server_name: str = system_info["Name"]
self.server_version: str | None = system_info.get("Version")
self.client_device_id: str = client_device_id
self.client_device_id: str = self.config_entry.data[CONF_CLIENT_DEVICE_ID]
self.user_id: str = user_id

self.session_ids: set[str] = set()
self.device_ids: set[str] = set()

async def _async_update_data(self) -> JellyfinDataT:
async def _async_update_data(self) -> dict[str, dict[str, Any]]:
"""Get the latest data from Jellyfin."""
return await self._fetch_data()

@abstractmethod
async def _fetch_data(self) -> JellyfinDataT:
"""Fetch the actual data."""


class SessionsDataUpdateCoordinator(
JellyfinDataUpdateCoordinator[dict[str, dict[str, Any]]]
):
"""Sessions update coordinator for Jellyfin."""

async def _fetch_data(self) -> dict[str, dict[str, Any]]:
"""Fetch the data."""
sessions = await self.hass.async_add_executor_job(
self.api_client.jellyfin.sessions
)
Expand Down
11 changes: 5 additions & 6 deletions homeassistant/components/jellyfin/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@ async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: JellyfinConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
data = entry.runtime_data
sessions = data.coordinators["sessions"]
coordinator = entry.runtime_data

return {
"entry": {
"title": entry.title,
"data": async_redact_data(entry.data, TO_REDACT),
},
"server": {
"id": sessions.server_id,
"name": sessions.server_name,
"version": sessions.server_version,
"id": coordinator.server_id,
"name": coordinator.server_name,
"version": coordinator.server_version,
},
"sessions": [
{
Expand All @@ -42,6 +41,6 @@ async def async_get_config_entry_diagnostics(
"now_playing": session_data.get("NowPlayingItem"),
"play_state": session_data.get("PlayState"),
}
for session_id, session_data in sessions.data.items()
for session_id, session_data in coordinator.data.items()
],
}
6 changes: 3 additions & 3 deletions homeassistant/components/jellyfin/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DEFAULT_NAME, DOMAIN
from .coordinator import JellyfinDataT, JellyfinDataUpdateCoordinator
from .coordinator import JellyfinDataUpdateCoordinator


class JellyfinEntity(CoordinatorEntity[JellyfinDataUpdateCoordinator[JellyfinDataT]]):
class JellyfinEntity(CoordinatorEntity[JellyfinDataUpdateCoordinator]):
"""Defines a base Jellyfin entity."""

_attr_has_entity_name = True

def __init__(
self,
coordinator: JellyfinDataUpdateCoordinator[JellyfinDataT],
coordinator: JellyfinDataUpdateCoordinator,
description: EntityDescription,
) -> None:
"""Initialize the Jellyfin entity."""
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/jellyfin/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Jellyfin media_player from a config entry."""
jellyfin_data = entry.runtime_data
coordinator = jellyfin_data.coordinators["sessions"]
coordinator = entry.runtime_data

@callback
def handle_coordinator_update() -> None:
Expand Down
Loading

0 comments on commit deb6a70

Please sign in to comment.