8000 Added datasource tagging functionality along with unit test and added… · ajbosco/server-client-python@00e3015 · GitHub
[go: up one dir, main page]

Skip to content

Commit 00e3015

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

File tree

5 files changed

+79
-9
lines changed

5 files changed

+79
-9
lines changed

samples/explore_datasource.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ def main():
6767
print(["{0}({1})".format(connection.id, connection.datasource_name)
6868
for connection in sample_datasource.connections])
6969

70+
# Add some tags to the datasource
71+
original_tag_set = set(sample_datasource.tags)
72+
sample_datasource.tags.update('a', 'b', 'c', 'd')
73+
server.datasources.update(sample_datasource)
74+
print("\nOld tag set: {}".format(original_tag_set))
75+
print("New tag set: {}".format(sample_datasource.tags))
76+
77+
# Delete all tags that were added by setting tags to original
78+
sample_datasource.tags = original_tag_set
79+
server.datasources.update(sample_datasource)
7080

7181
if __name__ == '__main__':
7282
main()

tableauserverclient/models/datasource_item.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .tag_item import TagItem
55
from .. import NAMESPACE
66
from ..datetime_helpers import parse_datetime
7+
import copy
78

89

910
class DatasourceItem(object):
@@ -12,13 +13,14 @@ def __init__(self, project_id, name=None):
1213
self._content_url = None
1314
self._created_at = None
1415
self._id = None
16+
self._initial_tags = set()
1517
self._project_name = None
16-
self._tags = set()
1718
self._datasource_type = None
1819
self._updated_at = None
1920
self.name = name
2021
self.owner_id = None
2122
self.project_id = project_id
23+
self.tags = set()
2224

2325
@property
2426
def connections(self):
@@ -52,10 +54,6 @@ def project_id(self, value):
5254
def project_name(self):
5355
return self._project_name
5456

55-
@property
56-
def tags(self):
57-
return self._tags
58-
5957
@property
6058
def datasource_type(self):
6159
return self._datasource_type
@@ -67,6 +65,12 @@ def updated_at(self):
6765
def _set_connections(self, connections):
6866
self._connections = connections
6967

68+
def _set_initial_tags(self, initial_tags):
69+
self._initial_tags = initial_tags
70+
71+
def _get_initial_tags(self):
72+
return self._initial_tags
73+
7074
def _parse_common_tags(self, datasource_xml):
7175
if not isinstance(datasource_xml, ET.Element):
7276
datasource_xml = ET.fromstring(datasource_xml).find('.//t:datasource', namespaces=NAMESPACE)
@@ -90,7 +94,8 @@ def _set_values(self, id, name, datasource_type, content_url, created_at,
9094
if updated_at:
9195
self._updated_at = updated_at
9296
if tags:
93-
self._tags = tags
97+
self.tags = tags
98+
self._initial_tags = copy.copy(tags)
9499
if project_id:
95100
self.project_id = project_id
96101
if project_name:

tableauserverclient/server/endpoint/datasources_endpoint.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .fileuploads_endpoint import Fileuploads
44
from .. import RequestFactory, DatasourceItem, PaginationItem, ConnectionItem
55
from ...filesys_helpers import to_filename
6+
from ...models.tag_item import TagItem
67
import os
78
import logging
89
import copy
@@ -22,6 +23,18 @@ class Datasources(Endpoint):
2223
def baseurl(self):
2324
return "{0}/sites/{1}/datasources".format(self.parent_srv.baseurl, self.parent_srv.site_id)
2425

26+
# Add new tags to datasource
27+
def _add_tags(self, datasource_id, tag_set):
28+
url = "{0}/{1}/tags".format(self.baseurl, datasource_id)
29+
add_req = RequestFactory.Tag.add_req(tag_set)
30+
server_response = self.put_request(url, add_req)
31+
return TagItem.from_response(server_response.content)
32+
33+
# Delete a datasources's tag by name
34+
def _delete_tag(self, datasource_id, tag_name):
35+
url = "{0}/{1}/tags/{2}".format(self.baseurl, datasource_id, tag_name)
36+
self.delete_request(url)
37+
2538
# Get all datasources
2639
@api(version="2.0")
2740
def get(self, req_options=None):
@@ -97,9 +110,24 @@ def update(self, datasource_item):
97110
if not datasource_item.id:
98111
error = 'Datasource item missing ID. Datasource must be retrieved from server first.'
99112
raise MissingRequiredFieldError(error)
113+
114+
# Remove and add tags to match the datasource item's tag set
115+
if datasource_item.tags != datasource_item._initial_tags:
116+
add_set = datasource_item.tags - datasource_item._initial_tags
117+
remove_set = datasource_item._initial_tags - datasource_item.tags
118+
for tag in remove_set:
119+
self._delete_tag(datasource_item.id, tag)
120+
if add_set:
121+
datasource_item.tags = self._add_tags(datasource_item.id, add_set)
122+
datasource_item._initial_tags = copy.copy(datasource_item.tags)
123+
logger.info('Updated datasource tags to {0}'.format(datasource_item.tags))
124+
125+
# Update the datasource itself
100126
url = "{0}/{1}".format(self.baseurl, datasource_item.id)
101127
update_req = RequestFactory.Datasource.update_req(datasource_item)
128+
print(update_req)
102129
server_response = self.put_request(url, update_req)
130+
print(server_response)
103131
logger.info('Updated datasource item (ID: {0})'.format(datasource_item.id))
104132
updated_datasource = copy.copy(datasource_item)
105133
return updated_datasource._parse_common_tags(server_response.content)

test/assets/datasource_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_datasource.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

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

9+
ADD_TAGS_XML = os.path.join(TEST_ASSET_DIR, 'datasource_add_tags.xml')
910
GET_XML = os.path.join(TEST_ASSET_DIR, 'datasource_get.xml')
1011
GET_EMPTY_XML = os.path.join(TEST_ASSET_DIR, 'datasource_get_empty.xml')
1112
GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, 'datasource_get_by_id.xml')
12-
UPDATE_XML = os.path.join(TEST_ASSET_DIR, 'datasource_update.xml')
1313
PUBLISH_XML = os.path.join(TEST_ASSET_DIR, 'datasource_publish.xml')
14-
14+
UPDATE_XML = os.path.join(TEST_ASSET_DIR, 'datasource_update.xml')
1515

1616
class DatasourceTests(unittest.TestCase):
1717
def setUp(self):
@@ -105,13 +105,31 @@ def test_update_copy_fields(self):
105105
m.put(self.baseurl + '/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb', text=response_xml)
106106
single_datasource = TSC.DatasourceItem('test', '1d0304cd-3796-429f-b815-7258370b9b74')
107107
single_datasource._id = '9dbd2263-16b5-46e1-9c43-a76bb8ab65fb'
108-
single_datasource._tags = ['a', 'b', 'c']
109108
single_datasource._project_name = 'Tester'
110109
updated_datasource = self.server.datasources.update(single_datasource)
111110

112111
self.assertEqual(single_datasource.tags, updated_datasource.tags)
113112
self.assertEqual(single_datasource._project_name, updated_datasource._project_name)
114113

114+
def test_update_tags(self):
115+
with open(ADD_TAGS_XML, 'rb') as f:
116+
add_tags_xml = f.read().decode('utf-8')
117+
with open(UPDATE_XML, 'rb') as f:
118+
update_xml = f.read().decode('utf-8')
119+
with requests_mock.mock() as m:
120+
m.put(self.baseurl + '/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/tags', text=add_tags_xml)
121+
m.delete(self.baseurl + '/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/tags/b', status_code=204)
122+
m.delete(self.baseurl + '/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb/tags/d', status_code=204)
123+
m.put(self.baseurl + '/9dbd2263-16b5-46e1-9c43-a76bb8ab65fb', text=update_xml)
124+
single_datasource = TSC.DatasourceItem('1d0304cd-3796-429f-b815-7258370b9b74')
125+
single_datasource._id = '9dbd2263-16b5-46e1-9c43-a76bb8ab65fb'
126+
single_datasource._initial_tags.update(['a', 'b', 'c', 'd'])
127+
single_datasource.tags.update(['a', 'c', 'e'])
128+
updated_datasource = self.server.datasources.update(single_datasource)
129+
130+
self.assertEqual(single_datasource.tags, updated_datasource.tags)
131+
self.assertEqual(single_datasource._initial_tags, updated_datasource._initial_tags)
132+
115133
def test_publish(self):
116134
with open(PUBLISH_XML, 'rb') as f:
117135
response_xml = f.read().decode('utf-8')

0 commit comments

Comments
 (0)
0