dagster-airbyte 0.23.16__tar.gz → 0.24.1__tar.gz
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 dagster-airbyte might be problematic. Click here for more details.
- {dagster-airbyte-0.23.16/dagster_airbyte.egg-info → dagster-airbyte-0.24.1}/PKG-INFO +1 -1
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/resources.py +80 -10
- dagster-airbyte-0.24.1/dagster_airbyte/version.py +1 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1/dagster_airbyte.egg-info}/PKG-INFO +1 -1
- dagster-airbyte-0.24.1/dagster_airbyte.egg-info/requires.txt +8 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/setup.py +3 -2
- dagster-airbyte-0.23.16/dagster_airbyte/version.py +0 -1
- dagster-airbyte-0.23.16/dagster_airbyte.egg-info/requires.txt +0 -8
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/LICENSE +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/MANIFEST.in +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/README.md +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/__init__.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/asset_defs.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/cli.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/__init__.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/__init__.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/destinations.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/sources.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/reconciliation.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/types.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/ops.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/py.typed +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/types.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/utils.py +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/SOURCES.txt +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/dependency_links.txt +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/entry_points.txt +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/not-zip-safe +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/top_level.txt +0 -0
- {dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/setup.cfg +0 -0
|
@@ -5,12 +5,14 @@ import sys
|
|
|
5
5
|
import time
|
|
6
6
|
from abc import abstractmethod
|
|
7
7
|
from contextlib import contextmanager
|
|
8
|
+
from datetime import datetime, timedelta
|
|
8
9
|
from typing import Any, Dict, List, Mapping, Optional, cast
|
|
9
10
|
|
|
10
11
|
import requests
|
|
11
12
|
from dagster import (
|
|
12
13
|
ConfigurableResource,
|
|
13
14
|
Failure,
|
|
15
|
+
InitResourceContext,
|
|
14
16
|
_check as check,
|
|
15
17
|
get_dagster_logger,
|
|
16
18
|
resource,
|
|
@@ -19,13 +21,17 @@ from dagster._config.pythonic_config import infer_schema_from_config_class
|
|
|
19
21
|
from dagster._core.definitions.resource_definition import dagster_maintained_resource
|
|
20
22
|
from dagster._utils.cached_method import cached_method
|
|
21
23
|
from dagster._utils.merger import deep_merge_dicts
|
|
22
|
-
from pydantic import Field
|
|
24
|
+
from pydantic import Field, PrivateAttr
|
|
23
25
|
from requests.exceptions import RequestException
|
|
24
26
|
|
|
25
27
|
from dagster_airbyte.types import AirbyteOutput
|
|
26
28
|
|
|
27
29
|
DEFAULT_POLL_INTERVAL_SECONDS = 10
|
|
28
30
|
|
|
31
|
+
# The access token expire every 3 minutes in Airbyte Cloud.
|
|
32
|
+
# Refresh is needed after 2.5 minutes to avoid the "token expired" error message.
|
|
33
|
+
AIRBYTE_CLOUD_REFRESH_TIMEDELTA_SECONDS = 150
|
|
34
|
+
|
|
29
35
|
|
|
30
36
|
class AirbyteState:
|
|
31
37
|
RUNNING = "running"
|
|
@@ -94,7 +100,11 @@ class BaseAirbyteResource(ConfigurableResource):
|
|
|
94
100
|
raise NotImplementedError()
|
|
95
101
|
|
|
96
102
|
def make_request(
|
|
97
|
-
self,
|
|
103
|
+
self,
|
|
104
|
+
endpoint: str,
|
|
105
|
+
data: Optional[Mapping[str, object]] = None,
|
|
106
|
+
method: str = "POST",
|
|
107
|
+
include_additional_request_params: bool = True,
|
|
98
108
|
) -> Optional[Mapping[str, object]]:
|
|
99
109
|
"""Creates and sends a request to the desired Airbyte REST API endpoint.
|
|
100
110
|
|
|
@@ -120,10 +130,11 @@ class BaseAirbyteResource(ConfigurableResource):
|
|
|
120
130
|
if data:
|
|
121
131
|
request_args["json"] = data
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
request_args
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
if include_additional_request_params:
|
|
134
|
+
request_args = deep_merge_dicts(
|
|
135
|
+
request_args,
|
|
136
|
+
self.all_additional_request_params,
|
|
137
|
+
)
|
|
127
138
|
|
|
128
139
|
response = requests.request(
|
|
129
140
|
**request_args,
|
|
@@ -244,7 +255,7 @@ class BaseAirbyteResource(ConfigurableResource):
|
|
|
244
255
|
|
|
245
256
|
|
|
246
257
|
class AirbyteCloudResource(BaseAirbyteResource):
|
|
247
|
-
"""This resource allows users to
|
|
258
|
+
"""This resource allows users to programmatically interface with the Airbyte Cloud API to launch
|
|
248
259
|
syncs and monitor their progress.
|
|
249
260
|
|
|
250
261
|
**Examples:**
|
|
@@ -255,7 +266,8 @@ class AirbyteCloudResource(BaseAirbyteResource):
|
|
|
255
266
|
from dagster_airbyte import AirbyteResource
|
|
256
267
|
|
|
257
268
|
my_airbyte_resource = AirbyteCloudResource(
|
|
258
|
-
|
|
269
|
+
client_id=EnvVar("AIRBYTE_CLIENT_ID"),
|
|
270
|
+
client_secret=EnvVar("AIRBYTE_CLIENT_SECRET"),
|
|
259
271
|
)
|
|
260
272
|
|
|
261
273
|
airbyte_assets = build_airbyte_assets(
|
|
@@ -269,7 +281,15 @@ class AirbyteCloudResource(BaseAirbyteResource):
|
|
|
269
281
|
)
|
|
270
282
|
"""
|
|
271
283
|
|
|
272
|
-
|
|
284
|
+
client_id: str = Field(..., description="The Airbyte Cloud client ID.")
|
|
285
|
+
client_secret: str = Field(..., description="The Airbyte Cloud client secret.")
|
|
286
|
+
|
|
287
|
+
_access_token_value: Optional[str] = PrivateAttr(default=None)
|
|
288
|
+
_access_token_timestamp: Optional[float] = PrivateAttr(default=None)
|
|
289
|
+
|
|
290
|
+
def setup_for_execution(self, context: InitResourceContext) -> None:
|
|
291
|
+
# Refresh access token when the resource is initialized
|
|
292
|
+
self._refresh_access_token()
|
|
273
293
|
|
|
274
294
|
@property
|
|
275
295
|
def api_base_url(self) -> str:
|
|
@@ -277,7 +297,32 @@ class AirbyteCloudResource(BaseAirbyteResource):
|
|
|
277
297
|
|
|
278
298
|
@property
|
|
279
299
|
def all_additional_request_params(self) -> Mapping[str, Any]:
|
|
280
|
-
|
|
300
|
+
# Make sure the access token is refreshed before using it when calling the API.
|
|
301
|
+
if self._needs_refreshed_access_token():
|
|
302
|
+
self._refresh_access_token()
|
|
303
|
+
return {
|
|
304
|
+
"headers": {
|
|
305
|
+
"Authorization": f"Bearer {self._access_token_value}",
|
|
306
|
+
"User-Agent": "dagster",
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def make_request(
|
|
311
|
+
self,
|
|
312
|
+
endpoint: str,
|
|
313
|
+
data: Optional[Mapping[str, object]] = None,
|
|
314
|
+
method: str = "POST",
|
|
315
|
+
include_additional_request_params: bool = True,
|
|
316
|
+
) -> Optional[Mapping[str, object]]:
|
|
317
|
+
# Make sure the access token is refreshed before using it when calling the API.
|
|
318
|
+
if include_additional_request_params and self._needs_refreshed_access_token():
|
|
319
|
+
self._refresh_access_token()
|
|
320
|
+
return super().make_request(
|
|
321
|
+
endpoint=endpoint,
|
|
322
|
+
data=data,
|
|
323
|
+
method=method,
|
|
324
|
+
include_additional_request_params=include_additional_request_params,
|
|
325
|
+
)
|
|
281
326
|
|
|
282
327
|
def start_sync(self, connection_id: str) -> Mapping[str, object]:
|
|
283
328
|
job_sync = check.not_none(
|
|
@@ -306,6 +351,31 @@ class AirbyteCloudResource(BaseAirbyteResource):
|
|
|
306
351
|
# Airbyte Cloud does not support streaming logs yet
|
|
307
352
|
return False
|
|
308
353
|
|
|
354
|
+
def _refresh_access_token(self) -> None:
|
|
355
|
+
response = check.not_none(
|
|
356
|
+
self.make_request(
|
|
357
|
+
endpoint="/applications/token",
|
|
358
|
+
data={
|
|
359
|
+
"client_id": self.client_id,
|
|
360
|
+
"client_secret": self.client_secret,
|
|
361
|
+
},
|
|
362
|
+
# Must not pass the bearer access token when refreshing it.
|
|
363
|
+
include_additional_request_params=False,
|
|
364
|
+
)
|
|
365
|
+
)
|
|
366
|
+
self._access_token_value = str(response["access_token"])
|
|
367
|
+
self._access_token_timestamp = datetime.now().timestamp()
|
|
368
|
+
|
|
369
|
+
def _needs_refreshed_access_token(self) -> bool:
|
|
370
|
+
return (
|
|
371
|
+
not self._access_token_value
|
|
372
|
+
or not self._access_token_timestamp
|
|
373
|
+
or self._access_token_timestamp
|
|
374
|
+
<= datetime.timestamp(
|
|
375
|
+
datetime.now() - timedelta(seconds=AIRBYTE_CLOUD_REFRESH_TIMEDELTA_SECONDS)
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
|
|
309
379
|
|
|
310
380
|
class AirbyteResource(BaseAirbyteResource):
|
|
311
381
|
"""This resource allows users to programatically interface with the Airbyte REST API to launch
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.24.1"
|
|
@@ -35,9 +35,10 @@ setup(
|
|
|
35
35
|
"Operating System :: OS Independent",
|
|
36
36
|
],
|
|
37
37
|
packages=find_packages(exclude=["dagster_airbyte_tests*"]),
|
|
38
|
+
include_package_data=True,
|
|
38
39
|
python_requires=">=3.8,<3.13",
|
|
39
40
|
install_requires=[
|
|
40
|
-
"dagster==1.
|
|
41
|
+
"dagster==1.8.1",
|
|
41
42
|
"requests",
|
|
42
43
|
],
|
|
43
44
|
zip_safe=False,
|
|
@@ -51,7 +52,7 @@ setup(
|
|
|
51
52
|
"requests-mock",
|
|
52
53
|
],
|
|
53
54
|
"managed": [
|
|
54
|
-
"dagster-managed-elements==0.
|
|
55
|
+
"dagster-managed-elements==0.24.1",
|
|
55
56
|
],
|
|
56
57
|
},
|
|
57
58
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.23.16"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/__init__.py
RENAMED
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/destinations.py
RENAMED
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/generated/sources.py
RENAMED
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte/managed/reconciliation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{dagster-airbyte-0.23.16 → dagster-airbyte-0.24.1}/dagster_airbyte.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|