castor-extractor 0.9.0__py3-none-any.whl → 0.10.0__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 +12 -0
- Dockerfile +16 -0
- castor_extractor/commands/extract_looker.py +1 -8
- castor_extractor/visualization/looker/__init__.py +1 -7
- castor_extractor/visualization/looker/api/__init__.py +1 -5
- castor_extractor/visualization/looker/api/client.py +6 -23
- castor_extractor/visualization/looker/api/utils.py +1 -26
- castor_extractor/visualization/looker/constant.py +0 -1
- castor_extractor/visualization/looker/extract.py +14 -15
- castor_extractor/visualization/looker/multithreading.py +5 -17
- castor_extractor/visualization/looker/parameters.py +0 -4
- castor_extractor/warehouse/redshift/queries/query.sql +16 -6
- {castor_extractor-0.9.0.dist-info → castor_extractor-0.10.0.dist-info}/METADATA +1 -1
- {castor_extractor-0.9.0.dist-info → castor_extractor-0.10.0.dist-info}/RECORD +16 -15
- {castor_extractor-0.9.0.dist-info → castor_extractor-0.10.0.dist-info}/WHEEL +0 -0
- {castor_extractor-0.9.0.dist-info → castor_extractor-0.10.0.dist-info}/entry_points.txt +0 -0
CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0 - 2023-11-28
|
|
4
|
+
|
|
5
|
+
* Looker : extract all Looker Explores, even if unused in Dashboards
|
|
6
|
+
|
|
7
|
+
## 0.9.2 - 2023-11-23
|
|
8
|
+
|
|
9
|
+
* Looker : remove deprecated all_looks parameter
|
|
10
|
+
|
|
11
|
+
## 0.9.1 - 2023-11-22
|
|
12
|
+
|
|
13
|
+
* Redshift : filter out queries exceeding 65535 char
|
|
14
|
+
|
|
3
15
|
## 0.9.0 - 2023-11-20
|
|
4
16
|
|
|
5
17
|
* Snowflake : Add key-pair authentication
|
Dockerfile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.5
|
|
2
|
+
|
|
3
|
+
FROM --platform=linux/amd64 python:3.10-slim
|
|
4
|
+
|
|
5
|
+
ARG EXTRA
|
|
6
|
+
ENV EXTRA=${EXTRA}
|
|
7
|
+
|
|
8
|
+
RUN pip install --upgrade pip && \
|
|
9
|
+
pip install castor-extractor[${EXTRA}]
|
|
10
|
+
|
|
11
|
+
ENV CASTOR_OUTPUT_DIRECTORY=/data
|
|
12
|
+
|
|
13
|
+
VOLUME [ "/data" ]
|
|
14
|
+
|
|
15
|
+
ENTRYPOINT castor-extract-${EXTRA}
|
|
16
|
+
CMD [ "--log-to-stdout" ]
|
|
@@ -27,13 +27,7 @@ def main():
|
|
|
27
27
|
action="store_true",
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
group.add_argument(
|
|
32
|
-
"--all-looks",
|
|
33
|
-
help="Use all_looks endpoint instead of the paginated search_looks",
|
|
34
|
-
action="store_true",
|
|
35
|
-
)
|
|
36
|
-
group.add_argument(
|
|
30
|
+
parser.add_argument(
|
|
37
31
|
"--search-per-folder",
|
|
38
32
|
help="Fetches Looks and Dashboards per folder",
|
|
39
33
|
action="store_true",
|
|
@@ -42,7 +36,6 @@ def main():
|
|
|
42
36
|
args = parser.parse_args()
|
|
43
37
|
|
|
44
38
|
looker.extract_all(
|
|
45
|
-
all_looks=args.all_looks,
|
|
46
39
|
base_url=args.base_url,
|
|
47
40
|
client_id=args.username,
|
|
48
41
|
client_secret=args.password,
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
from .api import
|
|
2
|
-
ApiClient,
|
|
3
|
-
Credentials,
|
|
4
|
-
dashboard_explore_names,
|
|
5
|
-
explore_names_associated_to_dashboards,
|
|
6
|
-
lookml_explore_names,
|
|
7
|
-
)
|
|
1
|
+
from .api import ApiClient, Credentials, lookml_explore_names
|
|
8
2
|
from .assets import LookerAsset
|
|
9
3
|
from .extract import extract_all, iterate_all_data
|
|
@@ -125,7 +125,7 @@ class ApiClient:
|
|
|
125
125
|
|
|
126
126
|
return Pager(_search, logger=self._logger).all(per_page=self.per_page)
|
|
127
127
|
|
|
128
|
-
def
|
|
128
|
+
def looks(self, folder_id: Optional[str] = None) -> List[Look]:
|
|
129
129
|
"""
|
|
130
130
|
Fetch looks via `search_looks` using pagination. The optional folder_id
|
|
131
131
|
allows restricting the search to the given folder.
|
|
@@ -156,22 +156,6 @@ class ApiClient:
|
|
|
156
156
|
# No pagination : see https://community.looker.com/looker-api-77/api-paging-limits-14598
|
|
157
157
|
return list(self._sdk.all_looks(fields=format_fields(LOOK_FIELDS)))
|
|
158
158
|
|
|
159
|
-
def looks(
|
|
160
|
-
self,
|
|
161
|
-
all_looks_endpoint: Optional[bool] = False,
|
|
162
|
-
folder_id: Optional[str] = None,
|
|
163
|
-
) -> List[Look]:
|
|
164
|
-
"""Lists looks of the given Looker account
|
|
165
|
-
|
|
166
|
-
By default, uses the endpoint `search_looks` that allows pagination and
|
|
167
|
-
filtering on a folder.
|
|
168
|
-
If `all_looks_endpoint` parameter is set to True, it uses `all_looks` endpoint.
|
|
169
|
-
"""
|
|
170
|
-
if all_looks_endpoint:
|
|
171
|
-
return self._all_looks()
|
|
172
|
-
|
|
173
|
-
return self._search_looks(folder_id)
|
|
174
|
-
|
|
175
159
|
def users(self) -> List[User]:
|
|
176
160
|
"""Lists users of the given Looker account"""
|
|
177
161
|
|
|
@@ -207,7 +191,7 @@ class ApiClient:
|
|
|
207
191
|
def explores(
|
|
208
192
|
self,
|
|
209
193
|
explore_names=Iterator[Tuple[str, str]],
|
|
210
|
-
) ->
|
|
194
|
+
) -> Iterator[LookmlModelExplore]:
|
|
211
195
|
"""Iterates explores of the given Looker account for the provided model/explore names"""
|
|
212
196
|
|
|
213
197
|
@safe_mode(self._safe_mode)
|
|
@@ -218,11 +202,10 @@ class ApiClient:
|
|
|
218
202
|
self._on_api_call()
|
|
219
203
|
return explore
|
|
220
204
|
|
|
221
|
-
|
|
222
|
-
_call(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return list(filter(None, explores))
|
|
205
|
+
for lookml_model_name, lookml_explore_name_ in explore_names:
|
|
206
|
+
explore_ = _call(lookml_model_name, lookml_explore_name_)
|
|
207
|
+
if explore_ is not None:
|
|
208
|
+
yield explore_
|
|
226
209
|
|
|
227
210
|
def connections(self) -> List[DBConnection]:
|
|
228
211
|
"""Lists databases connections of the given Looker account"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Iterable, Set, Tuple
|
|
2
2
|
|
|
3
|
-
from .sdk import
|
|
3
|
+
from .sdk import LookmlModel
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def lookml_explore_names(
|
|
@@ -22,28 +22,3 @@ def lookml_explore_names(
|
|
|
22
22
|
# accept hidden resources
|
|
23
23
|
if model.name and explore.name
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def dashboard_explore_names(
|
|
28
|
-
dashboards: Iterable[Dashboard],
|
|
29
|
-
) -> Set[Tuple[str, str]]:
|
|
30
|
-
"""Explores that appear in dashboards"""
|
|
31
|
-
elements = (
|
|
32
|
-
element
|
|
33
|
-
for dashboard in dashboards
|
|
34
|
-
for element in dashboard.dashboard_elements or []
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
(element.query.model, element.query.view)
|
|
39
|
-
for element in elements
|
|
40
|
-
if element.query and element.query.model and element.query.view
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def explore_names_associated_to_dashboards(
|
|
45
|
-
lookmls: Iterable[LookmlModel],
|
|
46
|
-
dashboard_explore_names_: Set[Tuple[str, str]],
|
|
47
|
-
):
|
|
48
|
-
"""Retrieve only explores that are associated to a looker dashboard"""
|
|
49
|
-
return lookml_explore_names(lookmls).intersection(dashboard_explore_names_)
|
|
@@ -20,6 +20,5 @@ KEY_LOOKER_THREAD_POOL_SIZE = "CASTOR_LOOKER_THREAD_POOL_SIZE"
|
|
|
20
20
|
BASE_URL = "CASTOR_LOOKER_BASE_URL"
|
|
21
21
|
CLIENT_ID = "CASTOR_LOOKER_CLIENT_ID"
|
|
22
22
|
CLIENT_SECRET = "CASTOR_LOOKER_CLIENT_SECRET" # noqa: S105
|
|
23
|
-
ALL_LOOKS = "CASTOR_LOOKER_ALL_LOOKS"
|
|
24
23
|
SEARCH_PER_FOLDER = "CASTOR_LOOKER_SEARCH_PER_FOLDER"
|
|
25
24
|
LOG_TO_STDOUT = "CASTOR_LOOKER_LOG_TO_STDOUT"
|
|
@@ -11,12 +11,8 @@ from ...utils import (
|
|
|
11
11
|
write_json,
|
|
12
12
|
write_summary,
|
|
13
13
|
)
|
|
14
|
-
from .api import
|
|
15
|
-
|
|
16
|
-
Credentials,
|
|
17
|
-
dashboard_explore_names,
|
|
18
|
-
explore_names_associated_to_dashboards,
|
|
19
|
-
)
|
|
14
|
+
from .api import ApiClient, Credentials, lookml_explore_names
|
|
15
|
+
from .api.sdk import LookmlModel
|
|
20
16
|
from .assets import LookerAsset
|
|
21
17
|
from .multithreading import MultithreadingFetcher
|
|
22
18
|
from .parameters import get_parameters
|
|
@@ -24,6 +20,15 @@ from .parameters import get_parameters
|
|
|
24
20
|
logger = logging.getLogger(__name__)
|
|
25
21
|
|
|
26
22
|
|
|
23
|
+
def _extract_explores_by_name(
|
|
24
|
+
lookmls: Iterable[LookmlModel], client: ApiClient
|
|
25
|
+
) -> Iterable[dict]:
|
|
26
|
+
explore_names = lookml_explore_names(lookmls)
|
|
27
|
+
explores = client.explores(explore_names)
|
|
28
|
+
for explore in explores:
|
|
29
|
+
yield deep_serialize(explore) # type: ignore
|
|
30
|
+
|
|
31
|
+
|
|
27
32
|
def _safe_mode(directory: str) -> SafeMode:
|
|
28
33
|
add_logging_file_handler(directory)
|
|
29
34
|
return SafeMode((Exception,), float("inf"))
|
|
@@ -47,7 +52,6 @@ def _client(
|
|
|
47
52
|
|
|
48
53
|
def iterate_all_data(
|
|
49
54
|
client: ApiClient,
|
|
50
|
-
all_looks: bool,
|
|
51
55
|
search_per_folder: bool,
|
|
52
56
|
thread_pool_size: int,
|
|
53
57
|
log_to_stdout: bool,
|
|
@@ -74,16 +78,14 @@ def iterate_all_data(
|
|
|
74
78
|
looks_stream = fetcher.fetch_assets(LookerAsset.LOOKS)
|
|
75
79
|
yield LookerAsset.LOOKS, StreamableList(looks_stream)
|
|
76
80
|
else:
|
|
77
|
-
yield LookerAsset.LOOKS, deep_serialize(client.looks(
|
|
81
|
+
yield LookerAsset.LOOKS, deep_serialize(client.looks())
|
|
78
82
|
|
|
79
83
|
logger.info("Extracting dashboards from Looker API")
|
|
80
84
|
if search_per_folder:
|
|
81
85
|
dashboards_stream = fetcher.fetch_assets(LookerAsset.DASHBOARDS)
|
|
82
86
|
yield LookerAsset.DASHBOARDS, StreamableList(dashboards_stream)
|
|
83
|
-
dashboard_explore_names_ = fetcher.explores
|
|
84
87
|
else:
|
|
85
88
|
dashboards = client.dashboards()
|
|
86
|
-
dashboard_explore_names_ = dashboard_explore_names(dashboards)
|
|
87
89
|
yield LookerAsset.DASHBOARDS, deep_serialize(dashboards)
|
|
88
90
|
|
|
89
91
|
logger.info("Extracting lookml models from Looker API")
|
|
@@ -91,10 +93,8 @@ def iterate_all_data(
|
|
|
91
93
|
yield LookerAsset.LOOKML_MODELS, deep_serialize(lookmls)
|
|
92
94
|
|
|
93
95
|
logger.info("Extracting explores from Looker API")
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
97
|
-
yield LookerAsset.EXPLORES, deep_serialize(client.explores(explore_names))
|
|
96
|
+
explores = _extract_explores_by_name(lookmls, client)
|
|
97
|
+
yield LookerAsset.EXPLORES, StreamableList(explores)
|
|
98
98
|
del lookmls
|
|
99
99
|
|
|
100
100
|
logger.info("Extracting connections from Looker API")
|
|
@@ -144,7 +144,6 @@ def extract_all(**kwargs) -> None:
|
|
|
144
144
|
|
|
145
145
|
data = iterate_all_data(
|
|
146
146
|
client=client,
|
|
147
|
-
all_looks=parameters.all_looks,
|
|
148
147
|
search_per_folder=parameters.search_per_folder,
|
|
149
148
|
thread_pool_size=parameters.thread_pool_size,
|
|
150
149
|
log_to_stdout=parameters.log_to_stdout,
|
|
@@ -2,13 +2,13 @@ import logging
|
|
|
2
2
|
import sys
|
|
3
3
|
from concurrent.futures import ThreadPoolExecutor
|
|
4
4
|
from functools import partial
|
|
5
|
-
from typing import Iterable, List, Set
|
|
5
|
+
from typing import Iterable, List, Set
|
|
6
6
|
|
|
7
7
|
from tqdm import tqdm # type: ignore
|
|
8
8
|
|
|
9
9
|
from ...utils import RetryStrategy, deep_serialize, retry
|
|
10
|
-
from . import ApiClient
|
|
11
|
-
from .api.sdk import
|
|
10
|
+
from . import ApiClient
|
|
11
|
+
from .api.sdk import SDKError
|
|
12
12
|
from .assets import LookerAsset
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
@@ -54,16 +54,6 @@ class MultithreadingFetcher:
|
|
|
54
54
|
self._thread_pool_size = thread_pool_size
|
|
55
55
|
self._log_to_stdout = log_to_stdout
|
|
56
56
|
|
|
57
|
-
self.explores: Set[Tuple[str, str]] = set()
|
|
58
|
-
|
|
59
|
-
def _save_explore_names(self, dashboards_per_folder: Iterable[Dashboard]):
|
|
60
|
-
"""
|
|
61
|
-
Since dashboards are streamed right to the file, we need to keep
|
|
62
|
-
the relevant information to extract Explores later.
|
|
63
|
-
"""
|
|
64
|
-
explores = dashboard_explore_names(dashboards_per_folder)
|
|
65
|
-
self.explores.update(explores)
|
|
66
|
-
|
|
67
57
|
def _progress_bar(self, fetch_results: Iterable, total: int) -> tqdm:
|
|
68
58
|
"""Create a tqdm progress bar with the appropriate logs destination"""
|
|
69
59
|
file = sys.stderr
|
|
@@ -73,7 +63,7 @@ class MultithreadingFetcher:
|
|
|
73
63
|
|
|
74
64
|
return tqdm(fetch_results, total=total, file=file)
|
|
75
65
|
|
|
76
|
-
def fetch_assets(self, asset: LookerAsset):
|
|
66
|
+
def fetch_assets(self, asset: LookerAsset) -> Iterable[dict]:
|
|
77
67
|
"""
|
|
78
68
|
Yields serialized Looks or Dashboards with a request per folder ID.
|
|
79
69
|
Requests are parallelised.
|
|
@@ -88,12 +78,10 @@ class MultithreadingFetcher:
|
|
|
88
78
|
fetch_results = executor.map(_fetch, self._folder_ids)
|
|
89
79
|
|
|
90
80
|
for results in self._progress_bar(fetch_results, total_folders):
|
|
91
|
-
if asset == LookerAsset.DASHBOARDS:
|
|
92
|
-
self._save_explore_names(results)
|
|
93
|
-
|
|
94
81
|
for result in results:
|
|
95
82
|
if not result:
|
|
96
83
|
continue
|
|
84
|
+
|
|
97
85
|
total_assets_count += len(result)
|
|
98
86
|
yield deep_serialize(result)
|
|
99
87
|
|
|
@@ -2,7 +2,6 @@ from typing import NamedTuple, Optional
|
|
|
2
2
|
|
|
3
3
|
from ...utils import OUTPUT_DIR, from_env, validate_baseurl
|
|
4
4
|
from .constant import (
|
|
5
|
-
ALL_LOOKS,
|
|
6
5
|
BASE_URL,
|
|
7
6
|
CLIENT_ID,
|
|
8
7
|
CLIENT_SECRET,
|
|
@@ -31,7 +30,6 @@ def _bool_env_variable(key: str) -> bool:
|
|
|
31
30
|
class Parameters(NamedTuple):
|
|
32
31
|
"""Parameters for Looker extraction"""
|
|
33
32
|
|
|
34
|
-
all_looks: bool
|
|
35
33
|
base_url: str
|
|
36
34
|
client_id: str
|
|
37
35
|
client_secret: str
|
|
@@ -63,13 +61,11 @@ def get_parameters(**kwargs) -> Parameters:
|
|
|
63
61
|
search_per_folder = kwargs.get("search_per_folder") or _bool_env_variable(
|
|
64
62
|
SEARCH_PER_FOLDER,
|
|
65
63
|
)
|
|
66
|
-
all_looks = kwargs.get("all_looks") or _bool_env_variable(ALL_LOOKS)
|
|
67
64
|
log_to_stdout = kwargs.get("log_to_stdout") or _bool_env_variable(
|
|
68
65
|
LOG_TO_STDOUT
|
|
69
66
|
)
|
|
70
67
|
|
|
71
68
|
return Parameters(
|
|
72
|
-
all_looks=all_looks,
|
|
73
69
|
base_url=base_url,
|
|
74
70
|
client_id=client_id,
|
|
75
71
|
client_secret=client_secret,
|
|
@@ -14,16 +14,26 @@ queries_deduplicated AS (
|
|
|
14
14
|
AND EXTRACT('hour' FROM q.starttime) BETWEEN p.hour_min AND p.hour_max
|
|
15
15
|
),
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
(
|
|
17
|
+
query AS (
|
|
19
18
|
SELECT
|
|
20
19
|
q.query,
|
|
21
|
-
|
|
20
|
+
qt.text,
|
|
21
|
+
qt.sequence,
|
|
22
|
+
COUNT(*) OVER(PARTITION BY q.query) AS sequence_count
|
|
22
23
|
FROM queries_deduplicated AS q
|
|
23
24
|
INNER JOIN pg_catalog.stl_querytext AS qt ON q.query = qt.query
|
|
25
|
+
),
|
|
26
|
+
|
|
27
|
+
raw_query_text AS
|
|
28
|
+
(
|
|
29
|
+
SELECT
|
|
30
|
+
q.query,
|
|
31
|
+
LISTAGG(q.text, '') WITHIN GROUP (ORDER BY q.sequence) AS agg_text
|
|
32
|
+
FROM query AS q
|
|
24
33
|
WHERE TRUE
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
-- LISTAGG raises an error when total length >= 65535
|
|
35
|
+
-- each sequence contains 200 char max
|
|
36
|
+
AND q.sequence_count < (65535 / 200)
|
|
27
37
|
GROUP BY q.query
|
|
28
38
|
),
|
|
29
39
|
|
|
@@ -59,7 +69,7 @@ read_query AS (
|
|
|
59
69
|
AND EXTRACT('hour' FROM q.starttime) BETWEEN p.hour_min AND p.hour_max
|
|
60
70
|
),
|
|
61
71
|
|
|
62
|
-
-- the DDL part is sensible to any change of JOIN and
|
|
72
|
+
-- the DDL part is sensible to any change of JOIN and AGGREGATION: test in the field prior to merging
|
|
63
73
|
ddl_query AS (
|
|
64
74
|
SELECT
|
|
65
75
|
(q.xid || '-' || q.query_part_rank)::VARCHAR(256) AS query_id,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
CHANGELOG.md,sha256
|
|
1
|
+
CHANGELOG.md,sha256=-SDIu5XMRtiE4Pp7-F8aCJteadjcjuxDwdvRIjKefBw,7349
|
|
2
|
+
Dockerfile,sha256=TC6hFjG3mvnt1nkw2EpaS42hRYaGA2YIPKgWhVSKTWc,303
|
|
2
3
|
LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
|
|
3
4
|
README.md,sha256=EL6JpZxvaQFOYv5WFuSjZvSk9Hcpsf7alMlUC5IPFjA,3423
|
|
4
5
|
castor_extractor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
6
|
castor_extractor/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
7
|
castor_extractor/commands/extract_bigquery.py,sha256=dU4OiYO1V0n32orvZnMh1_xtFKF_VxHNXcVsH3otY-g,1269
|
|
7
8
|
castor_extractor/commands/extract_domo.py,sha256=lwJ7XeYOeLMF2plf5PK3cL56N9n2yjcDsyRM6UFwKTM,1208
|
|
8
|
-
castor_extractor/commands/extract_looker.py,sha256=
|
|
9
|
+
castor_extractor/commands/extract_looker.py,sha256=gwjIQPOHrXevgU_o2l8vDHHQT8Sb-mGdwcceb6wJJbg,1483
|
|
9
10
|
castor_extractor/commands/extract_metabase_api.py,sha256=VPyEKO2VFXzk_OsbQnDhObE9siuBfoegechCZYPZi2k,778
|
|
10
11
|
castor_extractor/commands/extract_metabase_db.py,sha256=cAwoeHrRg29dDh6lUlXZZsoq8NPyMrH-Gx3ovHPD3ds,1269
|
|
11
12
|
castor_extractor/commands/extract_mode.py,sha256=-y8ML72sRVpBEjo9hB1WZyUPznqxnNn0iS8dfJu_ALg,953
|
|
@@ -88,22 +89,22 @@ castor_extractor/visualization/domo/client/endpoints.py,sha256=-B7mRKJ44Bg0hb3E5
|
|
|
88
89
|
castor_extractor/visualization/domo/client/pagination.py,sha256=BT9ZIb-GYGWEQZpK_80aAYKQ-xrr7VlfsFbZv9rcejQ,565
|
|
89
90
|
castor_extractor/visualization/domo/constants.py,sha256=AriJZPrCY5Z3HRUANrMu-4U0b7hQK_jRDcxiB-hbrQ4,233
|
|
90
91
|
castor_extractor/visualization/domo/extract.py,sha256=GWWRfPEMt4SgzBGFaTcoOabsoOqLRFIEFAtgXwb8LDI,2567
|
|
91
|
-
castor_extractor/visualization/looker/__init__.py,sha256=
|
|
92
|
-
castor_extractor/visualization/looker/api/__init__.py,sha256=
|
|
93
|
-
castor_extractor/visualization/looker/api/client.py,sha256=
|
|
92
|
+
castor_extractor/visualization/looker/__init__.py,sha256=Xu5bJ3743kaP8szMMp2NXCgvM1EdOQgtic4utUlO9Cc,145
|
|
93
|
+
castor_extractor/visualization/looker/api/__init__.py,sha256=rN03VMucxIqc0yfd17dIe3ZNFpcg5CA09epn1fKJg90,99
|
|
94
|
+
castor_extractor/visualization/looker/api/client.py,sha256=R-hnVK1TYaCPYaJ1wvpVUwa_AqQPu2RAcZz0kOK4l58,9582
|
|
94
95
|
castor_extractor/visualization/looker/api/client_test.py,sha256=wsi20-neBXHaahDqf4nwCp8Ew5fRFCmVHG3OqrePKFs,1868
|
|
95
96
|
castor_extractor/visualization/looker/api/constants.py,sha256=pZpq09tqcGi2Vh8orXxn9eil8ewfPUOLKfVuqgV2W-A,4126
|
|
96
97
|
castor_extractor/visualization/looker/api/sdk.py,sha256=hSNcRsCoFae3zmjWFGsMrhQCIP57TcMJ2SorMPYJwn4,3553
|
|
97
98
|
castor_extractor/visualization/looker/api/sdk_test.py,sha256=NHtKZTflPhqzBFHs1TyAQaubgxfzLLwYKFT8rEqR55I,1742
|
|
98
|
-
castor_extractor/visualization/looker/api/utils.py,sha256=
|
|
99
|
+
castor_extractor/visualization/looker/api/utils.py,sha256=NpP90CA-SwdUjHhaWFBsKpJz0Z9BXgDOahIqfc3R9tk,565
|
|
99
100
|
castor_extractor/visualization/looker/assets.py,sha256=4EwCI9VwIYRPrIjHU-ZnPY3Mf3cRykWACiYXanr5jFI,442
|
|
100
|
-
castor_extractor/visualization/looker/constant.py,sha256=
|
|
101
|
+
castor_extractor/visualization/looker/constant.py,sha256=0tX6KOGdc9O6FiHcoj08j-QIZyBI2Mhh8UQc_XahDaM,694
|
|
101
102
|
castor_extractor/visualization/looker/env.py,sha256=vPqirdeGKm3as2T-tBTjbpulQe8W7-3UE2j-Z57wFXk,1174
|
|
102
|
-
castor_extractor/visualization/looker/extract.py,sha256=
|
|
103
|
+
castor_extractor/visualization/looker/extract.py,sha256=vOIP8Hoxv05MiRa-l79YKOCHahuNiSW9uSKjwQQQQKs,5112
|
|
103
104
|
castor_extractor/visualization/looker/fields.py,sha256=WmiSehmczWTufCLg4r2Ozq2grUpzxDNvIAHyGuOoGs4,636
|
|
104
105
|
castor_extractor/visualization/looker/fields_test.py,sha256=7Cwq8Qky6aTZg8nCHp1gmPJtd9pGNB4QeMIRRWdHo5w,782
|
|
105
|
-
castor_extractor/visualization/looker/multithreading.py,sha256=
|
|
106
|
-
castor_extractor/visualization/looker/parameters.py,sha256=
|
|
106
|
+
castor_extractor/visualization/looker/multithreading.py,sha256=BB_oUkPo3LH96f1pPaywQ5Y8r2T7vo4hdAQl7y0bpPw,2596
|
|
107
|
+
castor_extractor/visualization/looker/parameters.py,sha256=Nk2hfrg3L9twU-51Q7Wdp9uaxy8M2_juEebWoLfIMPc,2427
|
|
107
108
|
castor_extractor/visualization/metabase/__init__.py,sha256=hSIoVgPzhQh-9H8XRUzga4EZSOYejGdH-qY_hBNGbyw,125
|
|
108
109
|
castor_extractor/visualization/metabase/assets.py,sha256=XeP8UzbqsrleBtdv2nJ2LtWC_p3TAL7g0zlrcjt82TM,2814
|
|
109
110
|
castor_extractor/visualization/metabase/client/__init__.py,sha256=ZMn272PqMoHyWkK0fBuXw9YEnc-OeszNn_BDlMc_FSI,52
|
|
@@ -254,7 +255,7 @@ castor_extractor/warehouse/redshift/queries/.sqlfluff,sha256=W4pFQiY8KMtXwn3WguY
|
|
|
254
255
|
castor_extractor/warehouse/redshift/queries/column.sql,sha256=VLmt8yfILajepv5ZEOyinA4101eZKHr1Mew4f2DqDk0,7044
|
|
255
256
|
castor_extractor/warehouse/redshift/queries/database.sql,sha256=_C0knW159YDfReGuWLjIdvxHzefo1Xg2xw2dJKJzNk8,299
|
|
256
257
|
castor_extractor/warehouse/redshift/queries/group.sql,sha256=8p0wlqllnwOTiAgiV237DvFYHGOEcYwaHdyqVQg3F6E,101
|
|
257
|
-
castor_extractor/warehouse/redshift/queries/query.sql,sha256=
|
|
258
|
+
castor_extractor/warehouse/redshift/queries/query.sql,sha256=yZNGnUdebvvDx0J0KMSJ2hNgkK4gPduyOfPM_7-DIfo,3465
|
|
258
259
|
castor_extractor/warehouse/redshift/queries/schema.sql,sha256=Mf6nooi2w2PhGxM2_kDAf3oQ8QnR-hpT5Y0AmUzghGg,585
|
|
259
260
|
castor_extractor/warehouse/redshift/queries/table.sql,sha256=y8CGOwPHH_Mr8g1Zvuz2U5ldL8zuPm5v3M5RPZqIhsE,2645
|
|
260
261
|
castor_extractor/warehouse/redshift/queries/table_freshness.sql,sha256=l61_ysmTEtuMwK9RmYmD5cu0HmD1RXwTEhX0ytBeyxg,726
|
|
@@ -288,7 +289,7 @@ castor_extractor/warehouse/synapse/queries/schema.sql,sha256=aX9xNrBD_ydwl-znGSF
|
|
|
288
289
|
castor_extractor/warehouse/synapse/queries/table.sql,sha256=mCE8bR1Vb7j7SwZW2gafcXidQ2fo1HwxcybA8wP2Kfs,1049
|
|
289
290
|
castor_extractor/warehouse/synapse/queries/user.sql,sha256=sTb_SS7Zj3AXW1SggKPLNMCd0qoTpL7XI_BJRMaEpBg,67
|
|
290
291
|
castor_extractor/warehouse/synapse/queries/view_ddl.sql,sha256=3EVbp5_yTgdByHFIPLHmnoOnqqLE77SrjAwFDvu4e54,249
|
|
291
|
-
castor_extractor-0.
|
|
292
|
-
castor_extractor-0.
|
|
293
|
-
castor_extractor-0.
|
|
294
|
-
castor_extractor-0.
|
|
292
|
+
castor_extractor-0.10.0.dist-info/METADATA,sha256=XnrJ7dly9vVplF9ksw1thIrfr3Y215iEPCJC4nfs_-A,5880
|
|
293
|
+
castor_extractor-0.10.0.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
|
294
|
+
castor_extractor-0.10.0.dist-info/entry_points.txt,sha256=cvLvgE8Yi10sIiafUVL86XZPMUUyu9x11CF5PshAyiw,1045
|
|
295
|
+
castor_extractor-0.10.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|