server-client-python icon indicating copy to clipboard operation
server-client-python copied to clipboard

TSC.Pager() with default options returns invalid page number

Open CodingOnWindowsOS opened this issue 1 year ago • 2 comments

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'

CodingOnWindowsOS avatar Oct 21 '23 21:10 CodingOnWindowsOS

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.

JStooke avatar Dec 13 '23 13:12 JStooke

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.

TrimPeachu avatar Jan 25 '24 06:01 TrimPeachu