Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle 0 item response in querysets #1501

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions tableauserverclient/server/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def __iter__(self: Self) -> Iterator[T]:
for page in count(1):
self.request_options.pagenumber = page
self._result_cache = []
self._pagination_item._page_number = None
try:
self._fetch_all()
except ServerResponseError as e:
Expand All @@ -85,6 +86,8 @@ def __iter__(self: Self) -> Iterator[T]:
# up overrunning the total number of pages. Catch the
# error and break out of the loop.
raise StopIteration
if len(self._result_cache) == 0:
return
yield from self._result_cache
# If the length of the QuerySet is unknown, continue fetching until
# the result cache is empty.
Expand Down Expand Up @@ -139,6 +142,7 @@ def __getitem__(self, k):
elif k in range(self.total_available):
# Otherwise, check if k is even sensible to return
self._result_cache = []
self._pagination_item._page_number = None
# Add one to k, otherwise it gets stuck at page boundaries, e.g. 100
self.request_options.pagenumber = max(1, math.ceil((k + 1) / size))
return self[k]
Expand All @@ -150,7 +154,7 @@ def _fetch_all(self: Self) -> None:
"""
Retrieve the data and store result and pagination item in cache
"""
if not self._result_cache:
if not self._result_cache and self._pagination_item._page_number is None:
response = self.model.get(self.request_options)
if isinstance(response, tuple):
self._result_cache, self._pagination_item = response
Expand All @@ -159,7 +163,7 @@ def _fetch_all(self: Self) -> None:
self._pagination_item = PaginationItem()

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

@property
def total_available(self: Self) -> int:
Expand Down
12 changes: 12 additions & 0 deletions test/test_pager.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
import os
import unittest
import xml.etree.ElementTree as ET

import requests_mock

Expand Down Expand Up @@ -122,3 +123,14 @@ def test_pager_view(self) -> None:
m.get(self.server.views.baseurl, text=view_xml)
for view in TSC.Pager(self.server.views):
assert view.name is not None

def test_queryset_no_matches(self) -> None:
elem = ET.Element("tsResponse", xmlns="http://tableau.com/api")
ET.SubElement(elem, "pagination", totalAvailable="0")
ET.SubElement(elem, "groups")
xml = ET.tostring(elem).decode("utf-8")
with requests_mock.mock() as m:
m.get(self.server.groups.baseurl, text=xml)
all_groups = self.server.groups.all()
groups = list(all_groups)
assert len(groups) == 0
Loading