quip / quip-api

Quip Automation REST API for editing documents, folders, and users
Apache License 2.0
297 stars 164 forks source link

Cannot use update_spreadsheet_row #61

Open shiihara0129 opened 5 years ago

shiihara0129 commented 5 years ago

It seems that the return value of API has been changed and update_spreadsheet_row() can not be used from 19/03/2019. This error occurs by this line. I tentatively changed to removed from the row_tree those that do not have an id

louismartin commented 5 years ago

Same problem, it seems to work better by replacing

return [x.attrib["id"] for x in row_tree]

with

return [x.attrib["id"] for x in row_tree if "id" in x.attrib]
manzensha commented 4 years ago

I did a lot of debugging on this one and I disagree that there should be an "if" statement. Here are my observations:

The normally callable function update_spreadsheet_row() runs into an error at this line:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/alexlazo/Packages/VMScripts/env/VMScripts-1.0/runtime/lib/python3.6/site-packages/quip.py", line 647, in get_row_ids
    return [x.attrib["id"] for x in row_tree]
  File "/home/alexlazo/Packages/VMScripts/env/VMScripts-1.0/runtime/lib/python3.6/site-packages/quip.py", line 647, in <listcomp>
    return [x.attrib["id"] for x in row_tree]
KeyError: 'id'

The problematic function is:

    def get_row_ids(self, row_tree):
        """Returns the ids of items in the given row `ElementTree`."""
        return [x.attrib["id"] for x in row_tree]

The problem here is that when you create a list comprehension for a single item dictionary, Python seems to error out for some reason. I'm not sure why this design choice was made, as the get_row_ids() function is only ever called in the update_spreadsheet_row() function, which will only ever return a single ID.

For verification that this is problematic, I tried running each function one by one, trying to understand the issue. See below:

client = quip.QuipClient(...)

sheet = client.get_first_spreadsheet("XXXXXXXX")

row = client.find_row_from_header(sheet, "Rank1", "Acme2")

xmlrow = ET.tostring(row)

All of the above work as expected, I can find the sheet, row, and successfully see the XML raw output. However, when trying the following, you start seeing the errors:

>>> ids = client.get_row_ids(row)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/alexlazo/Packages/VMScripts/env/VMScripts-1.0/runtime/lib/python3.6/site-packages/quip.py", line 647, in get_row_ids
    return [x.attrib["id"] for x in row_tree]
  File "/home/alexlazo/Packages/VMScripts/env/VMScripts-1.0/runtime/lib/python3.6/site-packages/quip.py", line 647, in <listcomp>
    return [x.attrib["id"] for x in row_tree]
KeyError: 'id'

Performing the call individually reveals the problem is with the list comprehension:

>>> type(row)
<class 'xml.etree.ElementTree.Element'>
>>> row.attrib["id"]
'XXXXXXXXXX'
>>> rowid = [x.attrib["id"] for x in row]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
KeyError: 'id'
>>> def call():
...  return row.attrib["id"]
... 
>>> call()
'XXXXXXXXXX'

My recommendation is one of the two following:

  1. rename the function altogether and have it simply return the single ID value, as it currently is only ever used in a single-line item
  2. create a new function that returns a single field item and keep this function as a separate one to be used in some future, yet-to-be-released feature.

Let me know if you have any questions, spent quite a bit of time on this issue but it seems to boil down to the list comprehension bugging out on an object that returns a single item.

tcafe commented 4 years ago

It fails to update one col ahead as section_id is referring based on index in a list of ids.

headers = self.get_spreadsheet_header_items(spreadsheet) It receives, headers = [None, A,B,C] (so header includes columns for row number)

ids = self.get_row_ids(row) it receives, ids=['s:xxxx','s:yyyy',s:zzzz'] (no id for row number col)

index = self.get_index_of_header(headers, "A") index is "1" for col "A"

section_id=ids[index] section_id become "s:yyyy" but actually we want to modify value for section id of 's:xxxx'

Assuming first column (where row number is shown) will have no id, section_id=ids[index-1] can be applied as workaround.

Or alternatively modify "get_spreadsheet_header_items" function to omit header if it's "None"

RuolinZheng08 commented 4 years ago
def get_row_ids(self, row_tree):
    """Returns the ids of items in the given row `ElementTree`."""
    return [x.attrib.get("id", "") for x in row_tree]

This works for me for now.