diff --git a/homeassistant/components/google_sheets/config_flow.py b/homeassistant/components/google_sheets/config_flow.py index 9f28e578d259..3597dec188e3 100644 --- a/homeassistant/components/google_sheets/config_flow.py +++ b/homeassistant/components/google_sheets/config_flow.py @@ -63,13 +63,14 @@ class OAuth2FlowHandler( if self.source == SOURCE_REAUTH: reauth_entry = self._get_reauth_entry() + assert reauth_entry.unique_id is not None _LOGGER.debug("service.open_by_key") try: await self.hass.async_add_executor_job( service.open_by_key, reauth_entry.unique_id, ) - except GSpreadException as err: + except (GSpreadException, PermissionError) as err: _LOGGER.error( "Could not find spreadsheet '%s': %s", reauth_entry.unique_id, @@ -83,7 +84,7 @@ class OAuth2FlowHandler( doc = await self.hass.async_add_executor_job( service.create, "Home Assistant" ) - except GSpreadException as err: + except (GSpreadException, PermissionError) as err: _LOGGER.error("Error creating spreadsheet: %s", str(err)) return self.async_abort(reason="create_spreadsheet_failure") diff --git a/homeassistant/components/google_sheets/manifest.json b/homeassistant/components/google_sheets/manifest.json index 6fae364df3b9..c17dc96c985c 100644 --- a/homeassistant/components/google_sheets/manifest.json +++ b/homeassistant/components/google_sheets/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/google_sheets", "integration_type": "service", "iot_class": "cloud_polling", - "requirements": ["gspread==5.5.0"] + "requirements": ["gspread==6.2.1"] } diff --git a/homeassistant/components/google_sheets/services.py b/homeassistant/components/google_sheets/services.py index 91f70f0c680c..5faf6bdc13e4 100644 --- a/homeassistant/components/google_sheets/services.py +++ b/homeassistant/components/google_sheets/services.py @@ -1,11 +1,10 @@ """Support for Google Sheets.""" -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast from google.auth.exceptions import RefreshError from google.oauth2.credentials import Credentials -from gspread import Client, Spreadsheet, Worksheet -from gspread.exceptions import APIError +from gspread import Client, GSpreadException, Spreadsheet, Worksheet from gspread.utils import ValueInputOption import voluptuous as vol @@ -21,7 +20,7 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_validation as cv, service from homeassistant.helpers.selector import ConfigEntrySelector from homeassistant.util import dt as dt_util -from homeassistant.util.json import JsonObjectType +from homeassistant.util.json import JsonArrayType, JsonObjectType from .const import DOMAIN @@ -69,6 +68,7 @@ def _get_worksheet(sheet: Spreadsheet, name: str | None) -> Worksheet: def _append_to_sheet(call: ServiceCall, entry: GoogleSheetsConfigEntry) -> None: """Run append in the executor.""" + assert entry.unique_id is not None client = Client(Credentials(entry.data[CONF_TOKEN][CONF_ACCESS_TOKEN])) # type: ignore[no-untyped-call] sheet = client.open_by_key(entry.unique_id) worksheet = _get_worksheet(sheet, call.data.get(WORKSHEET)) @@ -92,11 +92,12 @@ def _get_from_sheet( call: ServiceCall, entry: GoogleSheetsConfigEntry ) -> JsonObjectType: """Run get in the executor.""" + assert entry.unique_id is not None client = Client(Credentials(entry.data[CONF_TOKEN][CONF_ACCESS_TOKEN])) # type: ignore[no-untyped-call] sheet = client.open_by_key(entry.unique_id) worksheet = _get_worksheet(sheet, call.data.get(WORKSHEET)) all_values = worksheet.get_values() - return {"range": all_values[-call.data[ROWS] :]} + return {"range": cast(JsonArrayType, all_values[-call.data[ROWS] :])} async def _async_append_to_sheet(call: ServiceCall) -> None: @@ -110,7 +111,7 @@ async def _async_append_to_sheet(call: ServiceCall) -> None: except RefreshError: entry.async_start_reauth(call.hass) raise - except APIError as ex: + except (GSpreadException, PermissionError) as ex: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="append_failed" ) from ex @@ -127,7 +128,7 @@ async def _async_get_from_sheet(call: ServiceCall) -> ServiceResponse: except RefreshError: entry.async_start_reauth(call.hass) raise - except APIError as ex: + except (GSpreadException, PermissionError) as ex: raise HomeAssistantError( translation_domain=DOMAIN, translation_key="get_failed" ) from ex diff --git a/requirements_all.txt b/requirements_all.txt index e99326e503ee..905e1f5d1bb8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1223,7 +1223,7 @@ gridnet==5.0.1 growattServer==2.2.0 # homeassistant.components.google_sheets -gspread==5.5.0 +gspread==6.2.1 # homeassistant.components.guntamatic guntamatic==1.12.0 diff --git a/tests/components/google_sheets/test_config_flow.py b/tests/components/google_sheets/test_config_flow.py index 961efa0d3933..558548e77d21 100644 --- a/tests/components/google_sheets/test_config_flow.py +++ b/tests/components/google_sheets/test_config_flow.py @@ -302,7 +302,7 @@ async def test_reauth_abort( # Simulate failure looking up existing spreadsheet mock_open = Mock() mock_open.return_value.id = SHEET_ID - mock_open.side_effect = GSpreadException() + mock_open.side_effect = PermissionError() mock_client.return_value.open_by_key = mock_open aioclient_mock.post( diff --git a/tests/components/google_sheets/test_init.py b/tests/components/google_sheets/test_init.py index 5887e7f718ad..c4423d83bc65 100644 --- a/tests/components/google_sheets/test_init.py +++ b/tests/components/google_sheets/test_init.py @@ -456,7 +456,7 @@ async def test_refresh_error_starts_reauth( with ( patch( - "homeassistant.components.google_sheets.services.Client.request", + "homeassistant.components.google_sheets.services.Client.open_by_key", side_effect=RefreshError, ), pytest.raises(RefreshError), @@ -547,26 +547,23 @@ async def test_get_sheet_api_error_while_reading( ) -async def test_append_sheet_api_error( +async def test_append_sheet_permission_error( hass: HomeAssistant, setup_integration: ComponentSetup, config_entry: MockConfigEntry, ) -> None: - """Test append to sheet service call API error.""" + """Test append to sheet service call permission error.""" await setup_integration() entries = hass.config_entries.async_entries(DOMAIN) assert len(entries) == 1 assert entries[0].state is ConfigEntryState.LOADED - response = Response() - response.status_code = 503 - with ( pytest.raises(HomeAssistantError), patch( - "homeassistant.components.google_sheets.services.Client.request", - side_effect=APIError(response), + "homeassistant.components.google_sheets.services.Client.open_by_key", + side_effect=PermissionError, ), ): await hass.services.async_call(