airbyte-source-github 1.9.0rc3__py3-none-any.whl → 1.9.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of airbyte-source-github might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-source-github
3
- Version: 1.9.0rc3
3
+ Version: 1.9.1rc1
4
4
  Summary: Source implementation for GitHub.
5
5
  Home-page: https://airbyte.com
6
6
  License: ELv2
@@ -11,7 +11,7 @@ Classifier: License :: Other/Proprietary License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
- Requires-Dist: airbyte-cdk (>=7,<8)
14
+ Requires-Dist: airbyte-cdk (>=7.3.4,<8.0.0)
15
15
  Requires-Dist: sgqlc (==16.3)
16
16
  Project-URL: Documentation, https://docs.airbyte.com/integrations/sources/github
17
17
  Project-URL: Repository, https://github.com/airbytehq/airbyte
@@ -54,11 +54,11 @@ source_github/schemas/users.json,sha256=by1CEx3MW740S5F54KZfUDc2N1_UZ98Bb3fWlgCt
54
54
  source_github/schemas/workflow_jobs.json,sha256=Kk3N3FcCYBqOdR7FYvz2nAAFtLZBuVfR8Lxg-ORD39U,3934
55
55
  source_github/schemas/workflow_runs.json,sha256=XDmIsjtzka-ItEonImD3ZATZjxRNkbFo5-MPTtZDARA,19453
56
56
  source_github/schemas/workflows.json,sha256=gSNw8WZaVKbX4AL97PbjZHzvxcOltXqv9Ao1RNQOFXM,1470
57
- source_github/source.py,sha256=1o8eayigi4xSUeNHdCd-mhNswGUq_XQrVk2eihTjm1o,14246
57
+ source_github/source.py,sha256=rY85d7X_StM0_GYIRYwnvoGQcsbNA_ZtdRnNJdh9-lk,14588
58
58
  source_github/spec.json,sha256=7LOQm01fP_RvPF-HifhNPJ7i0AxT2LTNPaLAA3uOfNY,7443
59
59
  source_github/streams.py,sha256=uvCHATVyObHCz76tuknNqPETuGlyUdXGsa1YZc7B4JI,78285
60
- source_github/utils.py,sha256=ZVui5WgHL_ERYlgA5jk6OASjMs-woMuBOvGfupbE-Ys,5594
61
- airbyte_source_github-1.9.0rc3.dist-info/METADATA,sha256=iRdS4DBb_u_bQ9UL_uUrxb2zBRg7mlRlc4RxMJIl1Tg,5191
62
- airbyte_source_github-1.9.0rc3.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
63
- airbyte_source_github-1.9.0rc3.dist-info/entry_points.txt,sha256=gYhqVrTAZvMwuYByg0b_-o115yUFLLcfNxMrLZmiW9k,55
64
- airbyte_source_github-1.9.0rc3.dist-info/RECORD,,
60
+ source_github/utils.py,sha256=1mKZzLEaDe0m8BTw8Y-MxCXrJr1bZfaLPeSUbPN3vyQ,7243
61
+ airbyte_source_github-1.9.1rc1.dist-info/METADATA,sha256=AMbb8fqUONHqjtukcD-PcF9ky8ByW4C4IU-zobIUg2E,5199
62
+ airbyte_source_github-1.9.1rc1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
63
+ airbyte_source_github-1.9.1rc1.dist-info/entry_points.txt,sha256=gYhqVrTAZvMwuYByg0b_-o115yUFLLcfNxMrLZmiW9k,55
64
+ airbyte_source_github-1.9.1rc1.dist-info/RECORD,,
source_github/source.py CHANGED
@@ -9,6 +9,7 @@ from urllib.parse import urlparse
9
9
  from airbyte_cdk.models import FailureType
10
10
  from airbyte_cdk.sources import AbstractSource
11
11
  from airbyte_cdk.sources.streams import Stream
12
+ from airbyte_cdk.sources.streams.http.http_client import MessageRepresentationAirbyteTracedErrors
12
13
  from airbyte_cdk.sources.streams.http.requests_native_auth import MultipleTokenAuthenticator
13
14
  from airbyte_cdk.utils.traced_exception import AirbyteTracedException
14
15
  from source_github.utils import MultipleTokenAuthenticatorWithRateLimiter
@@ -184,7 +185,7 @@ class SourceGithub(AbstractSource):
184
185
  # 404 Client Error: Not Found for url: https://api.github.com/orgs/airbytehqBLA/repos?per_page=100
185
186
  org_name = message.split("https://api.github.com/orgs/")[1].split("/")[0]
186
187
  user_message = f'Organization name: "{org_name}" is unknown, "repository" config option should be updated. Please validate your repository config.'
187
- elif "401 Client Error: Unauthorized for url" in message:
188
+ elif "401 Client Error: Unauthorized for url" in message or ("Error: Unauthorized" in message and "401" in message):
188
189
  # 401 Client Error: Unauthorized for url: https://api.github.com/orgs/datarootsio/repos?per_page=100&sort=updated&direction=desc
