Returning to 'try' block after catching an exception
Duncan Booth
duncan.booth at invalid.invalid
Thu May 22 03:53:06 EDT 2008
bukzor <workitharder at gmail.com> wrote:
> On May 21, 4:33 pm, Karlo Lozovina <_karlo_ at _mosor.net_> wrote:
>> André <andre.robe... at gmail.com> wrote
>> innews:a9913f2d-0c1a-4492-bf58-5c7
> 8813c4458 at s50g2000hsb.googlegroups.com:
>>
>> > How about something like the following (untested)
>>
>> > done = False
>> > while not done:
>> > try:
>> > some_function()
>> > done = True
>> > except:
>> > some_function2()
>> > some_function3()
>>
>> Sure, that works, but I was aiming for something more elegant and
>> Pythonic
Catching only the specific exceptions you think you can handle would be
more Pythonic: that way things like sys.exit() will still work inside
some_function.
>
> It's hard to get around a while loop if you want to conditionally
> repeat something. There's no built-in way to do what you ask.
I prefer a 'for' loop rather than 'while' so I can limit the number of
retries.
The following may or may not be 'more pythonic', but is something I've
used. It's a factory to generate decorators which will retry the
decorated function. You have to specify the maximum number of retries,
the exceptions which indicate that it is retryable, and an optional
filter function which can try to do fixups or just specify some
additional conditions to be tested.
class TooManyRetries(Exception):
def __init__(self, inner):
self.inner = inner
def __str__(self):
return 'Too many retries: %s' % (str(self.inner),)
def retryable(max_retries, exceptions, filter=None):
"""Creates a decorator which will retry specific exceptions.
After there have been too many retries it raises TooManyRetries.
"""
def decorator(f):
def wrapper(*args, **kw):
for i in xrange(max_retries):
try:
return f(*args, **kw)
except exceptions, e:
exc_info = sys.exc_info()
# Check for retry even the last time in case the
# filter wants to do any logging.
if filter is not None and filter(e,
i==max_retries-1):
pass
else:
raise
# If we get here we have exceeded the maximum number of
# retries.
raise TooManyRetries, e, exc_info[2]
wrapper.__name__ = f.__name__
return wrapper
return decorator
def isConflictError(error, lasttime):
if (error.code==500
and error.hdrs['Bobo-Exception-Type']=='ConflictError'):
timestamp("Conflict Error", error.filename)
return True
return False
retryConflict = retryable(3, HTTPError, isConflictError)
# ----- some code showing it in use -----------
from mechanize import Browser
browser = Browser()
submit = retryConflict(browser.submit)
follow_link = retryConflict(browser.follow_link)
@retryConflict
def openpage(message, url, name=None):
global PASSWORD
if PASSWORD is None:
start = time.time()
PASSWORD = getpass.getpass()
#PASSWORD = raw_input("password?")
end = time.time()
logger.LASTTIME += end-start # Don't include input in timestamp.
resp = browser.open(url)
follow_relay()
if "ourloginpage" in browser.geturl():
# Not yet logged in
timestamp("Got login form")
browser.select_form(nr=0)
browser["user"] = USERID
browser["pass"] = PASSWORD
resp = browser.submit()
follow_relay()
if 'query' in [f.name for f in browser.forms()]:
if name=="query":
soup = BeautifulSoup(browser.response().read())
err = soup.find('td', 'tdbodywarning')
sys.exit(''.join(err.p.contents).strip())
timestamp(message, name, url)
return resp
More information about the Python-list
mailing list