10000 Merge branch 'tableau-development' into add-revision-support · elsherif/server-client-python@89fedde · GitHub
[go: up one dir, main page]

Skip to content

Commit 89fedde

Browse files
committed
Merge branch 'tableau-development' into add-revision-support
2 parents c47a597 + f078073 commit 89fedde

22 files changed

+406
-299
lines changed

.github/workflows/run-tests.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Python tests
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66
build:
@@ -24,13 +24,11 @@ jobs:
2424
run: |
2525
python -m pip install --upgrade pip
2626
pip install -e .[test]
27-
pip install mypy
2827
2928
- name: Test with pytest
3029
run: |
3130
pytest test
3231
33-
- name: Run Mypy but allow failures
32+
- name: Run Mypy tests
3433
run: |
35-
mypy --show-error-codes --disable-error-code misc tableauserverclient
36-
continue-on-error: true
34+
mypy --show-error-codes --disable-error-code misc --disable-error-code import tableauserverclient test

.github/workflows/slack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on: [push, pull_request, issues]
44

55
jobs:
66
slack-notifications:
7+
continue-on-error: true
78
runs-on: ubuntu-20.04
89
name: Sends a message to Slack when a push, a pull request or an issue is made
910
steps:

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ smoke=pytest
2626
[tool:pytest]
2727
testpaths = test smoke
2828
addopts = --junitxml=./test.junit.xml
29+
30+
[mypy]
31+
ignore_missing_imports = True

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# This makes work easier for offline installs or low bandwidth machines
1616
needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv)
1717
pytest_runner = ['pytest-runner'] if needs_pytest else []
18-
test_requirements = ['mock', 'pycodestyle', 'pytest', 'requests-mock>=1.0,<2.0']
18+
test_requirements = ['mock', 'pycodestyle', 'pytest', 'requests-mock>=1.0,<2.0', 'mypy==0.910']
1919

