robin900 / gspread-formatting

Complete cell formatting support for Google spreadsheets via gspread package.

Repository from Github https://github.comrobin900/gspread-formattingRepository from Github https://github.comrobin900/gspread-formatting

Adding a ConditionalFormatRule to a worksheet fails with missing sheetId

anderser opened this issue · comments

Describe the bug
Adding a ConditionalFormatRule to a worksheet fails with missing 1 required positional argument: 'sheetId'

Version and Environment
Version of package: 0.3.5
Python interpreter: Python 3.7
OS: OS X

To Reproduce
Steps to reproduce the behavior:
Open a worksheet using gspread and run:

        myrule = ConditionalFormatRule(
            ranges=[GridRange.from_a1_range('D2:D4', worksheet)],
            booleanRule=BooleanRule(
                condition=BooleanCondition('TEXT_EQ', ['Gul']),
                format=cellFormat(backgroundColorStyle=ColorStyle(rgbColor=Color(1,1,0)))
            )
        )

        rules = get_conditional_format_rules(worksheet)
        rules.clear()

        
        rules.append(myrule)
        rules.save() 

Expected behavior
The cells D2 to D4 should be colored if the value is equal to Gul. Formatting with format_cell_range etc works as excepted on the given worksheet.

Additional context
Error message:

lib/python3.7/site-packages/gspread_formatting/util.py", line 101, in _props_to_component
    return cls(**kwargs) if (kwargs or not none_if_empty) else None
TypeError: __init__() missing 1 required positional argument: 'sheetId'

Would you be able to post the full stacktrace?

File "/Users/username/workspace/myapp/apps/myapp/management/commands/export_dataframe_to_gsheet.py", line 209, in handle
    rules = get_conditional_format_rules(worksheet)
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/conditionals.py", line 17, in get_conditional_format_rules
    rules = [ ConditionalFormatRule.from_props(p) for p in sheet.get('conditionalFormats', []) ]
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/conditionals.py", line 17, in <listcomp>
    rules = [ ConditionalFormatRule.from_props(p) for p in sheet.get('conditionalFormats', []) ]
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/models.py", line 11, in from_props
    return _props_to_component(_CLASSES, _underlower(cls.__name__), props)
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/util.py", line 101, in _props_to_component
    return cls(**kwargs) if (kwargs or not none_if_empty) else None
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/conditionals.py", line 245, in __init__
    for v in ranges 
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/conditionals.py", line 245, in <listcomp>
    for v in ranges 
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/models.py", line 11, in from_props
    return _props_to_component(_CLASSES, _underlower(cls.__name__), props)
  File "/Users/username/.local/share/virtualenvs/myapp-EgRxHiym/lib/python3.7/site-packages/gspread_formatting/util.py", line 101, in _props_to_component
    return cls(**kwargs) if (kwargs or not none_if_empty) else None
TypeError: __init__() missing 1 required positional argument: 'sheetId'

BTW: print(worksheet) gives this output:
<Worksheet 'Sheet1' id:0>

And it seems to fail already at rules = get_conditional_format_rules(worksheet)

The test suite has lots of coverage for getting and modifying conditional format rules. Your exception is happening when the sheetId is 0 -- the test suite creates its own sheet for testing and that sheet's id is never 0 since it's never the default Sheet1 of a spreadsheet.

The Sheets API documentation seems to be pretty clear that sheetId property will always be present for any GridRange object in a JSON payload. And yet the exception you're seeing implies that sheetId is not present in one or more of the ranges in the API response JSON. I think it's unlikely, given the code and your stacktrace, that the sheetId property in the API response JSON is 0 and that some client-side code is discarding the property because its value is "false".

Would you be able to turn on requests/http debugging and re-run your script, capturing the API response JSON for get_conditional_format_rules? That would confirm for us what the API response is including or omitting.

@anderser Well, shucks -- I just changed the test suite locally to work on sheet1, the default worksheet, and the Sheets API responses truly do omit sheetId property from GridRange objects. I am very suspicious that this was not the API's behavior until just now!

The fix is to allow GridRange.sheetId to be absent when parsing JSON and to default to 0 in the GridRange python object. Release 0.3.6 now in PyPI contains the fix, let me know if it works for your example!

Wow! That was a swift bug response! I upgraded now, and it seems to work great. Thank you!

Hi!

I'm using the latest version and I'm getting the exact same stacktrace:

Traceback (most recent call last):
  File "C:/Users/Joni/PycharmProjects/Oppilasseuranta/Oppilaskorttien päivittäminen.py", line 88, in <module>
    rules = get_conditional_format_rules(worksheet)
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\conditionals.py", line 17, in get_conditional_format_rules
    rules = [ ConditionalFormatRule.from_props(p) for p in sheet.get('conditionalFormats', []) ]
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\conditionals.py", line 17, in <listcomp>
    rules = [ ConditionalFormatRule.from_props(p) for p in sheet.get('conditionalFormats', []) ]
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\models.py", line 11, in from_props
    return _props_to_component(_CLASSES, _underlower(cls.__name__), props)
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\util.py", line 101, in _props_to_component
    return cls(**kwargs) if (kwargs or not none_if_empty) else None
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\conditionals.py", line 242, in __init__
    for v in ranges 
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\conditionals.py", line 242, in <listcomp>
    for v in ranges 
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\models.py", line 11, in from_props
    return _props_to_component(_CLASSES, _underlower(cls.__name__), props)
  File "C:\Users\Joni\PycharmProjects\Oppilasseuranta\venv\lib\site-packages\gspread_formatting\util.py", line 101, in _props_to_component
    return cls(**kwargs) if (kwargs or not none_if_empty) else None
TypeError: __init__() missing 1 required positional argument: 'sheetId'

My code is exactly the same as anderser had: rules = get_conditional_format_rules(worksheet) with worksheet being sheet1 which has the id 0

@Jensiii666 Can you confirm that you're using either 0.3.6 or 0.3.7 of gspread-formatting? Because GridRange.__init__ does not have sheetId as a positional argument in these versions.

Hey!

Thank you for the answer and pointing me in the right direction. I just noticed that the venv indeed didn't have the updated version after all, so I had updated in the wrong place , haha oh man... All good and working now! :)

@Jensiii666 Glad it's working now, enjoy using the package!