Python remove try inside except? - python

In python I have a function called func() which could raise NoSuchElementException:
I'm trying to call it with input1 if not correct call it with input2 else give up.
Is there any better way to write this code for clarity:
submit_button = None
try:
submit_button = func(input1)
except NoSuchElementException:
try:
submit_button = func(input2)
except NoSuchElementException:
pass

you can do something like:
for i in [input1, input2]:
try:
submit_button = func(i)
break
except NoSuchElementException:
print(f"Input {i} failed")
else:
print("None of the options worked")
If the first input doesn't throw an exception you break the loop, otherwise you keep in the loop and try the second input.
This way you can try as many inputs as you want, just add them into the list
The else at the end executes if you never broke the loop, which means none of the options worked
This works well if you want to try several inputs and treat them equally. For only two inputs your code looks readable enough to me. (try this, if it doesn't work try that)

Just another option...
from contextlib import suppress
submit_button = None
for i in input1, input2:
with suppress(NoSuchElementException):
submit_button = func(i)
break

Related

Indentation after try and except in multiple for loops python

I'm using try and except indentation. How should I indent after I the try and except code.
Example:
try:
for elem in
browser.find_elements_by_xpath('/html/body/form[2]/table/tbody/tr[1]/td[1]/select/option'):
elem.click()
except StaleElementReferenceException:
for elem in browser.find_elements_by_xpath('/html/body/form[2]/table/tbody/tr[1]/td[1]/select/option'):
elem.click()
for ele in browser.find_elements_by_xpath('/html/body/form[2]/table/tbody/tr[1]/td[2]/table/tbody/tr[1]/td[1]/select/option'):
ele.click()
I'm using "try and except" because I keep getting an error of StaleElementReferenceException. The only thing is that I need to use try and except multiple times in loops.
It seems you did right, the next line after the except that is out of the except should be indented at the same level. So:
try:
bla()
except X as y:
foo()
bar()
Note the additional blank line before bar to keep the code more readable.
Also, in the try block you can move the call browser.find_elements_by_xpath to a variable assignment before, and that way keep your code a bit more readable.
e.g.
all_options = browser.find_elements_by_xpath(
'/html/body/form[2]/table/tbody/tr[1]/td[1]/select/option')
for option in all_options:
option.click()
In case you want to have another try except wrapping the other loop in the except, you can do that nicely in multiple ways. My recommendation is to wrap the loop in a function that will "convert" the exception to a return value:
def click_all_options(path):
try:
for option in browser.find_elements_by_xpath(path):
option.click()
return True
except StaleElementReferenceException:
return False
and in the code:
select1 = '/html/body/form[2]/table/tbody/tr[1]/td[1]/select/option'
select2 = '/html/body/form[2]/table/tbody/tr[1]/td[2]/table/tbody/tr[1]/td[1]/select/option'
result = click_all_options(select1):
if not result:
click_all_options(select2):

Try-except doesn't re-run the entire code inside a for loop

I'm really new to Python and writing code, and this code doesn't seem to rerun through all the lines after it hits the exception. I want it to start again from the try function after it hits the exception. Among these 40 web elements that the code is running through, maybe like 4-5 do not have this element (id="tt_single_values_spent) and will giveNoSuchElementException. What I want is that once my code will hit the error, it will skip it and continue to gather the information. I am 100% sure the problem is with the code and not the site itself
.
for i in range(40):
try:
act4 = browser.find_element_by_css_selector('dd[id="tt_single_values_spent"]').get_attribute('innerText')
time_log = re.sub('h', '', act4)
if time_log != str("Not Specified"):
total_time.append(float(time_log))
print(act4)
pyautogui.press("down", 1);time.sleep(0.5)
except NoSuchElementException:
print('Not found')
My result:
1h
45h
4h
13h
1h
31.8h
34.2h
5h
Not found
Not found
Not found
Not found
Not found
Not found
Not found
The reason your code repeatedly outputs "Not found" once it encounters a single "Not found" element, is that your code only advances elements within the try block.
Instead, you should always advance. You can do this with a finally block, or with code outside of the try-except block:
for i in range(40):
try:
act4 = browser.find_element_by_css_selector('dd[id="tt_single_values_spent"]').get_attribute('innerText')
time_log = re.sub('h', '', act4)
if time_log != str("Not Specified"):
total_time.append(float(time_log))
print(act4)
except NoSuchElementException:
print('Not found')
finally:
pyautogui.press("down", 1)
time.sleep(0.5)

Exception Handling

I'm trying to write a while loop to check for errors during an automated login. I want it to run through the login and if there is an error then refresh the page and start again. When I try to use the exception InvalidSelectorException: I get an undefined error. Is there another way I should write this? Or a different exception I should use?
while True:
try:
loginButton = browser.find_element_by_xpath('//*[#id="global-header"]/div[2]/ul/li[2]/a')
loginButton.click()
time.sleep(3)
iframe = browser.switch_to.frame('disneyid-iframe')
Username = browser.find_element_by_xpath('//*[#id="did-ui"]/div/div/section/section/form/section/')
Username.send_keys(usernameStr)
time.sleep(3)
password = browser.find_element_by_xpath('//*[#id="did-ui"]/div/div/section/section/form/section/div[2]/div/label/span[2]/input')
password.send_keys(passwordStr)
time.sleep(3)
nextButton = browser.find_element_by_xpath('//*[#id="did-ui"]/div/div/section/section/form/section/div[3]/button[2]')
nextButton.click()
break
except:
browser.refresh()
the exception clause with no exception fixed it.
You can also use the except statement with no exceptions defined as follows −
try:
You do your operations here;
......................
except:
If there is any exception, then execute this block.
......................
else:
If there is no exception then execute this block.

Python IF statement can't recognize else:

I am trying to verify if a row is displayed or not. I am using python and Selenium. Here is what I have tried so far
try:
row = self.driver.find_element_by_xpath(<row6>).is_displayed()
if row is False:
print("button is not displayed. Test is passed")
else:
do stuff
except:
NoSuchElementException
I am trying to achieve the following:
Page #1 will only display a button if Page #2 has row < 6.
I still have logic to write for the condition -> if row is False: . However, it should atleast print the string if it is false.
At the moment, the else: in my code is not working. There is no error displays but try: exits at the NoSuchElementException.
UPDATE: I have also tried the following code where I verify if button is displayed on page #1, go to the page #2 and validate if row6 is present. That works if button is displayed. If button is not displayed, it throws an error :NoSuchElementException: Message: Unable to locate element:
try:
button = self.driver.find_element_by_xpath(PATH)
if button.is_displayed():
do stuff
row = self.driver.find_element_by_xpath(<row6>)
if row.is_displayed():
do stuff
else:
do stuff
except:
button = self.driver.find_element_by_xpath("PATH").is_displayed()
if button is False:
print("button is hidden. Test is passed")
Any suggestion on how I can make this work??
I don't know Selenium, but it sounds like there may be multiple exceptions here, not all of the same type, and not where you might expect them to happen. For instance, everything is fine when row.is_displayed() evaluates to True, but an exception is thrown otherwise - This indicates to me that row might be None or some other unexpected result. I've taken a cursory look at the docs but I couldn't see right away.
Anyway - to debug this, try putting different sections of your code into try-except blocks:
try:
button = self.driver.find_element_by_xpath(PATH)
if button.is_displayed():
do stuff
try:
row = self.driver.find_element_by_xpath(<row6>)
except: # <-- Better if you test against a specific Exception!
print(" something is wrong with row! ")
try:
if row.is_displayed():
do stuff
else:
do stuff
except: # <-- Better if you test against a specific Exception!
print( " something is wrong with using row!" )
except: # <-- Better if you test against a specific Exception!
button = self.driver.find_element_by_xpath("PATH").is_displayed()
if button is False:
print("button is hidden. Test is passed")
Also, try to put a minimum amount of code inside each try-except, so that you know where the exception is coming from.
Maybe there's no hidden row6 to be found and an exception is raised.
The syntax of your except is wrong: as it is, it will catch all exceptions and then just do nothing with the NoSuchElementException object.
Did you mean:
except NoSuchElementException:
#do something when no row6 found

Try two expressions with `try except`

I have two expressions. I need to try one expression, if it is raise an exception try another, but if the second raises an exception too - to raise the exception.
I tried this, but it is looks ugly and I am not sure it is the best way to solve this issue:
try:
image = self.images.order_by(func.random()).limit(1)
except:
try:
image = self.images.order_by(func.rand()).limit(1)
except ProgrammingError:
raise ProgrammingError(
'The database engine must be PostgtreSQL or MySQL')
How do you do it?
Making a separate function is very helpful.
def get_random_image(self):
for rand in func.random, func.rand:
try:
return self.images.order_by(rand()).limit(1)
except ProgrammingError:
pass
raise ProgrammingError('This database engine is not supported')
Use a loop:
for methname in ("random", "rand"):
try:
image = self.images.order_by(getattr(func, methname)()).limit(1)
break
except ProgrammingError:
continue
else:
raise ProgrammingError("The database engine must be PostgtreSQL or MySQL")
The loop's else clause is executed only if the loop terminates normally (i.e., without a break) which is why we break after doing the image assignment. If you consider this too tricksy, because the else clause is so infrequently used with for, then this would also work:
image = None
for methname in ("random", "rand"):
try:
image = self.images.order_by(getattr(func, methname)()).limit(1)
except ProgrammingError:
continue
if not image:
raise ProgrammingError("The database engine must be PostgtreSQL or MySQL")
In this particular case, I'd actually try and detect the database before selecting the function. Can you reach the database connection from your code? If so, just switch on the drivername:
random = None
if drivername == 'postgres':
random = func.random
elif drivername == 'mysql':
random = func.rand
else:
raise ValueError('This module requires that you use PostgreSQL or MySQL')
Then, when selecting images, use the random value:
image = self.images.order_by(random()).limit(1)
Actually it MIGHT be a design flaw. Raising exceptions is to act on an event that should normally not occur. If you want to do something functionally into an except (except for handling the exception), than it looks like the first statement that you want to try is not a statement that should get an exception at all.
So instead of:
try:
do statement 1
except ...
try:
do statement 2
except:
think about :
if (statement_1 result == ...)
try:
do statement 2
except:
If you want to check if rand or random is a function of a class, you also could use
if 'rand' in dir(some object of a class)

Categories

Resources