10000 Added view tagging functionality along with unit test and added sampl… · SamEBae/server-client-python@391fdec · GitHub
[go: up one dir, main page]

Skip to content

Commit 391fdec

Browse files
lbrendanlRussell Hay
authored andcommitted
Added view tagging functionality along with unit test and added sample code.
For upcoming 2.6 REST API Version.
1 parent 00e3015 commit 391fdec

File tree

6 files changed

+98
-1
lines changed

6 files changed

+98
-1
lines changed

samples/explore_datasource.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def main():
6868
for connection in sample_datasource.connections])
6969

7070
# Add some tags to the datasource
71+
server.version = 2.6
7172
original_tag_set = set(sample_datasource.tags)
7273
sample_datasource.tags.update('a', 'b', 'c', 'd')
7374
server.datasources.update(sample_datasource)

samples/explore_workbook.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ def main():
9090
sample_workbook.tags = original_tag_set
9191
server.workbooks.update(sample_workbook)
9292

93+
# Add tag to just one view
94+
server.version = 2.6
95+
sample_view = sample_workbook.views[0]
96+
original_tag_set = set(sample_view.tags)
97+
sample_view.tags.add("view_tag")
98+
server.views.update(sample_view)
99+
100+
# Delete tag from just one view
101+
sample_view.tags = original_tag_set
102+
server.views.update(sample_view)
103+
93104
if args.download:
94105
# Download
95106
path = server.workbooks.download(sample_workbook.id, args.download)

tableauserverclient/models/view_item.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ def __init__(self):
88
self._content_url = None
99
self._id = None
1010
self._image = None
11+
self._initial_tags = set()
1112
self._name = None
1213
self._owner_id = None
1314
self._preview_image = None
1415
self._total_views = None
1516
self._workbook_id = None
17+
self.tags = set()
1618

1719
@property
1820
def content_url(self):
@@ -49,6 +51,24 @@ def total_views(self):
4951
def workbook_id(self):
5052
return self._workbook_id
5153

54+
# Add new tags to workbook
55+
def _add_tags(self, workbook_id, tag_set):
56+
url = "{0}/{1}/tags".format(self.baseurl, workbook_id)
57+
add_req = RequestFactory.Tag.add_req(tag_set)
58+
server_response = self.put_request(url, add_req)
59+
return TagItem.from_response(server_response.content)
60+
61+
# Delete a workbook's tag by name
62+
def _delete_tag(self, workbook_id, tag_name):
63+
url = "{0}/{1}/tags/{2}".format(self.baseurl, workbook_id, tag_name)
64+
self.delete_request(url)
65+
66+
def _get_initial_tags(self):
67+
return self._initial_tags
68+
69+
def _set_initial_tags(self, initial_tags):
70+
self._initial_tags = initial_tags
71+
5272
@classmethod
5373
def from_response(cls, resp, workbook_id=''):
5474
return cls.from_xml_element(ET.fromstring(resp), workbook_id)

tableauserverclient/server/endpoint/views_endpoint.py

Lines changed: 35 additions & 1 deletion
F438
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from .endpoint import Endpoint, api
22
from .exceptions import MissingRequiredFieldError
3-
from .. import ViewItem, PaginationItem
3+
from .. import RequestFactory, ViewItem, PaginationItem
4+
from ...models.tag_item import TagItem
45
import logging
6+
import copy
57

68
logger = logging.getLogger('tableau.endpoint.views')
79

@@ -12,6 +14,18 @@ def baseurl(self):
1214
return "{0}/sites/{1}".format(self.parent_srv.baseurl, self.parent_srv.site_id)
1315

