castor-extractor 0.24.54__py3-none-any.whl → 0.24.57__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,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.24.57 - 2025-09-24
4
+
5
+ * Sigma:
6
+ * fix pagination
7
+ * remove redundant element lineages endpoint
8
+ * extract data model sources
9
+
10
+ ## 0.24.56 - 2025-09-24
11
+
12
+ * bump dependencies
13
+
14
+ ## 0.24.55 - 2025-09-19
15
+
16
+ * Fix encoding in LocalStorage - force to utf-8
17
+
3
18
  ## 0.24.54 - 2025-09-18
4
19
 
5
20
  * SqlServer: fix typo in the extraction query of schemas
@@ -26,7 +26,7 @@ from .collection import (
26
26
  group_by,
27
27
  mapping_from_rows,
28
28
  )
29
- from .constants import OUTPUT_DIR
29
+ from .constants import ENCODING_UTF8, OUTPUT_DIR
30
30
  from .deprecate import deprecate_python
31
31
  from .env import from_env
32
32
  from .files import explode, search_files
@@ -1 +1,2 @@
1
1
  OUTPUT_DIR = "CASTOR_OUTPUT_DIRECTORY"
2
+ ENCODING_UTF8 = "utf-8"
@@ -4,6 +4,7 @@ from collections.abc import Iterable, Iterator
4
4
  from io import StringIO
5
5
  from typing import Optional
6
6
 
7
+ from .constants import ENCODING_UTF8
7
8
  from .formatter import CsvFormatter, Formatter
8
9
  from .time import current_timestamp
9
10
  from .write import timestamped_filename
@@ -58,11 +59,11 @@ class LocalStorage(AbstractStorage):
58
59
 
59
60
  def put(self, name: str, data: Iterable[dict]) -> str:
60
61
  path = self.path(name)
61
- with open(path, "w") as file:
62
+ with open(path, "w", encoding=ENCODING_UTF8) as file:
62
63
  self._formatter.serialize(file, data)
63
64
  return path
64
65
 
65
66
  def get(self, name: str) -> Iterator[dict]:
66
67
  path = self.path(name)
67
- with open(path, "r") as file:
68
+ with open(path, "r", encoding=ENCODING_UTF8) as file:
68
69
  return self._formatter.deserialize(StringIO(file.read()))
@@ -3,11 +3,11 @@ import logging
3
3
  import os
4
4
  import sys
5
5
  from datetime import datetime
6
+ from importlib.metadata import version
6
7
  from typing import Any
7
8
 
8
- import pkg_resources
9
+ from ..utils import ENCODING_UTF8
9
10
 
10
- ENCODING = "utf8"
11
11
  SUMMARY_FILENAME = "summary.json"
12
12
 
13
13
  logger = logging.getLogger(__name__)
@@ -33,15 +33,14 @@ def write_json(filename: str, data: Any):
33
33
  """
34
34
  write the data to a json file at path filename
35
35
  """
36
- with open(filename, "w", encoding=ENCODING) as f:
36
+ with open(filename, "w", encoding=ENCODING_UTF8) as f:
37
37
  json.dump(data, f)
38
38
  logger.info(f"Wrote output file: {filename} ({f.tell()} bytes)")
39
39
 
40
40
 
41
41
  def _current_version() -> str:
42
42
  """fetch the current version of castor extractor running"""
43
- packages = pkg_resources.require("castor-extractor")
44
- return str(packages[0].version)
43
+ return version("castor-extractor")
45
44
 
46
45
 
47
46
  def write_summary(output_directory: str, ts: int, **kwargs):
@@ -5,11 +5,11 @@ class SigmaAsset(ExternalAsset):
5
5
  """Sigma assets"""
6
6
 
7
7
  DATAMODELS = "datamodels"
8
+ DATAMODEL_SOURCES = "datamodel_sources"
8
9
  DATASETS = "datasets"
9
10
  DATASET_SOURCES = "dataset_sources"
10
11
  ELEMENTS = "elements"
11
12
  FILES = "files"
12
- LINEAGES = "lineages"
13
13
  MEMBERS = "members"
14
14
  QUERIES = "queries"
15
15
  WORKBOOKS = "workbooks"
@@ -1,17 +1,13 @@
1
1
  import logging
2
2
  from collections.abc import Iterator
