How to properly handle multiple Runtime errors? - python

Program description:
Program accepts a file name and a segment, consisting of two numbers (each divided by one space). Then it outputs all lines from existing file where their indicies lie within the given segment.
My solution:
import sys
try:
par = input("Input (<file> <low border of the segment> <high border of the segment>): ").split(' ')
print(17 * '-')
f = par[0]
f_lines = [line.strip("\n") for line in f if line != "\n"]
length = len(f_lines)
if (par == ''):
raise RuntimeError('Error: undefined')
if (par[2] == None) or (par[2] == ''):
raise RuntimeError('Error: segment is limited')
if ((par[1] and par[2]) == None) or ((par[1] and par[2]) == ''):
raise RuntimeError('Error: segment undefined')
if (int(par[2]) >= length):
raise RuntimeError('Error: segment can not be greater than length the amount of lines')
if (par[1] == ''):
a = 0
if (par[2] == ''):
b = 0
segment = [int(par[1]), (int(par[2]) + 1)]
with open(par[0]) as f:
data = f.read().splitlines()
for k in range(segment[0], segment[1]):
print(data[k])
except (FileNotFoundError, IOError, NameError):
print('[!] Error: your input is incorrect. The file may be missing or something else. \n[?] For further information see full error logs: \n',sys.exc_info())
except RuntimeError as e:
print(e)
Problem:
When I try running my program in different ways to test each of my Runtime errors I always get this message:
Traceback (most recent call last):
File "C:\Users\1\Desktop\IT\pycharm\sem_2.py", line 10, in <module>
if (par[2] == None) or (par[2] == ''):
IndexError: list index out of range
I cannot wrap my head around how can I properly handle multiple Runtime errors so they would display as a text message. I haven't found any solution to my question anywhere online, so I'm trying to ask here.
I will appreciate any help, thanks in advance.

Your code would catch FileNotFoundError, IOError, NameError and RuntimeError but what is actually thrown is IndexError and that is not handled.
You may want to add IndexError it to the first except block:
except (FileNotFoundError, IOError, NameError, IndexError):
print('[!] Error: input incorrect!') # ^^^^^^^^^^^^
or perhaps add another except block if you want a custom message for IndexError:
except (FileNotFoundError, IOError, NameError):
print('[!] Error: input incorrect!')
except IndexError:
print('[!] Error: IndexError just happened!')
By the way, the following will always be False because the code in parentheses will resolve to a bool first, which can either be True or False and these are obviously never equal to '' or None:
((par[1] and par[2]) == None) or ((par[1] and par[2]) == '')
You may way want to rewrite it to:
(par[1] is None and par[2] is None) or (par[1] == '' and par[2] == '')

Related

Handling propagating errors

In my code I have a main function, which calls a function that reads some data from a file and returns this data, which is then used in diffrent ways. Obviously there is a risk that the user inputs a filename that is not to be found, resulting in an error. I want to catch this error and output a error message written by me without the traceback etc. I tried using a standard try-except statement, which works almost as intended, except now the data is not read so there are new errors as I try to calculate using empty variabels. Using sys.exit or raise SystemExit in the exception block results in errors beeig written in the console with tracebacks and the whole point of catching the first error feels redundant. I could wrap the whole program in a try-statement, but I have never seen that being done and it feels wrong. How can I either terminate the program in a clean way or hide all the subsequent errors?
def getData(fileName):
try:
file = open(fileName,"r")
data = file.readlines()
file.close()
x = []
y = []
for i in data:
noNewline = i.rstrip('\n')
x.append(float(noNewline.split("\t")[0]))
y.append(float(noNewline.split("\t")[1]))
return x,y
except FileNotFoundError:
print("Some error messages")
def main(fileName):
x,y = getData(fileName)
# diffrent calculations with x and y
Because main is a function, you could return on an error:
def main(filename):
try:
x, y = getData(filename)
except FileNotFoundError:
print("file not found")
return
# calculations here
Solution
sys.exit and SystemExit take optional arguments—0 is considered a successful termination.
Example
sys.exit(0)
raise SystemExit(0)
References
Python sys.exit: https://docs.python.org/3/library/sys.html#sys.exit
below
def getData(fileName):
file = open(fileName,"r")
data = file.readlines()
file.close()
x = []
y = []
for i in data:
noNewline = i.rstrip('\n')
x.append(float(noNewline.split("\t")[0]))
y.append(float(noNewline.split("\t")[1]))
return x,y
def main(fileName):
# if you only want to handle exception coming from 'getData'
try:
x,y = getData(fileName)
except Exception as e:
print(f'could not get data using file {filename}. Reason: {str(e)}')
return
# do something with x,y
if __name__ == "__main__":
main('get_the_file_name_from_somewhere.txt')

Python - try/except not working when variable assigned to sys.argv

