Search code examples
pythonpython-3.xgoogle-apigspreadpython-tenacity

Python3 retrying with tenacity (w/out decorators) gives error claiming "missing arguments" when using gspread


I'm trying to use the tenacity module to avoid frequent requesting errors (APIErrors) from gspread. I understand the common examples of tenacity use decorators, but I want to use tenacity's Retrying() function so I can have it retry gspread's spreadsheet cell updating method sheet.update_acell() instead.

For some reason, using a retry with the sheet.update_acell() doesn't actually 'give' the arguments to the function (or something). A contrived multiple argument example works perfectly however.

My code (except for imports and google API credential stuff):

# gspread authorization
gs_client = gspread.authorize(creds)
workbook = gs_client.open_by_key(sheet_key)
sheet = workbook.sheet1

ret = tenacity.Retrying(stop=tenacity.stop_after_attempt(30),
                        wait=tenacity.wait_exponential(multiplier=0.5, max=60))

# contrived example
def retry_example(arg0, arg1):
    print(arg0, arg1)
ret.call(retry_example,'foo','bar')  #works perfectly

# gspread example
ret.call(sheet.update_acell(),'A1',1)  #doesn't work, the arguments aren't found

Output:

foo bar
Traceback (most recent call last):
  File "c:/Users/.../tenacitytest.py", line 28, in <module>
    ret.call(sheet.update_acell(),'A1',1)
TypeError: update_acell() missing 2 required positional arguments: 'label' and 'value'

Running the gspread stuff without tenacity works as it should, so I'm sure that I'm calling update_acell() correctly.

I feel like this may have to do with the fact that gspread's update_acell() is a method, unlike example_func()? Any help would be appreciated.


Solution

  • You should not use the parenthesis in the Retrying call. You should pass parameters like below

    Hope this will work ;)

    ret.call(sheet.update_acell,'A1',1)
    

    Example:

    from tenacity import Retrying, stop_after_attempt
    
    def foo(arg1, arg2):
        print('Arguments are: {} {}'.format(arg1, arg2))
        raise Exception('Throwing Exception')
    
    def bar(max_attempts=3):
        retryer = Retrying(stop=stop_after_attempt(max_attempts), reraise=True)
        retryer(foo, 'my arg1', 'my arg2')
    

    Let's try the Error Scenario:

    >>> from tenacity import Retrying, stop_after_attempt
    >>>
    >>> def foo(arg1, arg2):
    ...     print('Arguments are: {} {}'.format(arg1, arg2))
    ...     raise Exception('Throwing Exception')
    ...
    >>> def bar(max_attempts=3):
    ...     retryer = Retrying(stop=stop_after_attempt(max_attempts), reraise=True)
    ...     retryer(foo(), 'my arg1', 'my arg2')
    ...
    >>> bar()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in bar
    TypeError: foo() missing 2 required positional arguments: 'arg1' and 'arg2'
    >>>