189
190
  user_message = (
190
191
  "Github credentials have expired or changed, please review your credentials and re-authenticate or renew your access token."
@@ -203,6 +204,9 @@ class SourceGithub(AbstractSource):
203
204
  )
204
205
  return True, None
205
206
 
207
+ except MessageRepresentationAirbyteTracedErrors as e:
208
+ user_message = self.user_friendly_error_message(e.message)
209
+ return False, user_message or e.message
206
210
  except Exception as e:
207
211
  message = repr(e)
208
212
  user_message = self.user_friendly_error_message(message)
source_github/utils.py CHANGED
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
3
  #
4
-
4
+ import logging
5
5
  import time
6
6
  from dataclasses import dataclass
7
7
  from datetime import timedelta
@@ -10,10 +10,12 @@ from typing import Any, List, Mapping
10
10
 
11
11
  import requests
12
12
 
13
- from airbyte_cdk.models import SyncMode
13
+ from airbyte_cdk.models import FailureType, SyncMode
14
14
  from airbyte_cdk.sources.streams import Stream
15
+ from airbyte_cdk.sources.streams.http import HttpClient
15
16
  from airbyte_cdk.sources.streams.http.requests_native_auth import TokenAuthenticator
16
17
  from airbyte_cdk.sources.streams.http.requests_native_auth.abstract_token import AbstractHeaderAuthenticator
18
+ from airbyte_cdk.utils import AirbyteTracedException
17
19
  from airbyte_cdk.utils.datetime_helpers import AirbyteDateTime, ab_datetime_now, ab_datetime_parse
18
20
 
19
21
 
@@ -59,14 +61,30 @@ class MultipleTokenAuthenticatorWithRateLimiter(AbstractHeaderAuthenticator):
59
61
  DURATION = timedelta(seconds=3600) # Duration at which the current rate limit window resets
60
62
 
61
63
  def __init__(self, tokens: List[str], auth_method: str = "token", auth_header: str = "Authorization"):
64
+ self._logger = logging.getLogger("airbyte")
62
65
  self._auth_method = auth_method
63
66
  self._auth_header = auth_header
64
67
  self._tokens = {t: Token() for t in tokens}
68
+ # It would've been nice to instantiate a single client on this authenticator. However, we are checking
69
+ # the limits of each token which is associated with a TokenAuthenticator. And each HttpClient can only
70
+ # correspond to one authenticator.
71
+ self._token_to_http_client: Mapping[str, HttpClient] = self._initialize_http_clients(tokens)
65
72
  self.check_all_tokens()
66
73
  self._tokens_iter = cycle(self._tokens)
67
74
  self._active_token = next(self._tokens_iter)
68
75
  self._max_time = 60 * 10 # 10 minutes as default
69
76
 
77
+ def _initialize_http_clients(self, tokens: List[str]) -> Mapping[str, HttpClient]:
78
+ return {
79
+ token: HttpClient(
80
+ name="token_validator",
81
+ logger=self._logger,
82
+ authenticator=TokenAuthenticator(token, auth_method=self._auth_method),
83
+ use_cache=False, # We don't want to reuse cached valued because rate limit values change frequently
84
+ )
85
+ for token in tokens
86
+ }
87
+
70
88
  @property
71
89
  def auth_header(self) -> str:
72
90
  return self._auth_header
@@ -114,14 +132,27 @@ class MultipleTokenAuthenticatorWithRateLimiter(AbstractHeaderAuthenticator):
114
132
 
115
133
  def _check_token_limits(self, token: str):
116
134
  """check that token is not limited"""
117
- headers = {"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"}
118
- rate_limit_info = (
119
- requests.get(
120
- "https://api.github.com/rate_limit", headers=headers, auth=TokenAuthenticator(token, auth_method=self._auth_method)
121
- )
122
- .json()
123
- .get("resources")
135
+
136
+ http_client = self._token_to_http_client.get(token)
137
+ if not http_client:
138
+ raise ValueError("No HttpClient was initialized for this token. This is unexpected. Please contact Airbyte support.")
139
+
140
+ _, response = http_client.send_request(
141
+ http_method="GET",
142
+ url="https://api.github.com/rate_limit",
143
+ headers={"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"},
144
+ request_kwargs={},
124
145
  )
146
+
147
+ response_body = response.json()
148
+ if "resources" not in response_body:
149
+ raise AirbyteTracedException(
150
+ failure_type=FailureType.config_error,
151
+ internal_message=f"Token rate limit info response did not contain expected key: resources",
152
+ message="Unable to validate token. Please double check that specified authentication tokens are correct",
153
+ )
154
+
155
+ rate_limit_info = response_body.get("resources")
125
156
  token_info = self._tokens[token]
126
157
  remaining_info_core = rate_limit_info.get("core")
127
158
  token_info.count_rest, token_info.reset_at_rest = (