retry a function with backoff with different argument and timeout - python

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))

Related

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)

How to use 'assert' command to limit an input to only take number of columns in a set of data?

I have written a function that can retrieve specific columns of data when given an input of the data and a variable called col_num but I need to write an assert command that does not let the input col_num exceed the number of columns in the data (For this I am assuming that I do not know the number of columns or there are too many to count).
My function is as follows:
import numpy as np
data = np.loadtxt('data.csv', delimiter = ',', skiprows = 1)
def get_column(data, col_num):
assert(len(data.shape) == 2
assert type(col_num) is int
#assert goes here
return data[:, col_num]
Any help would be greatly appreciated, thanks!
EDIT: I have added an image of the code which the function must satisfy.
https://i.stack.imgur.com/TlpMw.png
The code satisfies the middle cell but causes an error with the bottom one.
Firstly, don't use assert for runtime checking. It can be optimised away: raise an exception instead.
Secondly, as the comments point out, you do have the data:
if data.shape[1] < col_num:
raise ValueError(f"Supplied col num of {col_num} is greater than {data.shape[1]} columns")
Edit:
Your assertion is failing because you are not actually testing for a negative column number: you need to add a line doing so. But I repeat what I said above: assert belongs I'm the test suite itself, or in development, but not in production code. You have no guarantee it won't be optimised away.
Not sure exactly what you're trying to achieve here, replacing IndexErrors with AssertionErrors. The assert will crash the program if the condition evaluates to False, but so would an uncaught IndexError. You're throwing away useful exception information, both the type and messages, only to raise a more general exception.
If you don't intend to do or log anything if an error occurs, just let the exception happen.
If you need to log it or do something, catch the IndexError. If you can't fully handle it in the function, catch it, do what you can, then re-raise the exception:
import numpy as np
data = np.loadtxt('data.csv', delimiter = ',', skiprows = 1)
def get_column(data, col_num):
try:
return data[:, col_num]
except IndexError as e:
logging.exception(e)
raise e

Python exception handling, corner case scenario failing

I am learning python exception handling. I came across a challenge where I had to define a function to raise exceptions when certain conditions didn't meet. I was able to raise exceptions just fine for all the hidden test cases but one. Here's my code below:
def Handle_Exc1():
try:
a=int(input())
b=int(input())
if not (a<150 and b>100):
raise ValueError('Input integers value out of range.')
except ValueError as e:
print(e)
else:
try:
c=a+b
if c>400:
raise ValueError('Their sum is out of range')
except ValueError as f:
print(f)
else:
print("All in range")
The above code worked for all the hidden test cases but one. I cannot find out what kind of scenario or whats the input is given either. However, the code should have been able to handle all the scenarios. But it isn't. Need your help to figure out how I could have made this code foolproof.
Any help is much appreciated.
Thanks in advance.
Mahi
can you tell that one hidden test scenario which is failing & what input is given you can pass the variable in error, you don't have to create try and except block every time you just allow in outer scope
try:
a=int(input('a:'))
b=int(input('b:'))
if a>=150 :
raise ValueError('Input integer a value out of range. it should be less than 150,you provide :',a)
elif b<= 100:
raise ValueError('Input integer b value out of range. it should be greater than 100,you provide :',b)
c = a+b
if c>400:
raise ValueError('Their sum is greater than 400. sum is :',c)
except ValueError as f:
print(f)
I figured out the answer. I missed to include values 150 and 100 in the if statement. Working code below:
def Handle_Exc1():
try:
a=int(input())
b=int(input())
if not (a<=150 and b>=100):
raise ValueError('Input integers value out of range.')
c=a+b
if c>400:
raise ValueError('Their sum is out of range')
except ValueError as f:
print(f)
else:
print("All in range")
This passed all the test cases.

Use the same else block for nested try blocks in 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()

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