Skip to content

Commit 90c80d2

Browse files
jorwoodsjacalata
andauthored
Jorwoods/type hint projects (#941)
* Type hint projects * Type hint ProjectRequest * Re-add params to project create * Update test_group.py Co-authored-by: Jac <jacalata@users.noreply.github.com>
1 parent 80480fb commit 90c80d2

File tree

5 files changed

+59
-42
lines changed

5 files changed

+59
-42
lines changed

tableauserverclient/models/project_item.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,28 @@
66
from .exceptions import UnpopulatedPropertyError
77

88

9+
from typing import List, Optional, TYPE_CHECKING
10+
11+
912
class ProjectItem(object):
1013
class ContentPermissions:
11-
LockedToProject = "LockedToProject"
12-
ManagedByOwner = "ManagedByOwner"
13-
LockedToProjectWithoutNested = "LockedToProjectWithoutNested"
14-
15-
def __init__(self, name, description=None, content_permissions=None, parent_id=None):
14+
LockedToProject: str = "LockedToProject"
15+
ManagedByOwner: str = "ManagedByOwner"
16+
LockedToProjectWithoutNested: str = "LockedToProjectWithoutNested"
17+
18+
def __init__(
19+
self,
20+
name: str,
21+
description: Optional[str] = None,
22+
content_permissions: Optional[str] = None,
23+
parent_id: Optional[str] = None,
24+
) -> None:
1625
self._content_permissions = None
17-
self._id = None
18-
self.description = description
19-
self.name = name
20-
self.content_permissions = content_permissions
21-
self.parent_id = parent_id
26+
self._id: Optional[str] = None
27+
self.description: Optional[str] = description
28+
self.name: str = name
29+
self.content_permissions: Optional[str] = content_permissions
30+
self.parent_id: Optional[str] = parent_id
2231

2332
self._permissions = None
2433
self._default_workbook_permissions = None
@@ -31,7 +40,7 @@ def content_permissions(self):
3140

3241
@content_permissions.setter
3342
@property_is_enum(ContentPermissions)
34-
def content_permissions(self, value):
43+
def content_permissions(self, value: Optional[str]) -> None:
3544
self._content_permissions = value
3645

3746
@property
@@ -63,24 +72,24 @@ def default_flow_permissions(self):
6372
return self._default_flow_permissions()
6473

6574
@property
66-
def id(self):
75+
def id(self) -> Optional[str]:
6776
return self._id
6877

6978
@property
70-
def name(self):
79+
def name(self) -> str:
7180
return self._name
7281

7382
@name.setter
7483
@property_not_empty
75-
def name(self, value):
84+
def name(self, value: str) -> None:
7685
self._name = value
7786

7887
@property
79-
def owner_id(self):
88+
def owner_id(self) -> Optional[str]:
8089
return self._owner_id
8190

8291
@owner_id.setter
83-
def owner_id(self, value):
92+
def owner_id(self, value: str) -> None:
8493
raise NotImplementedError("REST API does not currently support updating project owner.")
8594

8695
def is_default(self):
@@ -126,7 +135,7 @@ def _set_default_permissions(self, permissions, content_type):
126135
)
127136

128137
@classmethod
129-
def from_response(cls, resp, ns):
138+
def from_response(cls, resp, ns) -> List["ProjectItem"]:
130139
all_project_items = list()
131140
parsed_response = ET.fromstring(resp)
132141
all_project_xml = parsed_response.findall(".//t:project", namespaces=ns)

tableauserverclient/server/endpoint/projects_endpoint.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from tableauserverclient.server.request_factory import ProjectRequest
12
from .endpoint import api, Endpoint, XML_CONTENT_TYPE
23
from .exceptions import MissingRequiredFieldError
34
from .permissions_endpoint import _PermissionsEndpoint
@@ -9,20 +10,26 @@
910

1011
logger = logging.getLogger("tableau.endpoint.projects")
1112

13+
from typing import List, Optional, Tuple, TYPE_CHECKING
14+
15+
if TYPE_CHECKING:
16+
from ..server import Server
17+
from ..request_options import RequestOptions
18+
1219

1320
class Projects(Endpoint):
14-
def __init__(self, parent_srv):
21+
def __init__(self, parent_srv: "Server") -> None:
1522
super(Projects, self).__init__(parent_srv)
1623

1724
self._permissions = _PermissionsEndpoint(parent_srv, lambda: self.baseurl)
1825
self._default_permissions = _DefaultPermissionsEndpoint(parent_srv, lambda: self.baseurl)
1926

2027
@property
21-
def baseurl(self):
28+
def baseurl(self) -> str:
2229
return "{0}/sites/{1}/projects".format(self.parent_srv.baseurl, self.parent_srv.site_id)
2330

