castor-extractor 0.24.20__py3-none-any.whl → 0.24.21__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 +4 -0
- castor_extractor/commands/extract_looker_studio.py +6 -0
- castor_extractor/visualization/looker_studio/assets.py +5 -1
- castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +1 -2
- castor_extractor/visualization/looker_studio/client/credentials.py +21 -0
- castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +2 -2
- castor_extractor/visualization/looker_studio/extract.py +13 -2
- {castor_extractor-0.24.20.dist-info → castor_extractor-0.24.21.dist-info}/METADATA +5 -1
- {castor_extractor-0.24.20.dist-info → castor_extractor-0.24.21.dist-info}/RECORD +12 -13
- castor_extractor/visualization/looker_studio/client/scopes.py +0 -6
- {castor_extractor-0.24.20.dist-info → castor_extractor-0.24.21.dist-info}/LICENCE +0 -0
- {castor_extractor-0.24.20.dist-info → castor_extractor-0.24.21.dist-info}/WHEEL +0 -0
- {castor_extractor-0.24.20.dist-info → castor_extractor-0.24.21.dist-info}/entry_points.txt +0 -0
CHANGELOG.md
CHANGED
|
@@ -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,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=
|
|
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(),
|
|
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
|
-
|
|
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.
|
|
3
|
+
Version: 0.24.21
|
|
4
4
|
Summary: Extract your metadata assets.
|
|
5
5
|
Home-page: https://www.castordoc.com/
|
|
6
6
|
License: EULA
|
|
@@ -215,6 +215,10 @@ For any questions or bug report, contact us at [support@coalesce.io](mailto:supp
|
|
|
215
215
|
|
|
216
216
|
# Changelog
|
|
217
217
|
|
|
218
|
+
## 0.24.21 - 2025-05-26
|
|
219
|
+
|
|
220
|
+
* Looker Studio: add option to skip the extraction of view activity logs
|
|
221
|
+
|
|
218
222
|
## 0.24.20 - 2025-05-19
|
|
219
223
|
|
|
220
224
|
* Powerbi: allow custom api base and login url
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CHANGELOG.md,sha256=
|
|
1
|
+
CHANGELOG.md,sha256=tja1IyeA0_DdgOOJLdH8WMTmSRucj5bnvR0G0tg_Nsk,17859
|
|
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=
|
|
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
|
|
@@ -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=
|
|
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=
|
|
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=
|
|
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=
|
|
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/
|
|
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.
|
|
430
|
-
castor_extractor-0.24.
|
|
431
|
-
castor_extractor-0.24.
|
|
432
|
-
castor_extractor-0.24.
|
|
433
|
-
castor_extractor-0.24.
|
|
428
|
+
castor_extractor-0.24.21.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
|
|
429
|
+
castor_extractor-0.24.21.dist-info/METADATA,sha256=Yg7Sgskg-uUeas31S1Uit1F7L1tPcVCLFy2U3rBlzIY,25312
|
|
430
|
+
castor_extractor-0.24.21.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
431
|
+
castor_extractor-0.24.21.dist-info/entry_points.txt,sha256=_F-qeZCybjoMkNb9ErEhnyqXuG6afHIFQhakdBHZsr4,1803
|
|
432
|
+
castor_extractor-0.24.21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|