I have the following code that occasionally crashes due to a permissions bug. I am trying to wrap it up in a try / except statement that will keep trying to launch the driver until successful...
def init_driver():
ffprofile = webdriver.FirefoxProfile("my_profile")
ffprofile.add_extension(extension="myaddon.xpi")
return driver
driver = init_driver()
I have seen examples letting me print a message if an error occurs but how do I get it to keep retrying? Does anybody have an example they can point me at?
Here's a loop that iterates over attempts:
while True:
try:
driver = init_driver()
break
except Foo:
continue
Note that this is not a bare except clause. Bare excepts are dangerous because they can capture things like NameError that are so rarely meant to be caught. You should put the specific exception you expect to catch here.
Here's one way to do it if you don't want to use a loop. Just recall the function on the exception
import sys
def init_driver(tries=0):
try:
ffprofile = webdriver.FirefoxProfile("my_profile");
ffprofile.add_extension(extension="myaddon.xpi")
return driver
except Exception: #This should be the exception you expect and not a catch all
if tries < sys.getrecursionlimit(): #By default 1,000 can be bumped up by setrecursionlimit
return init_driver(tries+1)
#just for kicks
#else:
#sys.setrecursionlimit(sys.getrecursionlimit() + 1)
#print("Yes we'll win this game the old-fashioned way, the tried and true way:")
#print("We'll cheat!")
#refactor / prettify if's to call init_driver if you want to cheat.
else:
print("OH NO RECURSION LIMIT HIT!!!!!! (ノಠ益ಠ)ノ彡┻━┻")
driver = init_driver()
Other answers are fine but they will keep retrying until it hits the recursion depth limit. Consider adding a retry limit:
def init_driver(retry_limit=10, nretry=0):
if nretry >= retry_limit:
return # retry limit reached, maybe raise an exception?
try:
ffprofile = webdriver.FirefoxProfile("my_profile");
ffprofile.add_extension(extension="myaddon.xpi")
except SomeException:
return init_driver(nretry=nretry+1)
return ffprofile
driver = init_driver()
Do like this:
def init_driver():
driver = None
ffprofile = webdriver.FirefoxProfile("my_profile");
ffprofile.add_extension(extension="myaddon.xpi")
# do something with a valid profile and set driver to something other than None
return driver
driver = None
while driver is None:
driver = init_driver()
Here is a recursive solution (with keeping track of the retries):
def init_driver(retries=0):
try:
ffprofile = webdriver.FirefoxProfile("my_profile");
ffprofile.add_extension(extension="myaddon.xpi")
except:
print('attempt nr. ' + str(retries))
return init_driver(retries+1)
return driver
Just a small change required. Where Foo is the specific exception you get with the permissions bug.
def init_driver():
try:
ffprofile = webdriver.FirefoxProfile("my_profile");
ffprofile.add_extension(extension="myaddon.xpi")
return driver
except Foo:
return init_driver()
driver = init_driver()
Related
I have started using Python Selenium and wrote a script shown below.
This prints a return code linked to the test that fails (test01, test02, test03, ..).
Ignore that each test is checking the same thing.
I'm just trying to understand if there's a cleaner way to write the tests because each one repetitively declares global res, and then has a try/except block.
Could anyone offer some advice on how to improve this please?
# global variable for return code. Zero is success.
res=0
#atexit.register
def send_health():
print ("res=%s") % res
class Login(unittest2.TestCase):
#classmethod
def setUpClass(inst):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
inst.driver = webdriver.Firefox(firefox_binary=binary)
inst.base_url = "https://stackoverflow.com"
def test01(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test01.png')
res=1
return
def test02(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test02.png')
res=2
return
def test03(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test03.png')
res=3
return
if __name__ == "__main__":
unittest2.main()
There is no need for global variables here at all. You are inside a class; use self.res throughout.
That's exactly what setUp instance method is for, quite similar to setUpClass method that is run once per test class.
def setUp(self):
# this code will be executed before each and every test
self.res = 0
def tearDown(self):
# this code will be executed post each and every test.
By the way, why are you using global variables? There's no need for them. In fact, there's seldom a valid rationale for using globals. Moreover, tests need to be isolated and independent, using global variables would violate that rule.
Thanks for the tips above. I've reduced the code down to this version which hopefully looks cleaner and more standard:
class Login(unittest2.TestCase):
#classmethod
def handleError(self, e, res):
print ("Test failed with exception: %s" % e)
self.result = res
sys.exit()
#classmethod
def setUpClass(self):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
self.driver = webdriver.Firefox(firefox_binary=binary)
self.base_url = "https://stackoverflow.com"
self.result = 0
def test01(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 1)
def test02(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 2)
def test03(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 3)
#classmethod
def tearDownClass(self):
self.driver.quit()
print ("res=%s") % self.result
if __name__ == "__main__":
unittest2.main()
elem = browser.find_element_by_xpath(".//label[#class = 'checkbox' and contains(.,'Últimos 15 días')]/input")
if ( elem.is_selected() ):
print "already selected"
else:
elem.click()
In my code elem.click() gets gives an error sometimes. If it does, I need to call elem = browser.find_element_by_xpath again i.e. the first line of the code.
Is there a way to achieve this using exception handling in python.
Help will be much appreciated.
From what I can understand this can be done with exception handling.
you could try the following:
elem = browser.find_element_by_xpath(".//label[#class = 'checkbox' and contains(.,'Últimos 15 días')]/input")
if ( elem.is_selected() ):
print "already selected"
else:
while True:
try:
#code to try to run that might cause an error
elem.click()
except Exception:
#code to run if it fails
browser.find_element_by_xpath
else:
#code to run if it is the try is successful
break
finally:
#code to run regardless
You need try/except statement there.
try:
elem.click()
except Exception: # you need to find out which exception type is raised
pass
# do somthing else ...
generic way to handle exception in python is
try:
1/0
except Exception, e:
print e
So in your case it would give
try:
elem = browser.find_element_by_xpath(".//label[#class = 'checkbox' and contains(.,'Últimos 15 días')]/input")
except Exception, e:
elem = browser.find_element_by_xpath
if ( elem.is_selected() ):
print "already selected"
else:
elem.click()
It is better to use the more specific exception type. If you use the generic Exception class, you might catch other exception where you want a different handling
Look at try and except
while elem == None:
try:
elem = browser.find_element_by_xpath(".//label[#class = 'checkbox' and contains(.,'Últimos 15 días')]/input")
if ( elem.is_selected() ):
print "already selected"
else:
elem.click()
except Exception, e:
elem = None
Obviously using the specific exception that is raised from the click.
I have several IO operation that I carry out on class init but they often fail with IOError. What I would like to do is delay a few hundred ms and try again until success or some defined timeout. How can I make sure each individual command succeeds before continuing/ending the loop? I assume there is a better way than an if statement for each item and a counter to check if all commands succeeded.
My current code below often fails with IOError and hangs the rest of the application.
def __init__(self):
print("Pressure init.")
self.readCoefficients()
def readCoefficients(self):
global a0_MSB;
global a0_LSB;
global b1_MSB;
global b1_LSB;
global b2_MSB;
global b2_LSB;
global c12_MSB;
global c12_LSB;
a0_MSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_A0_COEFF_MSB+0);
a0_LSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_A0_COEFF_LSB+0);
b1_MSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_B1_COEFF_MSB+0);
b1_LSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_B1_COEFF_LSB+0);
b2_MSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_B2_COEFF_MSB+0);
b2_LSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_B2_COEFF_LSB+0);
c12_MSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_C12_COEFF_MSB+0);
c12_LSB = Pressure.bus.read_byte_data(Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_C12_COEFF_LSB+0);
Are you wanting to retry each one of those last 8 lines independently or as a group? If independently you will want to make a little helper function:
def retry_function(tries, function, *args, **kwargs):
for try in range(tries):
try:
return function(*args, **kwargs)
except IOError as e:
time.sleep(.005)
raise e # will be the last error from inside the loop. be sure tries is at least 1 or this will be undefined!
Then call it like this:
a0_MSB = retry_function(5, Pressure.bus.read_byte_data, Pressure.MPL115A2_ADDRESS,Pressure.MPL115A2_REGISTER_A0_COEFF_MSB+0)
If not independently but as a group, you probably still want this helper function. But you'll have to rewrite it to handle a list of functions/arguments, or pass in another custom function
If it's OK for you that all the files are read one after the other, you can use a simple function.
import time
# ...
def readCoefficients(self):
global a0_MSB;
global a0_LSB;
global b1_MSB;
global b1_LSB;
global b2_MSB;
global b2_LSB;
global c12_MSB;
global c12_LSB;
max_retries = 15
a0_MSB = self.readretry(Pressure.MPL115A2_REGISTER_A0_COEFF_MSB+0, max_retries)
a0_LSB = self.readretry(Pressure.MPL115A2_REGISTER_A0_COEFF_LSB+0, max_retries)
b1_MSB = self.readretry(Pressure.MPL115A2_REGISTER_B1_COEFF_MSB+0, max_retries)
b1_LSB = self.readretry(Pressure.MPL115A2_REGISTER_B1_COEFF_LSB+0, max_retries)
b2_MSB = self.readretry(Pressure.MPL115A2_REGISTER_B2_COEFF_MSB+0, max_retries)
b2_LSB = self.readretry(Pressure.MPL115A2_REGISTER_B2_COEFF_LSB+0, max_retries)
c12_MSB = self.readretry(Pressure.MPL115A2_REGISTER_C12_COEFF_MSB+0, max_retries)
c12_LSB = self.readretry(Pressure.MPL115A2_REGISTER_C12_COEFF_LSB+0, max_retries)
def readretry(self, address, max_retries):
for i in range(max_retries):
try:
return Pressure.bus.read_byte_data(
Pressure.MPL115A2_ADDRESS,
address
)
except IOError as e:
# print(e)
time.sleep(0.1)
else:
raise IOError("Reading failed after multiple tries")
Note: You should not use globals, most specially in classes.
This is another way of doing it. this code tries to read all addresses, and saves the one that failed. Then waits a little and retries all the addresses that failed until all addresses have been read properly or the number of allowed retries exceeded.
def readCoefficients(self):
(
a0_MSB, a0_LSB,
b1_MSB, b1_LSB,
b2_MSB, b2_LSB,
c12_MSB, c12_LSB) = self.mio_read(15,
Pressure.MPL115A2_REGISTER_A0_COEFF_MSB+0,
Pressure.MPL115A2_REGISTER_A0_COEFF_LSB+0,
Pressure.MPL115A2_REGISTER_B1_COEFF_MSB+0,
Pressure.MPL115A2_REGISTER_B1_COEFF_LSB+0,
Pressure.MPL115A2_REGISTER_B2_COEFF_MSB+0,
Pressure.MPL115A2_REGISTER_B2_COEFF_LSB+0,
Pressure.MPL115A2_REGISTER_C12_COEFF_MSB+0,
Pressure.MPL115A2_REGISTER_C12_COEFF_LSB+0
)
def mio_read(self, max_retries, *addresses):
# Create storage for results
results = [None] * len(addresses)
# Keep track of the index of a particular address in the list of results
ios = list(enumerate(addresses))
for i in range(max_retries):
failedios = []
for index, address in ios:
try:
results[index] = Pressure.bus.read_byte_data(
Pressure.MPL115A2_ADDRESS,
address
)
except IOError as e:
# Place address in the queue for the next round
failedios.append((index, address))
# If all succeeded
if len(failedios) == 0:
return results
# Time may be reduced as so was spent checking other addresses
time.sleep(0.1)
ios = failedios
else:
raise IOError(",".join((addr for ind, addr in failedios)))
Can I return to executing the try block after exception occurs?
For example:
try:
do_smth1()
except:
pass
try:
do_smth2()
except:
pass
vs.
try:
do_smth1()
do_smth2()
except:
??? # magic word to proceed to do_smth2() if there was exception in do_smth1
No, you cannot do that. That's just the way Python has its syntax. Once you exit a try-block because of an exception, there is no way back in.
What about a for-loop though?
funcs = do_smth1, do_smth2
for func in funcs:
try:
func()
except Exception:
pass # or you could use 'continue'
Note however that it is considered a bad practice to have a bare except. You should catch for a specific exception instead. I captured for Exception because that's as good as I can do without knowing what exceptions the methods might throw.
While the other answers and the accepted one are correct and should be followed in real code, just for completeness and humor, you can try the fuckitpy ( https://github.com/ajalt/fuckitpy ) module.
Your code can be changed to the following:
#fuckitpy
def myfunc():
do_smth1()
do_smth2()
Then calling myfunc() would call do_smth2() even if there is an exception in do_smth1())
Note: Please do not try it in any real code, it is blasphemy
You can achieve what you want, but with a different syntax. You can use a "finally" block after the try/except. Doing this way, python will execute the block of code regardless the exception was thrown, or not.
Like this:
try:
do_smth1()
except:
pass
finally:
do_smth2()
But, if you want to execute do_smth2() only if the exception was not thrown, use a "else" block:
try:
do_smth1()
except:
pass
else:
do_smth2()
You can mix them too, in a try/except/else/finally clause.
Have fun!
'continue' is allowed within an 'except' or 'finally' only if the try block is in a loop. 'continue' will cause the next iteration of the loop to start.
So you can try put your two or more functions in a list and use loop to call your function.
Like this:
funcs = [f,g]
for func in funcs:
try: func()
except: continue
For full information you can go to this link
You could iterate through your methods...
for m in [do_smth1, do_smth2]:
try:
m()
except:
pass
one way you could handle this is with a generator. Instead of calling the function, yield it; then whatever is consuming the generator can send the result of calling it back into the generator, or a sentinel if the generator failed: The trampoline that accomplishes the above might look like so:
def consume_exceptions(gen):
action = next(gen)
while True:
try:
result = action()
except Exception:
# if the action fails, send a sentinel
result = None
try:
action = gen.send(result)
except StopIteration:
# if the generator is all used up, result is the return value.
return result
a generator that would be compatible with this would look like this:
def do_smth1():
1 / 0
def do_smth2():
print "YAY"
def do_many_things():
a = yield do_smth1
b = yield do_smth2
yield "Done"
>>> consume_exceptions(do_many_things())
YAY
Note that do_many_things() does not call do_smth*, it just yields them, and consume_exceptions calls them on its behalf
I don't think you want to do this. The correct way to use a try statement in general is as precisely as possible. I think it would be better to do:
try:
do_smth1()
except Stmnh1Exception:
# handle Stmnh1Exception
try:
do_smth2()
except Stmnh2Exception:
# handle Stmnh2Exception
Depending on where and how often you need to do this, you could also write a function that does it for you:
def live_dangerously(fn, *args, **kw):
try:
return fn(*args, **kw)
except Exception:
pass
live_dangerously(do_smth1)
live_dangerously(do_smth2)
But as other answers have noted, having a null except is generally a sign something else is wrong with your code.
This can be done with exec() in a custom function, a list of strings, and a for loop.
The function with exec():
def try_it(string):
try:
exec(string)
print(f'Done: {string}')
except:
print(f'Error. Could not do: {string}')
More on exec():
exec(object)
This function supports dynamic execution of Python code. object must be either a string or a code object.
Example list of strings and for loop:
do_smth_list = ['do_smth1()', 'do_smth2()', 'do_smth3()']
for smth in do_smth_list:
try_it(smth)
This definitely isn't the cleanest way of doing it, but you can put it in a while loop with a variable set to true, and when it runs the function successfully it sets the variable to false, whereas if it fails it keeps the variable set to true.
x = True
while x == True:
try:
do_smth1()
do_smth2()
x = False
except Exception:
x = True
This way what happens is that the while loop will keep on looping the try except section again and again until it works, in which x is set to false and the loop stops
Also, you can implement a break in the while loop instead of basing it on a variable, for example:
while True:
try:
do_smth1()
do_smth2()
break
except Excpetion:
pass
P.S It is good ettiquete to put a specific exception for the except section, instead of leaving it for any exception. It makes the code cleaner and is more sensible when managing errors especially in bigger projects
special_func to avoid try-except repetition:
def special_func(test_case_dict):
final_dict = {}
exception_dict = {}
def try_except_avoider(test_case_dict):
try:
for k,v in test_case_dict.items():
final_dict[k]=eval(v) #If no exception evaluate the function and add it to final_dict
except Exception as e:
exception_dict[k]=e #extract exception
test_case_dict.pop(k)
try_except_avoider(test_case_dict) #recursive function to handle remaining functions
finally: #cleanup
final_dict.update(exception_dict)
return final_dict #combine exception dict and final dict
return try_except_avoider(test_case_dict)
Run code:
def add(a,b):
return (a+b)
def sub(a,b):
return (a-b)
def mul(a,b):
return (a*b)
case = {"AddFunc":"add(8,8)","SubFunc":"sub(p,5)","MulFunc":"mul(9,6)"}
solution = special_func(case)
Output looks like:
{'AddFunc': 16, 'MulFunc': 54, 'SubFunc': NameError("name 'p' is not defined")}
To convert to variables:
locals().update(solution)
Variables would look like:
AddFunc = 16, MulFunc = 54, SubFunc = NameError("name 'p' is not defined")
If do_smth1() worked, then do_smth2() will not be tried.
try:
x=do_smth1()
except:
try:
x=do_smth2()
except:
x="Both Failed"
print (x)
My code about this:
try:
self.cookie = Cookie.SimpleCookie(os.environ["HTTP_COOKIE"])
tmpuid = self.cookie["uid"].value
tmpsid = self.cookie["sid"].value
except Exception as e:
if not str(e).startswith('No cookie set'):
import traceback
traceback.print_exc()
return False
Is "return False" needed after "traceback.print_exc()"?
Sure, The exception only stops on No cookie set exceptions. If it is any other exception the program will return False instead of continued to the next statement