Skip to content

Commit

Permalink
Merge branch 'dev' into patch-12
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinHjelmare authored Oct 15, 2024
2 parents 67f4033 + d2db25c commit b2315ed
Show file tree
Hide file tree
Showing 37 changed files with 1,566 additions and 813 deletions.
1 change: 1 addition & 0 deletions .core_files.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ tests: &tests
- tests/*.py
- tests/auth/**
- tests/backports/**
- tests/components/conftest.py
- tests/components/diagnostics/**
- tests/components/history/**
- tests/components/logbook/**
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ jobs:
- name: Upload pytest_buckets
uses: actions/[email protected]
with:
name: pytest_buckets
name: pytest_buckets-${{ matrix.python-version }}
path: pytest_buckets.txt
overwrite: true

Expand Down Expand Up @@ -919,7 +919,7 @@ jobs:
- name: Download pytest_buckets
uses: actions/[email protected]
with:
name: pytest_buckets
name: pytest_buckets-${{ matrix.python-version }}
- name: Compile English translations
run: |
. venv/bin/activate
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ jobs:
uses: actions/[email protected]

- name: Initialize CodeQL
uses: github/codeql-action/[email protected].12
uses: github/codeql-action/[email protected].13
with:
languages: python

- name: Perform CodeQL Analysis
uses: github/codeql-action/[email protected].12
uses: github/codeql-action/[email protected].13
with:
category: "/language:python"
2 changes: 1 addition & 1 deletion homeassistant/components/backup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:

async def async_handle_create_service(call: ServiceCall) -> None:
"""Service handler for creating backups."""
await backup_manager.generate_backup()
await backup_manager.async_create_backup()

hass.services.async_register(DOMAIN, "create", async_handle_create_service)

Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/backup/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from homeassistant.util import slugify

from .const import DOMAIN
from .manager import BackupManager
from .manager import BaseBackupManager


@callback
Expand All @@ -36,8 +36,8 @@ async def get(
if not request["hass_user"].is_admin:
return Response(status=HTTPStatus.UNAUTHORIZED)

manager: BackupManager = request.app[KEY_HASS].data[DOMAIN]
backup = await manager.get_backup(slug)
manager: BaseBackupManager = request.app[KEY_HASS].data[DOMAIN]
backup = await manager.async_get_backup(slug=slug)

if backup is None or not backup.path.exists():
return Response(status=HTTPStatus.NOT_FOUND)
Expand Down
60 changes: 47 additions & 13 deletions homeassistant/components/backup/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import abc
import asyncio
from dataclasses import asdict, dataclass
import hashlib
Expand Down Expand Up @@ -53,15 +54,48 @@ async def async_post_backup(self, hass: HomeAssistant) -> None:
"""Perform operations after a backup finishes."""


class BackupManager:
"""Backup manager for the Backup integration."""
class BaseBackupManager(abc.ABC):
"""Define the format that backup managers can have."""

def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the backup manager."""
self.hass = hass
self.backup_dir = Path(hass.config.path("backups"))
self.backing_up = False
self.backups: dict[str, Backup] = {}
self.backing_up = False

async def async_post_backup_actions(self, **kwargs: Any) -> None:
"""Post backup actions."""

async def async_pre_backup_actions(self, **kwargs: Any) -> None:
"""Pre backup actions."""

@abc.abstractmethod
async def async_create_backup(self, **kwargs: Any) -> Backup:
"""Generate a backup."""

@abc.abstractmethod
async def async_get_backups(self, **kwargs: Any) -> dict[str, Backup]:
"""Get backups.
Return a dictionary of Backup instances keyed by their slug.
"""

@abc.abstractmethod
async def async_get_backup(self, *, slug: str, **kwargs: Any) -> Backup | None:
"""Get a backup."""

@abc.abstractmethod
async def async_remove_backup(self, *, slug: str, **kwargs: Any) -> None:
"""Remove a backup."""


class BackupManager(BaseBackupManager):
"""Backup manager for the Backup integration."""

def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the backup manager."""
super().__init__(hass=hass)
self.backup_dir = Path(hass.config.path("backups"))
self.platforms: dict[str, BackupPlatformProtocol] = {}
self.loaded_backups = False
self.loaded_platforms = False
Expand All @@ -84,7 +118,7 @@ def _add_platform(
return
self.platforms[integration_domain] = platform

async def pre_backup_actions(self) -> None:
async def async_pre_backup_actions(self, **kwargs: Any) -> None:
"""Perform pre backup actions."""
if not self.loaded_platforms:
await self.load_platforms()
Expand All @@ -100,7 +134,7 @@ async def pre_backup_actions(self) -> None:
if isinstance(result, Exception):
raise result

async def post_backup_actions(self) -> None:
async def async_post_backup_actions(self, **kwargs: Any) -> None:
"""Perform post backup actions."""
if not self.loaded_platforms:
await self.load_platforms()
Expand Down Expand Up @@ -151,14 +185,14 @@ def _read_backups(self) -> dict[str, Backup]:
LOGGER.warning("Unable to read backup %s: %s", backup_path, err)
return backups

async def get_backups(self) -> dict[str, Backup]:
async def async_get_backups(self, **kwargs: Any) -> dict[str, Backup]:
"""Return backups."""
if not self.loaded_backups:
await self.load_backups()

return self.backups

async def get_backup(self, slug: str) -> Backup | None:
async def async_get_backup(self, *, slug: str, **kwargs: Any) -> Backup | None:
"""Return a backup."""
if not self.loaded_backups:
await self.load_backups()
Expand All @@ -180,23 +214,23 @@ async def get_backup(self, slug: str) -> Backup | None:

return backup

async def remove_backup(self, slug: str) -> None:
async def async_remove_backup(self, *, slug: str, **kwargs: Any) -> None:
"""Remove a backup."""
if (backup := await self.get_backup(slug)) is None:
if (backup := await self.async_get_backup(slug=slug)) is None:
return

await self.hass.async_add_executor_job(backup.path.unlink, True)
LOGGER.debug("Removed backup located at %s", backup.path)
self.backups.pop(slug)

async def generate_backup(self) -> Backup:
async def async_create_backup(self, **kwargs: Any) -> Backup:
"""Generate a backup."""
if self.backing_up:
raise HomeAssistantError("Backup already in progress")

try:
self.backing_up = True
await self.pre_backup_actions()
await self.async_pre_backup_actions()
backup_name = f"Core {HAVERSION}"
date_str = dt_util.now().isoformat()
slug = _generate_slug(date_str, backup_name)
Expand Down Expand Up @@ -229,7 +263,7 @@ async def generate_backup(self) -> Backup:
return backup
finally:
self.backing_up = False
await self.post_backup_actions()
await self.async_post_backup_actions()

def _mkdir_and_generate_backup_contents(
self,
Expand Down
34 changes: 29 additions & 5 deletions homeassistant/components/backup/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def async_register_websocket_handlers(hass: HomeAssistant, with_hassio: bool) ->
websocket_api.async_register_command(hass, handle_backup_start)
return

websocket_api.async_register_command(hass, handle_details)
websocket_api.async_register_command(hass, handle_info)
websocket_api.async_register_command(hass, handle_create)
websocket_api.async_register_command(hass, handle_remove)
Expand All @@ -33,7 +34,7 @@ async def handle_info(
) -> None:
"""List all stored backups."""
manager = hass.data[DATA_MANAGER]
backups = await manager.get_backups()
backups = await manager.async_get_backups()
connection.send_result(
msg["id"],
{
Expand All @@ -43,6 +44,29 @@ async def handle_info(
)


@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required("type"): "backup/details",
vol.Required("slug"): str,
}
)
@websocket_api.async_response
async def handle_details(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Get backup details for a specific slug."""
backup = await hass.data[DATA_MANAGER].async_get_backup(slug=msg["slug"])
connection.send_result(
msg["id"],
{
"backup": backup,
},
)


@websocket_api.require_admin
@websocket_api.websocket_command(
{
Expand All @@ -57,7 +81,7 @@ async def handle_remove(
msg: dict[str, Any],
) -> None:
"""Remove a backup."""
await hass.data[DATA_MANAGER].remove_backup(msg["slug"])
await hass.data[DATA_MANAGER].async_remove_backup(slug=msg["slug"])
connection.send_result(msg["id"])


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


Expand All @@ -88,7 +112,7 @@ async def handle_backup_start(
LOGGER.debug("Backup start notification")

try:
await manager.pre_backup_actions()
await manager.async_pre_backup_actions()
except Exception as err: # noqa: BLE001
connection.send_error(msg["id"], "pre_backup_actions_failed", str(err))
return
Expand All @@ -110,7 +134,7 @@ async def handle_backup_end(
LOGGER.debug("Backup end notification")

try:
await manager.post_backup_actions()
await manager.async_post_backup_actions()
except Exception as err: # noqa: BLE001
connection.send_error(msg["id"], "post_backup_actions_failed", str(err))
return
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/homewizard/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"invalid_discovery_parameters": "Detected unsupported API version",
"invalid_discovery_parameters": "Invalid discovery parameters",
"device_not_supported": "This device is not supported",
"unknown_error": "[%key:common::config_flow::error::unknown%]",
"unsupported_api_version": "Detected unsupported API version",
"reauth_successful": "Enabling API was successful"
}
},
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/iotty/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]"
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]",
"missing_credentials": "[%key:common::config_flow::abort::oauth2_missing_credentials%]"
},
"create_entry": {
"default": "[%key:common::config_flow::create_entry::authenticated%]"
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/matter/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"addon_start_failed": "Failed to start the Matter Server add-on.",
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"not_matter_addon": "Discovered add-on is not the official Matter Server add-on.",
"reconfiguration_successful": "Successfully reconfigured the Matter integration."
},
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/nest/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
"missing_credentials": "[%key:common::config_flow::abort::oauth2_missing_credentials%]",
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
"unknown_authorize_url_generation": "[%key:common::config_flow::abort::unknown_authorize_url_generation%]",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/rova/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
},
"error": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
"invalid_rova_area": "Rova does not collect at this address"
"invalid_rova_area": "Rova does not collect at this address",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/spotify/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
"connection_error": "Could not fetch account information. Is the user registered in the Spotify Developer Dashboard?"
"connection_error": "Could not fetch account information. Is the user registered in the Spotify Developer Dashboard?",
"missing_credentials": "[%key:common::config_flow::abort::oauth2_missing_credentials%]"
},
"create_entry": {
"default": "Successfully authenticated with Spotify."
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/teslemetry/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

TESLEMETRY_SCHEMA = vol.Schema({vol.Required(CONF_ACCESS_TOKEN): str})
DESCRIPTION_PLACEHOLDERS = {
"name": "Teslemetry",
"short_url": "teslemetry.com/console",
"url": "[teslemetry.com/console](https://teslemetry.com/console)",
}
Expand Down
11 changes: 10 additions & 1 deletion homeassistant/components/teslemetry/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"config": {
"abort": {
"already_configured": "Account is already configured"
"already_configured": "Account is already configured",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"reauth_account_mismatch": "The reauthentication account does not match the original account"
},
"error": {
"invalid_access_token": "[%key:common::config_flow::error::invalid_access_token%]",
Expand All @@ -15,6 +17,13 @@
"access_token": "[%key:common::config_flow::data::access_token%]"
},
"description": "Enter an access token from {url}."
},
"reauth_confirm": {
"title": "[%key:common::config_flow::title::reauth%]",
"description": "The {name} integration needs to re-authenticate your account, please enter an access token from {url}",
"data": {
"access_token": "[%key:common::config_flow::data::access_token%]"
}
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/youtube/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"oauth_error": "[%key:common::config_flow::abort::oauth2_error%]",
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]"
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
"wrong_account": "Wrong account: please authenticate with the right account."
},
"error": {
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
Expand Down
Loading

0 comments on commit b2315ed

Please sign in to comment.