server-client-python
server-client-python copied to clipboard
TSC.Pager() with default options returns invalid page number
Describe the bug When using TSC.Pager() to retrieve all subscriptions on the Tableau site, invalid page number is returned. When the error is ignored, server.subscriptions returns 400 subscription items when there are 409.
If it helps, this functionality was working as late as 08/29/2023.
Versions Tableau Server version: 2022.1 Python version: Python 3.9.12 TSC Version: 3.15 Library version: 0.28
To Reproduce
import tableauserverclient as tsc
token_name = 'some_token_name'
token_value = 'some_token_value'
tableau_auth = tsc.PersonalAccessTokenAuth(token_name=token_name, personal_access_token=token_value)
server = tsc.Server('some_server')
server.add_http_options({'verify': False})
with server.auth.sign_in(tableau_auth):
# Ensure the most recent Tableau REST API version is used.
server.use_highest_version()
# Gather all subscriptions.
subscriptions = [subscription for subscription in tsc.Pager(server.subscriptions)]
Results What are the results or error messages received?
ServerResponseError:
400006: Bad Request
Invalid page number '5'
Ran in to the same issue. In my case it was when using the server.groups.populate_users running against a large group.
It seems like sometimes there are less items returned by the pager than the expected "total_available". Could be down to changes in membership while pager is running but i've also found a group that consistently returns one less member than total_available suggests.
So in my example total_available states 3706, but actual number returned from pager is 3705, the pager logic sees no more items in page, but more still to get, so attempts to pull the next page and fails as it doesn't exist.
Ended up adding a check here: https://github.com/tableau/server-client-python/blob/3ec49bccdb5cc2fb038476ddd77bcb0e1e32df56/tableauserverclient/server/pager.py#L50
To make sure it only retrieves a new page if the (current page number*page size) is less than total_available
# Get the rest on demand as a generator
while self._count < last_pagination_item.total_available:
if len(current_item_list) == 0 and last_pagination_item.page_number*last_pagination_item.page_size < last_pagination_item.total_available:
current_item_list, last_pagination_item = self._load_next_page(last_pagination_item)
try:
yield current_item_list.pop(0)
self._count += 1
except IndexError:
# The total count on Server changed while fetching exit gracefully
return
This then fails the next pop attempt and raises the IndexError that is already exited from gracefully.
This got it working locally but it'd be good to have this possibility handled in source.
Can confirm that @JStooke's fix worked for me as well in preventing the 'Invalid page number' error. In my case, however I was able to detect that root of problem was Tableau itself, as the group for which the code failed contained one person twice. It was showing in Tabelau as 100 users, same in the library, 100 as total_available but was only able to retrieve 99 and then failed. Removing the user from group and reinstating them fixed the issue on my end.