castor-extractor 0.23.3__py3-none-any.whl → 0.24.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 +4 -0
- castor_extractor/knowledge/confluence/client/client.py +0 -13
- castor_extractor/knowledge/confluence/client/endpoints.py +1 -1
- {castor_extractor-0.23.3.dist-info → castor_extractor-0.24.0.dist-info}/METADATA +5 -1
- {castor_extractor-0.23.3.dist-info → castor_extractor-0.24.0.dist-info}/RECORD +8 -43
- castor_extractor/visualization/tableau/__init__.py +0 -3
- castor_extractor/visualization/tableau/assets.py +0 -49
- castor_extractor/visualization/tableau/client/__init__.py +0 -2
- castor_extractor/visualization/tableau/client/client.py +0 -229
- castor_extractor/visualization/tableau/client/client_utils.py +0 -75
- castor_extractor/visualization/tableau/client/credentials.py +0 -104
- castor_extractor/visualization/tableau/client/project.py +0 -28
- castor_extractor/visualization/tableau/client/safe_mode.py +0 -70
- castor_extractor/visualization/tableau/constants.py +0 -9
- castor_extractor/visualization/tableau/errors.py +0 -5
- castor_extractor/visualization/tableau/extract.py +0 -121
- castor_extractor/visualization/tableau/gql_fields.py +0 -249
- castor_extractor/visualization/tableau/tests/__init__.py +0 -0
- castor_extractor/visualization/tableau/tests/unit/__init__.py +0 -0
- castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_1_get.json +0 -15
- castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_2_get.json +0 -15
- castor_extractor/visualization/tableau/tests/unit/assets/rest_api/auth.xml +0 -7
- castor_extractor/visualization/tableau/tests/unit/assets/rest_api/project_get.xml +0 -9
- castor_extractor/visualization/tableau/tests/unit/assets/rest_api/user_get.xml +0 -8
- castor_extractor/visualization/tableau/tests/unit/assets/rest_api/view_get_usage.xml +0 -24
- castor_extractor/visualization/tableau/tests/unit/assets/rest_api/workbook_get.xml +0 -19
- castor_extractor/visualization/tableau/tests/unit/graphql/__init__.py +0 -0
- castor_extractor/visualization/tableau/tests/unit/graphql/paginated_object_test.py +0 -63
- castor_extractor/visualization/tableau/tests/unit/rest_api/__init__.py +0 -0
- castor_extractor/visualization/tableau/tests/unit/rest_api/auth_test.py +0 -39
- castor_extractor/visualization/tableau/tests/unit/rest_api/credentials_test.py +0 -13
- castor_extractor/visualization/tableau/tests/unit/rest_api/projects_test.py +0 -59
- castor_extractor/visualization/tableau/tests/unit/rest_api/usages_test.py +0 -49
- castor_extractor/visualization/tableau/tests/unit/rest_api/users_test.py +0 -52
- castor_extractor/visualization/tableau/tests/unit/rest_api/workbooks_test.py +0 -60
- castor_extractor/visualization/tableau/tests/unit/utils/__init__.py +0 -1
- castor_extractor/visualization/tableau/tests/unit/utils/env_key.py +0 -6
- castor_extractor/visualization/tableau/tsc_fields.py +0 -46
- castor_extractor/visualization/tableau/types.py +0 -11
- castor_extractor/visualization/tableau/usage.py +0 -14
- {castor_extractor-0.23.3.dist-info → castor_extractor-0.24.0.dist-info}/LICENCE +0 -0
- {castor_extractor-0.23.3.dist-info → castor_extractor-0.24.0.dist-info}/WHEEL +0 -0
- {castor_extractor-0.23.3.dist-info → castor_extractor-0.24.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
import tableauserverclient as TSC # type: ignore
|
|
4
|
-
|
|
5
|
-
from ....utils import SerializedAsset
|
|
6
|
-
from ..assets import TableauAsset
|
|
7
|
-
from ..constants import SAFE_MODE_PAGE_SIZE
|
|
8
|
-
from ..errors import TableauErrorCode
|
|
9
|
-
from ..types import PageReturn, ServerResponseError
|
|
10
|
-
from ..usage import compute_usage_views
|
|
11
|
-
from .client_utils import extract_asset
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _paginated_option(page_number: int) -> TSC.RequestOptions:
|
|
17
|
-
"""Set up the Paginated option for TSC.RequestOptions"""
|
|
18
|
-
return TSC.RequestOptions(
|
|
19
|
-
pagesize=SAFE_MODE_PAGE_SIZE,
|
|
20
|
-
pagenumber=page_number,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _next_usage_page(client, page_number: int) -> PageReturn:
|
|
25
|
-
"""
|
|
26
|
-
Request views per page
|
|
27
|
-
return Usages | ServerResponseError | TableauErrorCode
|
|
28
|
-
"""
|
|
29
|
-
options = _paginated_option(page_number)
|
|
30
|
-
try:
|
|
31
|
-
all_usages_items, _ = client._server.views.get(options, usage=True)
|
|
32
|
-
return all_usages_items, None
|
|
33
|
-
|
|
34
|
-
except ServerResponseError as error:
|
|
35
|
-
expected = TableauErrorCode.PAGE_NUMBER_NOT_FOUND
|
|
36
|
-
if error.code == expected.value:
|
|
37
|
-
return None, expected
|
|
38
|
-
raise error
|
|
39
|
-
|
|
40
|
-
except ServerResponseError as error:
|
|
41
|
-
return None, error
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def safe_mode_fetch_usage(client) -> SerializedAsset:
|
|
45
|
-
"""
|
|
46
|
-
Iterate throught each page
|
|
47
|
-
Returns computed usages when page number is not found
|
|
48
|
-
Log errors if ServerResponseError is return
|
|
49
|
-
"""
|
|
50
|
-
list_usages: list[dict] = []
|
|
51
|
-
page_number: int = 0
|
|
52
|
-
|
|
53
|
-
while True:
|
|
54
|
-
page_number += 1
|
|
55
|
-
usages, error = _next_usage_page(client, page_number)
|
|
56
|
-
if error == TableauErrorCode.PAGE_NUMBER_NOT_FOUND:
|
|
57
|
-
return compute_usage_views(list_usages)
|
|
58
|
-
|
|
59
|
-
if error:
|
|
60
|
-
logger.warning(error)
|
|
61
|
-
client.errors.append(str(error))
|
|
62
|
-
continue
|
|
63
|
-
|
|
64
|
-
if not usages:
|
|
65
|
-
continue
|
|
66
|
-
|
|
67
|
-
new_usages = [
|
|
68
|
-
extract_asset(usage, TableauAsset.USAGE) for usage in usages
|
|
69
|
-
]
|
|
70
|
-
list_usages.extend(new_usages)
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from collections.abc import Iterable
|
|
3
|
-
|
|
4
|
-
from ...utils import (
|
|
5
|
-
OUTPUT_DIR,
|
|
6
|
-
current_timestamp,
|
|
7
|
-
deep_serialize,
|
|
8
|
-
from_env,
|
|
9
|
-
get_output_filename,
|
|
10
|
-
write_errors_logs,
|
|
11
|
-
write_json,
|
|
12
|
-
write_summary,
|
|
13
|
-
)
|
|
14
|
-
from .assets import TableauAsset
|
|
15
|
-
from .client import ApiClient as Client
|
|
16
|
-
|
|
17
|
-
logger = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def iterate_all_data(
|
|
21
|
-
client: Client,
|
|
22
|
-
) -> Iterable[tuple[TableauAsset, list]]:
|
|
23
|
-
"""Iterate over the extracted Data from Tableau"""
|
|
24
|
-
|
|
25
|
-
logger.info("Extracting USER from Tableau API")
|
|
26
|
-
yield TableauAsset.USER, deep_serialize(client.fetch(TableauAsset.USER))
|
|
27
|
-
|
|
28
|
-
logger.info("Extracting WORKBOOK from Tableau API")
|
|
29
|
-
yield (
|
|
30
|
-
TableauAsset.WORKBOOK,
|
|
31
|
-
deep_serialize(
|
|
32
|
-
client.fetch(TableauAsset.WORKBOOK),
|
|
33
|
-
),
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
logger.info("Extracting DASHBOARD from Tableau API")
|
|
37
|
-
yield (
|
|
38
|
-
TableauAsset.DASHBOARD,
|
|
39
|
-
deep_serialize(
|
|
40
|
-
client.fetch(TableauAsset.DASHBOARD),
|
|
41
|
-
),
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
logger.info("Extracting PUBLISHED DATASOURCE from Tableau API")
|
|
45
|
-
yield (
|
|
46
|
-
TableauAsset.PUBLISHED_DATASOURCE,
|
|
47
|
-
deep_serialize(
|
|
48
|
-
client.fetch(TableauAsset.PUBLISHED_DATASOURCE),
|
|
49
|
-
),
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
logger.info("Extracting PROJECT from Tableau API")
|
|
53
|
-
yield (
|
|
54
|
-
TableauAsset.PROJECT,
|
|
55
|
-
deep_serialize(
|
|
56
|
-
client.fetch(TableauAsset.PROJECT),
|
|
57
|
-
),
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
logger.info("Extracting USAGE from Tableau API")
|
|
61
|
-
yield TableauAsset.USAGE, deep_serialize(client.fetch(TableauAsset.USAGE))
|
|
62
|
-
|
|
63
|
-
logger.info("Extracting WORKBOOK_TO_DATASOURCE from Tableau API")
|
|
64
|
-
yield (
|
|
65
|
-
TableauAsset.WORKBOOK_TO_DATASOURCE,
|
|
66
|
-
deep_serialize(
|
|
67
|
-
client.fetch(TableauAsset.WORKBOOK_TO_DATASOURCE),
|
|
68
|
-
),
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
logger.info("Extracting DATASOURCE from Tableau API")
|
|
72
|
-
yield (
|
|
73
|
-
TableauAsset.DATASOURCE,
|
|
74
|
-
deep_serialize(
|
|
75
|
-
client.fetch(TableauAsset.DATASOURCE),
|
|
76
|
-
),
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
logger.info("Extracting CUSTOM_SQL_TABLE from Tableau API")
|
|
80
|
-
yield (
|
|
81
|
-
TableauAsset.CUSTOM_SQL_TABLE,
|
|
82
|
-
deep_serialize(
|
|
83
|
-
client.fetch(TableauAsset.CUSTOM_SQL_TABLE),
|
|
84
|
-
),
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
logger.info("Extracting CUSTOM_SQL_QUERY from Tableau API")
|
|
88
|
-
yield (
|
|
89
|
-
TableauAsset.CUSTOM_SQL_QUERY,
|
|
90
|
-
deep_serialize(
|
|
91
|
-
client.fetch(TableauAsset.CUSTOM_SQL_QUERY),
|
|
92
|
-
),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
logger.info("Extracting FIELD from Tableau API")
|
|
96
|
-
yield TableauAsset.FIELD, deep_serialize(client.fetch(TableauAsset.FIELD))
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def extract_all(client: Client, **kwargs: str) -> None:
|
|
100
|
-
"""
|
|
101
|
-
Extract Data from tableau
|
|
102
|
-
Store data locally in files under the output_directory
|
|
103
|
-
If errors from Tableau's API are catch store them locally in file under the output_directory
|
|
104
|
-
"""
|
|
105
|
-
output_directory = kwargs.get("output_directory") or from_env(OUTPUT_DIR)
|
|
106
|
-
|
|
107
|
-
timestamp = current_timestamp()
|
|
108
|
-
|
|
109
|
-
for key, data in iterate_all_data(client):
|
|
110
|
-
filename = get_output_filename(key.value, output_directory, timestamp)
|
|
111
|
-
write_json(filename, data)
|
|
112
|
-
|
|
113
|
-
write_summary(
|
|
114
|
-
output_directory,
|
|
115
|
-
timestamp,
|
|
116
|
-
base_url=client.base_url(),
|
|
117
|
-
client_name=client.name(),
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
if client.errors:
|
|
121
|
-
write_errors_logs(output_directory, timestamp, client.errors)
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
# Fields which will be use for Tableau GraphQL API
|
|
2
|
-
from enum import Enum
|
|
3
|
-
from typing import Union
|
|
4
|
-
|
|
5
|
-
from .assets import TableauAsset, TableauGraphqlAsset
|
|
6
|
-
|
|
7
|
-
FIELDS = "fields"
|
|
8
|
-
OBJECT_TYPE = "object_type"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class GQLQueryFields(Enum):
|
|
12
|
-
BIN_FIELDS: str = """
|
|
13
|
-
datasource {
|
|
14
|
-
... on PublishedDatasource {
|
|
15
|
-
name
|
|
16
|
-
luid
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
dataType
|
|
20
|
-
description
|
|
21
|
-
fields {
|
|
22
|
-
id
|
|
23
|
-
}
|
|
24
|
-
folderName
|
|
25
|
-
id
|
|
26
|
-
name
|
|
27
|
-
role
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
CALCULATED_FIELDS: str = """
|
|
31
|
-
datasource {
|
|
32
|
-
... on PublishedDatasource {
|
|
33
|
-
name
|
|
34
|
-
luid
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
fields {
|
|
38
|
-
id
|
|
39
|
-
}
|
|
40
|
-
dataType
|
|
41
|
-
description
|
|
42
|
-
folderName
|
|
43
|
-
id
|
|
44
|
-
name
|
|
45
|
-
role
|
|
46
|
-
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
COLUMN_FIELDS: str = """
|
|
50
|
-
columns {
|
|
51
|
-
id
|
|
52
|
-
name
|
|
53
|
-
table {
|
|
54
|
-
... on DatabaseTable {
|
|
55
|
-
id
|
|
56
|
-
description
|
|
57
|
-
name
|
|
58
|
-
fullName
|
|
59
|
-
schema
|
|
60
|
-
database {
|
|
61
|
-
name
|
|
62
|
-
luid
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
datasource {
|
|
69
|
-
... on PublishedDatasource {
|
|
70
|
-
name
|
|
71
|
-
luid
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
dataType
|
|
75
|
-
description
|
|
76
|
-
folderName
|
|
77
|
-
id
|
|
78
|
-
name
|
|
79
|
-
role
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
CUSTOM_SQL_TABLE: str = """
|
|
83
|
-
id
|
|
84
|
-
name
|
|
85
|
-
columns {
|
|
86
|
-
referencedByFields {
|
|
87
|
-
datasource {
|
|
88
|
-
... on PublishedDatasource {
|
|
89
|
-
luid
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
... on EmbeddedDatasource {
|
|
93
|
-
id
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
"""
|
|
99
|
-
|
|
100
|
-
CUSTOM_SQL_QUERY: str = """
|
|
101
|
-
id
|
|
102
|
-
name
|
|
103
|
-
query
|
|
104
|
-
database {
|
|
105
|
-
name
|
|
106
|
-
connectionType
|
|
107
|
-
}
|
|
108
|
-
tables {
|
|
109
|
-
name
|
|
110
|
-
}
|
|
111
|
-
"""
|
|
112
|
-
|
|
113
|
-
DASHBOARDS: str = """
|
|
114
|
-
id
|
|
115
|
-
name
|
|
116
|
-
path
|
|
117
|
-
tags {
|
|
118
|
-
name
|
|
119
|
-
}
|
|
120
|
-
workbook {
|
|
121
|
-
luid # to retrieve the parent
|
|
122
|
-
}
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
DATASOURCE: str = """
|
|
126
|
-
... on PublishedDatasource {
|
|
127
|
-
luid
|
|
128
|
-
}
|
|
129
|
-
id
|
|
130
|
-
name
|
|
131
|
-
hasExtracts
|
|
132
|
-
upstreamTables {
|
|
133
|
-
id
|
|
134
|
-
schema
|
|
135
|
-
name
|
|
136
|
-
fullName
|
|
137
|
-
database {
|
|
138
|
-
id
|
|
139
|
-
name
|
|
140
|
-
connectionType
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
"""
|
|
144
|
-
|
|
145
|
-
GROUP_FIELDS: str = """
|
|
146
|
-
datasource {
|
|
147
|
-
... on PublishedDatasource {
|
|
148
|
-
name
|
|
149
|
-
luid
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
dataType
|
|
153
|
-
description
|
|
154
|
-
fields {
|
|
155
|
-
id
|
|
156
|
-
}
|
|
157
|
-
folderName
|
|
158
|
-
id
|
|
159
|
-
name
|
|
160
|
-
role
|
|
161
|
-
"""
|
|
162
|
-
|
|
163
|
-
SHEET: str = """
|
|
164
|
-
containedInDashboards {
|
|
165
|
-
id
|
|
166
|
-
}
|
|
167
|
-
id
|
|
168
|
-
index
|
|
169
|
-
name
|
|
170
|
-
upstreamFields{
|
|
171
|
-
name
|
|
172
|
-
}
|
|
173
|
-
workbook {
|
|
174
|
-
luid
|
|
175
|
-
}
|
|
176
|
-
"""
|
|
177
|
-
|
|
178
|
-
WORKBOOK_TO_DATASOURCE: str = """
|
|
179
|
-
luid
|
|
180
|
-
id
|
|
181
|
-
embeddedDatasources {
|
|
182
|
-
id
|
|
183
|
-
name
|
|
184
|
-
}
|
|
185
|
-
upstreamDatasources {
|
|
186
|
-
luid
|
|
187
|
-
name
|
|
188
|
-
}
|
|
189
|
-
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
QueryInfo = list[dict[str, Union[GQLQueryFields, TableauGraphqlAsset]]]
|
|
193
|
-
|
|
194
|
-
QUERY_FIELDS: dict[TableauAsset, QueryInfo] = {
|
|
195
|
-
TableauAsset.CUSTOM_SQL_TABLE: [
|
|
196
|
-
{
|
|
197
|
-
FIELDS: GQLQueryFields.CUSTOM_SQL_TABLE,
|
|
198
|
-
OBJECT_TYPE: TableauGraphqlAsset.CUSTOM_SQL,
|
|
199
|
-
},
|
|
200
|
-
],
|
|
201
|
-
TableauAsset.CUSTOM_SQL_QUERY: [
|
|
202
|
-
{
|
|
203
|
-
FIELDS: GQLQueryFields.CUSTOM_SQL_QUERY,
|
|
204
|
-
OBJECT_TYPE: TableauGraphqlAsset.CUSTOM_SQL,
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
TableauAsset.DASHBOARD: [
|
|
208
|
-
{
|
|
209
|
-
FIELDS: GQLQueryFields.DASHBOARDS,
|
|
210
|
-
OBJECT_TYPE: TableauGraphqlAsset.DASHBOARD,
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
TableauAsset.DATASOURCE: [
|
|
214
|
-
{
|
|
215
|
-
FIELDS: GQLQueryFields.DATASOURCE,
|
|
216
|
-
OBJECT_TYPE: TableauGraphqlAsset.DATASOURCE,
|
|
217
|
-
},
|
|
218
|
-
],
|
|
219
|
-
TableauAsset.FIELD: [
|
|
220
|
-
{
|
|
221
|
-
FIELDS: GQLQueryFields.BIN_FIELDS,
|
|
222
|
-
OBJECT_TYPE: TableauGraphqlAsset.BIN_FIELD,
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
FIELDS: GQLQueryFields.CALCULATED_FIELDS,
|
|
226
|
-
OBJECT_TYPE: TableauGraphqlAsset.CALCULATED_FIELD,
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
FIELDS: GQLQueryFields.COLUMN_FIELDS,
|
|
230
|
-
OBJECT_TYPE: TableauGraphqlAsset.COLUMN_FIELD,
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
FIELDS: GQLQueryFields.GROUP_FIELDS,
|
|
234
|
-
OBJECT_TYPE: TableauGraphqlAsset.GROUP_FIELD,
|
|
235
|
-
},
|
|
236
|
-
],
|
|
237
|
-
TableauAsset.SHEET: [
|
|
238
|
-
{
|
|
239
|
-
FIELDS: GQLQueryFields.SHEET,
|
|
240
|
-
OBJECT_TYPE: TableauGraphqlAsset.SHEETS,
|
|
241
|
-
},
|
|
242
|
-
],
|
|
243
|
-
TableauAsset.WORKBOOK_TO_DATASOURCE: [
|
|
244
|
-
{
|
|
245
|
-
FIELDS: GQLQueryFields.WORKBOOK_TO_DATASOURCE,
|
|
246
|
-
OBJECT_TYPE: TableauGraphqlAsset.WORKBOOK_TO_DATASOURCE,
|
|
247
|
-
},
|
|
248
|
-
],
|
|
249
|
-
}
|
|
File without changes
|
|
File without changes
|
castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_1_get.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"data": {
|
|
3
|
-
"datasourcesConnection": {
|
|
4
|
-
"pageInfo": {
|
|
5
|
-
"hasNextPage": true,
|
|
6
|
-
"endCursor": "eyJ0eXBlIjoiUHVibGlzaGVkRGF0YXNvdXJjZSIsInNjb3BlIjoic2l0ZXMvMSIsInNvcnRPcmRlclZhbHVlIjp7Imxhc3RJZCI6IjAwMzllNWQ1LTI1ZmEtMTk2Yi1jNjZlLWMwNjc1ODM5ZTBiMCJ9fQ=="
|
|
7
|
-
},
|
|
8
|
-
"nodes": [
|
|
9
|
-
{
|
|
10
|
-
"id": "0039e5d5-25fa-196b-c66e-c0675839e0b0"
|
|
11
|
-
}
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
castor_extractor/visualization/tableau/tests/unit/assets/graphql/metadata/metadata_2_get.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"data": {
|
|
3
|
-
"datasourcesConnection": {
|
|
4
|
-
"pageInfo": {
|
|
5
|
-
"hasNextPage": false,
|
|
6
|
-
"endCursor": "eyJ0eXBlIjoiUHVibGlzaGVkRGF0YXNvdXJjZSIsInNjb3BlIjoic2l0ZXMvMSIsInNvcnRPcmRlclZhbHVlIjp7Imxhc3RJZCI6IjAwYjE5MWNlLTYwNTUtYWZmNS1lMjc1LWMyNjYxMGM4YzRkNiJ9fQ=="
|
|
7
|
-
},
|
|
8
|
-
"nodes": [
|
|
9
|
-
{
|
|
10
|
-
"id": "00b191ce-6055-aff5-e275-c26610c8c4d6"
|
|
11
|
-
}
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?>
|
|
2
|
-
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.3.xsd">
|
|
3
|
-
<credentials token="eIX6mvFsqyansa4KqEI1UwOpS8ggRs2l">
|
|
4
|
-
<site id="6b7179ba-b82b-4f0f-91ed-812074ac5da6" contentUrl="Samples" />
|
|
5
|
-
<user id="1a96d216-e9b8-497b-a82a-0b899a965e01" />
|
|
6
|
-
</credentials>
|
|
7
|
-
</tsResponse>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?>
|
|
2
|
-
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.3.xsd">
|
|
3
|
-
<pagination pageNumber="1" pageSize="100" totalAvailable="3" />
|
|
4
|
-
<projects>
|
|
5
|
-
<project id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20760" name="default" description="The default project that was automatically created by Tableau." contentPermissions="ManagedByOwner"><owner id="dd2239f6-ddf1-4107-981a-4cf94e415794" /></project>
|
|
6
|
-
<project id="1d0304cd-3796-429f-b815-7258370b9b74" name="Tableau" description="" contentPermissions="ManagedByOwner"><owner id="2a47bbf8-8900-4ebb-b0a4-2723bd7c46c3" /></project>
|
|
7
|
-
<project id="4cc52973-5e3a-4d1f-a4fb-5b5f73796edf" name="Tableau/Child_1" description="" contentPermissions="ManagedByOwner" parentProjectId="1d0304cd-3796-429f-b815-7258370b9b74"><owner id="dd2239f6-ddf1-4107-981a-4cf94e415794" /></project>
|
|
8
|
-
</projects>
|
|
9
|
-
</tsResponse>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?>
|
|
2
|
-
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.3.xsd">
|
|
3
|
-
<pagination pageNumber="1" pageSize="100" totalAvailable="2" />
|
|
4
|
-
<users>
|
|
5
|
-
<user id="dd2239f6-ddf1-4107-981a-4cf94e415794" name="alice" siteRole="Publisher" lastLogin="2016-08-16T23:17:06Z" externalAuthUserId="" fullName="alice cook" email="alicecook@test.com" />
|
|
6
|
-
<user id="2a47bbf8-8900-4ebb-b0a4-2723bd7c46c3" name="Bob" siteRole="Interactor" externalAuthUserId="" fullName="Bob Smith" email="bob@test.com" />
|
|
7
|
-
</users>
|
|
8
|
-
</tsResponse>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?>
|
|
2
|
-
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.3.xsd">
|
|
3
|
-
<pagination pageNumber="1" pageSize="100" totalAvailable="3" />
|
|
4
|
-
<views>
|
|
5
|
-
<view id="d79634e1-6063-4ec9-95ff-50acbf609ff5" name="ENDANGERED SAFARI" contentUrl="SafariSample/sheets/ENDANGEREDSAFARI">
|
|
6
|
-
<workbook id="3cc6cd06-89ce-4fdc-b935-5294135d6d42" />
|
|
7
|
-
<owner id="5de011f8-5aa9-4d5b-b991-f462c8dd6bb7" />
|
|
8
|
-
<tags />
|
|
9
|
-
<usage totalViewCount="7" />
|
|
10
|
-
</view>
|
|
11
|
-
<view id="f79634e1-6063-4ec9-95ff-50acbf609ff5" name="ENDANGERED SAFARI" contentUrl="SafariSample/sheets/ENDANGEREDSAFARI">
|
|
12
|
-
<workbook id="3cc6cd06-89ce-4fdc-b935-5294135d6d42" />
|
|
13
|
-
<owner id="5de011f8-5aa9-4d5b-b991-f462c8dd6bb7" />
|
|
14
|
-
<tags />
|
|
15
|
-
<usage totalViewCount="4" />
|
|
16
|
-
</view>
|
|
17
|
-
<view id="fd252f73-593c-4c4e-8584-c032b8022adc" name="Overview" contentUrl="Superstore/sheets/Overview" createdAt="2002-05-30T09:00:00Z" updatedAt="2002-06-05T08:00:59Z" sheetType="story">
|
|
18
|
-
<workbook id="6d13b0ca-043d-4d42-8c9d-3f3313ea3a00" />
|
|
19
|
-
<owner id="5de011f8-5aa9-4d5b-b991-f462c8dd6bb7" />
|
|
20
|
-
<tags />
|
|
21
|
-
<usage totalViewCount="13" />
|
|
22
|
-
</view>
|
|
23
|
-
</views>
|
|
24
|
-
</tsResponse>
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?>
|
|
2
|
-
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.3.xsd">
|
|
3
|
-
<pagination pageNumber="1" pageSize="100" totalAvailable="2" />
|
|
4
|
-
<workbooks>
|
|
5
|
-
<workbook id="6d13b0ca-043d-4d42-8c9d-3f3313ea3a00" name="Superstore" description="description for Superstore" contentUrl="Superstore" webpageUrl="http://tableauserver/#/workbooks/1/views" showTabs="false" size="1" createdAt="1" updatedAt="1">
|
|
6
|
-
<project id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20760" name="default" />
|
|
7
|
-
<owner id="5de011f8-5aa9-4d5b-b991-f462c8dd6bb7" />
|
|
8
|
-
<tags />
|
|
9
|
-
</workbook>
|
|
10
|
-
<workbook id="3cc6cd06-89ce-4fdc-b935-5294135d6d42" name="SafariSample" description="description for SafariSample" contentUrl="SafariSample" webpageUrl="http://tableauserver/#/workbooks/2/views" showTabs="false" size="26" createdAt="1" updatedAt="1">
|
|
11
|
-
<project id="ee8c6e70-43b6-11e6-af4f-f7b0d8e20760" name="default" />
|
|
12
|
-
<owner id="5de011f8-5aa9-4d5b-b991-f462c8dd6bb7" />
|
|
13
|
-
<tags>
|
|
14
|
-
<tag label="Safari" />
|
|
15
|
-
<tag label="Sample" />
|
|
16
|
-
</tags>
|
|
17
|
-
</workbook>
|
|
18
|
-
</workbooks>
|
|
19
|
-
</tsResponse>
|
|
File without changes
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import unittest
|
|
3
|
-
from unittest import mock
|
|
4
|
-
|
|
5
|
-
import requests_mock # type: ignore
|
|
6
|
-
import tableauserverclient as TSC # type: ignore
|
|
7
|
-
|
|
8
|
-
from .....tableau import TableauAsset
|
|
9
|
-
from ....client import ApiClient, get_paginated_objects
|
|
10
|
-
from ....constants import TABLEAU_SERVER_VERSION
|
|
11
|
-
from ..utils import KEYS
|
|
12
|
-
|
|
13
|
-
TEST_ASSET_DIR = os.path.join(
|
|
14
|
-
os.path.dirname(__file__),
|
|
15
|
-
"../assets/graphql/metadata",
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
METADATA_1 = os.path.join(TEST_ASSET_DIR, "metadata_1_get.json")
|
|
19
|
-
METADATA_2 = os.path.join(TEST_ASSET_DIR, "metadata_2_get.json")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
EXPECTED_PAGINATED = [
|
|
23
|
-
{"id": "0039e5d5-25fa-196b-c66e-c0675839e0b0"},
|
|
24
|
-
{"id": "00b191ce-6055-aff5-e275-c26610c8c4d6"},
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class PaginatedObjectTests(unittest.TestCase):
|
|
29
|
-
@mock.patch.dict(os.environ, KEYS)
|
|
30
|
-
def setUp(self):
|
|
31
|
-
self._client = ApiClient()
|
|
32
|
-
self._client._server = TSC.Server("http://test")
|
|
33
|
-
|
|
34
|
-
# Fake signin
|
|
35
|
-
self._client._server._site_id = "dad65087-b08b-4603-af4e-2887b8aafc67"
|
|
36
|
-
self._client._server._auth_token = "j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM"
|
|
37
|
-
self._client._server.version = TABLEAU_SERVER_VERSION
|
|
38
|
-
|
|
39
|
-
self.baseurl = self._client._server.metadata.baseurl
|
|
40
|
-
|
|
41
|
-
def test_paginated_object_with_datasources(self):
|
|
42
|
-
with open(METADATA_1, "rb") as f:
|
|
43
|
-
response_1_json = f.read().decode()
|
|
44
|
-
|
|
45
|
-
with open(METADATA_2, "rb") as f:
|
|
46
|
-
response_2_json = f.read().decode()
|
|
47
|
-
|
|
48
|
-
with requests_mock.mock() as m:
|
|
49
|
-
m.post(
|
|
50
|
-
self.baseurl,
|
|
51
|
-
[
|
|
52
|
-
{"text": response_1_json, "status_code": 200},
|
|
53
|
-
{"text": response_2_json, "status_code": 200},
|
|
54
|
-
],
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
results = get_paginated_objects(
|
|
58
|
-
self._client._server,
|
|
59
|
-
TableauAsset.DATASOURCE,
|
|
60
|
-
self._client._page_size,
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
self.assertEqual(results, EXPECTED_PAGINATED)
|
|
File without changes
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import os.path
|
|
2
|
-
import unittest
|
|
3
|
-
from unittest import mock
|
|
4
|
-
|
|
5
|
-
import requests_mock # type: ignore
|
|
6
|
-
|
|
7
|
-
from ....client import ApiClient
|
|
8
|
-
from ..utils import KEYS
|
|
9
|
-
|
|
10
|
-
TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), "../assets/rest_api/")
|
|
11
|
-
|
|
12
|
-
AUTH_XML = os.path.join(TEST_ASSET_DIR, "auth.xml")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class AuthTests(unittest.TestCase):
|
|
16
|
-
@mock.patch.dict(os.environ, KEYS)
|
|
17
|
-
def setUp(self):
|
|
18
|
-
self._client = ApiClient()
|
|
19
|
-
self.baseurl = self._client._server.auth.baseurl
|
|
20
|
-
|
|
21
|
-
def test_auth(self):
|
|
22
|
-
with open(AUTH_XML, "rb") as f:
|
|
23
|
-
response_xml = f.read().decode("utf-8")
|
|
24
|
-
with requests_mock.mock() as m:
|
|
25
|
-
m.post(self.baseurl + "/signin", text=response_xml)
|
|
26
|
-
self._client.login()
|
|
27
|
-
|
|
28
|
-
self.assertEqual(
|
|
29
|
-
"eIX6mvFsqyansa4KqEI1UwOpS8ggRs2l",
|
|
30
|
-
self._client._server.auth_token,
|
|
31
|
-
)
|
|
32
|
-
self.assertEqual(
|
|
33
|
-
"6b7179ba-b82b-4f0f-91ed-812074ac5da6",
|
|
34
|
-
self._client._server.site_id,
|
|
35
|
-
)
|
|
36
|
-
self.assertEqual(
|
|
37
|
-
"1a96d216-e9b8-497b-a82a-0b899a965e01",
|
|
38
|
-
self._client._server.user_id,
|
|
39
|
-
)
|