gooddata-pipelines 1.50.0__py3-none-any.whl → 1.50.1.dev2__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 gooddata-pipelines might be problematic. Click here for more details.
- gooddata_pipelines/__init__.py +18 -0
- gooddata_pipelines/api/gooddata_api.py +55 -0
- gooddata_pipelines/backup_and_restore/backup_manager.py +36 -62
- gooddata_pipelines/backup_and_restore/constants.py +3 -7
- gooddata_pipelines/backup_and_restore/models/storage.py +4 -5
- gooddata_pipelines/ldm_extension/__init__.py +1 -0
- gooddata_pipelines/ldm_extension/input_processor.py +286 -0
- gooddata_pipelines/ldm_extension/input_validator.py +185 -0
- gooddata_pipelines/ldm_extension/ldm_extension_manager.py +283 -0
- gooddata_pipelines/ldm_extension/models/__init__.py +1 -0
- gooddata_pipelines/ldm_extension/models/aliases.py +9 -0
- gooddata_pipelines/ldm_extension/models/analytical_object.py +33 -0
- gooddata_pipelines/ldm_extension/models/custom_data_object.py +90 -0
- gooddata_pipelines/provisioning/entities/users/models/users.py +10 -1
- gooddata_pipelines/provisioning/entities/users/users.py +38 -0
- gooddata_pipelines/provisioning/provisioning.py +2 -3
- gooddata_pipelines/utils/__init__.py +9 -0
- gooddata_pipelines/utils/rate_limiter.py +64 -0
- {gooddata_pipelines-1.50.0.dist-info → gooddata_pipelines-1.50.1.dev2.dist-info}/METADATA +11 -3
- {gooddata_pipelines-1.50.0.dist-info → gooddata_pipelines-1.50.1.dev2.dist-info}/RECORD +22 -12
- {gooddata_pipelines-1.50.0.dist-info → gooddata_pipelines-1.50.1.dev2.dist-info}/WHEEL +0 -0
- {gooddata_pipelines-1.50.0.dist-info → gooddata_pipelines-1.50.1.dev2.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -11,6 +11,7 @@ from gooddata_sdk.catalog.user.entity_model.user_group import CatalogUserGroup
|
|
|
11
11
|
from gooddata_pipelines.provisioning.entities.users.models.users import (
|
|
12
12
|
UserFullLoad,
|
|
13
13
|
UserIncrementalLoad,
|
|
14
|
+
UserProfile,
|
|
14
15
|
)
|
|
15
16
|
from gooddata_pipelines.provisioning.provisioning import Provisioning
|
|
16
17
|
from gooddata_pipelines.provisioning.utils.context_objects import UserContext
|
|
@@ -30,6 +31,8 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
30
31
|
source_group_incremental: list[UserIncrementalLoad]
|
|
31
32
|
source_group_full: list[UserFullLoad]
|
|
32
33
|
|
|
34
|
+
current_user_id: str
|
|
35
|
+
|
|
33
36
|
FULL_LOAD_TYPE: type[UserFullLoad] = UserFullLoad
|
|
34
37
|
INCREMENTAL_LOAD_TYPE: type[UserIncrementalLoad] = UserIncrementalLoad
|
|
35
38
|
|
|
@@ -37,6 +40,19 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
37
40
|
super().__init__(host, token)
|
|
38
41
|
self.upstream_user_cache: dict[UserId, UserModel] = {}
|
|
39
42
|
|
|
43
|
+
def _get_current_user_id(self) -> str:
|
|
44
|
+
"""Gets the current user ID."""
|
|
45
|
+
|
|
46
|
+
profile_response = self._api.get_profile()
|
|
47
|
+
|
|
48
|
+
if not profile_response.ok:
|
|
49
|
+
raise Exception("Failed to get current user profile")
|
|
50
|
+
|
|
51
|
+
profile_json = profile_response.json()
|
|
52
|
+
profile = UserProfile.model_validate(profile_json)
|
|
53
|
+
|
|
54
|
+
return profile.user_id
|
|
55
|
+
|
|
40
56
|
def _try_get_user(
|
|
41
57
|
self, user: UserModel, model: type[UserModel]
|
|
42
58
|
) -> UserModel | None:
|
|
@@ -99,6 +115,14 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
99
115
|
for its existence and create it if needed.
|
|
100
116
|
|
|
101
117
|
"""
|
|
118
|
+
|
|
119
|
+
if user.user_id == self.current_user_id:
|
|
120
|
+
self.logger.warning(
|
|
121
|
+
f"Skipping creation/update of current user: {user.user_id}. "
|
|
122
|
+
+ "Current user should not be modified.",
|
|
123
|
+
)
|
|
124
|
+
return
|
|
125
|
+
|
|
102
126
|
user_context = UserContext(
|
|
103
127
|
user_id=user.user_id,
|
|
104
128
|
user_groups=user.user_groups,
|
|
@@ -118,6 +142,13 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
118
142
|
|
|
119
143
|
def _delete_user(self, user_id: str) -> None:
|
|
120
144
|
"""Deletes user from the project."""
|
|
145
|
+
if user_id == self.current_user_id:
|
|
146
|
+
self.logger.warning(
|
|
147
|
+
f"Skipping deletion of current user: {user_id}."
|
|
148
|
+
+ " Current user should not be deleted.",
|
|
149
|
+
)
|
|
150
|
+
return
|
|
151
|
+
|
|
121
152
|
try:
|
|
122
153
|
self._api._sdk.catalog_user.get_user(user_id)
|
|
123
154
|
except NotFoundException:
|
|
@@ -135,6 +166,9 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
135
166
|
|
|
136
167
|
def _provision_incremental_load(self) -> None:
|
|
137
168
|
"""Runs the incremental provisioning logic."""
|
|
169
|
+
# Set the current user ID
|
|
170
|
+
self.current_user_id = self._get_current_user_id()
|
|
171
|
+
|
|
138
172
|
for user in self.source_group_incremental:
|
|
139
173
|
# Attempt to process each user. On failure, log the error and continue
|
|
140
174
|
try:
|
|
@@ -146,6 +180,10 @@ class UserProvisioner(Provisioning[UserFullLoad, UserIncrementalLoad]):
|
|
|
146
180
|
|
|
147
181
|
def _provision_full_load(self) -> None:
|
|
148
182
|
"""Runs the full load provisioning logic."""
|
|
183
|
+
|
|
184
|
+
# Set the current user ID
|
|
185
|
+
self.current_user_id = self._get_current_user_id()
|
|
186
|
+
|
|
149
187
|
# Get all upstream users
|
|
150
188
|
catalog_upstream_users: list[CatalogUser] = self._api.list_users()
|
|
151
189
|
|
|
@@ -50,7 +50,7 @@ class Provisioning(Generic[TFullLoadSourceData, TIncrementalSourceData]):
|
|
|
50
50
|
) -> TProvisioning:
|
|
51
51
|
"""Creates a provisioner instance using a GoodData profile file."""
|
|
52
52
|
content = profile_content(profile, profiles_path)
|
|
53
|
-
return cls(
|
|
53
|
+
return cls(host=content["host"], token=content["token"])
|
|
54
54
|
|
|
55
55
|
@staticmethod
|
|
56
56
|
def _validate_credentials(host: str, token: str) -> None:
|
|
@@ -165,5 +165,4 @@ class Provisioning(Generic[TFullLoadSourceData, TIncrementalSourceData]):
|
|
|
165
165
|
|
|
166
166
|
self.logger.error(exception_message)
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
raise Exception(exception_message)
|
|
168
|
+
raise Exception(exception_message)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# (C) 2025 GoodData Corporation
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import threading
|
|
5
|
+
import functools
|
|
6
|
+
from typing import Callable, Any, Literal
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RateLimiter:
|
|
10
|
+
"""
|
|
11
|
+
Rate limiter usable as a decorator and as a context manager.
|
|
12
|
+
- Shared instance decorator: limiter = RateLimiter(); @limiter
|
|
13
|
+
- Per-function decorator: @RateLimiter(calls_per_second=2)
|
|
14
|
+
- Context manager: with RateLimiter(2): ...
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, calls_per_second: float = 1.0) -> None:
|
|
18
|
+
if calls_per_second <= 0:
|
|
19
|
+
raise ValueError("calls_per_second must be greater than 0")
|
|
20
|
+
|
|
21
|
+
self.calls_per_second = calls_per_second
|
|
22
|
+
self.min_interval = 1.0 / calls_per_second
|
|
23
|
+
|
|
24
|
+
self._lock = threading.Lock()
|
|
25
|
+
self._last_call_time = 0.0
|
|
26
|
+
|
|
27
|
+
def wait_if_needed(self) -> float:
|
|
28
|
+
"""Sleep if needed to maintain the rate limit, return actual sleep time."""
|
|
29
|
+
with self._lock:
|
|
30
|
+
now = time.monotonic()
|
|
31
|
+
since_last = now - self._last_call_time
|
|
32
|
+
|
|
33
|
+
if since_last < self.min_interval:
|
|
34
|
+
sleep_time = self.min_interval - since_last
|
|
35
|
+
time.sleep(sleep_time)
|
|
36
|
+
self._last_call_time = time.monotonic()
|
|
37
|
+
return sleep_time
|
|
38
|
+
else:
|
|
39
|
+
self._last_call_time = now
|
|
40
|
+
return 0.0
|
|
41
|
+
|
|
42
|
+
# Decorator support
|
|
43
|
+
def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
|
|
44
|
+
@functools.wraps(func)
|
|
45
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
46
|
+
self.wait_if_needed()
|
|
47
|
+
return func(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
return wrapper
|
|
50
|
+
|
|
51
|
+
# Context manager support
|
|
52
|
+
def __enter__(self) -> "RateLimiter":
|
|
53
|
+
self.wait_if_needed()
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def __exit__(
|
|
57
|
+
self, exc_type: Any, exc_val: Any, exc_tb: Any
|
|
58
|
+
) -> Literal[False]:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def reset(self) -> None:
|
|
62
|
+
"""Reset the limiter (useful in tests)."""
|
|
63
|
+
with self._lock:
|
|
64
|
+
self._last_call_time = 0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gooddata-pipelines
|
|
3
|
-
Version: 1.50.
|
|
3
|
+
Version: 1.50.1.dev2
|
|
4
4
|
Summary: GoodData Cloud lifecycle automation pipelines
|
|
5
5
|
Author-email: GoodData <support@gooddata.com>
|
|
6
6
|
License: MIT
|
|
@@ -8,7 +8,7 @@ License-File: LICENSE.txt
|
|
|
8
8
|
Requires-Python: >=3.10
|
|
9
9
|
Requires-Dist: boto3-stubs<2.0.0,>=1.39.3
|
|
10
10
|
Requires-Dist: boto3<2.0.0,>=1.39.3
|
|
11
|
-
Requires-Dist: gooddata-sdk~=1.50.
|
|
11
|
+
Requires-Dist: gooddata-sdk~=1.50.1.dev2
|
|
12
12
|
Requires-Dist: pydantic<3.0.0,>=2.11.3
|
|
13
13
|
Requires-Dist: requests<3.0.0,>=2.32.3
|
|
14
14
|
Requires-Dist: types-pyyaml<7.0.0,>=6.0.12.20250326
|
|
@@ -74,4 +74,12 @@ full_load_data: list[UserFullLoad] = UserFullLoad.from_list_of_dicts(
|
|
|
74
74
|
provisioner.full_load(full_load_data)
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
## Bugs & Requests
|
|
78
|
+
|
|
79
|
+
Please use the [GitHub issue tracker](https://github.com/gooddata/gooddata-python-sdk/issues) to submit bugs
|
|
80
|
+
or request features.
|
|
81
|
+
|
|
82
|
+
## Changelog
|
|
83
|
+
|
|
84
|
+
See [Github releases](https://github.com/gooddata/gooddata-python-sdk/releases) for released versions
|
|
85
|
+
and a list of changes.
|
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
gooddata_pipelines/__init__.py,sha256=
|
|
1
|
+
gooddata_pipelines/__init__.py,sha256=UyE19wWfPh2R_5O0KSAS4XLllP3km3iGkDzRQFBd7jQ,2415
|
|
2
2
|
gooddata_pipelines/_version.py,sha256=Zi8Ht5ofjFeSYGG5USixQtJNB1po6okh0Rez8VyAsFM,200
|
|
3
3
|
gooddata_pipelines/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
gooddata_pipelines/api/__init__.py,sha256=0WaBI2XMdkkZgnUsQ9kqipNzh2l2zamZvUt_qjp8xCk,106
|
|
5
5
|
gooddata_pipelines/api/exceptions.py,sha256=rddQXfv8Ktckz7RONKBnKfm53M7dzPCh50Dl1k-8hqs,1545
|
|
6
|
-
gooddata_pipelines/api/gooddata_api.py,sha256=
|
|
6
|
+
gooddata_pipelines/api/gooddata_api.py,sha256=8AZ5-mGGvo_4pPFjaf_DxkzQQqp2dRtiRPTM2sIdfYs,10934
|
|
7
7
|
gooddata_pipelines/api/gooddata_api_wrapper.py,sha256=t7dFrXJ6X4yXS9XDthOmvd2CyzdnDDNPeIngTEW72YU,1152
|
|
8
8
|
gooddata_pipelines/api/gooddata_sdk.py,sha256=wd5O4e9BQLWUawt6odrs5a51nqFGthBkvqh9WOiW36Q,13734
|
|
9
9
|
gooddata_pipelines/api/utils.py,sha256=3QY_aYH17I9THoCINE3l-n5oj52k-gNeT1wv6Z_VxN8,1433
|
|
10
10
|
gooddata_pipelines/backup_and_restore/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
11
11
|
gooddata_pipelines/backup_and_restore/backup_input_processor.py,sha256=ex1tGwETdHDDBRJ_DGKZsZbH6uoRuOrbGbKOC976H5s,7940
|
|
12
|
-
gooddata_pipelines/backup_and_restore/backup_manager.py,sha256=
|
|
13
|
-
gooddata_pipelines/backup_and_restore/constants.py,sha256=
|
|
12
|
+
gooddata_pipelines/backup_and_restore/backup_manager.py,sha256=kWxhxe5K8_oK3tz2e1RBMpyHHv18_UA_QVlXQeb7UUk,15227
|
|
13
|
+
gooddata_pipelines/backup_and_restore/constants.py,sha256=m8wAYhVGlRlfAgiC_54wJr6N8HDEAT7hIfrH1N2UrQY,884
|
|
14
14
|
gooddata_pipelines/backup_and_restore/csv_reader.py,sha256=0Kw7mJT7REj3Gjqfsc6YT9MbhcqfCGNB_SKBwzTI1rk,1268
|
|
15
15
|
gooddata_pipelines/backup_and_restore/models/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
16
16
|
gooddata_pipelines/backup_and_restore/models/input_type.py,sha256=CBKJigKdmZ-NJD9MSfNhq89bo86W0AqCMMoyonbd1QA,239
|
|
17
|
-
gooddata_pipelines/backup_and_restore/models/storage.py,sha256=
|
|
17
|
+
gooddata_pipelines/backup_and_restore/models/storage.py,sha256=BcgOGIk4u3EaH0u0gArDHQpDyIPjx_c3fmoc-i_Ptj4,2795
|
|
18
18
|
gooddata_pipelines/backup_and_restore/models/workspace_response.py,sha256=eQbYLgRQc17IRG0yPTAJVrD-Xs05SzuwtzoNrPT2DoY,833
|
|
19
19
|
gooddata_pipelines/backup_and_restore/storage/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
20
20
|
gooddata_pipelines/backup_and_restore/storage/base_storage.py,sha256=67wdItlG3neExeb_eCUDQhswdUB62X5Nyj9sOImB_Hg,487
|
|
21
21
|
gooddata_pipelines/backup_and_restore/storage/local_storage.py,sha256=NvhPRzRAvuSpc5qCDyPqZaMB0i1jeZOZczaSwjUSGEg,1155
|
|
22
22
|
gooddata_pipelines/backup_and_restore/storage/s3_storage.py,sha256=ZAysu4sPMAvdWs3RUroHHp2XZLHeU_LhJ5qBHlBQ7n4,3732
|
|
23
|
+
gooddata_pipelines/ldm_extension/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
24
|
+
gooddata_pipelines/ldm_extension/input_processor.py,sha256=lNIx6YfU4OJpSLyAitCoPwwf6eFIT6OyivRnqYX5O-o,11678
|
|
25
|
+
gooddata_pipelines/ldm_extension/input_validator.py,sha256=sAl-tixrS69G_lP19U9CjKHiWZinXOcjeAqwiydVctQ,7459
|
|
26
|
+
gooddata_pipelines/ldm_extension/ldm_extension_manager.py,sha256=XHNBMAaiUvIzBib3zz9mYcmGk6YOkIhqrxYfQaV9s9Q,11483
|
|
27
|
+
gooddata_pipelines/ldm_extension/models/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
28
|
+
gooddata_pipelines/ldm_extension/models/aliases.py,sha256=vmac3fGhTjGQqclW3Be42kE-ooC3ZBtYS8JqpXmBy_g,231
|
|
29
|
+
gooddata_pipelines/ldm_extension/models/analytical_object.py,sha256=biWgRdczuF-IRz7zQNWrWAWmc-r7_OpSdDJA7klI7ME,913
|
|
30
|
+
gooddata_pipelines/ldm_extension/models/custom_data_object.py,sha256=wH2ZrgjKiuFCDB2BTUntyGbEw-oFuwtaepYKdtSwgHY,2771
|
|
23
31
|
gooddata_pipelines/logger/__init__.py,sha256=W-fJvMStnsDUY52AYFhx_LnS2cSCFNf3bB47Iew2j04,129
|
|
24
32
|
gooddata_pipelines/logger/logger.py,sha256=yIMdvqsmOSGQLI4U_tQwxX5E2q_FXUu0Ko7Hv39slFM,3549
|
|
25
33
|
gooddata_pipelines/provisioning/__init__.py,sha256=RZDEiv8nla4Jwa2TZXUdp1NSxg2_-lLqz4h7k2c4v5Y,854
|
|
26
|
-
gooddata_pipelines/provisioning/provisioning.py,sha256=
|
|
34
|
+
gooddata_pipelines/provisioning/provisioning.py,sha256=UUHClT0q6O1XDAgiR2M23eFgtU3uEFBp87-b13-m97I,6166
|
|
27
35
|
gooddata_pipelines/provisioning/assets/wdf_setting.json,sha256=nxOLGZkEQiMdARcUDER5ygqr3Zu-MQlLlUyXVhPUq64,280
|
|
28
36
|
gooddata_pipelines/provisioning/entities/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
29
37
|
gooddata_pipelines/provisioning/entities/user_data_filters/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
@@ -33,11 +41,11 @@ gooddata_pipelines/provisioning/entities/user_data_filters/models/udf_models.py,
|
|
|
33
41
|
gooddata_pipelines/provisioning/entities/users/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
34
42
|
gooddata_pipelines/provisioning/entities/users/permissions.py,sha256=2k3oPI7WyABcD2TMmLPsMUDrAjnKM7Vw56kz_RWhcmI,7135
|
|
35
43
|
gooddata_pipelines/provisioning/entities/users/user_groups.py,sha256=-2Nca01ZMjXmnAGDUuKP5G7mqFyn4MnsgZsnS2oy7vg,8511
|
|
36
|
-
gooddata_pipelines/provisioning/entities/users/users.py,sha256=
|
|
44
|
+
gooddata_pipelines/provisioning/entities/users/users.py,sha256=BPTbE0-lvwkgoTVwLUbMqmlq7L597nwRCSK5FaM8F4I,7730
|
|
37
45
|
gooddata_pipelines/provisioning/entities/users/models/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
38
46
|
gooddata_pipelines/provisioning/entities/users/models/permissions.py,sha256=buyNtDShvAJL4mFZSV-UqK_9JAL_2-AaIlGYCHibhHo,7244
|
|
39
47
|
gooddata_pipelines/provisioning/entities/users/models/user_groups.py,sha256=Odp4yZoK2vC40jgh7FBKmaIINpwffl62uoaT8Xxr-14,1160
|
|
40
|
-
gooddata_pipelines/provisioning/entities/users/models/users.py,sha256=
|
|
48
|
+
gooddata_pipelines/provisioning/entities/users/models/users.py,sha256=hR5on68NEpw3KAPooR3Z1TRUzV5nbp0jrrOLUDW8P24,2424
|
|
41
49
|
gooddata_pipelines/provisioning/entities/workspaces/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
|
|
42
50
|
gooddata_pipelines/provisioning/entities/workspaces/models.py,sha256=-ehte9HLNos3l6yLip4mZU6wBcmY_Yzwq0t0m0fhwPI,2031
|
|
43
51
|
gooddata_pipelines/provisioning/entities/workspaces/workspace.py,sha256=jngaEKNlMfhjRr4rQ2ECQDoh0gk7KaZTMuTazPLECnM,11505
|
|
@@ -48,7 +56,9 @@ gooddata_pipelines/provisioning/utils/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pj
|
|
|
48
56
|
gooddata_pipelines/provisioning/utils/context_objects.py,sha256=HJoeumH_gXwM6X-GO3HkC4w-6RYozz6-aqQOhDnu7no,879
|
|
49
57
|
gooddata_pipelines/provisioning/utils/exceptions.py,sha256=1WnAOlPhqOf0xRcvn70lxAlLb8Oo6m6WCYS4hj9uzDU,3630
|
|
50
58
|
gooddata_pipelines/provisioning/utils/utils.py,sha256=uF3k5hmoM5d6UoWWfPGCQgT_861zcU-ACyaQHHOOncY,2434
|
|
51
|
-
gooddata_pipelines
|
|
52
|
-
gooddata_pipelines
|
|
53
|
-
gooddata_pipelines-1.50.
|
|
54
|
-
gooddata_pipelines-1.50.
|
|
59
|
+
gooddata_pipelines/utils/__init__.py,sha256=s9TtSjKqo1gSGWOVoGrXaGi1TsbRowjRDYKtjmKy7BY,155
|
|
60
|
+
gooddata_pipelines/utils/rate_limiter.py,sha256=owbcEZhUxlTnE7rRHiWQ8XBC-vML2fVPbt41EeGEM7o,2002
|
|
61
|
+
gooddata_pipelines-1.50.1.dev2.dist-info/METADATA,sha256=7ikqYG7cNfxQm5dBgWO1PcPvGqANtyYj6MoX2BQQsVA,3642
|
|
62
|
+
gooddata_pipelines-1.50.1.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
63
|
+
gooddata_pipelines-1.50.1.dev2.dist-info/licenses/LICENSE.txt,sha256=PNC7WXGIo6OKkNoPLRxlVrw6jaLcjSTUsSxy9Xcu9Jo,560365
|
|
64
|
+
gooddata_pipelines-1.50.1.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|