Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """Custom data update coordinator for the GitHub integration."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from aiogithubapi import (
8  GitHubAPI,
9  GitHubConnectionException,
10  GitHubEventModel,
11  GitHubException,
12  GitHubRatelimitException,
13  GitHubResponseModel,
14 )
15 
16 from homeassistant.const import EVENT_HOMEASSISTANT_STOP
17 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
19 
20 from .const import FALLBACK_UPDATE_INTERVAL, LOGGER, REFRESH_EVENT_TYPES
21 
22 GRAPHQL_REPOSITORY_QUERY = """
23 query ($owner: String!, $repository: String!) {
24  rateLimit {
25  cost
26  remaining
27  }
28  repository(owner: $owner, name: $repository) {
29  default_branch_ref: defaultBranchRef {
30  commit: target {
31  ... on Commit {
32  message: messageHeadline
33  url
34  sha: oid
35  }
36  }
37  }
38  stargazers_count: stargazerCount
39  forks_count: forkCount
40  full_name: nameWithOwner
41  id: databaseId
42  watchers(first: 1) {
43  total: totalCount
44  }
45  discussion: discussions(
46  first: 1
47  orderBy: {field: CREATED_AT, direction: DESC}
48  ) {
49  total: totalCount
50  discussions: nodes {
51  title
52  url
53  number
54  }
55  }
56  issue: issues(
57  first: 1
58  states: OPEN
59  orderBy: {field: CREATED_AT, direction: DESC}
60  ) {
61  total: totalCount
62  issues: nodes {
63  title
64  url
65  number
66  }
67  }
68  pull_request: pullRequests(
69  first: 1
70  states: OPEN
71  orderBy: {field: CREATED_AT, direction: DESC}
72  ) {
73  total: totalCount
74  pull_requests: nodes {
75  title
76  url
77  number
78  }
79  }
80  release: latestRelease {
81  name
82  url
83  tag: tagName
84  }
85  refs(
86  first: 1
87  refPrefix: "refs/tags/"
88  orderBy: {field: TAG_COMMIT_DATE, direction: DESC}
89  ) {
90  tags: nodes {
91  name
92  target {
93  url: commitUrl
94  }
95  }
96  }
97  }
98 }
99 """
100 
101 
103  """Data update coordinator for the GitHub integration."""
104 
105  def __init__(
106  self,
107  hass: HomeAssistant,
108  client: GitHubAPI,
109  repository: str,
110  ) -> None:
111  """Initialize GitHub data update coordinator base class."""
112  self.repositoryrepository = repository
113  self._client_client = client
114  self._last_response_last_response: GitHubResponseModel[dict[str, Any]] | None = None
115  self._subscription_id_subscription_id: str | None = None
116  self.datadatadata = {}
117 
118  super().__init__(
119  hass,
120  LOGGER,
121  name=repository,
122  update_interval=FALLBACK_UPDATE_INTERVAL,
123  )
124 
125  async def _async_update_data(self) -> GitHubResponseModel[dict[str, Any]]:
126  """Update data."""
127  owner, repository = self.repositoryrepository.split("/")
128  try:
129  response = await self._client_client.graphql(
130  query=GRAPHQL_REPOSITORY_QUERY,
131  variables={"owner": owner, "repository": repository},
132  )
133  except (GitHubConnectionException, GitHubRatelimitException) as exception:
134  # These are expected and we dont log anything extra
135  raise UpdateFailed(exception) from exception
136  except GitHubException as exception:
137  # These are unexpected and we log the trace to help with troubleshooting
138  LOGGER.exception(exception)
139  raise UpdateFailed(exception) from exception
140 
141  self._last_response_last_response = response
142  return response.data["data"]["repository"]
143 
144  async def _handle_event(self, event: GitHubEventModel) -> None:
145  """Handle an event."""
146  if event.type in REFRESH_EVENT_TYPES:
147  await self.async_request_refreshasync_request_refresh()
148 
149  @staticmethod
150  async def _handle_error(error: GitHubException) -> None:
151  """Handle an error."""
152  LOGGER.error("An error occurred while processing new events - %s", error)
153 
154  async def subscribe(self) -> None:
155  """Subscribe to repository events."""
156  self._subscription_id_subscription_id = await self._client_client.repos.events.subscribe(
157  self.repositoryrepository,
158  event_callback=self._handle_event_handle_event,
159  error_callback=self._handle_error_handle_error,
160  )
161  self.hasshass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.unsubscribeunsubscribe)
162 
163  def unsubscribe(self, *args) -> None:
164  """Unsubscribe to repository events."""
165  self._client_client.repos.events.unsubscribe(subscription_id=self._subscription_id_subscription_id)
GitHubResponseModel[dict[str, Any]] _async_update_data(self)
Definition: coordinator.py:125
None __init__(self, HomeAssistant hass, GitHubAPI client, str repository)
Definition: coordinator.py:110