3
- from concurrent.futures import ThreadPoolExecutor
4
3
  from functools import partial
5
4
  from http import HTTPStatus
6
5
  from typing import Callable, Iterable, Optional
7
6
 
8
- from pydantic import BaseModel
9
-
10
7
  from ....utils import (
11
8
  APIClient,
12
9
  RequestSafeMode,
13
10
  fetch_all_pages,
14
- retry,
15
11
  )
16
12
  from ..assets import SigmaAsset
17
13
  from .authentication import SigmaBearerAuth
@@ -55,38 +51,12 @@ SIGMA_SAFE_MODE = RequestSafeMode(
55
51
  max_errors=_VOLUME_IGNORED,
56
52
  status_codes=_IGNORED_ERROR_CODES,
57
53
  )
58
- SIGMA_SAFE_MODE_LINEAGE = RequestSafeMode(
59
- max_errors=_VOLUME_IGNORED,
60
- status_codes=(
61
- *_IGNORED_ERROR_CODES,
62
- HTTPStatus.FORBIDDEN,
63
- ),
64
- )
65
- _THREADS_LINEAGE = 10 # empirically found; hit the rate limit with 20 workers
66
54
  _RETRY_NUMBER = 1
67
55
  _RETRY_BASE_MS = 60_000
68
56
 
69
57
 
70
- class LineageContext(BaseModel):
71
- """all info needed to build the endpoint for lineage retrieval"""
72
-
73
- workbook_id: str
74
- element_id: str
75
-
76
-
77
- class Lineage(BaseModel):
78
- """holds response from lineage API and context used to retrieve it"""
79
-
80
- lineage: dict
81
- context: LineageContext
82
-
83
-
84
58
  class SigmaClient(APIClient):
85
- def __init__(
86
- self,
87
- credentials: SigmaCredentials,
88
- safe_mode: Optional[RequestSafeMode] = None,
89
- ):
59
+ def __init__(self, credentials: SigmaCredentials):
90
60
  auth = SigmaBearerAuth(
91
61
  host=credentials.host,
92
62
  token_payload=credentials.token_payload,
@@ -96,7 +66,7 @@ class SigmaClient(APIClient):
96
66
  auth=auth,
97
67
  headers=_SIGMA_HEADERS,
98
68
  timeout=_SIGMA_TIMEOUT_S,
99
- safe_mode=safe_mode or SIGMA_SAFE_MODE,
69
+ safe_mode=SIGMA_SAFE_MODE,
100
70
  )
101
71
 
102
72
  def _get_paginated(
@@ -175,68 +145,6 @@ class SigmaClient(APIClient):
175
145
  page=page, workbook_id=workbook_id
176
146
  )
177
147
 
178
- @retry(
179
- (ConnectionError,),
180
- max_retries=_RETRY_NUMBER,
181
- base_ms=_RETRY_BASE_MS,
182
- log_exc_info=True,
183
- )
184
- def _get_lineage(self, lineage_context: LineageContext) -> Lineage:
185
- """
186
- return the lineage from API and other ids needed to characterize
187
- lineage in castor
188
- """
189
- workbook_id = lineage_context.workbook_id
190
- element_id = lineage_context.element_id
191
- endpoint = SigmaEndpointFactory.lineage(workbook_id, element_id)
192
- return Lineage(lineage=self._get(endpoint), context=lineage_context)
193
-
194
- @staticmethod
195
- def _lineage_context(elements: list[dict]) -> list[LineageContext]:
196
- """
197
- Helper function to prepare context for lineage retrieval.
198
- Elements without associated columns are skipped.
199
- """
200
- contexts: list[LineageContext] = []
201
- for element in elements:
202
- if element.get("columns") is None:
203
- continue
204
-
205
- context = LineageContext(
206
- workbook_id=element["workbook_id"],
207
- element_id=element["elementId"],
208
- )
209
- contexts.append(context)
210
- return contexts
211
-
212
- def _get_all_lineages(self, elements: list[dict]) -> Iterator[dict]:
213
- """
214
- The safe mode is temporarily modified to include 403 errors.
215
-
216
- Due to concurrency issues, we force a refresh of the token in hopes that
217
- the lineage extraction takes less than the token expiration time of
218
- 1 hour.
219
- """
220
- safe_mode = self._safe_mode
221
- self._safe_mode = SIGMA_SAFE_MODE_LINEAGE
222
-
223
- lineage_context = self._lineage_context(elements)
224
-
225
- with ThreadPoolExecutor(max_workers=_THREADS_LINEAGE) as executor:
226
- results = executor.map(self._get_lineage, lineage_context)
227
-
228
- for lineage in results:
229
- if not lineage.lineage:
230
- continue
231
-
232
- yield {
233
- **lineage.lineage,
234
- "workbook_id": lineage.context.workbook_id,
235
- "element_id": lineage.context.element_id,
236
- }
237
-
238
- self._safe_mode = safe_mode
239
-
240
148
  @staticmethod
