Python KeyError and ValueError inconsistency? - python

I've found an inconsistency between ValueError and KeyError. The former will treat \n as a newline; the latter treats it as raw text. Is this behavior normal/expected?
TeX_dict is a dictionary to convert parts of dictionary keys to TeX formatted strings that are used when generating plots. part is one such part. Here are two examples of part:
a&b is successfully split and converted in the dictionary.
a,b&c is not.
When I raise a ValueError, the \n newline characters generate a new line. When I raise a KeyError, they do not.
geo_split = lambda thing: '\&'.join([
TeX_dict[x]
for x in thing.split('&')
])
try:
TeX = geo_split(part)
except KeyError:
msg = ("You have programmed limited functionality for "
"geometric mean keys. They can only handle species "
"that are hard coded into "
"``pccv.TeX_labels.axis_labels``.\n\n" #
"The following part failed: {}\n"
).format(part)
raise ValueError(msg) # If this is KeyError, the new lines don't print.
Here is a sample output from each:
ValueError: You have programmed limited functionality for geometric mean keys.
They can only handle species that are hard coded into
``pccv.TeX_labels.axis_labels``.
KeyError: 'You have programmed limited functionality for geometric mean keys.
They can only handle species that are hard coded into
``pccv.TeX_labels.axis_labels``.\n\nThe following part failed: a,p1&p2\n'

