Handling propagating errors - python

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

Related

how to continue processing after exception in python without aborting

I have a block of code where exception is happening for some records while executing an imported method (pls see below). My goal is NOT to stop execution, but perhaps print (to understand what's wrong with the data) some values when in error and continue. I tried various way to use "try...except", but no luck! Can someone pls take a look and suggest? Many thanks in advance!
code below
if student_name not in original_df_names_flat:
for org in orgs:
data = calculate(org, data)
result = imported_module.execute(data) # here's the line where exception happens
return result
else:
return data
if student_name not in original_df_names_flat:
for org in orgs:
data = calculate(org, data)
result = None # May fail to get assigned if error in imported_module
try:
result = imported_module.execute(data) # here's the line where exception happens
except Exception as e:
print(f'{e}') # probably better to log the exception
return result
else:
return data
I guess an exception can occur in 2 places. So try this. It covers your exception line and the other possibility. So your program should keep running.
Secondly I have adjusted the indentation of the second try clause so the loop processes all data in orgs. To return all results I have added a list 'results'.
if student_name not in original_df_names_flat:
results = []
for org in orgs:
try:
data = calculate(org, data)
except Exception as e:
print(str(e))
try:
result = imported_module.execute(data) # here's the line where exception happens
results.append(result)
except Exception as e:
print(str(e))
return results
else:
return data
the below solution took care of the problem:
if student_name not in original_df_names_flat:
for org in orgs:
data = calculate(org, data)
try:
result = imported_module.execute(data) # here's the line where exception happens
except exception as e:
print ("exception happened", e)
pass
return data
return result
else:
return data
the above solution took care of the problem

How to properly handle multiple Runtime errors?

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] == '')

I am getting unbound local error while pickle loading a file

