Use the same else block for nested try blocks in python - python

I'm fitting a function to some data and some initial parameter values cause an overflow error. I want to catch it in my code, give it new initial parameters, and try again. My solution is to nest try except blocks.
try:
foo(args1)
except:
args2 = make_new_args()
try:
foo(args2)
except:
give_up_and_move_on()
else:
process_data()
else:
process_data()
I was wondering if there's a way to eliminate one of the else clauses, since they're the same code.

This looks a lot like some retry logic with modifications to the arguments; you could try this:
MAX_RETRIES = 2
for retries in range(MAX_RETRIES):
try:
foo(args)
except:
args = make_new_args()
else:
process_data()
break
if retries + 1 >= MAX_RETRIES:
give_up_and_move_on()

Related

retry a function with backoff with different argument and timeout

I am trying to implement a retry ability whenever a function fails with an index error. I started with this:
I know the reason for failure is passing high value to curr_val, but setting high values will generate better output
#these lines are inside another for loop
curr_val=40
while True:
try:
ret1, ret2 = extract(arg1,arg2,val=curr_val)
except IndexError:
curr_val -=5
continue
break
##process ret1
According to this answer, it is possible to use the decorator (like tenacity) to handle such cases, supporting any kind of exception.
my current try with tenacity is as follows:
curr_val = 5
#tenacity.retry(wait=tenacity.wait_fixed(1))
def try_to_extract():
try:
return extract(arg1,arg2,val=curr_val)
except Exception:
curr_val -=1
raise
However, it does not have access to the outside variables and keeps raising exception, without changing curr_val
Can anyone let me know how to handle this? meaning using curr_val inside retry and handle this case. (retrying with another argument(decremented curr_val), in case of failure or timeout)
the iterator can help this.
#tenacity.retry
def try_to_extract(value_iter):
curr_val = next(value_iter)
print(curr_val)
try:
return extract(arg1,arg2,val=curr_val)
except Exception:
raise
curr_val = 40
try_to_extract(itertools.count(curr_val, -1))

Python Exceptions difficulty

I am trying to complete a lab soon but I am having difficulty, the prompt is:
A pedometer treats walking 2,000 steps as walking 1 mile. Write a steps_to_miles() function that takes the number of steps as a parameter and returns the miles walked. The steps_to_miles() function throws a ValueError object with the message "Exception: Negative step count entered." when the number of steps is negative. Complete the main() program that reads the number of steps from a user, calls the steps_to_miles() function, and outputs the returned value from the steps_to_miles() function. Use a try-except block to catch any ValueError object thrown by the steps_to_miles() function and output the exception message.
Output each floating-point value with two digits after the decimal point, which can be achieved as follows:
print('{:.2f}'.format(your_value))
I have been working on it for awhile now, my code is:
def steps_to_miles():
steps = int(input())
if steps < 0:
raise ValueError
return steps
if __name__ == '__main__':
try:
steps = steps_to_miles()
miles_walked = float(steps / 2000)
print('{:.2f}'.format(miles_walked))
except ValueError:
print('Exception: Negative step count entered.')
(Sorry for formatting errors...) The code runs but is only giving me 4 out of the 10 points due to Zybooks stating "test_passed function missing" and "Test stepsToMiles(-3850), should throw an exception". What am I missing or how can fix it? Or alternatively is there another way to write the code?
def steps_to_miles(steps):
if steps < 0:
raise ValueError
return float(steps / 2000)
if __name__ == '__main__':
steps = int(input())
try:
miles_walked = steps_to_miles(steps)
except ValueError:
print('Exception: Negative step count entered.')
print('{:.2f}'.format(miles_walked))
in body of try, need use only 'danger' code
your function was unworked becourse: you dont send any parameter, and it dont return value
input moved into main . It was next error: steps was local variable, which dont used in global namespace, and in function main
We can't do a lot to help you with an automatic homework grader, you should probably ask your teacher or TA. Here are a few pointers:
Your steps_to_miles does not take any arguments, according to the assignment it should take a single integer argument.
The ValueError you throw does not have a message attached to it.
steps_to_miles should divide its argument by 2000 but it doesn't do so. Instead you divide by 2000 outside of the function.
You print a specific string in your except block instead of printing the exception's actual message.
You may need to make your error message a variable, in regards to your zyBooks giving you this error: "Test stepsToMiles(-3850).
I would try this in your function: raise ValueError('Exception: Negative step count entered.')
I would also write in this in your final "except" statement.
except ValueError as err:
print(err)
this should work:
def steps_to_miles(num_steps):
if num_steps < 0:
raise ValueError("Exception: Negative step count entered.")
return num_steps / 2000
if __name__ == '__main__':
num_steps = int(input())
try:
num_miles = steps_to_miles(num_steps)
print('{:.2f}'.format(num_miles))
except ValueError as e:
print(e)

Python: Selenium: How to write a try - except code to attempt iteration again

