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

Skip to content
10000

Commit 391fdec

Browse files
lbrendanlRussell Hay
authored and
Russell Hay
committed
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
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