8000 fix: handle 0 item response in querysets (#1501) · tableau/server-client-python@2ff9697 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2ff9697

Browse files
authored
fix: handle 0 item response in querysets (#1501)
* fix: handle 0 item response in querysets A flaw in the __iter__ logic introduced to handle scenarios where a pagination element is not included in the response xml resulted in an infinite loop. This PR introduces a few changes to protect against this: 1. After running QuerySet._fetch_all(), if the result_cache is empty, return instead of performing other comparisons. 2. Ensure that any non-None total_available is returned from the PaginationItem's object. 3. In _fetch_all, check if there is a PaginationItem that has been populated so as to not call the server side endpoint muliple times before returning. * fix: null out PaginationItem._page_number Tests were failing because the fetch_all method added a second check before fetching the next page. This fix will allow the next page to be retrieved when used normally --------- Co-authored-by: Jordan Woods <13803242+jorwoods@users.noreply.github.com>
1 parent 9f59af1 commit 2ff9697

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

tableauserverclient/server/query.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def __iter__(self: Self) -> Iterator[T]:
7777
for page in count(1):
7878
self.request_options.pagenumber = page
7979
self._result_cache = []
80+
self._pagination_item._page_number = None
8081
try:
8182
self._fetch_all()
8283
except ServerResponseError as e:
@@ -85,6 +86,8 @@ def __iter__(self: Self) -> Iterator[T]:
8586
# up overrunning the total number of pages. Catch the
8687
# error and break out of the loop.
8788
raise StopIteration
89+
if len(self._result_cache) == 0:
90+
return
8891
yield from self._result_cache
8992
# If the length of the QuerySet is unknown, continue fetching until
9093
# the result cache is empty.
@@ -139,6 +142,7 @@ def __getitem__(self, k):
139142
elif k in range(self.total_available):
140143
# Otherwise, check if k is even sensible to return
141144
self._result_cache = []
145+
self._pagination_item._page_number = None
142146
# Add one to k, otherwise it gets stuck at page boundaries, e.g. 100
143147
self.request_options.pagenumber = max(1, math.ceil((k + 1) / size))
144148
return self[k]
@@ -150,7 +154,7 @@ def _fetch_all(self: Self) -> None:
150154
"""
151155
Retrieve the data and store result and pagination item in cache
152156
"""
153-
if not self._result_cache:
157+
if not self._result_cache and self._pagination_item._page_number is None:
154158
response = self.model.get(self.request_options)
155159
if isinstance(response, tuple):
156160
self._result_cache, self._pagination_item = response
@@ -159,7 +163,7 @@ def _fetch_all(self: Self) -> None:
159163
self._pagination_item = PaginationItem()
160164

161165
def __len__(self: Self) -> int:
162-
return self.total_available or sys.maxsize
166+
return sys.maxsize if self.total_available is None else self.total_available
163167

164168
@property
165169
def total_available(self: Self) -> int:

test/test_pager.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import contextlib
22
import os
33
import unittest
4+
import xml.etree.ElementTree as ET
45

56
import requests_mock
67

@@ -122,3 +123,14 @@ def test_pager_view(self) -> None:
122123
m.get(self.server.views.baseurl, text=view_xml)
123124
for view in TSC.Pager(self.server.views):
124125
assert view.name is not None
126+
127+
def test_queryset_no_matches(self) -> None:
128+
elem = ET.Element("tsResponse", xmlns="http://tableau.com/api")
129+
ET.SubElement(elem, "pagination", totalAvailable="0")
130+
ET.SubElement(elem, "groups")
131+
xml = ET.tostring(elem).decode("utf-8")
132+
with requests_mock.mock() as m:
133+
m.get(self.server.groups.baseurl, text=xml)
134+
all_groups = self.server.groups.all()
135+
groups = list(all_groups)
136+
assert len(groups) == 0

0 commit comments

Comments
 (0)
0