2020
setup(
2121
name='tableauserverclient',

tableauserverclient/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class NotThisMethod(Exception):
5151
"""Exception raised if a method is not valid for the current scenario."""
5252

5353

54-
LONG_VERSION_PY = {}
54+
LONG_VERSION_PY = {} # type: ignore
5555
HANDLERS = {}
5656

5757

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import time
22

33
# Polling for server-side events (such as job completion) uses exponential backoff for the sleep intervals between polls
4-
ASYNC_POLL_MIN_INTERVAL=0.5
5-
ASYNC_POLL_MAX_INTERVAL=30
6-
ASYNC_POLL_BACKOFF_FACTOR=1.4
4+
ASYNC_POLL_MIN_INTERVAL = 0.5
5+
ASYNC_POLL_MAX_INTERVAL = 30
6+
ASYNC_POLL_BACKOFF_FACTOR = 1.4
77

88

9-
class ExponentialBackoffTimer():
9+
class ExponentialBackoffTimer:
1010
def __init__(self, *, timeout=None):
1111
self.start_time = time.time()
1212
self.timeout = timeout
@@ -15,7 +15,7 @@ def __init__(self, *, timeout=None):
1515
def sleep(self):
1616
max_sleep_time = ASYNC_POLL_MAX_INTERVAL
1717
if self.timeout is not None:
18-
elapsed = (time.time() - self.start_time)
18+
elapsed = time.time() - self.start_time
1919
if elapsed >= self.timeout:
2020
raise TimeoutError(f"Timeout after {elapsed} seconds waiting for asynchronous event")
2121
remaining_time = self.timeout - elapsed
@@ -27,4 +27,4 @@ def sleep(self):
2727
max_sleep_time = max(max_sleep_time, ASYNC_POLL_MIN_INTERVAL)
2828

2929
time.sleep(min(self.current_sleep_interval, max_sleep_time))
30-
self.current_sleep_interval *= ASYNC_POLL_BACKOFF_FACTOR
30+
self.current_sleep_interval *= ASYNC_POLL_BACKOFF_FACTOR

tableauserverclient/models/database_item.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ def dqws(self):
5353
def content_permissions(self):
5454
return self._content_permissions
5555

56+
@content_permissions.setter
57+
@property_is_enum(ContentPermissions)
58+
def content_permissions(self, value):
59+
self._content_permissions = value
60+
5661
@property
5762
def permissions(self):
5863
if self._permissions is None:
@@ -67,11 +72,6 @@ def default_table_permissions(self):
6772
raise UnpopulatedPropertyError(error)
6873
return self._default_table_permissions()
6974

70-
@content_permissions.setter
71-
@property_is_enum(ContentPermissions)
72-
def content_permissions(self, value):
73-
self._content_permissions = value
74-
7575
@property
7676
def id(self):
7777
return self._id

tableauserverclient/models/datasource_item.py

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,87 +9,96 @@
99
from ..datetime_helpers import parse_datetime
1010
import copy
1111

12+
from typing import Dict, List, Optional, Set, Tuple, TYPE_CHECKING, Union
13+
14+
if TYPE_CHECKING:
15+
from .permissions_item import PermissionsRule
16+
from .connection_item import ConnectionItem
17+
import datetime
18+
1219

1320
class DatasourceItem(object):
1421
class AskDataEnablement:
1522
Enabled = "Enabled"
1623
Disabled = "Disabled"
1724
SiteDefault = "SiteDefault"
1825

19-
def __init__(self, project_id, name=None):
26+
def __init__(self, project_id: str, name: str = None) -> None:
2027
self._ask_data_enablement = None
2128
self._certified = None
2229
self._certification_note = None
2330
self._connections = None
24-
self._content_url = None
31+
self._content_url: Optional[str] = None
2532
self._created_at = None
2633
self._datasource_type = None
2734
self._description = None
2835
self._encrypt_extracts = None
2936
self._has_extracts = None
30-
self._id = None
31-
self._initial_tags = set()
32-
self._project_name = None
33-
self._revisions = None
37+
self._id: Optional[str] = None
38+
self._initial_tags: Set = set()
39+
self._project_name: Optional[str] = None
40+
self._revisions: List = None
3441
self._updated_at = None
3542
self._use_remote_query_agent = None
3643
self._webpage_url = None
3744
self.description = None
3845
self.name = name
39-
self.owner_id = None
46+
self.owner_id: Optional[str] = None
4047
self.project_id = project_id
41-
self.tags = set()
48+
self.tags: Set[str] = set()
4249

4350
self._permissions = None
4451
self._data_quality_warnings = None
4552

53+
return None
54+
4655
@property
47-
def ask_data_enablement(self):
56+
def ask_data_enablement(self) -> Optional["DatasourceItem.AskDataEnablement"]:
4857
return self._ask_data_enablement
4958

5059
@ask_data_enablement.setter
5160
@property_is_enum(AskDataEnablement)
52-
def ask_data_enablement(self, value):
61+
def ask_data_enablement(self, value: Optional["DatasourceItem.AskDataEnablement"]):
5362
self._ask_data_enablement = value
5463

5564
@property
56-
def connections(self):
65+
def connections(self) -> Optional[List["ConnectionItem"]]:
5766
if self._connections is None:
5867
error = "Datasource item must be populated with connections first."
5968
raise UnpopulatedPropertyError(error)
6069
return self._connections()
6170

6271
@property
63-
def permissions(self):
72+
def permissions(self) -> Optional[List["PermissionsRule"]]:
6473
if self._permissions is None:
6574
error = "Project item must be populated with permissions first."
6675
raise UnpopulatedPropertyError(error)
6776
return self._permissions()
6877

6978
@property
70-
def content_url(self):
79+
def content_url(self) -> Optional[str]:
7180
return self._content_url
7281

7382
@property
74-
def created_at(self):
83+
def created_at(self) -> Optional["datetime.datetime"]:
7584
return self._created_at
7685

7786
@property
78-
def certified(self):
87+
def certified(self) -> Optional[bool]:
7988
return self._certified
8089

8190
@certified.setter
8291
@property_not_nullable
8392
@property_is_boolean
84-
def certified(self, value):
93+
def certified(self, value: Optional[bool]):
8594
self._certified = value
8695

8796
@property
88-
def certification_note(self):
97+
def certification_note(self) -> Optional[str]:
8998
return self._certification_note
9099

91100
@certification_note.setter
92-
def certification_note(self, value):
101+
def certification_note(self, value: Optional[str]):
93102
self._certification_note = value
94103

95104
@property
@@ -98,7 +107,7 @@ def encrypt_extracts(self):
98107

99108
@encrypt_extracts.setter
100109
@property_is_boolean
101-
def encrypt_extracts(self, value):
110+
def encrypt_extracts(self, value: Optional[bool]):
102111
self._encrypt_extracts = value
103112

104113
@property
@@ -109,53 +118,53 @@ def dqws(self):
109118
return self._data_quality_warnings()
110119

111120
@property
112-
def has_extracts(self):
121+
def has_extracts(self) -> Optional[bool]:
113122
return self._has_extracts
114123

115124
@property
116-
def id(self):
125+
def id(self) -> Optional[str]:
117126
return self._id
118127

119128
@property
120-
def project_id(self):
129+
def project_id(self) -> str:
121130
return self._project_id
122131

123132
@project_id.setter
124133
@property_not_nullable
125-
def project_id(self, value):
134+
def project_id(self, value: str):
126135
self._project_id = value
127136

128137
@property
129-
def project_name(self):
138+
def project_name(self) -> Optional[str]:
130139
return self._project_name
131140

132141
@property
133-
def datasource_type(self):
142+
def datasource_type(self) -> Optional[str]:
134143
return self._datasource_type
135144

136145
@property
137-
def description(self):
146+
def description(self) -> Optional[str]:
138147
return self._description
139148

140149
@description.setter
141-
def description(self, value):
150+
def description(self, value: str):
142151
self._description = value
143152

144153
@property
145-
def updated_at(self):
154+
def updated_at(self) -> Optional["datetime.datetime"]:
146155
return self._updated_at
147156

148157
@property
149-
def use_remote_query_agent(self):
158+
def use_remote_query_agent(self) -> Optional[bool]:
150159
return self._use_remote_query_agent
151160

152161
@use_remote_query_agent.setter
153162
@property_is_boolean
154-
def use_remote_query_agent(self, value):
163+
def use_remote_query_agent(self, value: bool):
155164
self._use_remote_query_agent = value
156165

157166
@property
158-
def webpage_url(self):
167+
def webpage_url(self) -> Optional[str]:
159168
return self._webpage_url
160169

161170
@property
@@ -282,7 +291,7 @@ def _set_values(
282291
self._webpage_url = webpage_url
283292

284293
@classmethod
285-
def from_response(cls, resp, ns):
294+
def from_response(cls, resp: str, ns: Dict) -> List["DatasourceItem"]:
286295
all_datasource_items = list()
287296
parsed_response = ET.fromstring(resp)
288297
all_datasource_xml = parsed_response.findall(".//t:datasource", namespaces=ns)
@@ -333,16 +342,16 @@ def from_response(cls, resp, ns):
333342
return all_datasource_items
334343

335344
@staticmethod
336-
def _parse_element(datasource_xml, ns):
337-
id_ = datasource_xml.get('id', None)
338-
name = datasource_xml.get('name', None)
339-
datasource_type = datasource_xml.get('type', None)
340-
description = datasource_xml.get('description', None)
341-
content_url = datasource_xml.get('contentUrl', None)
342-
created_at = parse_datetime(datasource_xml.get('createdAt', None))
343-
updated_at = parse_datetime(datasource_xml.get('updatedAt', None))
344-
certification_note = datasource_xml.get('certificationNote', None)
345-
certified = str(datasource_xml.get('isCertified', None)).lower() == 'true'
345+
def _parse_element(datasource_xml: ET.Element, ns: Dict) -> Tuple:
346+
id_ = datasource_xml.get("id", None)
347+
name = datasource_xml.get("name", None)
348+
datasource_type = datasource_xml.get("type", None)
349+
description = datasource_xml.get("description", None)
350+
content_url = datasource_xml.get("contentUrl", None)
351+
created_at = parse_datetime(datasource_xml.get("createdAt", None))
352+
updated_at = parse_datetime(datasource_xml.get("updatedAt", None))
353+
certification_note = datasource_xml.get("certificationNote", None)
354+
certified = str(datasource_xml.get("isCertified", None)).lower() == "true"
346355
certification_note = datasource_xml.get("certificationNote", None)
347356
certified = str(datasource_xml.get("isCertified", None)).lower() == "true"
348357
content_url = datasource_xml.get("contentUrl", None)

tableauserverclient/models/dqw_item.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,6 @@ def severe(self):
8080
def severe(self, value):
8181
self._severe = value
8282

83-
@property
84-
def active(self):
85-
return self._active
86-
87-
@active.setter
88-
def active(self, value):
89-
self._active = value
90-
9183
@property
9284
def created_at(self):
9385
return self._created_at

tableauserverclient/models/job_item.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ class FinishCode:
99
Status codes as documented on
1010
https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_jobs_tasks_and_schedules.htm#query_job
1111
"""
12+
1213
Success = 0
1314
Failed = 1
1415
Cancelled = 2
1516

16-
1717
def __init__(
1818
self,
1919
id_,

tableauserverclient/models/project_item.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ def __init__(self, name, description=None, content_permissions=None, parent_id=N
2929
def content_permissions(self):
3030
return self._content_permissions
3131

32+
@content_permissions.setter
33+
@property_is_enum(ContentPermissions)
34+
def content_permissions(self, value):
35+
self._content_permissions = value
36+
3237
@property
3338
def permissions(self):
3439
if self._permissions is None:
@@ -57,11 +62,6 @@ def default_flow_permissions(self):
5762
raise UnpopulatedPropertyError(error)
5863
return self._default_flow_permissions()
5964

60-
@content_permissions.setter
61-
@property_is_enum(ContentPermissions)
62-
def content_permissions(self, value):
63-
self._content_permissions = value
64-
6565
@property
6666
def id(self):
6767
return self._id

0 commit comments

Comments
 (0)
0