David542
David542

Reputation: 110432

While loop decorator

I am using the ftp library which is incredibly finicky when downloading a bunch of files. This will error about once every 20 tries:

ftp.cwd(locale_dir)

So, what I do which fixes it is:

while True:
    try:
        ftp.cwd(locale_dir)
    except:
        continue
    break

How would I write a python decorator to do this, as I have to do the above on about 10 ftp commands in a script. It would be nice if I could have something like:

retry_on_failure(ftp.cwd(locale_dir))

Upvotes: 4

Views: 5262

Answers (2)

Blckknght
Blckknght

Reputation: 104792

You can't use the syntax you want, because in that code ftp.cwd(locale_dir) gets called before retry_on_failure, so any exception it raises will prevent the retry function from running. You could separate the function and its arguments, however, and call something like retry_on_failure(ftp.cwd, (locale_dir,)).

Here's an implementation that would work with that syntax. (Note, this isn't a decorator, as that's usually meant in Python.)

def retry_on_failure(func, args=(), kwargs={}):
    while True:
        try:
            return func(*args, **kwargs)
        except Exception:
            pass

This will of course run forever if the function always raises an exception, so use with care. You could add a limit to the number of repetitions or add logging if you wanted to.

Upvotes: 1

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48100

You may create decorator as:

def retry_on_failure(count=10): # <- default count as 10
    def retry_function(function):
        def wrapper(*args, **kwargs):
            while count > 0:
                try:
                   func_response = function(view, request, *args, **kwargs)
                   break  # <- breaks the while loop if success 
                except:
                   count -= 1
                   func_response = None
            return func_response
        return wrapper
    return retry_function

Now create your file download function with this decorator as:

@retry_on_failure(count=20)  # <- will make attempts upto 20 times if unable to downlaod 
def download_file(file_name):
    ftp.cwd(file_namee)

You may use this decorator with any function, where you need to make a retry attempt in case of any exception (not just your file download function). This is the beauty of decorators, these are generic adoptable by any function ;)

In order to make a call to download_file fuction, just do:

download_file(file_name)

Upvotes: 4

Related Questions