This is a peculiarity of the KeyError implementation.
/* If args is a tuple of exactly one item, apply repr to args[0].
This is done so that e.g. the exception raised by {}[''] prints
KeyError: ''
rather than the confusing
KeyError
alone. The downside is that if KeyError is raised with an explanatory
string, that string will be displayed in quotes. Too bad.
If args is anything else, use the default BaseException__str__().
You could work around it by passing something that overrides __repr__:
class Wrapper(str):
def __repr__(self):
return str(self)
raise KeyError(Wrapper('hello\nthere'))

Related

Time limit exceeded in valid parentheses problem

I am trying to solve the following problem in python (not for anything, just trying to learn how to code), and I keep getting the time limit exceeded error.
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.
Can someone please explain why the code won't run?
Detail on my logic: I am trying to check if the input has any values (or else return true immediately), then whether it has any closed parentheses next to each other. The idea is that every true input must have either '()', '[]', or '{}' somewhere in the string. Then, I would remove those pairs until either there are no more characters, and I know it's true, or it can't find any and it is false.
If this is a poor way to think about the problem and you plan to offer a different way, please also help me understand why this code doesn't run.
class Solution:
def isValid(self, s: str) -> bool:
l = ['()','[]','{}']
while s != '':
while l[0] in s or l[1] in s or l[2] in s:
try:
s.replace(s[s.index(l[0])],'')
except:
ValueError
try:
s.replace(s[s.index(l[1])],'')
except:
ValueError
try:
s.replace(s[s.index(l[2])],'')
except:
ValueError
continue
return False
return True
s.replace(...) returns the modified string. It doesn't modify s in place; it can't, since strings are immutable.
There are other mistakes but I'll leave them as an exercise for you to figure out. Fixing this will at least get you past the infinite loop.
In addition to the above answers, it seems like you are trying to catch a ValueError when s.index() fails.
The code you have will instead catch any exception, not just ValueError.
You can do it like this:
try:
# try code
except ValueError as e:
# handle ValueError

How to properly raise errors and log them when comparing variables or validating formats with custom if statements?

In a module I am writing, I have a need for checking that incoming data matches particular requirements and formats. I thought I knew a good way to do this, but I need to add logging functionality and it made me realise I must be writing my code improperly. A MWE of what I am currently doing is:
string1 = 'Hello, World!' # represents something like a column name in an incoming dataframe
string2 = 'Hello, World?' # represents what the column name should be according to an incoming config file
if string1 != string2:
raise ValueError('Input from string1 does not match expected value given in string2')
That works perfectly, and the raised error can be grabbed by my pytest functions as well. But it is not part of a try except sequence, and I dont see how it can be. try doesn't behave like an if and except requires the specific error to actually be raised first.
This poses a problem because I dont know how to capture the raised error with python's logging module without needless code duplication. The best I can do is:
import logging
string1 = 'Hello, World!' # represents something like a column name in an incoming dataframe
string2 = 'Hello, World?' # represents what the column name should be according to an incoming config file
if string1 != string2:
logging.error('Input from string1 does not match expected value given in string2')
raise ValueError('Input from string1 does not match expected value given in string2')
But that is two, nearly identical lines to do the same thing. logging.error doesnt actually halt the code, which I need to happen, and I cant find a way to capture the raise ValueError(...) with logging.
Obviously, with this example, logging is just going to print to the terminal, but ultimately, it will be printing to a file (and I know how to do that).
What is the best way to write such a test of variables to have both logging and raised error functionality?
The idea is to put the raise in a try block and do the logging in the except. Here's how you'd do it for this small example:
string1 = 'Hello, World!'
string2 = 'Hello, World?'
try:
if string1 != string2:
raise ValueError('Input from string1 does not match expected value given in string2')
except ValueError as e:
logging.error(e)
raise
In real life, it tends to look more like:
try:
do_some_complex_thing()
except Exception as e:
log.error(e)
where do_some_complex_thing() might have a lot going on inside of it -- by wrapping it all in one outer try block you can make sure that any otherwise-unhandled exception is logged in a single spot.
I'm not very familiar with the logging module but this might help:
Exceptions in python are just objects, and you can generate them without raising them immediately.
err = ValueError('Input from string1 does not match expected value given in string2')
# log the error like you would in an except block and then
raise err

How to end the program and return to the menu?

I want to it so that if the user enters a symbol that it is not allowed it ends and returns to the menu. However what happens is it still displays the user's score they got on the password. I want it so that it does not display this if a prohibited symbol is entered. Here is my code:
for c in user_password:
if c not in symbols:
print("Some symbols you entered are not allowed")
break
print(user_score)
If symbols is just a list of allowed characters such as:
symbols = [";", ",", ".", "-"]
then even if user_password contains only letters and these symbols, the print will still happen as normal characters (letters a-z) won't be in symbols.
You should try a raise Exception of your choice. For example, it seems like you have a ValueError.
So you can write :
for c in user_password:
if c not in symbols:
raise ValueError("The symbol {} you entered is not allowed".format(c))
print(user_score)
This will make the job.
Note that you can raise any error (KeyError, AttributeError, IOError and so) for any reason, so for the sake of clarity you have to choose the good test-error and the closer exception to raise.
For example you can list the different symbols that are not allowed.
I hope this will help you.

What is a reliable isnumeric() function for python 3?

I am attempting to do what should be very simple and check to see if a value in an Entry field is a valid and real number. The str.isnumeric() method does not account for "-" negative numbers, or "." decimal numbers.
I tried writing a function for this:
def IsNumeric(self, event):
w = event.widget
if (not w.get().isnumeric()):
if ("-" not in w.get()):
if ("." not in w.get()):
w.delete(0, END)
w.insert(0, '')
This works just fine until you go back and type letters in there. Then it fails.
I researched the possibility of using the .split() method, but I could not figure out a reliable regex to deal for it.
This is a perfectly normal thing that needs to be done. Any ideas?
try:
float(w.get())
except ValueError:
# wasn't numeric
It sounds like you might just need to know whether passing some string to float will give a result (i.e. it is a nice numeric value), or an error (i.e. the string doesn't represent a number). Try this:
def isnum(s):
try:
float(s)
except:
return(False)
else:
return(True)
I realise this is an old question but I've just faced this problem.
You can do something like:
if re.sub("[^0-9\\-\\.]", "", "-0.18"):

Python: Convert a string to an integer

Does anybody have a quickie for converting an unsafe string to an int?
The string typically comes back as: '234\r\n' or something like that.
In this case I want 234. If '-1\r\n', I want -1. I never want the method to fail but I don't want to go so far as try, except, pass just to hide errors either (in case something extreme happens).
In this case you do have a way to avoid try/except, although I wouldn't recommend it (assuming your input string is named s, and you're in a function that must return something):
xs = s.strip()
if xs[0:1] in '+-': xs = xs[1:]
if xs.isdigit(): return int(s)
else: ...
the ... part in the else is where you return whatever it is you want if, say, s was 'iamnotanumber', '23skidoo', empty, all-spaces, or the like.
Unless a lot of your input strings are non-numbers, try/except is better:
try: return int(s)
except ValueError: ...
you see the gain in conciseness, and in avoiding the fiddly string manipulation and test!-)
I see many answers do int(s.strip()), but that's supererogatory: the stripping's not needed!
>>> int(' 23 ')
23
int knows enough to ignore leading and trailing whitespace all by itself!-)
import re
int(re.sub(r'[^\d-]+', '', your_string))
This will strip everything except for numbers and the "-" sign. If you can be sure that there won't be ever any excess characters except for whitespace, use gruszczy's method instead.
int('243\r\n'.strip())
But that won't help you, if something else than a number is passed. Always put try, except and catch ValueError.
Anyway, this also works: int('243\n\r '), so maybe you don't even need strip.
EDIT:
Why don't you just write your own function, that will catch the exception and return a sane default and put into some utils module?
try:
x=int("234\r\n".strip())
except ValueError:
x=0
def str_to_int(a):
str_to_int_output=""
for i in range(len(a)):
for b in range(10):
if a[i]==str(b):
str_to_int_output+=a[i]
return int(str_to_int_output)
fn for "str to float" is a bit more comlicated, but i think i can do it if it is needed.
You could just:
def to_int(unsafe_string):
return int(unsafe_string.strip())
But it will throw a ValueError if the stripped unsafe_string is not a valid number. You can of course catch the ValueError and do what you like with it.
Without knowing what kinds of inputs you are expecting, it's hard to say what is 'enough' to solve this. If you are just worried about trailing newlines, then Xavier Combelle's or gruszczy's answer is enough:
try:
x = int(value)
except ValueError:
x = 0
If you have to find any integer, anywhere in a string, then you might need something like this:
import re
try:
x = int(re.search(r'(0|(-?[1-9][0-9]*))', searchstring).group(0))
except TypeError: # Catch exception if re.search returns None
x = 0
Under Python 3.0 (IDLE) this worked nicely
strObj = "234\r\n"
try:
#a=int(strObj)
except ValueError:
#a=-1
print(a)
>>234
If you're dealing with input you cannot trust, you never should anyway, then it's a good idea to use try, except, pass blocks to control exceptions when users provide incompatible data. It might server you better to think about try, except, pass structures as defensive measures for protecting data compatibility rather than simply hidding errors.
try:
a=int(strObj) #user sets strObj="abc"
except ValueError:
a=-1
if a != -1:
#user submitted compatible data
else:
#inform user of their error
I hope this helps.

Categories