8000 Type hint views (#949) · tableau/server-client-python@820005c · GitHub
[go: up one dir, main page]

Skip to content

Commit 820005c

Browse files
jorwoodsjacalata
authored andcommitted
Type hint views (#949)
* Type hint views
1 parent 083eb2c commit 820005c

File tree

4 files changed

+67
-53
lines changed

4 files changed

+67
-53
lines changed

tableauserverclient/models/view_item.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,32 @@
44
from .tag_item import TagItem
55
import copy
66

7+
from typing import ByteString, Callable, Iterable, List, Optional, Set, TYPE_CHECKING
8+
9+
if TYPE_CHECKING:
10+
from datetime import datetime
11+
from .permissions_item import PermissionsRule
12+
713

814
class ViewItem(object):
9-
def __init__(self):
10-
self._content_url = None
11-
self._created_at = None
12-
self._id = None
13-
self._image = None
14-
self._initial_tags = set()
15-
self._name = None
16-
self._owner_id = None
17-
self._preview_image = None
18-
self._project_id = None
19-
self._pdf = None
20-
self._csv = None
21-
self._total_views = None
22-
self._sheet_type = None
23-
self._updated_at = None
24-
self._workbook_id = None
25-
self._permissions = None
26-
self.tags = set()
15+
def __init__(self) -> None:
16+
self._content_url: Optional[str] = None
17+
self._created_at: Optional["datetime"] = None
18+
self._id: Optional[str] = None
19+
self._image: Optional[Callable[[], bytes]] = None
20+
self._initial_tags: Set[str] = set()
21+
self._name: Optional[str] = None
22+
self._owner_id: Optional[str] = None
23+
self._preview_image: Optional[Callable[[], bytes]] = None
24+
self._project_id: Optional[str] = None
25+
self._pdf: Optional[Callable[[], bytes]] = None
26+
self._csv: Optional[Callable[[], Iterable[bytes]]] = None
27+
self._total_views: Optional[int] = None
28+
self._sheet_type: Optional[str] = None
29+
self._updated_at: Optional["datetime"] = None
30+
self._workbook_id: Optional[str] = None
31+
self._permissions: Optional[Callable[[], List["PermissionsRule"]]] = None
32+
self.tags: Set[str] = set()
2733

2834
def _set_preview_image(self, preview_image):
2935
self._preview_image = preview_image
@@ -38,59 +44,59 @@ def _set_csv(self, csv):
3844
self._csv = csv
3945

4046
@property
41-
def content_url(self):
47+
def content_url(self) -> Optional[str]:
4248
return self._content_url
4349

4450
@property
45-
def created_at(self):
51+
def created_at(self) -> Optional["datetime"]:
4652
return self._created_at
4753

4854
@property
49-
def id(self):
55+
def id(self) -> Optional[str]:
5056
return self._id
5157

5258
@property
53-
def image(self):
59+
def image(self) -> bytes:
5460
if self._image is None:
5561
error = "View item must be populated with its png image first."
5662
raise UnpopulatedPropertyError(error)
5763
return self._image()
5864

5965
@property
60-
def name(self):
66+
def name(self) -> Optional[str]:
6167
return self._name
6268

6369
@property
64-
def owner_id(self):
70+
def owner_id(self) -> Optional[str]:
6571
return self._owner_id
6672

6773
@property
68-
def preview_image(self):
74+
def preview_image(self) -> bytes:
6975
if self._preview_image is None:
7076
error = "View item must be populated with its preview image first."
7177
raise UnpopulatedPropertyError(error)
7278
return self._preview_image()
7379

7480
@property
75-
def project_id(self):
81+
def project_id(self) -> Optional[str]:
7682
return self._project_id
7783

7884
@property
79-
def pdf(self):
85+
def pdf(self) -> bytes:
8086
if self._pdf is None:
8187
error = "View item must be populated with its pdf first."
8288
raise UnpopulatedPropertyError(error)
8389
return self._pdf()
8490

8591
@property
86-
def csv(self):
92+
def csv(self) -> Iterable[bytes]:
8793
if self._csv is None:
8894
error = "View item must be populated with its csv first."
8995
raise UnpopulatedPropertyError(error)
9096
return self._csv()
9197

9298
@property
93-
def sheet_type(self):
99+
def sheet_type(self) -> Optional[str]:
94100
return self._sheet_type
95101

96102
@property
@@ -101,29 +107,29 @@ def total_views(self):
101107
return self._total_views
102108

103109
@property
104-
def updated_at(self):
110+
def updated_at(self) -> Optional["datetime"]:
105111
return self._updated_at
106112

107113
@property
108-
def workbook_id(self):
114+
def workbook_id(self) -> Optional[str]:
109115
return self._workbook_id
110116

111117
@property
112-
def permissions(self):
118+
def permissions(self) -> List["PermissionsRule"]:
113119
if self._permissions is None:
114120
error = "View item must be populated with permissions first."
115121
raise UnpopulatedPropertyError(error)
116122
return self._permissions()
117123

118-
def _set_permissions(self, permissions):
124+
def _set_permissions(self, permissions: Callable[[], List["PermissionsRule"]]) -> None:
119125
self._permissions = permissions
120126

121127
@classmethod
122-
def from_response(cls, resp, ns, workbook_id=""):
128+
def from_response(cls, resp, ns, workbook_id="") -> List["ViewItem"]:
123129
return cls.from_xml_element(ET.fromstring(resp), ns, workbook_id)
124130

125131
@classmethod
126-
def from_xml_element(cls, parsed_response, ns, workbook_id=""):
132+
def from_xml_element(cls, parsed_response, ns, workbook_id="") -> List["ViewItem"]:
127133
all_view_items = list()
128134
all_view_xml = parsed_response.findall(".//t:view", namespaces=ns)
129135
for view_xml in all_view_xml:

tableauserverclient/server/endpoint/views_endpoint.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99

1010
logger = logging.getLogger("tableau.endpoint.views")
1111

12+
from typing import Iterable, List, Optional, Tuple, TYPE_CHECKING
13+
14+
if TYPE_CHECKING:
15+
from ..request_options import RequestOptions, CSVRequestOptions, PDFRequestOptions, ImageRequestOptions
16+
1217

1318
class Views(QuerysetEndpoint):
1419
def __init__(self, parent_srv):
@@ -18,15 +23,17 @@ def __init__(self, parent_srv):
1823

1924
# Used because populate_preview_image functionaliy requires workbook endpoint
2025
@property
21-
def siteurl(self):
26+
def siteurl(self) -> str:
2227
return "{0}/sites/{1}".format(self.parent_srv.baseurl, self.parent_srv.site_id)
2328

2429
@property
25-
def baseurl(self):
30+
def baseurl(self) -> str:
2631
return "{0}/views".format(self.siteurl)
2732

2833
@api(version="2.2")
29-
def get(self, req_options=None, usage=False):
34+
def get(
35+
self, req_options: Optional["RequestOptions"] = None, usage: bool = False
36+
) -> Tuple[List[ViewItem], PaginationItem]:
3037
logger.info("Querying all views on site")
3138
url = self.baseurl
3239
if usage:
@@ -37,7 +44,7 @@ def get(self, req_options=None, usage=False):
3744
return all_view_items, pagination_item
3845

3946
@api(version="3.1")
40-
def get_by_id(self, view_id):
47+
def get_by_id(self, view_id: str) -> ViewItem:
4148
if not view_id:
4249
error = "View item missing ID."
4350
raise MissingRequiredFieldError(error)
@@ -47,7 +54,7 @@ def get_by_id(self, view_id):
4754
return ViewItem.from_response(server_response.content, self.parent_srv.namespace)[0]
4855

4956
@api(version="2.0")
50-
def populate_preview_image(self, view_item):
57+
def populate_preview_image(self, view_item: ViewItem) -> None:
5158
if not view_item.id or not view_item.workbook_id:
5259
error = "View item missing ID or workbook ID."
5360
raise MissingRequiredFieldError(error)
@@ -58,14 +65,14 @@ def image_fetcher():
5865
view_item._set_preview_image(image_fetcher)
5966
logger.info("Populated preview image for view (ID: {0})".format(view_item.id))
6067

61-
def _get_preview_for_view(self, view_item):
68+
def _get_preview_for_view(self, view_item: ViewItem) -> bytes:
6269
url = "{0}/workbooks/{1}/views/{2}/previewImage".format(self.siteurl, view_item.workbook_id, view_item.id)
6370
server_response = self.get_request(url)
6471
image = server_response.content
6572
return image
6673

6774
@api(version="2.5")
68-
def populate_image(self, view_item, req_options=None):
75+
def populate_image(self, view_item: ViewItem, req_options: Optional["ImageRequestOptions"] = None) -> None:
6976
if not view_item.id:
7077
error = "View item missing ID."
7178
raise MissingRequiredFieldError(error)
@@ -76,14 +83,14 @@ def image_fetcher():
7683
view_item._set_image(image_fetcher)
7784
logger.info("Populated image for view (ID: {0})".format(view_item.id))
7885

79-
def _get_view_image(self, view_item, req_options):
86+
def _get_view_image(self, view_item: ViewItem, req_options: Optional["ImageRequestOptions"]) -> bytes:
8087
url = "{0}/{1}/image".format(self.baseurl, view_item.id)
8188
server_response = self.get_request(url, req_options)
8289
image = server_response.content
8390
return image
8491

8592
@api(version="2.7")
86-
def populate_pdf(self, view_item, req_options=None):
93+
def populate_pdf(self, view_item: ViewItem, req_options: Optional["PDFRequestOptions"] = None) -> None:
8794
if not view_item.id:
8895
error = "View item missing ID."
8996
raise MissingRequiredFieldError(error)
@@ -94,14 +101,14 @@ def pdf_fetcher():
94101
view_item._set_pdf(pdf_fetcher)
95102
logger.info("Populated pdf for view (ID: {0})".format(view_item.id))
96103

97-
def _get_view_pdf(self, view_item, req_options):
104+
def _get_view_pdf(self, view_item: ViewItem, req_options: Optional["PDFRequestOptions"]) -> bytes:
98105
url = "{0}/{1}/pdf".format(self.baseurl, view_item.id)
99106
server_response = self.get_request(url, req_options)
100107
pdf = server_response.content
101108
return pdf
102109

103110
@api(version="2.7")
104-
def populate_csv(self, view_item, req_options=None):
111+
def populate_csv(self, view_item: ViewItem, req_options: Optional["CSVRequestOptions"] = None) -> None:
105112
if not view_item.id:
106113
error = "View item missing ID."
107114
raise MissingRequiredFieldError(error)
@@ -112,15 +119,15 @@ def csv_fetcher():
112119
view_item._set_csv(csv_fetcher)
113120
logger.info("Populated csv for view (ID: {0})".format(view_item.id))
114121

115-
def _get_view_csv(self, view_item, req_options):
122+
def _get_view_csv(self, view_item: ViewItem, req_options: Optional["CSVRequestOptions"]) -> Iterable[bytes]:
116123
url = "{0}/{1}/data".format(self.baseurl, view_item.id)
117124

118125
with closing(self.get_request(url, request_object=req_options, parameters={"stream": True})) as server_response:
119126
csv = server_response.iter_content(1024)
120127
return csv
121128

122129
@api(version="3.2")
123-
def populate_permissions(self, item):
130+
def populate_permissions(self, item: ViewItem) -> None:
124131
self._permissions.populate(item)
125132

126133
@api(version="3.2")
@@ -132,7 +139,7 @@ def delete_permission(self, item, capability_item):
132139
return self._permissions.delete(item, capability_item)
133140

134141
# Update view. Currently only tags can be updated
135-
def update(self, view_item):
142+
def update(self, view_item: ViewItem) -> ViewItem:
136143
if not view_item.id:
137144
error = "View item missing ID. View must be retrieved from server first."
138145
raise MissingRequiredFieldError(error)

test/test_project.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ def test_update_missing_id(self) -> None:
137137
self.assertRaises(TSC.MissingRequiredFieldError, self.server.projects.update, single_project)
138138

139139
def test_create(self) -> None:
140+
140141
with open(CREATE_XML, "rb") as f:
141142
response_xml = f.read().decode("utf-8")
142143
with requests_mock.mock() as m:

test/test_view.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def test_get_by_id(self):
7979
self.assertEqual("2002-06-05T08:00:59Z", format_datetime(view.updated_at))
8080
self.assertEqual("story", view.sheet_type)
8181

82-
def test_get_by_id_missing_id(self):
82+
def test_get_by_id_missing_id(self) -> None:
8383
self.assertRaises(TSC.MissingRequiredFieldError, self.server.views.get_by_id, None)
8484

8585
def test_get_with_usage(self):
@@ -117,7 +117,7 @@ def test_get_with_usage_and_filter(self):
117117
self.assertEqual("Overview", all_views[1].name)
118118
self.assertEqual(13, all_views[1].total_views)
119119

120-
def test_get_before_signin(self):
120+
def test_get_before_signin(self) -> None:
121121
self.server._auth_token = None
122122
self.assertRaises(TSC.NotSignedInError, self.server.views.get)
123123

@@ -136,7 +136,7 @@ def test_populate_preview_image(self):
136136
self.server.views.populate_preview_image(single_view)
137137
self.assertEqual(response, single_view.preview_image)
138138

139-
def test_populate_preview_image_missing_id(self):
139+
def test_populate_preview_image_missing_id(self) -> None:
140140
single_view = TSC.ViewItem()
141141
single_view._id = "d79634e1-6063-4ec9-95ff-50acbf609ff5"
142142
self.assertRaises(TSC.MissingRequiredFieldError, self.server.views.populate_preview_image, single_view)
@@ -211,7 +211,7 @@ def test_populate_csv_default_maxage(self):
211211
csv_file = b"".join(single_view.csv)
212212
self.assertEqual(response, csv_file)
213213

214-
def test_populate_image_missing_id(self):
214+
def test_populate_image_missing_id(self) -> None:
215215
single_view = TSC.ViewItem()
216216
single_view._id = None
217217
self.assertRaises(TSC.MissingRequiredFieldError, self.server.views.populate_image, single_view)

0 commit comments

Comments
 (0)
0