I am. Pickle loading two files one by one and I am getting an unbound local error while closing them.
I used exception handling while opening the file and in the except block it shows unbound local error while closing the files.
though i used filenotfound In the exception block as it is a necessary exception to handle.no indentation errors are there i just am not able to handle the error stating.
"Traceback (most recent call last):
File "d:\Python\t.py", line 648, in dispdeisel
fdl=open("D:/Python/deisel/"+str(z1)+".txt","rb+")
FileNotFoundError: [Errno 2] No such file or directory: 'D:/Python/deisel/Wed Apr 29 2020.txt'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "d:\Python\t.py", line 820, in <module>
b.dispdeisel()
File "d:\Python\t.py", line 664, in dispdeisel
fdl.close()
UnboundLocalError: local variable 'fdl' referenced before assignment"
k1=[]
try:
tdc=open("D:/Python/deisel/collection.txt","rb+")
fdl=open("D:/Python/deisel/"+str(z1)+".txt","rb+")
while True:
self.f1=pickle.load(tdc)
self.fd=pickle.load(fdl)
k1.append(self.f1)
kd.append(self.fd)
except EOFError and FileNotFoundError:
qa=0
for i in kd:
if "L"in i:
qa1=i[:-1]
qa=qa+int(qa)
else:
qa=qa+int(i[0])
print (" Total Collection for Deisel on date ",z1,"is",qa)
tdc.close()
fdl.close()
In your example code, when this line is reached (and causes an error):
tdc=open("D:/Python/deisel/collection.txt","rb+")
.. then the next line will never be executed and fdl won't have a value.
After the error, execution continues after except EOFError and FileNotFoundError: and this line is reached:
fdl.close()
Since fdl was never defined (as that line was skipped), it has no value and that's the cause of your error.
One way of fixing it would be to deal with the exceptions more cleanly:
class SomeClass:
def some_method(self, z1):
# initialisation
qa = 0
kd = []
k1 = []
try:
tdc = open("D:/Python/deisel/collection.txt","rb+")
try:
fdl = open("D:/Python/deisel/"+str(z1)+".txt","rb+")
try:
try:
while True:
self.f1 = pickle.load(tdc)
self.fd = pickle.load(fdl)
k1.append(self.f1)
kd.append(self.fd)
except EOFError:
pass # no message needed, but not the nicest way to use the exception
for i in kd:
if "L" in i:
# this bit makes no sense to me, but it's not relevant
qa1 = i[:-1]
qa = qa + int(qa)
else:
qa = qa + int(i[0])
print(" Total Collection for Deisel on date ", z1, "is", qa)
finally:
tdc.close()
fdl.close()
except FileNotFoundError:
tdc.close() # this is open, closing it
pass # some error message perhaps?
except FileNotFoundError:
pass # some error message perhaps?
This is better, but not very Pythonic and only illustrates how you could solve your problem - it's not at all how I recommend you write this.
Closer to what you probably need:
import pickle
class SomeClass:
def some_method(self, z1):
# initialisation
qa = 0
kd = []
k1 = []
try:
with open("D:/Python/deisel/collection.txt","rb+") as tdc:
try:
with open("D:/Python/deisel/"+str(z1)+".txt","rb+") as fdl:
try:
while True:
self.f1 = pickle.load(tdc)
self.fd = pickle.load(fdl)
k1.append(self.f1)
kd.append(self.fd)
except EOFError:
pass # no message needed, but not the nicest way to use the exception
for i in kd:
if "L" in i:
# this bit makes no sense to me, but it's not relevant
qa1 = i[:-1]
qa = qa + int(qa)
else:
qa = qa + int(i[0])
print(" Total Collection for Deisel on date ", z1, "is", qa)
except FileNotFoundError:
pass # some error message perhaps?
except FileNotFoundError:
pass # some error message perhaps?
with does exactly what you're trying to do and cleans up the file handle, guaranteed.
And this still has the issue of getting multiple pickles from files, with no guarantee the number of pickles will be the same for both - if you write these pickles yourself, why not pickle a list of objects and avoid that mess?
In general, don't use exceptions if you expect them to occur, instead code directly what you expect - it's easier to read and maintain and it generally performs better:
import pickle
from pathlib import Path
class SomeClass:
def some_method(self, z1):
# initialisation
qa = 0
kd = []
k1 = []
fn1 = "D:/Python/deisel/collection.txt"
fn2 = "D:/Python/deisel/"+str(z1)+".txt"
if not Path(fn1).is_file() or not Path(fn2).is_file():
return # some error message perhaps?
with open(fn1, "rb+") as tdc:
with open(fn2, "rb+") as fdl:
try:
while True:
# not using self.f1 and .fd, since it seems they are just local
# also: why are you loading k1 anyway, you're not using it?
k1.append(pickle.load(tdc))
kd.append(pickle.load(fdl))
except EOFError:
pass # no message needed, but not the nicest way to use the exception
for i in kd:
if "L" in i:
qa1 = i[:-1]
qa = qa + int(qa)
else:
qa = qa + int(i[0])
print(" Total Collection for Deisel on date ", z1, "is", qa)
I don't know about the rest of your code, but you could probably get rid of the EOF exception as well, if you pickle in a predictable way and it seems the load of f1 into k1 only serves the purpose of being a possible limit to how many elements are loaded from kd, which is wasteful.
Note how, with every example, the code gets more readable and shorter. Shorter by itself is not a good thing, but if your code becomes more easy to read and understand, performs better and is shorter on top, you know you're on the right track.

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

lxml: Obtain file current line number when calling etree.iterparse(f)

Since no one answer or comment this post, I decide to have this post rewritten.
Consider the following Python code using lxml:
treeIter = etree.iterparse(fObj)
for event, ele in treeIter:
if ele.tag == 'logRoot':
try:
somefunction(ele)
except InternalException as e:
e.handle(*args)
ele.clear()
InternalException is user-defined and wraps all exceptions from somefunction() besides lxml.etree.XMLSyntaxError. InternalException has well-defined handler function .handle().
fObj has "trueRoot" as top-level tag, and many "logRoot" as 2nd-level leaves.
My question is: Is there a way to record current line number when handling the exception e? *args can be replaced by any arguments available.
Any suggestion is much appreciated.
import lxml.etree as ET
import io
def div(x):
return 1/x
content = '''\
<trueRoot>
<logRoot a1="x1"> 2 </logRoot>
<logRoot a1="x1"> 1 </logRoot>
<logRoot a1="x1"> 0 </logRoot>
</trueRoot>
'''
for event, elem in ET.iterparse(io.BytesIO(content), events=('end', ), tag='logRoot'):
num = int(elem.text)
print('Calling div({})'.format(num))
try:
div(num)
except ZeroDivisionError as e:
print('Ack! ZeroDivisionError on line {}'.format(elem.sourceline))
prints
Calling div(2)
Calling div(1)
Calling div(0)
Ack! ZeroDivisionError on line 4

Categories

Resources