Home Assistant Unofficial Reference 2024.12.1
api.py
Go to the documentation of this file.
1 """API for Google Tasks bound to Home Assistant OAuth."""
2 
3 from functools import partial
4 import json
5 import logging
6 from typing import Any
7 
8 from google.oauth2.credentials import Credentials
9 from googleapiclient.discovery import Resource, build
10 from googleapiclient.errors import HttpError
11 from googleapiclient.http import BatchHttpRequest, HttpRequest
12 
13 from homeassistant.const import CONF_ACCESS_TOKEN
14 from homeassistant.core import HomeAssistant
15 from homeassistant.helpers import config_entry_oauth2_flow
16 
17 from .exceptions import GoogleTasksApiError
18 
19 _LOGGER = logging.getLogger(__name__)
20 
21 MAX_TASK_RESULTS = 100
22 
23 
24 def _raise_if_error(result: Any | dict[str, Any]) -> None:
25  """Raise a GoogleTasksApiError if the response contains an error."""
26  if not isinstance(result, dict):
27  raise GoogleTasksApiError(
28  f"Google Tasks API replied with unexpected response: {result}"
29  )
30  if error := result.get("error"):
31  message = error.get("message", "Unknown Error")
32  raise GoogleTasksApiError(f"Google Tasks API response: {message}")
33 
34 
36  """Provide Google Tasks authentication tied to an OAuth2 based config entry."""
37 
38  def __init__(
39  self,
40  hass: HomeAssistant,
41  oauth2_session: config_entry_oauth2_flow.OAuth2Session,
42  ) -> None:
43  """Initialize Google Tasks Auth."""
44  self._hass_hass = hass
45  self._oauth_session_oauth_session = oauth2_session
46 
47  async def async_get_access_token(self) -> str:
48  """Return a valid access token."""
49  await self._oauth_session_oauth_session.async_ensure_token_valid()
50  return self._oauth_session_oauth_session.token[CONF_ACCESS_TOKEN]
51 
52  async def _get_service(self) -> Resource:
53  """Get current resource."""
54  token = await self.async_get_access_tokenasync_get_access_token()
55  return await self._hass_hass.async_add_executor_job(
56  partial(build, "tasks", "v1", credentials=Credentials(token=token))
57  )
58 
59  async def list_task_lists(self) -> list[dict[str, Any]]:
60  """Get all TaskList resources."""
61  service = await self._get_service_get_service()
62  cmd: HttpRequest = service.tasklists().list()
63  result = await self._execute_execute(cmd)
64  return result["items"]
65 
66  async def list_tasks(self, task_list_id: str) -> list[dict[str, Any]]:
67  """Get all Task resources for the task list."""
68  service = await self._get_service_get_service()
69  cmd: HttpRequest = service.tasks().list(
70  tasklist=task_list_id,
71  maxResults=MAX_TASK_RESULTS,
72  showCompleted=True,
73  showHidden=True,
74  )
75  result = await self._execute_execute(cmd)
76  return result["items"]
77 
78  async def insert(
79  self,
80  task_list_id: str,
81  task: dict[str, Any],
82  ) -> None:
83  """Create a new Task resource on the task list."""
84  service = await self._get_service_get_service()
85  cmd: HttpRequest = service.tasks().insert(
86  tasklist=task_list_id,
87  body=task,
88  )
89  await self._execute_execute(cmd)
90 
91  async def patch(
92  self,
93  task_list_id: str,
94  task_id: str,
95  task: dict[str, Any],
96  ) -> None:
97  """Update a task resource."""
98  service = await self._get_service_get_service()
99  cmd: HttpRequest = service.tasks().patch(
100  tasklist=task_list_id,
101  task=task_id,
102  body=task,
103  )
104  await self._execute_execute(cmd)
105 
106  async def delete(
107  self,
108  task_list_id: str,
109  task_ids: list[str],
110  ) -> None:
111  """Delete a task resources."""
112  service = await self._get_service_get_service()
113  batch: BatchHttpRequest = service.new_batch_http_request()
114 
115  def response_handler(_, response, exception: HttpError) -> None:
116  if exception is not None:
117  raise GoogleTasksApiError(
118  f"Google Tasks API responded with error ({exception.status_code})"
119  ) from exception
120  if response:
121  data = json.loads(response)
122  _raise_if_error(data)
123 
124  for task_id in task_ids:
125  batch.add(
126  service.tasks().delete(
127  tasklist=task_list_id,
128  task=task_id,
129  ),
130  request_id=task_id,
131  callback=response_handler,
132  )
133  await self._execute_execute(batch)
134 
135  async def move(
136  self,
137  task_list_id: str,
138  task_id: str,
139  previous: str | None,
140  ) -> None:
141  """Move a task resource to a specific position within the task list."""
142  service = await self._get_service_get_service()
143  cmd: HttpRequest = service.tasks().move(
144  tasklist=task_list_id,
145  task=task_id,
146  previous=previous,
147  )
148  await self._execute_execute(cmd)
149 
150  async def _execute(self, request: HttpRequest | BatchHttpRequest) -> Any:
151  try:
152  result = await self._hass_hass.async_add_executor_job(request.execute)
153  except HttpError as err:
154  raise GoogleTasksApiError(
155  f"Google Tasks API responded with error ({err.status_code})"
156  ) from err
157  if result:
158  _raise_if_error(result)
159  return result
Any _execute(self, HttpRequest|BatchHttpRequest request)
Definition: api.py:150
None __init__(self, HomeAssistant hass, config_entry_oauth2_flow.OAuth2Session oauth2_session)
Definition: api.py:42
None move(self, str task_list_id, str task_id, str|None previous)
Definition: api.py:140
list[dict[str, Any]] list_tasks(self, str task_list_id)
Definition: api.py:66
None insert(self, str task_list_id, dict[str, Any] task)
Definition: api.py:82
None delete(self, str task_list_id, list[str] task_ids)
Definition: api.py:110
None patch(self, str task_list_id, str task_id, dict[str, Any] task)
Definition: api.py:96
None _raise_if_error(Any|dict[str, Any] result)
Definition: api.py:24