square/connect-python-sdk

list_inventory method response does not include link to support pagination

Closed this issue ยท 8 comments

The list_inventory method works on a v1 endpoint that paginates when there are > 1,000 inventoried item variants. The raw endpoint's response includes a header with a link to supply in the subsequent request and retrieve the next batch of results. But the return value of this sdk method only includes an array of V1InventoryEntry objects, and no link, cursor or other value to supply (presumably as the value for the batch_token parameter) in subsequent requests. Please advise if I'm missing something (which is quite possible) or whether pagination isn't actually supported by the list_inventory method (yet).

You should be able to retrieve the batch token from the response header using the this method:

batch_token = api_instance.api_client.last_response.getbatch_token()

Thanks; sorry about that - I totally overlooked the v1 Pagination example in the documentation. I got around to testing with it today, and it worked for me in Python 2 but not 3. In Python 3.5.2, I get the following traceback:

Traceback (most recent call last):
  File "C:\Projects\dev\repos\retailSquareAutomation\paginate.py", line 130, in <module>
    token = invnApi.api_client.last_response.getbatch_token()
  File "C:\Users\cschweiger\AppData\Local\Continuum\Anaconda3\envs\retailSquareAutomation\lib\site-packages\squareconnect\rest.py", line 97, in getbatch_token
    parsed_url = urlparse.urlparse(next_url)
AttributeError: 'function' object has no attribute 'urlparse'

I took a look at the relevant imports in rest.py, and changing them like so:

try:
    # for python3
    from urllib.parse import urlencode
    from urllib.parse import urlparse
    from urllib.parse import parse_qs
except ImportError:
    # for python2
    from urllib import urlencode
    from urlparse import urlparse
    from urlparse import parse_qs

and then modifying the getbatch_token method like so:

def getbatch_token(self):
    link_header = self.getheader('Link')
    if link_header != None:
        match = re.match("^<([^>]+)>;rel='next'$", link_header)
        if match != None:
            next_url = match.group(1)
            parsed_url = urlparse(next_url)
            parameters = parse_qs(parsed_url.query)
            if parameters.has_key('batch_token'):
                return parameters['batch_token'][0]
    return None

should do the trick and work in both Python 2 and 3.

MHova commented
  1. Great writeup @cschweiger. One nit: I think has_key() was removed in Python3 in favor of in so some adjustments will have to be made to if parameters.has_key('batch_token'):.
  2. Any movement on this issue, admins? This seems like a pretty big and easily-solvable problem. I'm surprised nobody else has chimed in on this.
keeth commented

I'm seeing the same thing. Seems like V1 pagination is broken in Python 3.

1. Great writeup @cschweiger. One nit: I think `has_key()` was removed in Python3 in favor of `in` so some adjustments will have to be made to `if parameters.has_key('batch_token'):`.

2. Any movement on this issue, admins? This seems like a pretty big and easily-solvable problem. I'm surprised nobody else has chimed in on this.

Regarding @MHova's point 1, I ran into this issue as well and implemented the simple fix you suggested for Python 3 compatibility (i.e., in vs. has_key):

def getbatch_token(self):
        link_header = self.getheader('Link')
        if link_header != None:
            match = re.match("^<([^>]+)>;rel='next'$", link_header)
            if match != None:
                next_url = match.group(1)
                parsed_url = urlparse(next_url)
                parameters = parse_qs(parsed_url.query)
                if 'batch_token' in parameters:
                    return parameters['batch_token'][0]
return None

The issue still is present for me. The error I'm getting is:

if parameters.has_key('batch_token'):

AttributeError: 'dict' object has no attribute 'has_key'

I tried changing rest.py as shown above but I do not have permissions. Any ideas?

@samwelch1 I'm hoping the PR I made a while back is merged at some point (discussed in #86), but in the meantime I've been keeping a fork with that one change in place up-to-date for my own uses (just brought it up to 2.20190612.1). You can find it here:

https://github.com/davedgd/connect-python-sdk

To install it via pip, first uninstall any existing ones and then use:

pip install git+https://github.com/davedgd/connect-python-sdk/

Alternatively, clone the repo, edit that one line in rest.py, and then do the same with your own repo.

In any case, this while solve the issue for now, even if it's less than ideal.

Best,

David

PS. The only other option is to use Python 2 in place of 3 unfortunately, since the issue revolves around has_key() not being in 3.

We apologize for the delay, but the fix has just been merged for version 2.20190710.1. Thank you for using Square :)