I have this section in my code:
# I/O files
inp_arq = sys.argv[1]
out_arq = sys.argv[2]
pad_ref = "pad_ref03.fasta"
tes_mdl = "model_05_weights.best.hdf5"
and at the end:
try:
results_df.to_csv(out_arq,index = False)
print(f"File saved as: {out_arq}")
except IndexError:
print("No output file created")
If no file is passed in as out_arq (sys.argv[2]) it should run the script and print "No output file created" at the end. But I'm getting the "IndexError: list index out of range."
But if I comment out the "out_arq = sys.argv[2]" line and change the code to:
try:
results_df.to_csv(sys.argv[2],index = False)
print(f"File saved as: {sys.argv[2]}")
except IndexError:
print("No output file created")
It works and I got the message, but I'm not sure why. I'd like to have all my I/O file/vars at the begginig of the script, but with this one (out_arq) I can't.
How can I solve this? And why this happens?
If you look at the stack trace that is printed by the exception, you should see that the exception is raised on this line:
out_arq = sys.argv[2]
This is outside the try block, so the exception is not caught, and causes your program to terminate.
A solution is to check, before indexing the array, whether the element exists:
out_arq = sys.argv[2] if len(sys.argv) >= 3 else None
Then use if instead of try:
if out_arq:
results_df.to_csv(out_arq,index = False)
print(f"File saved as: {out_arq}")
else:
print("No output file created")

Error in try/except construction [duplicate]

This question already has an answer here:
Python try except else invalid syntax?
(1 answer)
Closed 6 years ago.
Im just sitting for 10 minutes staring at a simple piece of code, which I have copied from a guide and I can't understand why I am getting an error.
def transformation(x):
date_format = "%d/%m/%Y"
try:
a = dt.date(int(x[6:10]), int(x[3:5]), int(x[0:2]))
else:
a = dt.datetime.strptime(x, date_format)
finally:
return a
File "<ipython-input-91-f1f6fe70d542>", line 5
else:
^
SyntaxError: invalid syntax
Maybe this is just me... Whats wrong?
After adding except:
def transformation(x):
date_format = "%d/%m/%Y"
try:
a = dt.date(int(x[6:10]), int(x[3:5]), int(x[0:2]))
except pass
else:
a = dt.datetime.strptime(x, date_format)
finally:
return a
File "<ipython-input-93-c2285c857574>", line 5
except pass
^
SyntaxError: invalid syntax
You need an except clause to use else:
The try ... except statement has an optional else clause, which, when
present, must follow all except clauses
[Emphasis mine]
I just saw it from the python document page, so I'm just gonna quote what it says to you:
The try ... except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except IOError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()

Condition not being evaluated as expected

I have a piece of code that acts as a listener of a button and evaluates whether some fields above this button are filled in:
def goListener(self):
if all( [self.nme.get() != "", self.dsc.get() != "", self.imp.get != ""] ):
name = self.nme.get()
desc = self.dsc.get()
while True:
try:
imp = int(self.imp.get())
break
except:
imp = int(self.imp.get())
When I run this program with different fields filled in or otherwise, it gets it right and produces the error message I ask it to with every combination except where nme and dsc are filled in but imp isn't, this produces the error message:
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__
return self.func(*args)
File "C:\Python33\todo.py", line 68, in goListener
imp = int(self.imp.get())
ValueError: invalid literal for int() with base 10: ''
This is running the except block by the way, which it shouldn't. Is this a problem with the evaluation, or am I missing something here?
You have:
self.imp.get != ""
You are failing to invoke the .get() method. Try:
self.imp.get() != ""
If imp = int(self.imp.get()) throws an error, calling it again outside of a try block will throw the same error.
The except block is for code that should run when there is an exception:
try:
imp = int(self.imp.get())
break
except:
print "Something bad happened"

Error when the Email formencode validator

I wanted to create an IDN-aware formencode validator to use in one of my projects. I used a portion of code from the Django project (http://code.djangoproject.com/svn/django/trunk/django/core/validators.py) to do that, but there must be a trivial error in my code I can't find :
class Email(formencode.validators.Email):
def _to_python(self, value, state):
try:
return super(Email, self)._to_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
print 'heywo !'
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self)._to_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
return value
else:
raise e
When I try to validate an email with an IDN domain (ex: test#wääl.de), the Invalid exception raised by the first call is thrown, and the portion of code after the first except is never executed ('heywo !' is never printed).
There is an example :
>>> from test.lib.validators import Email
>>> Email().to_python(u'test#zääz.de')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /api.py", line 416, in to_python
vp(value, state)
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /validators.py", line 1352, in validate_python
value, state)
Invalid: The domain portion of the email address is invalid (the portion after the #: z\xe4\xe4z.de)
What did I do wrong ?
Thanks.
Okay, found the answer. I was overloading _to_python instead of validate_python. The class now looks like :
class Email(formencode.validators.Email):
def validate_python(self, value, state):
try:
super(Email, self).validate_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self).validate_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
else:
raise e
It's working perfectly :)

Categories

Resources