Bump onedrive to 0.0.8 (#137423)

* Bump onedrive to 0.0.6

* bump to 0.0.7

* bump to 0.0.8

* Improve coverage
This commit is contained in:
Josef Zweck 2025-02-05 15:26:58 +01:00 committed by GitHub
parent c4411914c2
commit 4d7bd1291d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 46 additions and 61 deletions

View File

@ -2,8 +2,10 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from typing import cast
from onedrive_personal_sdk import OneDriveClient from onedrive_personal_sdk import OneDriveClient
from onedrive_personal_sdk.exceptions import ( from onedrive_personal_sdk.exceptions import (
@ -13,6 +15,7 @@ from onedrive_personal_sdk.exceptions import (
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -22,7 +25,6 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
) )
from homeassistant.helpers.instance_id import async_get as async_get_instance_id from homeassistant.helpers.instance_id import async_get as async_get_instance_id
from .api import OneDriveConfigEntryAccessTokenProvider
from .const import DATA_BACKUP_AGENT_LISTENERS, DOMAIN from .const import DATA_BACKUP_AGENT_LISTENERS, DOMAIN
@ -31,7 +33,7 @@ class OneDriveRuntimeData:
"""Runtime data for the OneDrive integration.""" """Runtime data for the OneDrive integration."""
client: OneDriveClient client: OneDriveClient
token_provider: OneDriveConfigEntryAccessTokenProvider token_function: Callable[[], Awaitable[str]]
backup_folder_id: str backup_folder_id: str
@ -46,9 +48,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: OneDriveConfigEntry) ->
session = OAuth2Session(hass, entry, implementation) session = OAuth2Session(hass, entry, implementation)
token_provider = OneDriveConfigEntryAccessTokenProvider(session) async def get_access_token() -> str:
await session.async_ensure_token_valid()
return cast(str, session.token[CONF_ACCESS_TOKEN])
client = OneDriveClient(token_provider, async_get_clientsession(hass)) client = OneDriveClient(get_access_token, async_get_clientsession(hass))
# get approot, will be created automatically if it does not exist # get approot, will be created automatically if it does not exist
try: try:
@ -81,7 +85,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: OneDriveConfigEntry) ->
entry.runtime_data = OneDriveRuntimeData( entry.runtime_data = OneDriveRuntimeData(
client=client, client=client,
token_provider=token_provider, token_function=get_access_token,
backup_folder_id=backup_folder.id, backup_folder_id=backup_folder.id,
) )

View File

@ -1,34 +0,0 @@
"""API for OneDrive bound to Home Assistant OAuth."""
from typing import cast
from onedrive_personal_sdk import TokenProvider
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.helpers import config_entry_oauth2_flow
class OneDriveConfigFlowAccessTokenProvider(TokenProvider):
"""Provide OneDrive authentication tied to an OAuth2 based config entry."""
def __init__(self, token: str) -> None:
"""Initialize OneDrive auth."""
super().__init__()
self._token = token
def async_get_access_token(self) -> str:
"""Return a valid access token."""
return self._token
class OneDriveConfigEntryAccessTokenProvider(TokenProvider):
"""Provide OneDrive authentication tied to an OAuth2 based config entry."""
def __init__(self, oauth_session: config_entry_oauth2_flow.OAuth2Session) -> None:
"""Initialize OneDrive auth."""
super().__init__()
self._oauth_session = oauth_session
def async_get_access_token(self) -> str:
"""Return a valid access token."""
return cast(str, self._oauth_session.token[CONF_ACCESS_TOKEN])

View File