2431
@api(version="2.0")
25-
def get(self, req_options=None):
32+
def get(self, req_options: Optional["RequestOptions"] = None) -> Tuple[List[ProjectItem], PaginationItem]:
2633
logger.info("Querying all projects on site")
2734
url = self.baseurl
2835
server_response = self.get_request(url, req_options)
@@ -31,7 +38,7 @@ def get(self, req_options=None):
3138
return all_project_items, pagination_item
3239

3340
@api(version="2.0")
34-
def delete(self, project_id):
41+
def delete(self, project_id: str) -> None:
3542
if not project_id:
3643
error = "Project ID undefined."
3744
raise ValueError(error)
@@ -40,7 +47,7 @@ def delete(self, project_id):
4047
logger.info("Deleted single project (ID: {0})".format(project_id))
4148

4249
@api(version="2.0")
43-
def update(self, project_item, samples=False):
50+
def update(self, project_item: ProjectItem, samples: bool = False) -> ProjectItem:
4451
if not project_item.id:
4552
error = "Project item missing ID."
4653
raise MissingRequiredFieldError(error)
@@ -54,7 +61,7 @@ def update(self, project_item, samples=False):
5461
return updated_project
5562

5663
@api(version="2.0")
57-
def create(self, project_item, samples=False):
64+
def create(self, project_item: ProjectItem, samples: bool = False) -> ProjectItem:
5865
params = {"params": {RequestOptions.Field.PublishSamples: samples}}
5966
url = self.baseurl
6067
create_req = RequestFactory.Project.create_req(project_item)
@@ -64,7 +71,7 @@ def create(self, project_item, samples=False):
6471
return new_project
6572

6673
@api(version="2.0")
67-
def populate_permissions(self, item):
74+
def populate_permissions(self, item: ProjectItem) -> None:
6875
self._permissions.populate(item)
6976

7077
@api(version="2.0")

tableauserverclient/server/request_factory.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from ..models import DataAlertItem
1212
from ..models import FlowItem
1313
from ..models import ConnectionItem
14+
from ..models import ProjectItem
15+
1416

1517
def _add_multipart(parts: Dict) -> Tuple[Any, str]:
1618
mime_multipart_parts = list()
@@ -451,7 +453,7 @@ def _add_all_capabilities(self, capabilities_element, capabilities_map):
451453

452454

453455
class ProjectRequest(object):
454-
def update_req(self, project_item):
456+
def update_req(self, project_item: "ProjectItem") -> bytes:
455457
xml_request = ET.Element("tsRequest")
456458
project_element = ET.SubElement(xml_request, "project")
457459
if project_item.name:
@@ -464,7 +466,7 @@ def update_req(self, project_item):
464466
project_element.attrib["parentProjectId"] = project_item.parent_id
465467
return ET.tostring(xml_request)
466468

467-
def create_req(self, project_item):
469+
def create_req(self, project_item: "ProjectItem") -> bytes:
468470
xml_request = ET.Element("tsRequest")
469471
project_element = ET.SubElement(xml_request, "project")
470472
project_element.attrib["name"] = project_item.name

test/test_group.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ def test_add_user_missing_user_id(self) -> None:
146146

147147
self.assertRaises(ValueError, self.server.groups.add_user, single_group, "")
148148

149-
150149
def test_add_user_missing_group_id(self) -> None:
151150
single_group = TSC.GroupItem("test")
152151
single_group._users = []

test/test_project.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
class ProjectTests(unittest.TestCase):
20-
def setUp(self):
20+
def setUp(self) -> None:
2121
self.server = TSC.Server("http://test")
2222

2323
# Fake signin
@@ -26,7 +26,7 @@ def setUp(self):
2626

2727
self.baseurl = self.server.projects.baseurl
2828

29-
def test_get(self):
29+
def test_get(self) -> None:
3030
with open(GET_XML, "rb") as f:
3131
response_xml = f.read().decode("utf-8")
3232
with requests_mock.mock() as m:
@@ -53,19 +53,19 @@ def test_get(self):
5353
self.assertEqual("1d0304cd-3796-429f-b815-7258370b9b74", all_projects[2].parent_id)
5454
self.assertEqual("dd2239f6-ddf1-4107-981a-4cf94e415794", all_projects[2].owner_id)
5555

56-
def test_get_before_signin(self):
56+
def test_get_before_signin(self) -> None:
5757
self.server._auth_token = None
5858
self.assertRaises(TSC.NotSignedInError, self.server.projects.get)
5959