1416
@api(version="2.2")
17+
# Add new tags to view
18+
def _add_tags(self, view_id, tag_set):
19+
url = "{0}/views/{1}/tags".format(self.baseurl, view_id)
20+
add_req = RequestFactory.Tag.add_req(tag_set)
21+
server_response = self.put_request(url, add_req)
22+
return TagItem.from_response(server_response.content)
23+
24+
# Delete a view's tag by name
25+
def _delete_tag(self, view_id, tag_name):
26+
url = "{0}/views/{1}/tags/{2}".format(self.baseurl, view_id, tag_name)
27+
self.delete_request(url)
28+
1529
def get(self, req_options=None):
1630
logger.info('Querying all views on site')
1731
url = "{0}/views".format(self.baseurl)
@@ -41,3 +55,23 @@ def populate_image(self, view_item, req_options=None):
4155
server_response = self.get_request(url, req_options)
4256
view_item._image = server_response.content
4357
logger.info("Populated image for view (ID: {0})".format(view_item.id))
58+
59+
# Update view. Currently only tags can be updated
60+
def update(self, view_item):
61+
if not view_item.id:
62+
error = "View item missing ID. View must be retrieved from server first."
63+
raise MissingRequiredFieldError(error)
64+
65+
# Remove and add tags to match the view item's tag set
66+
if view_item.tags != view_item._initial_tags:
67+
add_set = view_item.tags - view_item._initial_tags
68+
remove_set = view_item._initial_tags - view_item.tags
69+
for tag in remove_set:
70+
self._delete_tag(view_item.id, tag)
71+
if add_set:
72+
view_item.tags = self._add_tags(view_item.id, add_set)
73+
view_item._initial_tags = copy.copy(view_item.tags)
74+
logger.info('Updated view tags to {0}'.format(view_item.tags))
75+
76+
# Returning view item to stay consistent with datasource/view update functions
77+
return view_item

test/assets/view_add_tags.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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.6.xsd">
3+
<tags>
4+
<tag label="a" />
5+
<tag label="b" />
6+
<tag label="c" />
7+
<tag label="d" />
8+
</tags>
9+
</tsResponse>

test/test_view.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), 'assets')
77

8+
ADD_TAGS_XML = os.path.join(TEST_ASSET_DIR, 'view_add_tags.xml')
89
GET_XML = os.path.join(TEST_ASSET_DIR, 'view_get.xml')
910
POPULATE_PREVIEW_IMAGE = os.path.join(TEST_ASSET_DIR, 'Sample View Image.png')
11+
UPDATE_XML = os.path.join(TEST_ASSET_DIR, 'workbook_update.xml')
1012

1113

1214
class ViewTests(unittest.TestCase):
@@ -89,3 +91,23 @@ def test_populate_image_missing_id(self):
8991
single_view = TSC.ViewItem()
9092
single_view._id = None
9193
self.assertRaises(TSC.MissingRequiredFieldError, self.server.views.populate_image, single_view)
94+
95+
def test_update_tags(self):
96+
with open(ADD_TAGS_XML, 'rb') as f:
97+
add_tags_xml = f.read().decode('utf-8')
98+
with open(UPDATE_XML, 'rb') as f:
99+
update_xml = f.read().decode('utf-8')
100+
with requests_mock.mock() as m:
101+
m.put(self.baseurl + '/views/d79634e1-6063-4ec9-95ff-50acbf609ff5/tags', text=add_tags_xml)
102+
m.delete(self.baseurl + '/views/d79634e1-6063-4ec9-95ff-50acbf609ff5/tags/b', status_code=204)
103+
m.delete(self.baseurl + '/views/d79634e1-6063-4ec9-95ff-50acbf609ff5/tags/d', status_code=204)
104+
m.put(self.baseurl + '/views/d79634e1-6063-4ec9-95ff-50acbf609ff5', text=update_xml)
105+
single_view = TSC.ViewItem()
106+
single_view._id = 'd79634e1-6063-4ec9-95ff-50acbf609ff5'
107+
single_view._initial_tags.update(['a', 'b', 'c', 'd'])
108+
single_view.tags.update(['a', 'c', 'e'])
109+
updated_view = self.server.views.update(single_view)
110+
111+
print("asdfasdf" + str(single_view) + str(updated_view))
112+
self.assertEqual(single_view.tags, updated_view.tags)
113+
self.assertEqual(single_view._initial_tags, updated_view._initial_tags)

0 commit comments

Comments
 (0)
0