I have a web-scraper which I am fairly happy with, except sometimes it misses iterations because it doesn't load the webpage fully (this is the nature of the website I am scraping. In these instances, I wish for my code to try the iteration again. At the moment, the framework of my code looks something like this:
data = []
for i in range(len(links)):
try:
driver.get(link[i])
a = driver.find_elements_by_xpath(#data in here)[0].text
data.append(a)
#this is then written to a csv
except:
print(i)
So at the moment, my code runs and then just lists for me which number instances failed. I then go back and manually input the data.
It would be much nicer for me if instead of doing this, my program attempted the failed instance again, that way I won't have missed data.
Any way I can achieve this?
Thanks
If you want to retry the same link[i] several times, you probably need an additional loop. Exactly what kind of loop depends on some details. If you want to keep trying until you succeed (assuming you can be sure that will eventually happen), then a while True loop would make the most sense. On the other hand, if you want to limit the number of tries, a for loop on a range would be better.
Here's a sketch of an implementation that tries up to three times:
max_tries = 3
data = []
for i, link in enumerate(links): # this is a slightly nicer way to do your main loop
for t in range(max_tries):
try:
driver.get(link)
a = driver.find_elements_by_xpath("#data in here")[0].text
data.append(a)
break # break out of the inner loop if we succeeded
except:
print("failed to load link", i, "retrying..." if t < max_tries-1 else "giving up.")
You could implement an iteration counter and also find out the difference between both lists, after the first try, for your piece of mind :)
data = []
intData = []
counter = 0
maxIterations = 2
def Diff(li1, li2):
return (list(set(li1) - set(li2)))
while counter < maxIterations:
for i in range(len(links)):
try:
if counter < 1:
driver.get(link[i])
a = driver.find_elements_by_xpath(#xpathstring)[0].text
data.append(a)
else:
driver.get(link[i])
a = driver.find_elements_by_xpath(#xpathstring)[0].text
intData.append(a)
counter += 1
except:
print(i)
counter += 1
# Find differences between first iterations and all consecutive ones
print(Diff(intData, data))

List Comprehension python?

I have a function like this:
for product in responseSoup.findAll("offersummary"):
try:
if product.lowestnewprice.formattedprice != None:
price.append(product.lowestnewprice.formattedprice.text)
else:
price.append("")
except:
price.append("")
I am confused how to do the if/else statement with the try/except block? Will list comprehension speed up efficiency?
[product.lowestnewprice.formattedprice for product in responseSoup.findAll("offersummary")]
Here is a very readable solution:
prices = []
for product in responseSoup.findAll("offersummary"):
price = product.get(lowestnewprice, {}).get(formattedprice, {}).get(text)
if price is not None:
prices.append(price)
else:
prices.append('')
If you really don't care about readability, here's a very atrocious looking one-liner:
price = [''
if product.get(lowestnewprice, {}).get(formattedprice, {}).get(
text) is None else
product.lowestnewprice.formattedprice.text
for product in responseSoup.findAll("offersummary")]
They do essentially the same thing, but, in my opinion, the more readable solution is better.
EDIT
I just figured out a much better one-liner:
price = [product.get(lowestnewprice,{}).get(formattedprice,{}).get(text) or ''
for product in responseSoup.findAll("offersummary")]
It's still less readable than the "very readable" solution, but it is not too bad. Now the decision really comes down to a matter of your preference.
try and except blocks are used to see if the following code works. If not and it matches the given error, run that block of code. Else, run the other line of code. For example:
try:
m = raw_input("Please enter an integer")
n = int(m)
except ValueError:
print "Invalid number"
else:
print n
So, the program attempts to assign m the input from the user. Then n is assigned the input as an integer. Now the error chosen is ValueError since if m is a string, the conversion to n will raise that error. If it does, then it does the code in the except block, which is to print "Invalid number". If the conversion is successful, then print n.
Now with your program, you will try the if and else block. If the code doesn't work and it raises the error given in the except block, it will do price.append(""). Else, it will run the code in the else block, which you don't have. You need the else: to work in your try/except block for it to work including a specified error after the keyword except in your except statement.

How to continue loop after catching exception

The below code produces exception while handling non int values but it doesn't continue the loop but rather comes out from the loop raising error. My intention is to provide the value of 0 for exception cases.
Sample Input:
Common Ruby Errors 45min
Rails for Python Developers lightning
Code:
class TimeNotProvidedError(Exception):
pass
def extract_input():
lines = []
__tracks = {}
try:
lines = [line.strip() for line in open('test.txt')]
except FileNotFoundError as e:
print("File Not Found", e)
for line in lines:
title, minutes = line.rsplit(maxsplit=1)
minutes = int(minutes[:-3])
try:
__tracks[title] = minutes
except TimeNotProvidedError:
__tracks[title] = 0
return __tracks
print(extract_input())
Traceback:
ValueError: invalid literal for int() with base 10: 'lightn'
You're getting the error when converting to int with this line: minutes = int(minutes[:-3]). That line isn't in the try block, so the exception isn't caught. Move that line inside the try block, and you'll get the behavior you wanted.
Furthermore, the exception you're catching is TimeNotProvidedError, which isn't what int throws when a conversion fails. Instead, it throws ValueError, so that's the exception type you need to catch.
The mere act of assigning to __tracks[title] is unlikely to cause an exception, and if it does, re-trying with another assignment probably won't work anyway. What you probably want in your loop is this:
title, minutes = line.rsplit(maxsplit=1)
try:
minutes = int(minutes[:-3])
except ValueError:
minutes = 0
__tracks[title] = minutes

Categories

Resources