Add Scaleway Object Storage backup integration#166868
Add Scaleway Object Storage backup integration#166868BjoernPetersen wants to merge 1 commit intohome-assistant:devfrom
Conversation
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
Pull request overview
Adds a new Home Assistant integration to store backups in Scaleway Object Storage, including config flow support and initial test coverage.
Changes:
- Introduces
scaleway_object_storageintegration (config flow, backup agent, exceptions, translations, quality scale metadata). - Adds config flow tests (user / reauth / reconfigure) and shared fixtures.
- Registers dependency (
aiohttp-s3-client), code ownership, strict typing, and generated registry updates.
Reviewed changes
Copilot reviewed 19 out of 21 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/components/scaleway_object_storage/test_config_flow_step_user.py | Adds user-step config flow tests. |
| tests/components/scaleway_object_storage/test_config_flow_step_reconfigure.py | Adds reconfigure-step config flow tests. |
| tests/components/scaleway_object_storage/test_config_flow_step_reauth.py | Adds reauth-step config flow tests. |
| tests/components/scaleway_object_storage/conftest.py | Adds shared fixtures for Scaleway Object Storage tests. |
| tests/components/scaleway_object_storage/init.py | Initializes the test package. |
| requirements_test_all.txt | Adds aiohttp-s3-client to test requirements. |
| requirements_all.txt | Adds aiohttp-s3-client to runtime requirements. |
| mypy.ini | Enables strict mypy settings for the new integration package. |
| homeassistant/generated/integrations.json | Registers the new integration in generated metadata. |
| homeassistant/generated/config_flows.py | Adds the integration domain to generated config flow registry. |
| homeassistant/components/scaleway_object_storage/strings.json | Adds config flow text, selector options, and exception translations. |
| homeassistant/components/scaleway_object_storage/quality_scale.yaml | Declares quality scale compliance status for the integration. |
| homeassistant/components/scaleway_object_storage/manifest.json | Defines integration metadata and dependency requirements. |
| homeassistant/components/scaleway_object_storage/helpers.py | Adds S3 client creation, connection check, and metadata read helpers. |
| homeassistant/components/scaleway_object_storage/exceptions.py | Adds translated, typed exception hierarchy for config/runtime errors. |
| homeassistant/components/scaleway_object_storage/const.py | Adds integration constants (config keys, limits, headers). |
| homeassistant/components/scaleway_object_storage/config_flow.py | Implements user / reauth / reconfigure config flow steps. |
| homeassistant/components/scaleway_object_storage/backup.py | Implements BackupAgent against Scaleway S3-compatible object storage. |
| homeassistant/components/scaleway_object_storage/init.py | Sets up the config entry and wires runtime client creation. |
| CODEOWNERS | Assigns ownership for the new integration and its tests. |
| .strict-typing | Marks the new integration for strict typing enforcement. |
homeassistant/components/scaleway_object_storage/config_flow.py
Outdated
Show resolved
Hide resolved
24c5809 to
0cd40e8
Compare
cffb3f4 to
f30177a
Compare
homeassistant/components/scaleway_object_storage/config_flow.py
Outdated
Show resolved
Hide resolved
homeassistant/components/scaleway_object_storage/config_flow.py
Outdated
Show resolved
Hide resolved
f30177a to
c3bf285
Compare
3b5b5e8 to
d6972ae
Compare
d6972ae to
b3830b6
Compare
b3830b6 to
9e2d0b5
Compare
9e2d0b5 to
aa362de
Compare
aa362de to
3e55dcb
Compare
homeassistant/components/scaleway_object_storage/config_flow.py
Outdated
Show resolved
Hide resolved
3e55dcb to
93ead40
Compare
93ead40 to
bb1dc56
Compare
bb1dc56 to
30ee6c2
Compare
30ee6c2 to
02045f0
Compare
| @@ -0,0 +1,165 @@ | |||
| """Integration-internal helper functions that bundle common interactions with the underlying aiohttp_s3_client.""" | |||
|
|
|||
There was a problem hiding this comment.
This module uses Mapping, AsyncGenerator, and Generator in runtime type annotations, but they are only imported under TYPE_CHECKING. Without from __future__ import annotations, this can raise NameError at import time. Fix by adding from __future__ import annotations at the top, or by importing these types unconditionally (outside TYPE_CHECKING).
| from __future__ import annotations |
| from http import HTTPStatus | ||
| import json | ||
| import logging | ||
| from typing import TYPE_CHECKING, Any |
There was a problem hiding this comment.
This module uses Mapping, AsyncGenerator, and Generator in runtime type annotations, but they are only imported under TYPE_CHECKING. Without from __future__ import annotations, this can raise NameError at import time. Fix by adding from __future__ import annotations at the top, or by importing these types unconditionally (outside TYPE_CHECKING).
| if TYPE_CHECKING: | ||
| from collections.abc import AsyncGenerator, Generator, Mapping |
There was a problem hiding this comment.
This module uses Mapping, AsyncGenerator, and Generator in runtime type annotations, but they are only imported under TYPE_CHECKING. Without from __future__ import annotations, this can raise NameError at import time. Fix by adding from __future__ import annotations at the top, or by importing these types unconditionally (outside TYPE_CHECKING).
| if TYPE_CHECKING: | |
| from collections.abc import AsyncGenerator, Generator, Mapping | |
| from collections.abc import AsyncGenerator, Generator, Mapping |
| @@ -0,0 +1,204 @@ | |||
| """Config flow for the Scaleway Object Storage integration.""" | |||
There was a problem hiding this comment.
ConfigFlowResult is referenced in return annotations but only imported under TYPE_CHECKING. Without postponed annotation evaluation, this can raise NameError at import time. Add from __future__ import annotations or import ConfigFlowResult at runtime.
| """Config flow for the Scaleway Object Storage integration.""" | |
| """Config flow for the Scaleway Object Storage integration.""" | |
| from __future__ import annotations |
| if TYPE_CHECKING: | ||
| from homeassistant.config_entries import ConfigFlowResult |
There was a problem hiding this comment.
ConfigFlowResult is referenced in return annotations but only imported under TYPE_CHECKING. Without postponed annotation evaluation, this can raise NameError at import time. Add from __future__ import annotations or import ConfigFlowResult at runtime.
tests/components/scaleway_object_storage/test_config_flow_step_reauth.py
Outdated
Show resolved
Hide resolved
|
|
||
| # Notify backup listeners | ||
| def notify_backup_listeners() -> None: | ||
| for listener in hass.data.get(DATA_BACKUP_AGENT_LISTENERS, []): |
There was a problem hiding this comment.
Iterating over the listeners list directly can break if a listener unregisters itself (or another listener) during callback execution, mutating the list while iterating. Iterate over a shallow copy (e.g., for listener in list(...):) to make this robust.
| for listener in hass.data.get(DATA_BACKUP_AGENT_LISTENERS, []): | |
| for listener in list(hass.data.get(DATA_BACKUP_AGENT_LISTENERS, [])): |
|
|
||
| return self._yield_chunks(response) | ||
|
|
||
| async def async_upload_backup( |
There was a problem hiding this comment.
The PR adds substantial new BackupAgent behavior (download/upload/list/get/delete, multipart uploads, error handling, and reauth triggering) but the added tests cover only config flows. Add tests for the backup agent methods (at least: async_list_backups success + ignored-object behavior, async_download_backup response cleanup on errors, and upload paths single vs multipart) to prevent regressions.
| @@ -0,0 +1,424 @@ | |||
| """BackupAgent implementation based on Scaleway Object Storage.""" | |||
|
|
|||
There was a problem hiding this comment.
The PR adds substantial new BackupAgent behavior (download/upload/list/get/delete, multipart uploads, error handling, and reauth triggering) but the added tests cover only config flows. Add tests for the backup agent methods (at least: async_list_backups success + ignored-object behavior, async_download_backup response cleanup on errors, and upload paths single vs multipart) to prevent regressions.
| # Get task results and filter out None values | ||
| return list(filter(None, (task.result() for task in backups))) | ||
|
|
||
| async def async_get_backup(self, backup_id: str, **kwargs: Any) -> AgentBackup: |
There was a problem hiding this comment.
The PR adds substantial new BackupAgent behavior (download/upload/list/get/delete, multipart uploads, error handling, and reauth triggering) but the added tests cover only config flows. Add tests for the backup agent methods (at least: async_list_backups success + ignored-object behavior, async_download_backup response cleanup on errors, and upload paths single vs multipart) to prevent regressions.
02045f0 to
ebd4df2
Compare
Proposed change
This PR adds a new Scaleway Object Storage integration that allows users to store Home Assistant backups in Scaleway Object Storage.
Type of change
Additional information
No AI tools were used to create this PR (except for the Copilot PR review over here).
I choose the
aiohttp-s3-clientpackage as a dependency because - other than aiobotocore - it's a fully async dependendency and offers type hints without a separate stub package.I plan to add further improvements and achieve a higher ranking on the quality scale in the future. This PR just adds what I consider a "basic" feature set.
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: