8000 Merge pull request #745 from tableau/fix_732 · tableau/server-client-python@d05ec12 · GitHub
[go: up one dir, main page]

Skip to content

Commit d05ec12

Browse files
author
Chris Shin
authored
Merge pull request #745 from tableau/fix_732
Server versions before 2020.1 do not accept encoded query param delimiters
2 parents 62b264c + 0bcff26 commit d05ec12

File tree

5 files changed

+70
-67
lines changed

5 files changed

+70
-67
lines changed

tableauserverclient/server/endpoint/endpoint.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .exceptions import ServerResponseError, InternalServerError, NonXMLResponseError
1+
from .exceptions import ServerResponseError, InternalServerError, NonXMLResponseError, EndpointUnavailableError
22
from functools import wraps
33
from xml.etree.ElementTree import ParseError
44
from ..query import QuerySet
@@ -39,11 +39,9 @@ def _safe_to_log(server_response):
3939
else:
4040
return server_response.content
4141

42-
def _make_request(self, method, url, content=None, request_object=None,
43-
auth_token=None, content_type=None, parameters=None):
42+
def _make_request(self, method, url, content=None, auth_token=None,
43+
content_type=None, parameters=None):
4444
parameters = parameters or {}
45-
if request_object is not None:
46-
parameters["params"] = request_object.get_query_params()
4745
parameters.update(self.parent_srv.http_options)
4846
parameters['headers'] = Endpoint._make_common_headers(auth_token, content_type)
4947

@@ -81,12 +79,22 @@ def _check_status(self, server_response):
8179
# anything else re-raise here
8280
raise
8381

84-
def get_unauthenticated_request(self, url, request_object=None):
85-
return self._make_request(self.parent_srv.session.get, url, request_object=request_object)
82+
def get_unauthenticated_request(self, url):
83+
return self._make_request(self.parent_srv.session.get, url)
8684

8785
def get_request(self, url, request_object=None, parameters=None):
88-
return self._make_request(self.parent_srv.session.get, url, auth_token=self.parent_srv.auth_token,
89-
request_object=request_object, parameters=parameters)
86+
if request_object is not None:
87+
try:
88+
# Query param delimiters don't need to be encoded for versions before 3.7 (2020.1)
89+
self.parent_srv.assert_at_least_version("3.7")
90+
parameters = parameters or {}
91+
parameters["params"] = request_object.get_query_params()
92+
except EndpointUnavailableError:
93+
url = request_object.apply_query_params(url)
94+
95+
return self._make_request(self.parent_srv.session.get, url,
96+
auth_token=self.parent_srv.auth_token,
97+
parameters=parameters)
9098

9199
def delete_request(self, url):
92100
# We don't return anything for a delete

tableauserverclient/server/request_options.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33

44
class RequestOptionsBase(object):
5+
# This method is used if server api version is below 3.7 (2020.1)
56
def apply_query_params(self, url):
6-
import warnings
7-
warnings.simplefilter('always', DeprecationWarning)
8-
warnings.warn('apply_query_params is deprecated, please use get_query_params instead.', DeprecationWarning)
97
try:
108
params = self.get_query_params()
119
params_list = ["{}={}".format(k, v) for (k, v) in params.items()]

test/test_request_option.py

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def setUp(self):
2020
self.server = TSC.Server('http://test')
2121

2222
# Fake signin
23+
self.server.version = "3.10"
2324
self.server._site_id = 'dad65087-b08b-4603-af4e-2887b8aafc67'
2425
self.server._auth_token = 'j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM'
2526

@@ -141,54 +142,77 @@ def test_multiple_filter_options(self):
141142
def test_double_query_params(self):
142143
with requests_mock.mock() as m:
143144
m.get(requests_mock.ANY)
144-
url = "http://test/api/2.3/sites/12345/views?queryParamExists=true"
145+
url = self.baseurl + "/views?queryParamExists=true"
145146
opts = TSC.RequestOptions()
146147

147148
opts.filter.add(TSC.Filter(TSC.RequestOptions.Field.Tags,
148149
TSC.RequestOptions.Operator.In,
149150
['stocks', 'market']))
151+
opts.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name,
152+
TSC.RequestOptions.Direction.Asc))
150153

151-
resp = self.server.workbooks._make_request(requests.get,
152-
url,
153-
content=None,
154-
request_object=opts,
155-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
156-
content_type='text/xml')
154+
resp = self.server.workbooks.get_request(url, request_object=opts)
157155
self.assertTrue(re.search('queryparamexists=true', resp.request.query))
158156
self.assertTrue(re.search('filter=tags%3ain%3a%5bstocks%2cmarket%5d', resp.request.query))
157+
self.assertTrue(re.search('sort=name%3aasc', resp.request.query))
158+
159+
# Test req_options for versions below 3.7
160+
def test_filter_sort_legacy(self):
161+
self.server.version = "3.6"
162+
with requests_mock.mock() as m:
163+
m.get(requests_mock.ANY)
164+
url = self.baseurl + "/views?queryParamExists=true"
165+
opts = TSC.RequestOptions()
166+
167+
opts.filter.add(TSC.Filter(TSC.RequestOptions.Field.Tags,
168+
TSC.RequestOptions.Operator.In,
169+
['stocks', 'market']))
170+
opts.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name,
171+
TSC.RequestOptions.Direction.Asc))
172+
173+
resp = self.server.workbooks.get_request(url, request_object=opts)
174+
self.assertTrue(re.search('queryparamexists=true', resp.request.query))
175+
self.assertTrue(re.search('filter=tags:in:%5bstocks,market%5d', resp.request.query))
176+
self.assertTrue(re.search('sort=name:asc', resp.request.query))
159177

160178
def test_vf(self):
161179
with requests_mock.mock() as m:
162180
m.get(requests_mock.ANY)
163-
url = "http://test/api/2.3/sites/123/views/456/data"
181+
url = self.baseurl + "/views/456/data"
164182
opts = TSC.PDFRequestOptions()
165183
opts.vf("name1#", "value1")
166184
opts.vf("name2$", "value2")
167185
opts.page_type = TSC.PDFRequestOptions.PageType.Tabloid
168186

169-
resp = self.server.workbooks._make_request(requests.get,
170-
url,
171-
content=None,
172-
request_object=opts,
173-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
174-
content_type='text/xml')
187+
resp = self.server.workbooks.get_request(url, request_object=opts)
175188
self.assertTrue(re.search('vf_name1%23=value1', resp.request.query))
176189
self.assertTrue(re.search('vf_name2%24=value2', resp.request.query))
177190
self.assertTrue(re.search('type=tabloid', resp.request.query))
178191

192+
# Test req_options for versions beloe 3.7
193+
def test_vf_legacy(self):
194+
self.server.version = "3.6"
195+
with requests_mock.mock() as m:
196+
m.get(requests_mock.ANY)
197+
url = self.baseurl + "/views/456/data"
198+
opts = TSC.PDFRequestOptions()
199+
opts.vf("name1@", "value1")
200+
opts.vf("name2$", "value2")
201+
opts.page_type = TSC.PDFRequestOptions.PageType.Tabloid
202+
203+
resp = self.server.workbooks.get_request(url, request_object=opts)
204+
self.assertTrue(re.search('vf_name1@=value1', resp.request.query))
205+
self.assertTrue(re.search('vf_name2\\$=value2', resp.request.query))
206+
self.assertTrue(re.search('type=tabloid', resp.request.query))
207+
179208
def test_all_fields(self):
180209
with requests_mock.mock() as m:
181210
m.get(requests_mock.ANY)
182-
url = "http://test/api/2.3/sites/123/views/456/data"
211+
url = self.baseurl + "/views/456/data"
183212
opts = TSC.RequestOptions()
184213
opts._all_fields = True
185214

186-
resp = self.server.users._make_request(requests.get,
187-
url,
188-
content=None,
189-
request_object=opts,
190-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
191-
content_type='text/xml')
215+
resp = self.server.users.get_request(url, request_object=opts)
192216
self.assertTrue(re.search('fields=_all_', resp.request.query))
193217

194218
def test_multiple_filter_options_shorthand(self):

test/test_requests.py

Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@ def test_make_get_request(self):
2323
m.get(requests_mock.ANY)
2424
url = "http://test/api/2.3/sites/dad65087-b08b-4603-af4e-2887b8aafc67/workbooks"
2525
opts = TSC.RequestOptions(pagesize=13, pagenumber=15)
26-
resp = self.server.workbooks._make_request(requests.get,
27-
url,
28-
content=None,
29-
request_object=opts,
30-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
31-
content_type='text/xml')
26+
resp = self.server.workbooks.get_request(url, request_object=opts)
3227

3328
self.assertTrue(re.search('pagesize=13', resp.request.query))
3429
self.assertTrue(re.search('pagenumber=15', resp.request.query))
@@ -37,10 +32,7 @@ def test_make_post_request(self):
3732
with requests_mock.mock() as m:
3833
m.post(requests_mock.ANY)
3934
url = "http://test/api/2.3/sites/dad65087-b08b-4603-af4e-2887b8aafc67/workbooks"
40-
resp = self.server.workbooks._make_request(requests.post,
41-
url,
42-
content=b'1337',
43-
request_object=None,
35+
resp = self.server.workbooks._make_request(requests.post, url, content=b'1337',
4436
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
4537
content_type='multipart/mixed')
4638
self.assertEqual(resp.request.headers['x-tableau-auth'], 'j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM')
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
class SortTests(unittest.TestCase):
99
def setUp(self):
1010
self.server = TSC.Server('http://test')
11+
self.server.version = "3.10"
1112
self.server._site_id = 'dad65087-b08b-4603-af4e-2887b8aafc67'
1213
self.server._auth_token = 'j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM'
1314
self.baseurl = self.server.workbooks.baseurl
@@ -24,12 +25,7 @@ def test_filter_equals(self):
2425
TSC.RequestOptions.Operator.Equals,
2526
'Superstore'))
2627

27-
resp = self.server.workbooks._make_request(requests.get,
28-
url,
29-
content=None,
30-
request_object=opts,
31-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
32-
content_type='text/xml')
28+
resp = self.server.workbooks.get_request(url, request_object=opts)
3329

3430
self.assertTrue(re.search('pagenumber=13', resp.request.query))
3531
self.assertTrue(re.search('pagesize=13', resp.request.query))
@@ -53,12 +49,7 @@ def test_filter_in(self):
5349
TSC.RequestOptions.Operator.In,
5450
['stocks', 'market']))
5551

56-
resp = self.server.workbooks._make_request(requests.get,
57-
url,
58-
content=None,
59-
request_object=opts,
60-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
61-
content_type='text/xml')
52+
resp = self.server.workbooks.get_request(url, request_object=opts)
6253
self.assertTrue(re.search('pagenumber=13', resp.request.query))
6354
self.assertTrue(re.search('pagesize=13', resp.request.query))
6455
self.assertTrue(re.search('filter=tags%3ain%3a%5bstocks%2cmarket%5d', resp.request.query))
@@ -71,12 +62,7 @@ def test_sort_asc(self):
7162
opts.sort.add(TSC.Sort(TSC.RequestOptions.Field.Name,
7263
TSC.RequestOptions.Direction.Asc))
7364

74-
resp = self.server.workbooks._make_request(requests.get,
75-
url,
76-
content=None,
77-
request_object=opts,
78-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
79-
content_type='text/xml')
65+
resp = self.server.workbooks.get_request(url, request_object=opts)
8066

8167
self.assertTrue(re.search('pagenumber=13', resp.request.query))
8268
self.assertTrue(re.search('pagesize=13', resp.request.query))
@@ -96,12 +82,7 @@ def test_filter_combo(self):
9682
TSC.RequestOptions.Operator.Equals,
9783
'Publisher'))
9884

99-
resp = self.server.workbooks._make_request(requests.get,
100-
url,
101-
content=None,
102-
request_object=opts,
103-
auth_token='j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM',
104-
content_type='text/xml')
85+
resp = self.server.workbooks.get_request(url, request_object=opts)
10586

10687
expected = 'pagenumber=13&pagesize=13&filter=lastlogin%3agte%3a' \
10788
'2017-01-15t00%3a00%3a00%3a00z%2csiterole%3aeq%3apublisher'