castor-extractor 0.24.20__py3-none-any.whl → 0.24.22__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 castor-extractor might be problematic. Click here for more details.

CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.24.22 - 2025-05-27
4
+
5
+ * Add retry for `Request.Timeout` on **ApiClient**
6
+
7
+ ## 0.24.21 - 2025-05-26
8
+
9
+ * Looker Studio: add option to skip the extraction of view activity logs
10
+
3
11
  ## 0.24.20 - 2025-05-19
4
12
 
5
13
  * Powerbi: allow custom api base and login url
@@ -24,6 +24,12 @@ def main():
24
24
  "This can be the same file path as for Looker Studio."
25
25
  ),
26
26
  )
27
+ parser.add_argument(
28
+ "--skip-view-activity-logs",
29
+ action="store_true",
30
+ default=False,
31
+ help="Skips the extraction of activity logs",
32
+ )
27
33
 
28
34
  parser.add_argument("-o", "--output", help="Directory to write to")
29
35
 
@@ -1,14 +1,11 @@
1
1
  from http import HTTPStatus
2
2
  from typing import Iterator, Optional
3
3
 
4
- import requests
5
-
6
4
  from ....utils import (
7
5
  APIClient,
8
6
  BearerAuth,
9
7
  RequestSafeMode,
10
8
  SerializedAsset,
11
- retry,
12
9
  )
13
10
  from ..assets import CoalesceAsset, CoalesceQualityAsset
14
11
  from .credentials import CoalesceCredentials
@@ -20,9 +17,6 @@ from .utils import column_names_per_node, is_test, test_names_per_node
20
17
 
21
18
  _LIMIT_MAX = 1_000
22
19
  _MAX_ERRORS = 50
23
- _RETRY_BASE_MS = 10 * 60 * 1000 # 10 minutes
24
- _RETRY_COUNT = 2
25
- _RETRY_EXCEPTIONS = [requests.exceptions.ConnectTimeout]
26
20
 
27
21
 
28
22
  def _run_result_payload(result: dict, query_result: dict) -> dict:
@@ -75,11 +69,6 @@ class CoalesceClient(APIClient):
75
69
  result = self._get(endpoint=endpoint)
76
70
  return result["data"]
77
71
 
78
- @retry(
79
- exceptions=_RETRY_EXCEPTIONS,
80
- max_retries=_RETRY_COUNT,
81
- base_ms=_RETRY_BASE_MS,
82
- )
83
72
  def _node_details(self, environment_id: int, node_id: str) -> dict:
84
73
  endpoint = CoalesceEndpointFactory.nodes(
85
74
  environment_id=environment_id, node_id=node_id
@@ -5,7 +5,7 @@ from typing import Callable, Literal, Optional
5
5
  import requests
6
6
  from requests import Response
7
7
 
8
- from ...retry import retry_request
8
+ from ...retry import retry, retry_request
9
9
  from .auth import Auth
10
10
  from .safe_request import RequestSafeMode, handle_response
11
11
  from .utils import build_url
@@ -21,6 +21,10 @@ DEFAULT_TIMEOUT = 60
21
21
  RETRY_ON_EXPIRED_TOKEN = 1
22
22
  RETRY_ON_GATEWAY_TIMEOUT = 3
23
23
 
24
+ _TIMEOUT_RETRY_BASE_MS = 10 * 60 * 1000 # 10 minutes
25
+ _TIMEOUT_RETRY_COUNT = 2
26
+ _TIMEOUT_RETRY_EXCEPTIONS = (requests.exceptions.Timeout,)
27
+
24
28
 
25
29
  def _generate_payloads(
26
30
  method: HttpMethod,
@@ -72,6 +76,11 @@ class APIClient:
72
76
  self._auth = auth
73
77
  self._safe_mode = safe_mode
74
78
 
79
+ @retry(
80
+ exceptions=_TIMEOUT_RETRY_EXCEPTIONS,
81
+ max_retries=_TIMEOUT_RETRY_COUNT,
82
+ base_ms=_TIMEOUT_RETRY_BASE_MS,
83
+ )
75
84
  def _call(
76
85
  self,
77
86
  method: HttpMethod,
@@ -26,6 +26,15 @@ class RetryStrategy(Enum):
26
26
  DEFAULT_STRATEGY = RetryStrategy.CONSTANT
27
27
 
28
28
 
29
+ def _warning(callable: Callable, exception: BaseException) -> None:
30
+ exception_type = type(exception)
31
+ exception_path = f"{exception_type.__module__}.{exception_type.__name__}"
32
+ callable_path = f"{callable.__module__}.{callable.__name__}"
33
+
34
+ msg = f"Exception '{exception_path}' occurred within `{callable_path}`"
35
+ logger.warning(msg)
36
+
37
+
29
38
  class Retry(BaseModel):
30
39
  """
31
40
  This class checks if the retry conditions are met, and if so, how long to
@@ -96,7 +105,7 @@ def retry(
96
105
  try:
97
106
  return None, callable(*args, **kwargs)
98
107
  except exceptions_ as err:
99
- logger.warning(f"Exception within {callable.__name__}")
108
+ _warning(callable, err)
100
109
  return err, None
101
110
 
102
111
  def _func(*args, **kwargs) -> Any:
@@ -139,7 +148,7 @@ def retry_request(
139
148
  status_code = err.response.status_code
140
149
  if status_code not in exceptions_:
141
150
  raise err
142
- logger.warning(f"Exception within {callable.__name__}")
151
+ _warning(callable, err)
143
152
  return err, None
144
153
 
145
154
  def _func(*args, **kwargs) -> Any:
@@ -1,7 +1,11 @@
1
- from ...types import ExternalAsset
1
+ from ...types import ExternalAsset, classproperty
2
2
 
3
3
 
4
4
  class LookerStudioAsset(ExternalAsset):
5
5
  ASSETS = "assets"
6
6
  SOURCE_QUERIES = "source_queries"
7
7
  VIEW_ACTIVITY = "view_activity"
8
+
9
+ @classproperty
10
+ def optional(cls) -> set["LookerStudioAsset"]:
11
+ return {LookerStudioAsset.VIEW_ACTIVITY}
@@ -12,7 +12,6 @@ from ....utils import (
12
12
  )
13
13
  from .credentials import LookerStudioCredentials
14
14
  from .pagination import LookerStudioPagination
15
- from .scopes import SCOPES
16
15
 
17
16
  USER_EMAIL_FIELD = "primaryEmail"
18
17
 
@@ -26,7 +25,7 @@ class AdminSDKClient:
26
25
  def __init__(self, credentials: LookerStudioCredentials):
27
26
  self._credentials = Credentials.from_service_account_info(
28
27
  credentials.model_dump(),
29
- scopes=SCOPES,
28
+ scopes=credentials.scopes,
30
29
  subject=credentials.admin_email, # impersonates an admin
31
30
  )
32
31
  self.directory_api = discovery.build(
@@ -1,5 +1,18 @@
1
+ from typing import Optional
2
+
1
3
  from pydantic import BaseModel, SecretStr, field_serializer
2
4
 
5
+ SCOPES_NO_ACTIVITY: tuple[str, ...] = (
6
+ "https://www.googleapis.com/auth/datastudio",
7
+ "https://www.googleapis.com/auth/userinfo.profile",
8
+ "https://www.googleapis.com/auth/admin.directory.user.readonly",
9
+ )
10
+
11
+ DEFAULT_SCOPES: tuple[str, ...] = (
12
+ *SCOPES_NO_ACTIVITY,
13
+ "https://www.googleapis.com/auth/admin.reports.audit.readonly",
14
+ )
15
+
3
16
 
4
17
  class LookerStudioCredentials(BaseModel):
5
18
  """
@@ -19,6 +32,14 @@ class LookerStudioCredentials(BaseModel):
19
32
  token_uri: str
20
33
  type: str
21
34
 
35
+ has_view_activity_logs: Optional[bool] = True
36
+ scopes: Optional[tuple] = DEFAULT_SCOPES
37
+
38
+ def model_post_init(self, __context):
39
+ """Set scopes based on has_view_activity_logs after initialization"""
40
+ if self.has_view_activity_logs is False:
41
+ self.scopes = SCOPES_NO_ACTIVITY
42
+
22
43
  @field_serializer("private_key")
23
44
  def dump_secret(self, pk):
24
45
  """When using model_dump, show private_key value"""
@@ -16,7 +16,6 @@ from .credentials import LookerStudioCredentials
16
16
  from .endpoints import LookerStudioAPIEndpoint
17
17
  from .enums import LookerStudioAssetType
18
18
  from .pagination import LookerStudioPagination
19
- from .scopes import SCOPES
20
19
 
21
20
 
22
21
  @contextmanager
@@ -47,7 +46,8 @@ class LookerStudioAPIAuth(BearerAuth):
47
46
  that user and make requests on that user's behalf.
48
47
  """
49
48
  self._credentials = Credentials.from_service_account_info(
50
- credentials.model_dump(), scopes=SCOPES
49
+ credentials.model_dump(),
50
+ scopes=credentials.scopes,
51
51
  )
52
52
  if subject:
53
53
  self._credentials = self._credentials.with_subject(subject)
@@ -23,8 +23,14 @@ LOOKER_STUDIO_ADMIN_EMAIL = "CASTOR_LOOKER_STUDIO_ADMIN_EMAIL"
23
23
 
24
24
  def iterate_all_data(
25
25
  client: LookerStudioClient,
26
+ has_view_activity_logs: bool = True,
26
27
  ) -> Iterable[tuple[LookerStudioAsset, Union[list, dict]]]:
27
- for asset in LookerStudioAsset:
28
+ assets_to_extract = LookerStudioAsset.mandatory
29
+
30
+ if has_view_activity_logs:
31
+ assets_to_extract.add(LookerStudioAsset.VIEW_ACTIVITY)
32
+
33
+ for asset in assets_to_extract:
28
34
  logger.info(f"Extracting {asset.name} from API")
29
35
  data = list(deep_serialize(client.fetch(asset)))
30
36
  yield asset, data
@@ -45,6 +51,8 @@ def _credentials(params: dict) -> LookerStudioCredentials:
45
51
  LOOKER_STUDIO_ADMIN_EMAIL
46
52
  )
47
53
  credentials["admin_email"] = admin_email
54
+ has_view_activity_logs = not params["skip_view_activity_logs"]
55
+ credentials["has_view_activity_logs"] = has_view_activity_logs
48
56
  return LookerStudioCredentials(**credentials)
49
57
 
50
58
 
@@ -68,7 +76,10 @@ def extract_all(**kwargs) -> None:
68
76
  the given output_directory.
69
77
  """
70
78
  output_directory = kwargs.get("output") or from_env(OUTPUT_DIR)
79
+
71
80
  credentials = _credentials(kwargs)
81
+ has_view_activity_logs = bool(credentials.has_view_activity_logs)
82
+
72
83
  bigquery_credentials = _bigquery_credentials_or_none(kwargs)
73
84
 
74
85
  client = LookerStudioClient(
@@ -77,7 +88,7 @@ def extract_all(**kwargs) -> None:
77
88
  )
78
89
  ts = current_timestamp()
79
90
 
80
- for key, data in iterate_all_data(client):
91
+ for key, data in iterate_all_data(client, has_view_activity_logs):
81
92
  filename = get_output_filename(key.name.lower(), output_directory, ts)
82
93
  write_json(filename, data)
83
94
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.24.20
3
+ Version: 0.24.22
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -215,6 +215,14 @@ For any questions or bug report, contact us at [support@coalesce.io](mailto:supp
215
215
 
216
216
  # Changelog
217
217
 
218
+ ## 0.24.22 - 2025-05-27
219
+
220
+ * Add retry for `Request.Timeout` on **ApiClient**
221
+
222
+ ## 0.24.21 - 2025-05-26
223
+
224
+ * Looker Studio: add option to skip the extraction of view activity logs
225
+
218
226
  ## 0.24.20 - 2025-05-19
219
227
 
220
228
  * Powerbi: allow custom api base and login url
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=NxSwszCNlJ8oD2ffivq3g75DK436mue9WwilR0r6bE4,17760
1
+ CHANGELOG.md,sha256=8EyATqcpMtcJ3LhQgQadRhcDiEULwOXYw40137Y5jgs,17936
2
2
  Dockerfile,sha256=xQ05-CFfGShT3oUqaiumaldwA288dj9Yb_pxofQpufg,301
3
3
  DockerfileUsage.md,sha256=2hkJQF-5JuuzfPZ7IOxgM6QgIQW7l-9oRMFVwyXC4gE,998
4
4
  LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
@@ -10,7 +10,7 @@ castor_extractor/commands/extract_confluence.py,sha256=blYcnDqywXNKRQ1aZAD9FclhL
10
10
  castor_extractor/commands/extract_databricks.py,sha256=SVKyoa-BBUQAM6HRHf1Wdg9-tpICic2yyvXQwHcNBhA,1264
11
11
  castor_extractor/commands/extract_domo.py,sha256=jvAawUsUTHrwCn_koK6StmQr4n_b5GyvJi6uu6WS0SM,1061
12
12
  castor_extractor/commands/extract_looker.py,sha256=cySLiolLCgrREJ9d0kMrJ7P8K3efHTBTzShalWVfI3A,1214
13
- castor_extractor/commands/extract_looker_studio.py,sha256=e79gbyTtCexRz5pg_Pp55GWkXJZWjm6NvVclmvcR0lM,916
13
+ castor_extractor/commands/extract_looker_studio.py,sha256=M7wx8XZScLizCI2vq80aj88vYrdiHChiCiebrrChlZY,1090
14
14
  castor_extractor/commands/extract_metabase_api.py,sha256=NXctea4GT_1iRDitY92nV3TKSqhjEUwYSxwPJMRS3iw,786
15
15
  castor_extractor/commands/extract_metabase_db.py,sha256=tYIhTPPgj1mN-07LyWcL6e-YoGp7HCWda58-5Ukyg_I,1255
16
16
  castor_extractor/commands/extract_mode.py,sha256=Q4iO-VAKMg4zFPejhAO-foZibL5Ht3jsnhWKwJ0oqUU,823
@@ -76,7 +76,7 @@ castor_extractor/transformation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
76
76
  castor_extractor/transformation/coalesce/__init__.py,sha256=CW_qdtEfwgJRsCyBlk5hNlxwEO-VV6mBXZvkRbND_J8,112
77
77
  castor_extractor/transformation/coalesce/assets.py,sha256=pzccYPP66c9PAnVroemx7-6MeRHw7Ft1OlTC6jIamAA,363
78
78
  castor_extractor/transformation/coalesce/client/__init__.py,sha256=VRmVpH29rOghtDQnCN7dAdA0dI0Lxseu4BC8rnwM9dU,80
79
- castor_extractor/transformation/coalesce/client/client.py,sha256=-fFxWtDPPruNmDPc6FXft_6RwRKEee4JM-13d90fms0,6442
79
+ castor_extractor/transformation/coalesce/client/client.py,sha256=o-BlVqdzcQ2RhrmShsNFXVhsmJF4i0pP6DmiWGAE2dY,6172
80
80
  castor_extractor/transformation/coalesce/client/credentials.py,sha256=jbJxjbdPspf-dzYKfeb7oqL_8TXd1nvkJrjAcdAnLPc,548
81
81
  castor_extractor/transformation/coalesce/client/endpoint.py,sha256=0uLh7dpA1vsR9qr_50SEYV_-heQE4BwED9oNMgYsL-w,1272
82
82
  castor_extractor/transformation/coalesce/client/type.py,sha256=oiiVP9NL0ijTXyQmaB8aJVYckc7m-m8ZgMyNIAduUKE,43
@@ -106,7 +106,7 @@ castor_extractor/utils/client/abstract.py,sha256=CWF7_afNpEZ3jor-22wXbKIvM20ukHk
106
106
  castor_extractor/utils/client/api/__init__.py,sha256=vlG7WXznYgLTn3XyMGsyUkgRkup8FbKM14EXJ8mv-b0,264
107
107
  castor_extractor/utils/client/api/auth.py,sha256=lq0K3UEl1vwIIa_vKTdlpIQPdE5K1-5DXmCwO4dKzng,1890
108
108
  castor_extractor/utils/client/api/auth_test.py,sha256=LlyXytnatg6ZzR4Zkvzk0BH99FYhHX7qn_nyr2MSnDI,1305
109
- castor_extractor/utils/client/api/client.py,sha256=d3I-RbKgy7dqONKj2hAuRxTr9i9U82RklIuRjnVppeM,4574
109
+ castor_extractor/utils/client/api/client.py,sha256=En1V9eglhB71q5jZwi5XhNZanLb7IUKfd4AT-sSexJk,4866
110
110
  castor_extractor/utils/client/api/client_test.py,sha256=FM3ZxsLLfMOBn44cXX6FIgnA31-5TTNIyp9D4LBwtXE,1222
111
111
  castor_extractor/utils/client/api/pagination.py,sha256=ph5TYqPiyFGgygsIhCATAHPIQ9UJNZyiTcqlyRdGEno,2460
112
112
  castor_extractor/utils/client/api/pagination_test.py,sha256=jCOgXFXrH-jrCxe2dfk80ZksJF-EtmpJPU11BGabsqk,1385
@@ -138,7 +138,7 @@ castor_extractor/utils/pager/pager.py,sha256=93Rw7jCz6GnqrS4HfYfKYV2xgEx2esl1qC9
138
138
  castor_extractor/utils/pager/pager_on_id.py,sha256=jBvmlEhkJ-sODkNyz1KyyXHobLsNhC4AwhOwYvLyB4E,1967
139
139
  castor_extractor/utils/pager/pager_on_id_test.py,sha256=eDGrIYPGffuKPUATgu5fiXIwPKdSwEXGgTtfMiHqoj0,1601
140
140
  castor_extractor/utils/pager/pager_test.py,sha256=PQOXQwQD2wOP0xzZfNTuLxcn3Bpa4FCASVklH71GO_s,1699
141
- castor_extractor/utils/retry.py,sha256=LvfBsE_R6g-U72hkN531rJDMj42zwkUqgIrrjlxctJs,4733
141
+ castor_extractor/utils/retry.py,sha256=xRlAxHRnjmjh2sDUuuUSS-s38pokoAvSgSKjdgWGqbc,5020
142
142
  castor_extractor/utils/retry_test.py,sha256=j_6IJStBomEhxmGpIY9IIlESgMxhcDpmIKj24unLqlA,2892
143
143
  castor_extractor/utils/safe.py,sha256=gvIMRIoggdVeYMl222IYqXnHVDninDklFMlAHt-WldA,1948
144
144
  castor_extractor/utils/safe_test.py,sha256=IHN1Z761tYMFslYC-2HAfkXmFPh4LYSqNLs4QZwykjk,2160
@@ -186,18 +186,17 @@ castor_extractor/visualization/looker/fields.py,sha256=7oC7p-3Wp7XHBP_FT_D1wH3kI
186
186
  castor_extractor/visualization/looker/fields_test.py,sha256=7Cwq8Qky6aTZg8nCHp1gmPJtd9pGNB4QeMIRRWdHo5w,782
187
187
  castor_extractor/visualization/looker/multithreading.py,sha256=Muuh3usBLqtv3sfHoyPYJ6jJ7V5ajR6N9ZJ_F-bNc60,2608
188
188
  castor_extractor/visualization/looker_studio/__init__.py,sha256=GccG-GJXoNhjXFPkw-rHHZ0SXVQTFKjqkMIYHVeu3T4,175
189
- castor_extractor/visualization/looker_studio/assets.py,sha256=lFIqr8EB6eK-Mf80R_x2qAscCyX7ZUcOcHVef1CM9B0,173
189
+ castor_extractor/visualization/looker_studio/assets.py,sha256=rI73rbVrfwkkepqZr0zPouP2lPUfJxSi21RKtOTHtAA,308
190
190
  castor_extractor/visualization/looker_studio/client/__init__.py,sha256=YkQaVDJa-7KSwdOLjtgKJMRiafbGNKC_46YVx0hYZ1Q,129
191
- castor_extractor/visualization/looker_studio/client/admin_sdk_client.py,sha256=hYKdU6TlWKkXx07r6HsZ4Wbxhasx8DP_jO6iDCjHjgk,3508
191
+ castor_extractor/visualization/looker_studio/client/admin_sdk_client.py,sha256=HIeyT9JTW1TPwVzD2Q-VfJ99jMP80Z-4CznKAnTnp2w,3493
192
192
  castor_extractor/visualization/looker_studio/client/client.py,sha256=6sTfLRUhuxhkqDjC2ZBEaw6YnR6ze8-_VW2rc1u9Ksk,3191
193
- castor_extractor/visualization/looker_studio/client/credentials.py,sha256=QImJPh8VctkrGt65UiU5hM12JI4WdCMSUFt88aiOoLw,657
193
+ castor_extractor/visualization/looker_studio/client/credentials.py,sha256=F4ISI8Ua_HJsMuGhYql28o3hKYR4sL_uzkrUkRiekRo,1347
194
194
  castor_extractor/visualization/looker_studio/client/endpoints.py,sha256=5eY-ffqNDdlDBOOpiF7LpjyHMrzeClJktidCr1pTDUs,669
195
195
  castor_extractor/visualization/looker_studio/client/enums.py,sha256=fHgemTaQpnwee8cw1YQVDsVnH--vTyFwT4Px8aVYYHQ,167
196
- castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py,sha256=oySC6rsppj67RSifxwSCw4bFrz1Irx6IFJhX7tc_v1E,4087
196
+ castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py,sha256=Phq378VEaFLD-nyP2_A1wge6HUP45jSthhlNjD7aqSg,4085
197
197
  castor_extractor/visualization/looker_studio/client/pagination.py,sha256=9HQ3Rkdiz2VB6AvYtZ0F-WouiD0pMmdZyAmkv-3wh08,783
198
198
  castor_extractor/visualization/looker_studio/client/queries/query.sql,sha256=Ub4rdrJ5WTPWKI-eVmXrNMv0Ktmti4b-93zZBr0xEB0,1426
199
- castor_extractor/visualization/looker_studio/client/scopes.py,sha256=824cqqgZuGq4L-rPNoHJe0ibXsxkRwB0CLG_kqw9Q0g,256
200
- castor_extractor/visualization/looker_studio/extract.py,sha256=cHyroNZ1fKoBTvIbEebnKDrU3xpkcEgIPJy75ljCL70,2607
199
+ castor_extractor/visualization/looker_studio/extract.py,sha256=uNpvg4wtFflmpkqXFfo_9Nm12AEKXBOCKKajIggySho,3026
201
200
  castor_extractor/visualization/metabase/__init__.py,sha256=3E36cmkMyEgBB6Ot5rWk-N75i0G-7k24QTlc-Iol4pM,193
202
201
  castor_extractor/visualization/metabase/assets.py,sha256=nu3FwQBU_hdS2DBvgXAwQlEEi76QiNK2tMKEtMyctaY,2874
203
202
  castor_extractor/visualization/metabase/client/__init__.py,sha256=KBvaPMofBRV3m_sZAnKNCrJGr-Z88EbpdzEzWPQ_uBk,99
@@ -426,8 +425,8 @@ castor_extractor/warehouse/sqlserver/queries/table.sql,sha256=kbBQP-TdG5px1IVgyx
426
425
  castor_extractor/warehouse/sqlserver/queries/user.sql,sha256=gOrZsMVypusR2dc4vwVs4E1a-CliRsr_UjnD2EbXs-A,94
427
426
  castor_extractor/warehouse/sqlserver/query.py,sha256=g0hPT-RmeGi2DyenAi3o72cTlQsLToXIFYojqc8E5fQ,533
428
427
  castor_extractor/warehouse/synapse/queries/column.sql,sha256=lNcFoIW3Y0PFOqoOzJEXmPvZvfAsY0AP63Mu2LuPzPo,1351
429
- castor_extractor-0.24.20.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
430
- castor_extractor-0.24.20.dist-info/METADATA,sha256=DvgjbhUmiYXzV9e3MXsEGuSfgOog38LrEBNmqFIAcyI,25213
431
- castor_extractor-0.24.20.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
432
- castor_extractor-0.24.20.dist-info/entry_points.txt,sha256=_F-qeZCybjoMkNb9ErEhnyqXuG6afHIFQhakdBHZsr4,1803
433
- castor_extractor-0.24.20.dist-info/RECORD,,
428
+ castor_extractor-0.24.22.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
429
+ castor_extractor-0.24.22.dist-info/METADATA,sha256=VTqwYHqBEng4wSZ5N88tT1z6Y2OdS9uETv4qIE3CZVw,25389
430
+ castor_extractor-0.24.22.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
431
+ castor_extractor-0.24.22.dist-info/entry_points.txt,sha256=_F-qeZCybjoMkNb9ErEhnyqXuG6afHIFQhakdBHZsr4,1803
432
+ castor_extractor-0.24.22.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- SCOPES = (
2
- "https://www.googleapis.com/auth/datastudio",
3
- "https://www.googleapis.com/auth/userinfo.profile",
4
- "https://www.googleapis.com/auth/admin.reports.audit.readonly",
5
- "https://www.googleapis.com/auth/admin.directory.user.readonly",
6
- )