8000 Add comments to clarify queryset iteration by jorwoods · Pull Request #1004 · tableau/server-client-python · GitHub
[go: up one dir, main page]

Skip to content

Add comments to clarify queryset iteration #1004

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

Merged
merged 1 commit into from
Mar 18, 2022
Merged
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
12 changes: 12 additions & 0 deletions tableauserverclient/server/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ def __init__(self, model):
self._pagination_item = None

def __iter__(self):
# Not built to be re-entrant. Starts back at page 1, and empties
# the result cache.
self.request_options.pagenumber = 1
self._result_cache = None
total = self.total_available
size = self.page_size
yield from self._result_cache

# Loop through the subsequent pages.
for page in range(1, math.ceil(total / size)):
self.request_options.pagenumber = page + 1
self._result_cache = None
Expand All @@ -31,12 +35,16 @@ def __getitem__(self, k):
page = self.page_number
size = self.page_size

# Create a range object for quick checking if k is in the cached result.
page_range = range((page - 1) * size, page * size)

if isinstance(k, slice):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is slice ever set here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k can either be an int or a slice object.

It could be a slice if it was called in the following manner:

server.workbooks.all()[10:40:3]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that example, if the client code calls

server.workbooks.all()[10:40:3]

Then __getitem__ receives k=slice(start=10, stop=40, step=3). Any of the typical slicing syntax will work. For server.workbooks.all()[:50] then k=slice(start=None, stop=50, step=None), then the None's get replaced with sensible defaults so that it acts the way that slicing would on a list.

If start is None, it becomes 0
If stop is None, it becomes the total number available
If step is None, it becomes 1

# Parse out the slice object, and assume reasonable defaults if no value provided.
step = k.step if k.step is not None else 1
start = k.start if k.start is not None else 0
stop = k.stop if k.stop is not None else self.total_available

# If negative values present in slice, convert to positive values
if start < 0:
start += self.total_available
if stop < 0:
Expand All @@ -48,6 +56,7 @@ def __getitem__(self, k):
slice_stop = stop if stop > 0 else None
k = slice(start, slice_stop, step)

# Fetch items from cache if present, otherwise, recursively fetch.
k_range = range(start, stop, step)
if all(i in page_range for i in k_range):
return self._result_cache[k]
Expand All @@ -57,12 +66,15 @@ def __getitem__(self, k):
k += self.total_available

if k in page_range:
# Fetch item from cache if present
return self._result_cache[k % size]
elif k in range(self.total_available):
# Otherwise, check if k is even sensible to return
self._result_cache = None
self.request_options.pagenumber = max(1, math.ceil(k / size))
return self[k]
else:
# If k is unreasonable, raise an IndexError.
raise IndexError

def _fetch_all(self):
Expand Down
0