castor-extractor 0.21.9__py3-none-any.whl → 0.22.1__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 +8 -0
- castor_extractor/commands/__init__.py +0 -3
- castor_extractor/commands/file_check.py +1 -2
- castor_extractor/file_checker/column.py +5 -5
- castor_extractor/file_checker/file.py +7 -7
- castor_extractor/file_checker/file_test.py +2 -2
- castor_extractor/file_checker/templates/generic_warehouse.py +4 -6
- castor_extractor/knowledge/confluence/client/client.py +2 -1
- castor_extractor/knowledge/confluence/extract.py +3 -2
- castor_extractor/knowledge/notion/client/client.py +3 -2
- castor_extractor/knowledge/notion/extract.py +3 -2
- castor_extractor/quality/soda/client/client.py +2 -1
- castor_extractor/quality/soda/client/pagination.py +1 -3
- castor_extractor/types.py +3 -3
- castor_extractor/uploader/env.py +2 -2
- castor_extractor/uploader/upload.py +4 -3
- castor_extractor/uploader/utils.py +1 -1
- castor_extractor/utils/__init__.py +1 -0
- castor_extractor/utils/client/abstract.py +2 -1
- castor_extractor/utils/client/api/auth.py +2 -2
- castor_extractor/utils/client/api/auth_test.py +2 -2
- castor_extractor/utils/client/api/client.py +3 -3
- castor_extractor/utils/client/api/pagination.py +3 -2
- castor_extractor/utils/client/api/safe_request.py +5 -5
- castor_extractor/utils/collection.py +7 -11
- castor_extractor/utils/dbt/client.py +3 -3
- castor_extractor/utils/dbt/client_test.py +2 -2
- castor_extractor/utils/deprecate.py +1 -2
- castor_extractor/utils/files.py +5 -5
- castor_extractor/utils/formatter.py +5 -4
- castor_extractor/utils/json_stream_write.py +2 -1
- castor_extractor/utils/object.py +2 -1
- castor_extractor/utils/pager/pager.py +2 -4
- castor_extractor/utils/pager/pager_on_id.py +2 -1
- castor_extractor/utils/pager/pager_on_id_test.py +5 -5
- castor_extractor/utils/pager/pager_test.py +3 -3
- castor_extractor/utils/retry.py +4 -3
- castor_extractor/utils/retry_test.py +2 -3
- castor_extractor/utils/safe.py +3 -3
- castor_extractor/utils/salesforce/client.py +2 -1
- castor_extractor/utils/salesforce/credentials.py +1 -3
- castor_extractor/utils/store.py +2 -1
- castor_extractor/utils/string.py +2 -2
- castor_extractor/utils/string_test.py +1 -3
- castor_extractor/utils/time.py +4 -0
- castor_extractor/utils/time_test.py +8 -1
- castor_extractor/utils/type.py +3 -2
- castor_extractor/utils/validation.py +4 -4
- castor_extractor/utils/write.py +2 -2
- castor_extractor/visualization/domo/client/client.py +8 -7
- castor_extractor/visualization/domo/client/credentials.py +2 -2
- castor_extractor/visualization/domo/client/endpoints.py +2 -2
- castor_extractor/visualization/domo/extract.py +3 -2
- castor_extractor/visualization/looker/api/client.py +17 -16
- castor_extractor/visualization/looker/api/utils.py +2 -2
- castor_extractor/visualization/looker/assets.py +1 -3
- castor_extractor/visualization/looker/extract.py +4 -3
- castor_extractor/visualization/looker/fields.py +3 -3
- castor_extractor/visualization/looker/multithreading.py +3 -3
- castor_extractor/visualization/looker_studio/__init__.py +6 -0
- castor_extractor/visualization/looker_studio/assets.py +6 -0
- castor_extractor/visualization/looker_studio/client/__init__.py +3 -0
- castor_extractor/visualization/looker_studio/client/admin_sdk_client.py +90 -0
- castor_extractor/visualization/looker_studio/client/client.py +37 -0
- castor_extractor/visualization/looker_studio/client/credentials.py +20 -0
- castor_extractor/visualization/looker_studio/client/endpoints.py +18 -0
- castor_extractor/visualization/looker_studio/client/enums.py +8 -0
- castor_extractor/visualization/looker_studio/client/looker_studio_api_client.py +102 -0
- castor_extractor/visualization/looker_studio/client/pagination.py +31 -0
- castor_extractor/visualization/looker_studio/client/scopes.py +6 -0
- castor_extractor/visualization/metabase/assets.py +1 -3
- castor_extractor/visualization/metabase/client/api/client.py +8 -7
- castor_extractor/visualization/metabase/extract.py +3 -2
- castor_extractor/visualization/metabase/types.py +1 -3
- castor_extractor/visualization/mode/client/client.py +6 -6
- castor_extractor/visualization/mode/extract.py +2 -2
- castor_extractor/visualization/powerbi/assets.py +1 -3
- castor_extractor/visualization/powerbi/client/client.py +12 -11
- castor_extractor/visualization/powerbi/client/credentials.py +3 -3
- castor_extractor/visualization/powerbi/client/endpoints.py +2 -2
- castor_extractor/visualization/powerbi/extract.py +3 -2
- castor_extractor/visualization/qlik/assets.py +1 -3
- castor_extractor/visualization/qlik/client/constants.py +1 -3
- castor_extractor/visualization/qlik/client/engine/error.py +1 -3
- castor_extractor/visualization/qlik/client/master.py +3 -3
- castor_extractor/visualization/qlik/client/rest.py +12 -12
- castor_extractor/visualization/qlik/extract.py +4 -3
- castor_extractor/visualization/salesforce_reporting/client/rest.py +3 -2
- castor_extractor/visualization/salesforce_reporting/client/soql.py +1 -3
- castor_extractor/visualization/salesforce_reporting/extract.py +3 -2
- castor_extractor/visualization/sigma/client/client.py +9 -8
- castor_extractor/visualization/sigma/client/credentials.py +1 -3
- castor_extractor/visualization/sigma/extract.py +3 -2
- castor_extractor/visualization/tableau/assets.py +1 -2
- castor_extractor/visualization/tableau/client/client.py +1 -2
- castor_extractor/visualization/tableau/client/client_utils.py +3 -2
- castor_extractor/visualization/tableau/client/credentials.py +3 -3
- castor_extractor/visualization/tableau/client/safe_mode.py +1 -2
- castor_extractor/visualization/tableau/extract.py +2 -2
- castor_extractor/visualization/tableau/gql_fields.py +3 -3
- castor_extractor/visualization/tableau/tsc_fields.py +1 -2
- castor_extractor/visualization/tableau/types.py +3 -3
- castor_extractor/visualization/tableau_revamp/client/client_metadata_api.py +3 -2
- castor_extractor/visualization/tableau_revamp/client/client_rest_api.py +3 -3
- castor_extractor/visualization/tableau_revamp/client/client_tsc.py +3 -2
- castor_extractor/visualization/tableau_revamp/client/gql_queries.py +1 -3
- castor_extractor/visualization/tableau_revamp/client/rest_fields.py +1 -3
- castor_extractor/visualization/tableau_revamp/extract.py +2 -2
- castor_extractor/visualization/thoughtspot/client/client.py +3 -2
- castor_extractor/visualization/thoughtspot/client/utils.py +1 -1
- castor_extractor/visualization/thoughtspot/extract.py +3 -2
- castor_extractor/warehouse/abstract/asset.py +4 -5
- castor_extractor/warehouse/abstract/extract.py +4 -3
- castor_extractor/warehouse/abstract/query.py +4 -4
- castor_extractor/warehouse/bigquery/client.py +8 -8
- castor_extractor/warehouse/bigquery/extract.py +1 -1
- castor_extractor/warehouse/bigquery/query.py +2 -2
- castor_extractor/warehouse/bigquery/types.py +2 -4
- castor_extractor/warehouse/databricks/api_client.py +15 -14
- castor_extractor/warehouse/databricks/client.py +16 -16
- castor_extractor/warehouse/databricks/extract.py +4 -4
- castor_extractor/warehouse/databricks/format.py +12 -12
- castor_extractor/warehouse/databricks/lineage.py +11 -11
- castor_extractor/warehouse/databricks/pagination.py +2 -2
- castor_extractor/warehouse/databricks/types.py +4 -4
- castor_extractor/warehouse/databricks/utils.py +5 -4
- castor_extractor/warehouse/mysql/query.py +2 -2
- castor_extractor/warehouse/postgres/query.py +2 -2
- castor_extractor/warehouse/redshift/client.py +1 -1
- castor_extractor/warehouse/redshift/query.py +2 -2
- castor_extractor/warehouse/salesforce/client.py +8 -8
- castor_extractor/warehouse/salesforce/extract.py +3 -4
- castor_extractor/warehouse/salesforce/format.py +19 -11
- castor_extractor/warehouse/salesforce/format_test.py +24 -10
- castor_extractor/warehouse/snowflake/query.py +5 -5
- castor_extractor/warehouse/sqlserver/client.py +1 -1
- castor_extractor/warehouse/sqlserver/query.py +2 -2
- {castor_extractor-0.21.9.dist-info → castor_extractor-0.22.1.dist-info}/METADATA +13 -6
- {castor_extractor-0.21.9.dist-info → castor_extractor-0.22.1.dist-info}/RECORD +142 -131
- {castor_extractor-0.21.9.dist-info → castor_extractor-0.22.1.dist-info}/LICENCE +0 -0
- {castor_extractor-0.21.9.dist-info → castor_extractor-0.22.1.dist-info}/WHEEL +0 -0
- {castor_extractor-0.21.9.dist-info → castor_extractor-0.22.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from functools import partial
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from tqdm import tqdm # type: ignore
|
|
6
6
|
|
|
@@ -29,7 +29,7 @@ class SalesforceClient(SalesforceBaseClient):
|
|
|
29
29
|
def name() -> str:
|
|
30
30
|
return "Salesforce"
|
|
31
31
|
|
|
32
|
-
def fetch_sobjects(self) ->
|
|
32
|
+
def fetch_sobjects(self) -> list[dict]:
|
|
33
33
|
"""Fetch all sobjects"""
|
|
34
34
|
logger.info("Extracting sobjects")
|
|
35
35
|
query = format_sobject_query()
|
|
@@ -39,7 +39,7 @@ class SalesforceClient(SalesforceBaseClient):
|
|
|
39
39
|
results = fetch_all_pages(request_, SalesforceSQLPagination)
|
|
40
40
|
return list(results)
|
|
41
41
|
|
|
42
|
-
def fetch_fields(self, sobject_name: str) ->
|
|
42
|
+
def fetch_fields(self, sobject_name: str) -> list[dict]:
|
|
43
43
|
"""Fetches fields of a given sobject"""
|
|
44
44
|
query = SOBJECT_FIELDS_QUERY_TPL.format(
|
|
45
45
|
entity_definition_id=sobject_name
|
|
@@ -55,7 +55,7 @@ class SalesforceClient(SalesforceBaseClient):
|
|
|
55
55
|
return None
|
|
56
56
|
return response["records"][0]["Description"]
|
|
57
57
|
|
|
58
|
-
def add_table_descriptions(self, sobjects:
|
|
58
|
+
def add_table_descriptions(self, sobjects: list[dict]) -> list[dict]:
|
|
59
59
|
"""
|
|
60
60
|
Add table descriptions.
|
|
61
61
|
We use the tooling API which does not handle well the LIMIT in SOQL
|
|
@@ -67,7 +67,7 @@ class SalesforceClient(SalesforceBaseClient):
|
|
|
67
67
|
described_sobjects.append({**sobject, "Description": description})
|
|
68
68
|
return described_sobjects
|
|
69
69
|
|
|
70
|
-
def tables(self) ->
|
|
70
|
+
def tables(self) -> list[dict]:
|
|
71
71
|
"""
|
|
72
72
|
Get Salesforce sobjects as tables
|
|
73
73
|
"""
|
|
@@ -77,13 +77,13 @@ class SalesforceClient(SalesforceBaseClient):
|
|
|
77
77
|
return list(self.formatter.tables(described_sobjects))
|
|
78
78
|
|
|
79
79
|
def columns(
|
|
80
|
-
self, sobject_names:
|
|
81
|
-
) ->
|
|
80
|
+
self, sobject_names: list[tuple[str, str]], show_progress: bool = True
|
|
81
|
+
) -> list[dict]:
|
|
82
82
|
"""
|
|
83
83
|
Get salesforce sobject fields as columns
|
|
84
84
|
show_progress: optionally deactivate the tqdm progress bar
|
|
85
85
|
"""
|
|
86
|
-
sobject_fields:
|
|
86
|
+
sobject_fields: dict[str, list[dict]] = dict()
|
|
87
87
|
for api_name, table_name in tqdm(
|
|
88
88
|
sobject_names, disable=not show_progress
|
|
89
89
|
):
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Dict, List, Tuple
|
|
3
2
|
|
|
4
3
|
from ...utils import AbstractStorage, LocalStorage, write_summary
|
|
5
4
|
from ...utils.salesforce import SalesforceCredentials
|
|
@@ -14,9 +13,9 @@ from .client import SalesforceClient
|
|
|
14
13
|
logger = logging.getLogger(__name__)
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
Paths =
|
|
16
|
+
Paths = dict[str, str]
|
|
18
17
|
|
|
19
|
-
SALESFORCE_CATALOG_ASSETS:
|
|
18
|
+
SALESFORCE_CATALOG_ASSETS: tuple[WarehouseAsset, ...] = (
|
|
20
19
|
WarehouseAsset.TABLE,
|
|
21
20
|
WarehouseAsset.COLUMN,
|
|
22
21
|
)
|
|
@@ -81,7 +80,7 @@ class SalesforceExtractionProcessor:
|
|
|
81
80
|
|
|
82
81
|
def extract_role(self) -> Paths:
|
|
83
82
|
"""extract no users and return the empty file location"""
|
|
84
|
-
users:
|
|
83
|
+
users: list[dict] = []
|
|
85
84
|
location = self._storage.put(WarehouseAsset.USER.value, users)
|
|
86
85
|
logger.info(f"Extracted {len(users)} users to {location}")
|
|
87
86
|
return {WarehouseAsset.USER.value: location}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from ...utils import group_by
|
|
4
5
|
from .constants import SCHEMA_NAME
|
|
5
6
|
|
|
6
|
-
_HAS_DUPLICATE_KEY = "#
|
|
7
|
+
_HAS_DUPLICATE_KEY = "#has_duplicate_label"
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def _clean(raw: str) -> str:
|
|
@@ -25,10 +26,10 @@ def _name(sobject: dict) -> str:
|
|
|
25
26
|
return f"{label} ({api_name})"
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
def _field_description(field:
|
|
29
|
-
context:
|
|
29
|
+
def _field_description(field: dict[str, Any]) -> str:
|
|
30
|
+
context: dict[str, str] = {}
|
|
30
31
|
|
|
31
|
-
field_definition:
|
|
32
|
+
field_definition: dict[str, str] = field.get("FieldDefinition") or {}
|
|
32
33
|
if description := field_definition.get("Description"):
|
|
33
34
|
context["Description"] = _clean(description)
|
|
34
35
|
if help_text := field.get("InlineHelpText"):
|
|
@@ -69,9 +70,15 @@ def _to_table_payload(sobject: dict) -> dict:
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
|
|
72
|
-
def
|
|
73
|
+
def _remove_duplicates(sobjects: list[dict]) -> list[dict]:
|
|
74
|
+
"""only keep one object per QualifiedApiName"""
|
|
75
|
+
by_name = group_by("QualifiedApiName", sobjects)
|
|
76
|
+
return [objects[0] for _, objects in by_name.items()]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _detect_duplicate_labels(sobjects: list[dict]) -> list[dict]:
|
|
73
80
|
"""
|
|
74
|
-
enrich the given data with "
|
|
81
|
+
enrich the given data with "has_duplicate_label" flag:
|
|
75
82
|
- True when another asset has the same Label in the list
|
|
76
83
|
- False otherwise
|
|
77
84
|
"""
|
|
@@ -89,18 +96,19 @@ class SalesforceFormatter:
|
|
|
89
96
|
"""
|
|
90
97
|
|
|
91
98
|
@staticmethod
|
|
92
|
-
def tables(sobjects:
|
|
99
|
+
def tables(sobjects: list[dict]) -> Iterator[dict]:
|
|
93
100
|
"""
|
|
94
101
|
formats the raw list of sobjects to tables
|
|
95
102
|
"""
|
|
96
|
-
sobjects =
|
|
103
|
+
sobjects = _remove_duplicates(sobjects)
|
|
104
|
+
sobjects = _detect_duplicate_labels(sobjects)
|
|
97
105
|
for sobject in sobjects:
|
|
98
106
|
yield _to_table_payload(sobject)
|
|
99
107
|
|
|
100
108
|
@staticmethod
|
|
101
|
-
def columns(sobject_fields:
|
|
109
|
+
def columns(sobject_fields: dict[str, list[dict]]) -> Iterator[dict]:
|
|
102
110
|
"""formats the raw list of sobject fields to columns"""
|
|
103
111
|
for table_name, fields in sobject_fields.items():
|
|
104
|
-
fields =
|
|
112
|
+
fields = _detect_duplicate_labels(fields)
|
|
105
113
|
for index, field in enumerate(fields):
|
|
106
114
|
yield _to_column_payload(field, index, table_name)
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
from typing import Dict, List, Tuple
|
|
2
|
-
|
|
3
1
|
from .format import (
|
|
4
2
|
_HAS_DUPLICATE_KEY,
|
|
5
3
|
SalesforceFormatter,
|
|
6
|
-
|
|
4
|
+
_detect_duplicate_labels,
|
|
7
5
|
_field_description,
|
|
8
6
|
_name,
|
|
7
|
+
_remove_duplicates,
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
def _tables_sobjects() ->
|
|
11
|
+
def _tables_sobjects() -> tuple[dict[str, str], ...]:
|
|
13
12
|
"""Returns 4 sobjects with 2 sharing the same label"""
|
|
14
13
|
a = {"Label": "a", "QualifiedApiName": "a_one"}
|
|
15
14
|
b = {"Label": "b", "QualifiedApiName": "b"}
|
|
16
|
-
c = {"Label": "c", "QualifiedApiName": "
|
|
15
|
+
c = {"Label": "c", "QualifiedApiName": "c_unique_so_doesnt_matter"}
|
|
17
16
|
a_prime = {"Label": "a", "QualifiedApiName": "a_two"}
|
|
18
|
-
|
|
17
|
+
b_exact_duplicate = {"Label": "b", "QualifiedApiName": "b"}
|
|
18
|
+
return a, b, c, a_prime, b_exact_duplicate
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def _columns_sobjects() ->
|
|
21
|
+
def _columns_sobjects() -> dict[str, list[dict]]:
|
|
22
22
|
a = {"Label": "First Name", "QualifiedApiName": "owner_name"}
|
|
23
23
|
b = {"Label": "First Name", "QualifiedApiName": "editor_name"}
|
|
24
24
|
c = {"Label": "Foo Bar", "QualifiedApiName": "foo_bar"}
|
|
@@ -81,14 +81,14 @@ def test__name():
|
|
|
81
81
|
assert _name(empty_label_sobject) == "empty_label"
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def
|
|
84
|
+
def test__detect_duplicate_labels():
|
|
85
85
|
objects = [
|
|
86
86
|
{"Label": "Foo"},
|
|
87
87
|
{"Label": "Bar"},
|
|
88
88
|
{"Label": "Foo"},
|
|
89
89
|
]
|
|
90
90
|
|
|
91
|
-
objects =
|
|
91
|
+
objects = _detect_duplicate_labels(objects)
|
|
92
92
|
assert objects == [
|
|
93
93
|
{"Label": "Foo", _HAS_DUPLICATE_KEY: True},
|
|
94
94
|
{"Label": "Bar", _HAS_DUPLICATE_KEY: False},
|
|
@@ -96,11 +96,25 @@ def test__detect_duplicates():
|
|
|
96
96
|
]
|
|
97
97
|
|
|
98
98
|
|
|
99
|
+
def test__remove_duplicates():
|
|
100
|
+
objects = [
|
|
101
|
+
{"QualifiedApiName": "Foo"},
|
|
102
|
+
{"QualifiedApiName": "Bar"},
|
|
103
|
+
{"QualifiedApiName": "Foo"},
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
objects = _remove_duplicates(objects)
|
|
107
|
+
assert len(objects) == 2
|
|
108
|
+
names = {sobject["QualifiedApiName"] for sobject in objects}
|
|
109
|
+
assert names == {"Foo", "Bar"}
|
|
110
|
+
|
|
111
|
+
|
|
99
112
|
def test_salesforce_formatter_tables():
|
|
100
113
|
sobjects = [*_tables_sobjects()]
|
|
101
|
-
tables = SalesforceFormatter.tables(sobjects)
|
|
114
|
+
tables = [t for t in SalesforceFormatter.tables(sobjects)]
|
|
102
115
|
expected_names = {"a (a_one)", "a (a_two)", "b", "c"}
|
|
103
116
|
payload_names = {t["table_name"] for t in tables}
|
|
117
|
+
assert len(tables) == 4 # we only keep one "b"
|
|
104
118
|
assert payload_names == expected_names
|
|
105
119
|
|
|
106
120
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Optional
|
|
2
2
|
|
|
3
3
|
from ..abstract import (
|
|
4
4
|
CATALOG_ASSETS,
|
|
@@ -14,7 +14,7 @@ DB_FILTERED_ASSETS = (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def _database_filter(db_list: Optional[
|
|
17
|
+
def _database_filter(db_list: Optional[list[str]], allow: bool) -> str:
|
|
18
18
|
if not db_list:
|
|
19
19
|
return ""
|
|
20
20
|
keyword = "IN" if allow else "NOT IN"
|
|
@@ -34,8 +34,8 @@ class SnowflakeQueryBuilder(AbstractQueryBuilder):
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self,
|
|
36
36
|
time_filter: Optional[TimeFilter] = None,
|
|
37
|
-
db_allowed: Optional[
|
|
38
|
-
db_blocked: Optional[
|
|
37
|
+
db_allowed: Optional[list[str]] = None,
|
|
38
|
+
db_blocked: Optional[list[str]] = None,
|
|
39
39
|
fetch_transient: Optional[bool] = False,
|
|
40
40
|
):
|
|
41
41
|
super().__init__(time_filter=time_filter)
|
|
@@ -52,7 +52,7 @@ class SnowflakeQueryBuilder(AbstractQueryBuilder):
|
|
|
52
52
|
|
|
53
53
|
return statement
|
|
54
54
|
|
|
55
|
-
def build(self, asset: WarehouseAsset) ->
|
|
55
|
+
def build(self, asset: WarehouseAsset) -> list[ExtractionQuery]:
|
|
56
56
|
query = self.build_default(asset)
|
|
57
57
|
|
|
58
58
|
if asset in DB_FILTERED_ASSETS:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Optional
|
|
2
2
|
|
|
3
3
|
from ..abstract import (
|
|
4
4
|
AbstractQueryBuilder,
|
|
@@ -19,6 +19,6 @@ class MSSQLQueryBuilder(AbstractQueryBuilder):
|
|
|
19
19
|
):
|
|
20
20
|
super().__init__(time_filter=time_filter)
|
|
21
21
|
|
|
22
|
-
def build(self, asset: WarehouseAsset) ->
|
|
22
|
+
def build(self, asset: WarehouseAsset) -> list[ExtractionQuery]:
|
|
23
23
|
query = self.build_default(asset)
|
|
24
24
|
return [query]
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: castor-extractor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.1
|
|
4
4
|
Summary: Extract your metadata assets.
|
|
5
5
|
Home-page: https://www.castordoc.com/
|
|
6
6
|
License: EULA
|
|
7
7
|
Author: Castor
|
|
8
8
|
Author-email: support@castordoc.com
|
|
9
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.9,<3.13
|
|
10
10
|
Classifier: License :: Other/Proprietary License
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -20,6 +19,7 @@ Provides-Extra: bigquery
|
|
|
20
19
|
Provides-Extra: databricks
|
|
21
20
|
Provides-Extra: dbt
|
|
22
21
|
Provides-Extra: looker
|
|
22
|
+
Provides-Extra: lookerstudio
|
|
23
23
|
Provides-Extra: metabase
|
|
24
24
|
Provides-Extra: mysql
|
|
25
25
|
Provides-Extra: postgres
|
|
@@ -32,6 +32,7 @@ Provides-Extra: tableau
|
|
|
32
32
|
Requires-Dist: cryptography (>=43.0.0,<44.0.0) ; extra == "snowflake"
|
|
33
33
|
Requires-Dist: databricks-sql-connector (>=3.2.0,<4.0.0) ; extra == "databricks" or extra == "all"
|
|
34
34
|
Requires-Dist: google-api-core (>=2.1.1,<3.0.0)
|
|
35
|
+
Requires-Dist: google-api-python-client (>=2.121.0,<3.0.0) ; extra == "lookerstudio" or extra == "all"
|
|
35
36
|
Requires-Dist: google-auth (>=2,<3)
|
|
36
37
|
Requires-Dist: google-cloud-core (>=2.1.0,<3.0.0)
|
|
37
38
|
Requires-Dist: google-cloud-storage (>=2,<3)
|
|
@@ -39,10 +40,8 @@ Requires-Dist: google-resumable-media (>=2.0.3,<3.0.0)
|
|
|
39
40
|
Requires-Dist: googleapis-common-protos (>=1.53.0,<2.0.0)
|
|
40
41
|
Requires-Dist: looker-sdk (>=24.16.0,<24.17.0) ; extra == "looker" or extra == "all"
|
|
41
42
|
Requires-Dist: msal (>=1.20.0,<2.0.0) ; extra == "powerbi" or extra == "all"
|
|
42
|
-
Requires-Dist: numpy (<1.25) ; (python_version >= "3.8" and python_version < "3.9") and (extra == "bigquery" or extra == "databricks" or extra == "all")
|
|
43
43
|
Requires-Dist: numpy (<2) ; extra == "bigquery" or extra == "databricks" or extra == "all"
|
|
44
44
|
Requires-Dist: numpy (>=1.26) ; (python_version >= "3.12" and python_version < "3.13") and (extra == "bigquery" or extra == "databricks" or extra == "all")
|
|
45
|
-
Requires-Dist: pandas (<2.1) ; (python_version >= "3.8" and python_version < "3.9") and (extra == "databricks" or extra == "all")
|
|
46
45
|
Requires-Dist: pandas (>=2.1) ; (python_version >= "3.12" and python_version < "3.13") and (extra == "databricks" or extra == "all")
|
|
47
46
|
Requires-Dist: psycopg2-binary (>=2.0.0,<3.0.0) ; extra == "metabase" or extra == "postgres" or extra == "redshift" or extra == "all"
|
|
48
47
|
Requires-Dist: pycryptodome (>=3.0.0,<4.0.0) ; extra == "metabase" or extra == "all"
|
|
@@ -52,7 +51,7 @@ Requires-Dist: pymssql (>=2.2.11,<3.0.0) ; extra == "sqlserver" or extra == "all
|
|
|
52
51
|
Requires-Dist: pymysql[rsa] (>=1.1.0,<2.0.0) ; extra == "mysql" or extra == "all"
|
|
53
52
|
Requires-Dist: python-dateutil (>=2.0.0,<=3.0.0)
|
|
54
53
|
Requires-Dist: requests (>=2.0.0,<3.0.0)
|
|
55
|
-
Requires-Dist: setuptools (>=75.
|
|
54
|
+
Requires-Dist: setuptools (>=75.6)
|
|
56
55
|
Requires-Dist: snowflake-connector-python (>=3.4.0,<4.0.0) ; extra == "snowflake" or extra == "all"
|
|
57
56
|
Requires-Dist: snowflake-sqlalchemy (!=1.2.5,<2.0.0) ; extra == "snowflake" or extra == "all"
|
|
58
57
|
Requires-Dist: sqlalchemy (>=1.4,<1.5)
|
|
@@ -208,6 +207,14 @@ For any questions or bug report, contact us at [support@castordoc.com](mailto:su
|
|
|
208
207
|
|
|
209
208
|
# Changelog
|
|
210
209
|
|
|
210
|
+
## 0.22.1 - 2024-12-05
|
|
211
|
+
|
|
212
|
+
* Salesforce: deduplicate tables
|
|
213
|
+
|
|
214
|
+
## 0.22.0 - 2024-12-04
|
|
215
|
+
|
|
216
|
+
* Stop supporting python3.8
|
|
217
|
+
|
|
211
218
|
## 0.21.9 - 2024-12-04
|
|
212
219
|
|
|
213
220
|
* Tableau: fix handling of timeout retry
|