sys.exit() does not exit program when catching exceptions - python

This program checks molecular formulas. I want the program to exit as soon as it detects an error in a formula. For example, the formula "a", is incorrect.
When I run it through my code:
def readletter():
if q.peek() in string.ascii_lowercase:
print(q.peek())
return q.get()
else:
raise Formelfel("Förväntad liten bokstav.")
def readLetter():
if q.peek() in string.ascii_uppercase:
print(q.peek())
return q.get()
else:
raise Formelfel("Förväntad stor bokstav.")
def readAtom():
X = ""
try:
X += readLetter()
except Formelfel:
print("Missing capital letter at end of row "+getRest())
sys.exit()
return
try:
x = readletter()
atom = X+x
except (Formelfel, TypeError):
atom = X
if atom in ATOMER:
return
else:
raise Formelfel("Okänd atom.")
def readGroup():
if q.peek() in string.ascii_uppercase or q.peek() in string.ascii_lowercase:
try:
readAtom()
except:
print("Unknown atom at end of row "+getRest())
sys.exit()
I get this output:
Missing capital letter and end of row a
Unknown atom at end of row
Why is this? I called sys.exit() before print("Unknown atom at end of row "+getRest()) so why does it still execute? I want only the first row of the output to be printed.

sys.exit raises a SystemExit exception. You are catching it with your except clause.
What you should do instead is catch a more specific class of exceptions, which does not include SystemExit.
Catching Exception will work:
def readGroup():
if q.peek() in string.ascii_uppercase or q.peek() in string.ascii_lowercase:
try:
readAtom()
except Exception:
print("Unknown atom at end of row "+getRest())
sys.exit()
You can learn more about exceptions and SystemExit in the docs.
Note that you should ideally catch something more specific than Exception (which is very broad, and may catch exceptions you don't intend to catch).

Because in python exit event is processed as SystemExit exception

Related

Try/except for check string in Python

I would like to use Try/ecept to check if a string is really a string. I made the following code:
nome = input('Name: ')
try:
if not nome.isalpha() or nome == '':
raise ValueError('Invalid!')
else:
print(f'Name {nome} valid.')
except ValueError as e:
print(f'Error: {e}')
But, I would like to do it without using the raise command, just try/except.
Can anyone help me? I thank you.
The only way to trigger an exception without raising it yourself is to attempt something invalid, such as this:
nome = input('Name: ')
try:
f = float(nome)
except ValueError as e:
print('Is alpha')
else:
print('Not alpha')
Here I try to convert the input to a float, and if there are any alpha characters in the value, it will raise the ValueError exception.

How should I insert try-except in this scenario

Task1
Write a script that reads a string from STDIN and raise ValueError
exception if the string has more than 10 characters or else prints the
read string.
I wrote the code like this
a = input("Enter a string")
if(len(a) > 10):
raise ValueError
else:
print(a)
Task2
Use try ... except clauses. Print the error message inside except
block.
I am now confused about how to use try-except here because to print any message in except block the program has to fail at try block.
My input will be PythonIsAmazing
You can just wrap the whole thing in try ... except as follows:
a = input("Enter a string: ")
try:
if(len(a) > 10):
raise ValueError
print(a)
except ValueError:
print("String was longer than 10 characters")
Alternatively, if you had lots of different ValueErrors that might be raised, you could give each a separate error message:
a = input("Enter a string: ")
try:
if(len(a) > 10):
raise ValueError("String was longer than 10 characters")
print(a)
except ValueError as e:
print(e)
Eg:
Enter a string: test
test
Enter a string: PythonIsAmazing
String was longer than 10 characters

I am getting an error when running this code saying str1 is not defined,when i have already defined it in try block

I am trying to write a small code block where in i take an input (user can enter any input in words or letters), my code should try to find if it is a positive or negative number or the entered value is a string.
try:
str1=int(input('Enter a number:'))
print('try block is completed')
except:
str1=str(str1)
if str1>0:
print('entered value is positive')
elif str1<0:
print('entered value is negative')
else:
print(str1)
The reason is the exception is caused in int(input(...)) so the str1 remains undeclared.
str1=input('Enter a number:')
try:
str1=int(str1)
print('try block is completed')
except:
str1=str(str1)
if str1>0:
print('entered value is positive')
elif str1<0:
print('entered value is negative')
else:
print(str1)
Modify your code like this to handle exception on integer and string
On your except branch you have the following call:
str1=str(str1)
Since you are on your except, and you haven't defined your str1 variable outside the try/except block, your statement will fail when it tries to cast the contentes of the str1 variable (which does not exist outside of the try branch).
A possible implementation to deal with this case would be to set str1 to None or an empty string on your except block. Something like this:
try:
str1 = int(input('Enter a number:'))
print('try block is completed')
except:
str1 = None
# First we check that our variable is not None (caught an exception)
try:
int_str1 = int(str1)
except:
int_str1 = None
if int_str1:
if int_str1 > 0:
print('entered value is positive')
elif int_str1 < 0:
print('entered value is negative')
else:
print('Could not get integer value of input')
It's because you use str1 in your except clause. If there is an exception during the processing of input or int, the variable str1 is never set.
If you add str1=None before your try statement, I am sure, it won't complain anymore, but you need to change your except clause then.
If you're just concerned about the cast to int, you could do:
str1= None
try:
str1=input('Enter a number:')
val=int(str1)
print('try block is completed')
except:
val=None
if val is None:
print('input is not a valid number')
elif val>0:
print('entered value is positive')
elif val<0:
print('entered value is negative')
else:
print(str1)
in the case fn an exception in the call int, the variable str1 never gets created, because int is evaluated (and raises the error) before str1 gets assigned.
also - in the case of an exception you'll get a TypeError for trying to compare a string with 0, so put all you int-assuming logic inside the try, like this:
str1=input('Enter a number:')
try:
str1=int(str1)
if str1>0:
print('entered value is positive')
elif str1<0:
print('entered value is negative')
except:
str1=str(str1)
print(str1)

Invalid Syntax while True statemtn

Here's my script:
def makeithappen():
word=""
while True:
try:
word=inputText()
except:
print("Something happened inputText")
else:
if len(word)>0:
break
elif word!=str:
break
For some reason however I get an invalid syntax error and I am not sure why.
def makeithappen():
word=""
while True:
try:
word=input() #is this supposed to be input()?
except:
print("Something happened inputText")
else:
if len(word)>0:
break
elif isinstance(word, basestring): #I never got the logic behind it
break
I think this is what you wanted to do. It exits if entered text is valid (length is more than 0) and input type is not of str (which is always false in case of python3).
#!/usr/bin/python
# -*- coding: utf-8 -*-
def makeithappen():
word=""
while True:
try:
word=raw_input("Go:")
except:
print("Something happened inputText")
else:
if len(word)>0:
print("Hello!!")
elif word!=str:
print("Bye!!")
break
makeithappen()

Python - Syntax check of molecular formulas

This is going to be a long question, I hope you guys have patience.
I am writing a program that checks if the syntax for a molecular formula is correct.
I have a BNF-syntax:
<formel>::= <mol> \n
<mol> ::= <group> | <group><mol>
<group> ::= <atom> |<atom><num> | (<mol>) <num>
<atom> ::= <LETTER> | <LETTER><letter>
<LETTER>::= A | B | C | ... | Z
<letter>::= a | b | c | ... | z
<num> ::= 2 | 3 | 4 | ...
and this is my code:
from linkedQFile import LinkedQ
import string
import sys
ATOMER = ["H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar"]
class FormelError(Exception):
pass
class Gruppfel(Exception):
pass
q = LinkedQ()
formel= "(Cl)2)3"
for symbol in formel:
q.put(symbol)
def readNum():
"""Reads digits larger than 1. Raises exception if condition is not fulfilled."""
try:
if int(q.peek()) >= 2:
print(q.peek())
q.get()
return
else:
q.get()
print("Too small digit at the end of row: "+getRest())
sys.exit()
except (ValueError,TypeError):
raise FormelError("Not a number.")
def readletter():
"""Reads lowercase letters and returns them."""
if q.peek() in string.ascii_lowercase:
print(q.peek())
return q.get()
else:
raise FormelError("Expected lowercase letter.")
def readLetter():
"""Reads capital letters and returns them."""
if q.peek() in string.ascii_uppercase:
print(q.peek())
return q.get()
else:
raise FormelError("Expected capital letter.")
def readAtom():
"""Reads atoms on the form X and Xx. Raises Exception if the format for an atom is not fulfilled or if the atom does not exist."""
X = ""
try:
X += readLetter()
except FormelError:
print("Missing capital letter at end of row: "+getRest())
sys.exit()
return
try:
x = readletter()
atom = X+x
except (FormelError, TypeError):
atom = X
if atom in ATOMER:
return
else:
raise FormelError("Unknown atom.")
def readGroup():
if q.peek() in string.ascii_uppercase or q.peek() in string.ascii_lowercase:
try:
readAtom()
except:
print("Unknown atom at end of row: "+getRest())
sys.exit()
try:
while True:
readNum()
except FormelError:
pass
return
if q.peek() == "(":
print(q.peek())
q.get()
try:
readMol()
except FormelError:
pass
if q.peek() == ")":
print(q.peek())
q.get()
else:
print("Missing right parenthesis at end of row: "+ getRest())
sys.exit()
return
digitfound = False
try:
while True:
readNum()
digitfound = True
except:
if digitfound:
return
print("Missing digit at end of row: "+getRest())
sys.exit()
return
raise FormelError("Incorrect start of group")
def readMol():
try:
readGroup()
except FormelError:
print("Incorrect start of group at end of row: "+getRest())
raise FormelError
if q.peek() == None:
return
if not q.peek() == ")":
try:
readMol()
except FormelError:
pass
def readFormel():
try:
readMol()
except:
return
print("Correct formula")
def getRest():
rest = ""
while not q.isEmpty():
rest += q.get()
return rest
readFormel()
Now the code is supposed to accept some given formulas and provide an error code for some given incorrect formulas. Let's look at these given formulas:
Correct:
Si(C3(COOH)2)4(H2O)7
Incorrect:
H2O)Fe
(Cl)2)3
The program accepts the correct formula, but unfortunately also the incorrect ones. The reason for this is that the if statement in:
if not q.peek() == ")":
try:
readMol()
except FormelError:
pass
makes it so that parentheses unbalanced to the right (with one or more parenthesis too much on the right side) slip through the code, instead of being detected as incorrect starts of a "group". How can I fix this, while still having Si(C3(COOH)2)4(H2O)7 being accepted as syntactically correct?
Thank you for your patience :)
Your code for readMol has this erroneous test (you even told us) for ")". Your grammar doesn't show a need for such a test, if you are coding (as you are) a recursive descent parser.
In fact, you grammar has a odd rule for mol:
<mol> ::= <group> | <group><mol>
This doesn't work well with recursive descent parsers. You have refactor such rules to share the common prefixes in each rule. In this case, it is easy:
<mol> ::= <group> ( <mol> | empty ) ;
Then you write the code directly from the grammar rule (see link above)
[You sort of did this, except for the ")" check.]
It should look something like this (I'm not a python expert):
def readMol():
try:
readGroup()
except FormelError:
print("Incorrect start of group at end of row: "+getRest())
raise FormelError
try:
readMol()
except FormelError:
pass
It is helpful when writing recursive descent parsers, to massage the grammar into a most-compatible form first (as I did with your mol rule). Then coding the individual recognizers is a purely mechanical task that is hard to get wrong.

Categories