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

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

Related

python: exception inside try doesn't jump to except

I am trying to search within the EU parliment votes' description.
They are standard xml files. So far I noticed 2 versions of the votes' result: where the description is text and where it is an url.
Fails at this file: https://www.europarl.europa.eu/doceo/document/PV-9-2022-09-12-RCV_FR.xml
Works fine on the following file: https://www.europarl.europa.eu/doceo/document/PV-9-2022-07-06-RCV_FR.xml
My problem is not the failure itself (that's why I added the try clause) but that code execution doesn't jump to the except path, just exits here with this: string indices must be integers
Please help, why isn't the error properly handled?
for currentfile in f:
mytree = ET.parse(xmlfiles + "\\" + currentfile)
myroot = mytree.getroot()
dixml = etree_to_dict(myroot)
for votes in dixml['PV.RollCallVoteResults']['RollCallVote.Result']:
try:
title = votes['RollCallVote.Description.Text'] #fails here
titletype = type(title)
if titletype == dict:
title=title['#text']
except :
title = votes['RollCallVote.Description.Text']['a']['#text']
try:
ltitle = title.lower()
except :
print(type(title))
if stringtosearch in ltitle:
print(title,currentfile)
edit:
full trace:
Message=string indices must be integers
Source=...debug.py
StackTrace:
File "...debug.py", line 44, in <module>
title = votes['RollCallVote.Description.Text']
During handling of the above exception, another exception occurred:
File "...debug.py", line 44, in <module>
title = votes['RollCallVote.Description.Text']
File "...debug.py", line 49, in <module> (Current frame)
title = votes['RollCallVote.Description.Text']['a']['#text']
This would happen if there is a new exception raised within your catch block, I would presume specifically the votes object at some point of you accessing it, raises this exception.
Try printing out votes and then each time you access it by indexing print it out you'll see to which extent you can continue accessing it via string index ( votes['string'] ).

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

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

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.

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"

Categories

Resources