60-
def test_delete(self):
60+
def test_delete(self) -> None:
6161
with requests_mock.mock() as m:
6262
m.delete(self.baseurl + "/ee8c6e70-43b6-11e6-af4f-f7b0d8e20760", status_code=204)
6363
self.server.projects.delete("ee8c6e70-43b6-11e6-af4f-f7b0d8e20760")
6464

65-
def test_delete_missing_id(self):
65+
def test_delete_missing_id(self) -> None:
6666
self.assertRaises(ValueError, self.server.projects.delete, "")
6767

68-
def test_update(self):
68+
def test_update(self) -> None:
6969
with open(UPDATE_XML, "rb") as f:
7070
response_xml = f.read().decode("utf-8")
7171
with requests_mock.mock() as m:
@@ -85,7 +85,7 @@ def test_update(self):
8585
self.assertEqual("LockedToProject", single_project.content_permissions)
8686
self.assertEqual("9a8f2265-70f3-4494-96c5-e5949d7a1120", single_project.parent_id)
8787

88-
def test_content_permission_locked_to_project_without_nested(self):
88+
def test_content_permission_locked_to_project_without_nested(self) -> None:
8989
with open(SET_CONTENT_PERMISSIONS_XML, "rb") as f:
9090
response_xml = f.read().decode("utf-8")
9191
with requests_mock.mock() as m:
@@ -104,7 +104,7 @@ def test_content_permission_locked_to_project_without_nested(self):
104104
self.assertEqual("LockedToProjectWithoutNested", project_item.content_permissions)
105105
self.assertEqual("7687bc43-a543-42f3-b86f-80caed03a813", project_item.parent_id)
106106

107-
def test_update_datasource_default_permission(self):
107+
def test_update_datasource_default_permission(self) -> None:
108108
response_xml = read_xml_asset(UPDATE_DATASOURCE_DEFAULT_PERMISSIONS_XML)
109109
with requests_mock.mock() as m:
110110
m.put(
@@ -132,11 +132,11 @@ def test_update_datasource_default_permission(self):
132132
self.assertEqual("Allow", updated_capabilities["Write"])
133133
self.assertEqual("Allow", updated_capabilities["Connect"])
134134

135-
def test_update_missing_id(self):
135+
def test_update_missing_id(self) -> None:
136136
single_project = TSC.ProjectItem("test")
137137
self.assertRaises(TSC.MissingRequiredFieldError, self.server.projects.update, single_project)
138138

139-
def test_create(self):
139+
def test_create(self) -> None:
140140
with open(CREATE_XML, "rb") as f:
141141
response_xml = f.read().decode("utf-8")
142142
with requests_mock.mock() as m:
@@ -152,10 +152,10 @@ def test_create(self):
152152
self.assertEqual("ManagedByOwner", new_project.content_permissions)
153153
self.assertEqual("9a8f2265-70f3-4494-96c5-e5949d7a1120", new_project.parent_id)
154154

155-
def test_create_missing_name(self):
155+
def test_create_missing_name(self) -> None:
156156
self.assertRaises(ValueError, TSC.ProjectItem, "")
157157

158-
def test_populate_permissions(self):
158+
def test_populate_permissions(self) -> None:
159159
with open(asset(POPULATE_PERMISSIONS_XML), "rb") as f:
160160
response_xml = f.read().decode("utf-8")
161161
with requests_mock.mock() as m:
@@ -176,7 +176,7 @@ def test_populate_permissions(self):
176176
},
177177
)
178178

179-
def test_populate_workbooks(self):
179+
def test_populate_workbooks(self) -> None:
180180
response_xml = read_xml_asset(POPULATE_WORKBOOK_DEFAULT_PERMISSIONS_XML)
181181
with requests_mock.mock() as m:
182182
m.get(
@@ -213,7 +213,7 @@ def test_populate_workbooks(self):
213213
},
214214
)
215215

216-
def test_delete_permission(self):
216+
def test_delete_permission(self) -> None:
217217
with open(asset(POPULATE_PERMISSIONS_XML), "rb") as f:
218218
response_xml = f.read().decode("utf-8")
219219
with requests_mock.mock() as m:
@@ -242,7 +242,7 @@ def test_delete_permission(self):
242242
m.delete("{}/{}/Write/Allow".format(self.baseurl, endpoint), status_code=204)
243243
self.server.projects.delete_permission(item=single_project, rules=rules)
244244

245-
def test_delete_workbook_default_permission(self):
245+
def test_delete_workbook_default_permission(self) -> None:
246246
with open(asset(POPULATE_WORKBOOK_DEFAULT_PERMISSIONS_XML), "rb") as f:
247247
response_xml = f.read().decode("utf-8")
248248

0 commit comments

Comments
 (0)