@ -109,7 +109,7 @@ class OneDriveBackupAgent(BackupAgent):
self._hass = hass self._hass = hass
self._entry = entry self._entry = entry
self._client = entry.runtime_data.client self._client = entry.runtime_data.client
self._token_provider = entry.runtime_data.token_provider self._token_function = entry.runtime_data.token_function
self._folder_id = entry.runtime_data.backup_folder_id self._folder_id = entry.runtime_data.backup_folder_id
self.name = entry.title self.name = entry.title
assert entry.unique_id assert entry.unique_id
@ -145,7 +145,7 @@ class OneDriveBackupAgent(BackupAgent):
) )
try: try:
item = await LargeFileUploadClient.upload( item = await LargeFileUploadClient.upload(
self._token_provider, file, session=async_get_clientsession(self._hass) self._token_function, file, session=async_get_clientsession(self._hass)
) )
except HashMismatchError as err: except HashMismatchError as err:
raise BackupAgentError( raise BackupAgentError(

View File

@ -12,7 +12,6 @@ from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler
from .api import OneDriveConfigFlowAccessTokenProvider
from .const import DOMAIN, OAUTH_SCOPES from .const import DOMAIN, OAUTH_SCOPES
@ -36,12 +35,12 @@ class OneDriveConfigFlow(AbstractOAuth2FlowHandler, domain=DOMAIN):
data: dict[str, Any], data: dict[str, Any],
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle the initial step.""" """Handle the initial step."""
token_provider = OneDriveConfigFlowAccessTokenProvider(
cast(str, data[CONF_TOKEN][CONF_ACCESS_TOKEN]) async def get_access_token() -> str:
) return cast(str, data[CONF_TOKEN][CONF_ACCESS_TOKEN])
graph_client = OneDriveClient( graph_client = OneDriveClient(
token_provider, async_get_clientsession(self.hass) get_access_token, async_get_clientsession(self.hass)
) )
try: try:

View File

@ -9,5 +9,5 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["onedrive_personal_sdk"], "loggers": ["onedrive_personal_sdk"],
"quality_scale": "bronze", "quality_scale": "bronze",
"requirements": ["onedrive-personal-sdk==0.0.4"] "requirements": ["onedrive-personal-sdk==0.0.8"]
} }

2
requirements_all.txt generated
View File

@ -1559,7 +1559,7 @@ omnilogic==0.4.5
ondilo==0.5.0 ondilo==0.5.0
# homeassistant.components.onedrive # homeassistant.components.onedrive
onedrive-personal-sdk==0.0.4 onedrive-personal-sdk==0.0.8
# homeassistant.components.onvif # homeassistant.components.onvif
onvif-zeep-async==3.2.5 onvif-zeep-async==3.2.5

View File

@ -1307,7 +1307,7 @@ omnilogic==0.4.5
ondilo==0.5.0 ondilo==0.5.0
# homeassistant.components.onedrive # homeassistant.components.onedrive
onedrive-personal-sdk==0.0.4 onedrive-personal-sdk==0.0.8
# homeassistant.components.onvif # homeassistant.components.onvif
onvif-zeep-async==3.2.5 onvif-zeep-async==3.2.5

View File

@ -67,8 +67,8 @@ def mock_config_entry(expires_at: int, scopes: list[str]) -> MockConfigEntry:
) )
@pytest.fixture(autouse=True) @pytest.fixture
def mock_onedrive_client() -> Generator[MagicMock]: def mock_onedrive_client_init() -> Generator[MagicMock]:
"""Return a mocked GraphServiceClient.""" """Return a mocked GraphServiceClient."""
with ( with (
patch( patch(
@ -80,19 +80,25 @@ def mock_onedrive_client() -> Generator[MagicMock]:
new=onedrive_client, new=onedrive_client,
), ),
): ):
client = onedrive_client.return_value yield onedrive_client
client.get_approot.return_value = MOCK_APPROOT
client.create_folder.return_value = MOCK_BACKUP_FOLDER
client.list_drive_items.return_value = [MOCK_BACKUP_FILE]
client.get_drive_item.return_value = MOCK_BACKUP_FILE
class MockStreamReader:
async def iter_chunked(self, chunk_size: int) -> AsyncIterator[bytes]:
yield b"backup data"
client.download_drive_item.return_value = MockStreamReader() @pytest.fixture(autouse=True)
def mock_onedrive_client(mock_onedrive_client_init: MagicMock) -> Generator[MagicMock]:
"""Return a mocked GraphServiceClient."""
client = mock_onedrive_client_init.return_value
client.get_approot.return_value = MOCK_APPROOT
client.create_folder.return_value = MOCK_BACKUP_FOLDER
client.list_drive_items.return_value = [MOCK_BACKUP_FILE]
client.get_drive_item.return_value = MOCK_BACKUP_FILE
yield client class MockStreamReader:
async def iter_chunked(self, chunk_size: int) -> AsyncIterator[bytes]:
yield b"backup data"
client.download_drive_item.return_value = MockStreamReader()
return client
@pytest.fixture @pytest.fixture

View File

@ -70,6 +70,7 @@ async def test_full_flow(
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
aioclient_mock: AiohttpClientMocker, aioclient_mock: AiohttpClientMocker,
mock_setup_entry: AsyncMock, mock_setup_entry: AsyncMock,
mock_onedrive_client_init: MagicMock,
) -> None: ) -> None:
"""Check full flow.""" """Check full flow."""
@ -79,6 +80,10 @@ async def test_full_flow(
await _do_get_token(hass, result, hass_client_no_auth, aioclient_mock) await _do_get_token(hass, result, hass_client_no_auth, aioclient_mock)
result = await hass.config_entries.flow.async_configure(result["flow_id"]) result = await hass.config_entries.flow.async_configure(result["flow_id"])
# Ensure the token callback is set up correctly
token_callback = mock_onedrive_client_init.call_args[0][0]
assert await token_callback() == "mock-access-token"
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert len(hass.config_entries.async_entries(DOMAIN)) == 1 assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1

View File

@ -16,10 +16,15 @@ from tests.common import MockConfigEntry
async def test_load_unload_config_entry( async def test_load_unload_config_entry(
hass: HomeAssistant, hass: HomeAssistant,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
mock_onedrive_client_init: MagicMock,
) -> None: ) -> None:
"""Test loading and unloading the integration.""" """Test loading and unloading the integration."""
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
# Ensure the token callback is set up correctly
token_callback = mock_onedrive_client_init.call_args[0][0]
assert await token_callback() == "mock-access-token"
assert mock_config_entry.state is ConfigEntryState.LOADED assert mock_config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(mock_config_entry.entry_id) await hass.config_entries.async_unload(mock_config_entry.entry_id)