241
149
  def _yield_deduplicated_queries(
242
150
  queries: Iterable[dict], workbook_id: str
@@ -266,6 +174,13 @@ class SigmaClient(APIClient):
266
174
 
267
175
  yield from self._yield_deduplicated_queries(queries, workbook_id)
268
176
 
177
+ def _get_all_datamodel_sources(
178
+ self, datamodels: list[dict]
179
+ ) -> Iterator[dict]:
180
+ yield from SigmaSourcesTransformer(
181
+ self, table_id_key="tableId"
182
+ ).get_datamodel_sources(datamodels)
183
+
269
184
  def _get_all_dataset_sources(self, datasets: list[dict]) -> Iterator[dict]:
270
185
  yield from SigmaSourcesTransformer(self).get_dataset_sources(datasets)
271
186
 
@@ -277,14 +192,22 @@ class SigmaClient(APIClient):
277
192
  def fetch(
278
193
  self,
279
194
  asset: SigmaAsset,
195
+ datamodels: Optional[list[dict]] = None,
280
196
  datasets: Optional[list[dict]] = None,
281
- elements: Optional[list[dict]] = None,
282
197
  workbooks: Optional[list[dict]] = None,
283
198
  ) -> Iterator[dict]:
284
199
  """Returns the needed metadata for the queried asset"""
285
200
  if asset == SigmaAsset.DATAMODELS:
286
201
  yield from self._get_all_datamodels()
287
202
 
203
+ elif asset == SigmaAsset.DATAMODEL_SOURCES:
204
+ if datamodels is None:
205
+ raise ValueError(
206
+ "Missing data models to extract data model sources"
207
+ )
208
+
209
+ yield from self._get_all_datamodel_sources(datamodels)
210
+
288
211
  elif asset == SigmaAsset.DATASETS:
289
212
  yield from self._get_all_datasets()
290
213
 
@@ -303,12 +226,6 @@ class SigmaClient(APIClient):
303
226
  elif asset == SigmaAsset.FILES:
304
227
  yield from self._get_all_files()
305
228
 
306
- elif asset == SigmaAsset.LINEAGES:
307
- if elements is None:
308
- raise ValueError("Missing elements to extract lineage")
309
-
310
- yield from self._get_all_lineages(elements)
311
-
312
229
  elif asset == SigmaAsset.MEMBERS:
313
230
  yield from self._get_all_members()
314
231
 
@@ -19,6 +19,10 @@ class SigmaEndpointFactory:
19
19
  def datamodels(cls) -> str:
20
20
  return f"v2/{cls.DATAMODELS}"
21
21
 
22
+ @classmethod
23
+ def datamodel_sources(cls, datamodel_id: str) -> str:
24
+ return f"v2/{cls.DATAMODELS}/{datamodel_id}/sources"
25
+
22
26
  @classmethod
23
27
  def datasets(cls) -> str:
24
28
  return f"v2/{cls.DATASETS}"
@@ -10,7 +10,7 @@ SIGMA_QUERIES_PAGINATION_LIMIT = 50
10
10
 
11
11
 
12
12
  class SigmaPagination(PaginationModel):
13
- next_page: Optional[str] = "0"
13
+ next_page: Optional[str] = None
14
14
  entries: list = Field(default_factory=list)
15
15
 
16
16
  model_config = ConfigDict(
@@ -27,3 +27,23 @@ class SigmaPagination(PaginationModel):
27
27
 
28
28
  def page_results(self) -> list:
29
29
  return self.entries
30
+
31
+
32
+ class SigmaTokenPagination(PaginationModel):
33
+ next_page_token: Optional[str] = "" # noqa: S105
34
+ entries: list = Field(default_factory=list)
35
+
36
+ model_config = ConfigDict(
37
+ alias_generator=to_camel,
38
+ populate_by_name=True,
39
+ from_attributes=True,
40
+ )
41
+
42
+ def is_last(self) -> bool:
43
+ return not self.next_page_token
44
+
45
+ def next_page_payload(self) -> dict:
46
+ return {"pageToken": self.next_page_token}
47
+
48
+ def page_results(self) -> list:
49
+ return self.entries
@@ -2,8 +2,9 @@ import logging
2
2
  from http import HTTPStatus
3
3
  from typing import TYPE_CHECKING, Callable, Iterator
4
4
 
5
- from ....utils import retry_request
5
+ from ....utils import fetch_all_pages, retry_request
6
6
  from .endpoints import SigmaEndpointFactory
7
+ from .pagination import SigmaTokenPagination
7
8
 
8
9
  if TYPE_CHECKING:
9
10
  from .client import SigmaClient
@@ -17,8 +18,11 @@ SIGMA_CONNECTION_PATH_SLEEP_MS = 30_000 # 30 seconds
17
18
  class SigmaSourcesTransformer:
18
19
  """Retrieves asset sources and enhances them with additional information."""
19
20
 
20
- def __init__(self, api_client: "SigmaClient"):
21
+ def __init__(
22
+ self, api_client: "SigmaClient", table_id_key: str = "inodeId"
23
+ ):
21
24
  self.api_client = api_client
25
+ self.table_id_key = table_id_key
22
26
 
23
27
  @retry_request(
24
28
  status_codes=(HTTPStatus.TOO_MANY_REQUESTS,),
@@ -38,9 +42,9 @@ class SigmaSourcesTransformer:
38
42
  logger.info("Mapping table ids to connection and path information")
39
43
 
40
44
  unique_table_ids = {
41
- source["inodeId"]
45
+ source[self.table_id_key]
42
46
  for asset_sources in all_sources
43
- for source in asset_sources["sources"]
47
+ for source in asset_sources.get("sources", [])
44
48
  if source["type"] == "table"
45
49
  }
46
50
 
@@ -49,15 +53,14 @@ class SigmaSourcesTransformer:
49
53
  for table_id in unique_table_ids
50
54
  }
51
55
 
52
- @staticmethod
53
- def _enhance_table_source(source: dict, table_to_path: dict) -> dict:
56
+ def _enhance_table_source(self, source: dict, table_to_path: dict) -> dict:
54
57
  """
55
58
  Combines a single table source with its connection and path information.
56
59
  """
57
60
  if source["type"] != "table":
58
61
  return source
59
62
 
60
- path_info = table_to_path.get(source["inodeId"], {})
63
+ path_info = table_to_path.get(source[self.table_id_key], {})
61
64
  source["connectionId"] = path_info.get("connectionId")
62
65
  source["path"] = path_info.get("path")
63
66
  return source
@@ -82,19 +85,35 @@ class SigmaSourcesTransformer:
82
85
  }
83
86
 
84
87
  def _get_all_sources(
85
- self, endpoint: Callable[[str], str], asset_ids: set[str]
88
+ self,
89
+ endpoint: Callable[[str], str],
90
+ asset_ids: set[str],
91
+ with_pagination: bool = False,
86
92
  ) -> Iterator[dict]:
87
93
  """Returns transformed sources for the given assets"""
88
94
  all_sources = []
89
95
 
90
96
  for asset_id in asset_ids:
91
- sources = self.api_client._get(endpoint=endpoint(asset_id))
97
+ endpoint_url = endpoint(asset_id)
98
+ if with_pagination:
99
+ request = self.api_client._get_paginated(endpoint=endpoint_url)
100
+ sources = list(fetch_all_pages(request, SigmaTokenPagination))
101
+ else:
102
+ sources = self.api_client._get(endpoint=endpoint_url)
92
103
  all_sources.append({"asset_id": asset_id, "sources": sources})
93
104
 
94
105
  table_to_path = self._map_table_id_to_connection_path(all_sources)
95
106
 
96
107
  yield from self._transform_sources(all_sources, table_to_path)
97
108
 
109
+ def get_datamodel_sources(self, datamodels: list[dict]) -> Iterator[dict]:
110
+ asset_ids = {datamodel["dataModelId"] for datamodel in datamodels}
111
+ yield from self._get_all_sources(
112
+ endpoint=SigmaEndpointFactory.datamodel_sources,
113
+ asset_ids=asset_ids,
114
+ with_pagination=True,
115
+ )
116
+
98
117
  def get_dataset_sources(self, datasets: list[dict]) -> Iterator[dict]:
99
118
  asset_ids = {dataset["datasetId"] for dataset in datasets}
100
119
  yield from self._get_all_sources(
@@ -23,8 +23,14 @@ def iterate_all_data(
23
23
  """Iterate over the extracted data from Sigma"""
24
24
 
25
25
  logger.info("Extracting DATA MODELS from API")
26
- datamodels = client.fetch(SigmaAsset.DATAMODELS)
27
- yield SigmaAsset.DATASETS, list(deep_serialize(datamodels))
26
+ datamodels = list(client.fetch(SigmaAsset.DATAMODELS))
27
+ yield SigmaAsset.DATASETS, deep_serialize(datamodels)
28
+
29
+ logger.info("Extracting DATAMODEL SOURCES from API")
30
+ datamodel_sources = client.fetch(
31
+ SigmaAsset.DATAMODEL_SOURCES, datamodels=datamodels
32
+ )
33
+ yield SigmaAsset.DATAMODEL_SOURCES, list(deep_serialize(datamodel_sources))
28
34
 
29
35
  logger.info("Extracting DATASETS from API")
30
36
  datasets = list(client.fetch(SigmaAsset.DATASETS))
@@ -62,10 +68,6 @@ def iterate_all_data(
62
68
  elements = list(client.fetch(SigmaAsset.ELEMENTS, workbooks=workbooks))
63
69
  yield SigmaAsset.ELEMENTS, list(deep_serialize(elements))
64
70
 
65
- logging.info("Extracting LINEAGES data from API")
66
- lineages = client.fetch(SigmaAsset.LINEAGES, elements=elements)
67
- yield SigmaAsset.LINEAGES, list(deep_serialize(lineages))
68
-
69
71
 
70
72
  def extract_all(**kwargs) -> None:
71
73
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.24.54
3
+ Version: 0.24.57
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -36,7 +36,7 @@ Requires-Dist: google-api-core (>=2.1.1,<3.0.0)
36
36
  Requires-Dist: google-api-python-client (>=2.121.0,<3.0.0) ; extra == "lookerstudio" or extra == "all"
37
37
  Requires-Dist: google-auth (>=2,<3)
38
38
  Requires-Dist: google-cloud-core (>=2.1.0,<3.0.0)
39
- Requires-Dist: google-cloud-storage (>=2,<3)
39
+ Requires-Dist: google-cloud-storage (>=3.1.0,<4.0.0)
40
40
  Requires-Dist: google-resumable-media (>=2.0.3,<3.0.0)
41
41
  Requires-Dist: googleapis-common-protos (>=1.53.0,<2.0.0)
42
42
  Requires-Dist: looker-sdk (>=25.0.0,<26.0.0) ; extra == "looker" or extra == "all"
@@ -215,6 +215,21 @@ For any questions or bug report, contact us at [support@coalesce.io](mailto:supp
215
215
 
216
216
  # Changelog
217
217
 
218
+ ## 0.24.57 - 2025-09-24
219
+
220
+ * Sigma:
221
+ * fix pagination
222
+ * remove redundant element lineages endpoint
223
+ * extract data model sources
224
+
225
+ ## 0.24.56 - 2025-09-24
226
+
227
+ * bump dependencies
228
+
229
+ ## 0.24.55 - 2025-09-19
230
+
231
+ * Fix encoding in LocalStorage - force to utf-8
232
+
218
233
  ## 0.24.54 - 2025-09-18
219
234
 
220
235
  * SqlServer: fix typo in the extraction query of schemas
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=UWQqKdcoyCIOs5Akoc9DqX5p2sBbFpk5mKXX_OBznUQ,20637
1
+ CHANGELOG.md,sha256=-WezbaTjM4tDXii_RVXSYDz39xuZYqWUsabdyqoh2Kc,20889
2
2
  Dockerfile,sha256=xQ05-CFfGShT3oUqaiumaldwA288dj9Yb_pxofQpufg,301
3
3
  DockerfileUsage.md,sha256=2hkJQF-5JuuzfPZ7IOxgM6QgIQW7l-9oRMFVwyXC4gE,998
4
4
  LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
@@ -95,7 +95,7 @@ castor_extractor/uploader/settings.py,sha256=sUZpg9eHemM99DMrBW8bnlMuoTmCmLCKq-D
95
95
  castor_extractor/uploader/upload.py,sha256=b2g9vWWjXWbt8Ms7brTc7OK_I7Z-1VSibNbppGoB2oQ,4764
96
96
  castor_extractor/uploader/upload_test.py,sha256=UgN7TnT9Chn6KVzRcAX0Tuvp7-tps3ugxGitlgb9TSY,462
97
97
  castor_extractor/uploader/utils.py,sha256=otAaySj5aeem6f0CTd0Te6ioJ6uP2J1p348j-SdIwDI,802
98
- castor_extractor/utils/__init__.py,sha256=z_BdKTUyuug3I5AzCuSGrAVskfLax4_olfORIjhZw_M,1691
98
+ castor_extractor/utils/__init__.py,sha256=LhcSQe50m5iv2zlEPfJUa3VY4pDcoMctqLByAWNV7As,1706
99
99
  castor_extractor/utils/argument_parser.py,sha256=S4EcIh3wNDjs3fOrQnttCcPsAmG8m_Txl7xvEh0Q37s,283
100
100
  castor_extractor/utils/argument_parser_test.py,sha256=wnyLFJ74iEiPxxLSbwFtckR7FIHxsFOVU38ljs9gqRA,633
101
101
  castor_extractor/utils/batch.py,sha256=SFlLmJgVjV2nVhIrjVIEp8wJ9du4dKKHq8YVYubnwQQ,448
@@ -119,7 +119,7 @@ castor_extractor/utils/client/uri.py,sha256=jmP9hY-6PRqdc3-vAOdtll_U6q9VCqSqmBAN
119
119
  castor_extractor/utils/client/uri_test.py,sha256=1XKF6qSseCeD4G4ckaNO07JXfGbt7XUVinOZdpEYrDQ,259
120
120
  castor_extractor/utils/collection.py,sha256=g2HmB0ievvYHWaZ8iEzkcPPkrBFsh6R6b_liBqcsMjc,3044
121
121
  castor_extractor/utils/collection_test.py,sha256=mlw33u4VidazQwWxJMvaFeYX3VB5CAj6rqRG-cRsLrw,2884
122
- castor_extractor/utils/constants.py,sha256=qBQprS9U66mS-RIBXiLujdTSV3WvGv40Bc0khP4Abdk,39
122
+ castor_extractor/utils/constants.py,sha256=xEUk-B__cqHPKz5_Ta9kHIsiR-a9qTXzpsTY-SzPRHo,63
123
123
  castor_extractor/utils/deprecate.py,sha256=aBIN2QqZUx5CBNZMFfOUhi8QqtPqRcJtmrN6xqfm-y8,805
124
124
  castor_extractor/utils/env.py,sha256=TqdtB50U8LE0993WhhEhpy89TJrHbjtIKjvg6KQ-5q0,596
125
125
  castor_extractor/utils/files.py,sha256=qKbfu5FRjsQdKnRmaJNd5EdX_F6gf5C5tV8LdoYKxs0,1527
@@ -148,7 +148,7 @@ castor_extractor/utils/salesforce/constants.py,sha256=7yPmUeyn4IHQiHLDutXE0L_OBd
148
148
  castor_extractor/utils/salesforce/credentials.py,sha256=m_11LIaBrYVgH2bLo-QnxaIY5KhEdtfVXz9r2lb_fd0,1123
149
149
  castor_extractor/utils/salesforce/credentials_test.py,sha256=FQRyNk2Jsh6KtYiW20oL43CVnGjXLcAjdFATkE7jK0s,586
150
150
  castor_extractor/utils/salesforce/pagination.py,sha256=wJq0rKLdacFRggyHwB6Fh3K6iXPvL4QWhsDvZdjQjM8,849
151
- castor_extractor/utils/store.py,sha256=hnyrFwCsL48e9QrsBns-n8FospujZrkUy1P2YHAh_C0,2067
151
+ castor_extractor/utils/store.py,sha256=KAg5TzLd8jak1Gh5NK-iPu2buQIYNofx6lpXye7MRDU,2152
152
152
  castor_extractor/utils/string.py,sha256=IQqNum7CJwuSvDGPbTAmz46YwtYDYgJKeXY7iixdjI4,2370
153
153
  castor_extractor/utils/string_test.py,sha256=u3P2tAPhyfCLvD19rH_JcpHhPuWTHUdg0z_N_-Kxwno,2501
154
154
  castor_extractor/utils/time.py,sha256=jmP1QWg4lv21Jp_Oy71lfJ47hjNOSgHiBOFf964RMPU,1732
@@ -158,7 +158,7 @@ castor_extractor/utils/url.py,sha256=0YaKAz3EC5PgTb5A2TNOlxf1DANK40yw6hs7ArEtJaU
158
158
  castor_extractor/utils/url_test.py,sha256=LWzNdOZqjrDeLmvhPBYmP35mzhm7jGAXi021thiro1Y,1425
159
159
  castor_extractor/utils/validation.py,sha256=dRvC9SoFVecVZuLQNN3URq37yX2sBSW3-NxIxkcol5o,1894
160
160
  castor_extractor/utils/validation_test.py,sha256=A7P6VmI0kYX2aGIeEN12y7LsY7Kpm8pE4bdVFhbBAMw,1184
161
- castor_extractor/utils/write.py,sha256=Z_RYm47XeHiUPPUMYMuAjQrVZ18CAkL3daQHQG1XPlM,2148
161
+ castor_extractor/utils/write.py,sha256=KQVWF29N766avzmSb129IUWrId5c_8BtnYhVLmU6YIs,2133
162
162
  castor_extractor/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
163
163
  castor_extractor/visualization/domo/__init__.py,sha256=1axOCPm4RpdIyUt9LQEvlMvbOPllW8rk63h6EjVgJ0Y,111
164
164
  castor_extractor/visualization/domo/assets.py,sha256=bK1urFR2tnlWkVkkhR32mAKMoKbESNlop-CNGx-65PY,206
@@ -270,17 +270,17 @@ castor_extractor/visualization/salesforce_reporting/client/rest.py,sha256=AqL1DT
270
270
  castor_extractor/visualization/salesforce_reporting/client/soql.py,sha256=ytZnX6zE-NoS_Kz12KghMcCM4ukPwhMj6U0rQZ_8Isk,1621
271
271
  castor_extractor/visualization/salesforce_reporting/extract.py,sha256=ScStilebLGf4HDTFqhVTQAvv_OrKxc8waycfBKdsVAc,1359
272
272
  castor_extractor/visualization/sigma/__init__.py,sha256=GINql4yJLtjfOJgjHaWNpE13cMtnKNytiFRomwav27Q,114
273
- castor_extractor/visualization/sigma/assets.py,sha256=uKGKDaeY1ejc7XGh4eFaNp2ygG7hgca132xsX4eCwKQ,380
273
+ castor_extractor/visualization/sigma/assets.py,sha256=iVZqi7XtNgSOVXy0jgeHZonVOeXi7jyikor8ztbECBc,398
274
274
  castor_extractor/visualization/sigma/client/__init__.py,sha256=YQv06FBBQHvBMFg_tN0nUcmUp2NCL2s-eFTXG8rXaBg,74
275
275
  castor_extractor/visualization/sigma/client/authentication.py,sha256=gHukrpfboIjZc_O9CcuDtrl6U-StH0J73VY2J74Bm9o,2279
276
- castor_extractor/visualization/sigma/client/client.py,sha256=De0xWJfUssfrwzyMNh8D2IIouUQzcS0qLUQrUYtjVkY,10827
276
+ castor_extractor/visualization/sigma/client/client.py,sha256=uUEZoTa1WU5bJEjOrgzWqSiJMKgbru5HPBEPazyu1Hc,8272
277
277
  castor_extractor/visualization/sigma/client/client_test.py,sha256=ae0ZOvKutCm44jnrJ-0_A5Y6ZGyDkMf9Ml3eEP8dNkY,581
278
278
  castor_extractor/visualization/sigma/client/credentials.py,sha256=XddAuQSmCKpxJ70TQgRnOj0vMPYVtiStk_lMMQ1AiNM,693
279
- castor_extractor/visualization/sigma/client/endpoints.py,sha256=i7KTKnl2Os6752CdtJl0vPSC_Z6JxmacodV_saOnce0,1662
280
- castor_extractor/visualization/sigma/client/pagination.py,sha256=1yLpCNps5FnDiPcXCcgHu23cxg15Gfc6FvE3AJleb2c,728
281
- castor_extractor/visualization/sigma/client/sources_transformer.py,sha256=n-5mZWSvzfTwpM5VP_bwlcxcaAwCKEEbpMCG_1KRVP4,3748
279
+ castor_extractor/visualization/sigma/client/endpoints.py,sha256=by9VIFml2whlzQT66f2m56RYBsqPrWdAmIP4JkTaBV4,1799
280
+ castor_extractor/visualization/sigma/client/pagination.py,sha256=9kCYQpO7hAH2qvYmnVjnGVUDLkpkEM6BgYlv-JTY8AE,1241
281
+ castor_extractor/visualization/sigma/client/sources_transformer.py,sha256=2f7REl70wYitopftMtYQU-E8kISVck67i7rGYgf3tkk,4552
282
282
  castor_extractor/visualization/sigma/client/sources_transformer_test.py,sha256=06yUHXyv65amXLKXhix6K3kkVc1kpBqSjIYcxbyMI4Y,2766
283
- castor_extractor/visualization/sigma/extract.py,sha256=poTh70Xm2D6BwbdGApLkjXy6-t4iZnOoMB5DPfaTLEI,2929
283
+ castor_extractor/visualization/sigma/extract.py,sha256=iRmRUzSnq_ObG9fxpOI5Rs07EKKT-VRLcyiti5-8D4c,2986
284
284
  castor_extractor/visualization/strategy/__init__.py,sha256=HOMv4JxqF5ZmViWi-pDE-PSXJRLTdXal_jtpHG_rlR8,123
285
285
  castor_extractor/visualization/strategy/assets.py,sha256=yFXF_dX01patC0HQ1eU7Jo_4DZ4m6IJEg0uCB71tMoI,480
286
286
  castor_extractor/visualization/strategy/client/__init__.py,sha256=XWP0yF5j6JefDJkDfX-RSJn3HF2ceQ0Yx1PLCfB3BBo,80
@@ -434,8 +434,8 @@ castor_extractor/warehouse/sqlserver/queries/user.sql,sha256=MAlnTis43E3Amu1e1Oz
434
434
  castor_extractor/warehouse/sqlserver/queries/view_ddl.sql,sha256=9rynvx6MWg3iZzrWPB7haZfVKEPkxulzryE2g19x804,315
435
435
  castor_extractor/warehouse/sqlserver/query.py,sha256=c8f7_SEMR17DhbtzuYphWqWDQ0sCRy-nR442RRBZVYw,1773
436
436
  castor_extractor/warehouse/synapse/queries/column.sql,sha256=lNcFoIW3Y0PFOqoOzJEXmPvZvfAsY0AP63Mu2LuPzPo,1351
437
- castor_extractor-0.24.54.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
438
- castor_extractor-0.24.54.dist-info/METADATA,sha256=jEfKI6ocldlGkpKQsrBrW-1Vn0e1n7IPS7NLzEzSCpg,28090
439
- castor_extractor-0.24.54.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
440
- castor_extractor-0.24.54.dist-info/entry_points.txt,sha256=_F-qeZCybjoMkNb9ErEhnyqXuG6afHIFQhakdBHZsr4,1803
441
- castor_extractor-0.24.54.dist-info/RECORD,,
437
+ castor_extractor-0.24.57.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
438
+ castor_extractor-0.24.57.dist-info/METADATA,sha256=uSN01JxGlu1gIF4bpBnZtHM3tLQKfU9qT0uimCqtrjI,28350
439
+ castor_extractor-0.24.57.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
440
+ castor_extractor-0.24.57.dist-info/entry_points.txt,sha256=_F-qeZCybjoMkNb9ErEhnyqXuG6afHIFQhakdBHZsr4,1803
441
+ castor_extractor-0.24.57.dist-info/RECORD,,