i have to check if the content of some variable are of some specific type (it is a sanity check i want to implement). If each one of these is not of the specified type then the program has to abort.
I'm not experienced in python, i've a glance to the official guide on the web where it is stated that it is possible to define own exceptions by class implementation. I don't know if that would be hard or not, but since i don't have to do something particularly complicated is it possible to do that in a simple way?
Update
I've implemented the exception int exception in the following way:
class TypeCheckingException(Exception):
def __init__(self,type_in,type_exp):
self.type_in = type_in
self.type_exp = type_exp
The specific line of the implementation its use are:
try:
if isinstance(var1,str) == 0:
raise TypeCheckingException(type(var1),str)
if isinstance(var2,str) == 0:
raise TypeCheckingException(type(var2),str)
if isinstance(var3,int) == 0:
raise TypeCheckingException(type(var3),int)
if isinstance(var4,int) == 0:
raise TypeCheckingException(type(var4),int)
if isinstance(var5,str) == 0:
raise TypeCheckingException(type(var5),str)
if isinstance(var6,float) == 0:
raise TypeCheckingException(type(var6),float)
except TypeCheckingException, tce:
print "Type expected input " + str(tce.type_in) + " while type expected is " + str(tce.type_exp) + "."
In this case works, but the error output is quite verbose... i'd like to make it shorter...
Any clue?
You want to use isinstance(variable, type).
>>> a = 'str'
>>> isinstance(a, str)
True
You won't need to use exception handling with this route. You can check for instance type, then exit, if necessary.
Related
I'm doing a project that is requiring a lot of input validation. I currently have a function defined as follows:
def get_valid_float(inputMessage,errorMessage):
while True:
variableInput = input(inputMessage)
try:
variableInput = float(variableInput)
return variableInput
except ValueError:
print(errorMessage)
This function allows me to choose a custom message to prompt the user. It will then validate that the user input is indeed a float, and will print a custom error message in the event that it is not. It will loop until the user gives a valid input.
However, I would rather not create a function to validate each and every data type. It seems like it would be best to combine these into one get_valid_input() function, and pass a third argument allowing me to choose what data type I am attempting to verify. For example, get_valid_input(complex,inputMessage,errorMessage).
I am obviously unable to pass a keyword as an argument. This makes me think the only way to do this would to be to do something like this:
def get_valid_float(dataType,inputMessage,errorMessage):
if dataType == "float"
while True:
variableInput = input(inputMessage)
try:
variableInput = float(variableInput)
return variableInput
except ValueError:
print(errorMessage)
elif dataType == "integer"
while True:
variableInput = input(inputMessage)
try:
variableInput = int(variableInput)
return variableInput
except ValueError:
print(errorMessage)
And so on, with an elif for every data type. Surely there is an easier way to do this, that somehow allows me to execute the line variableInput = {dataType}(variableInput) to confirm that they input a value of data type "dataType". Any ideas?
Just pass as an argument the actual data type, rather than the name of the data type. E.g:
def get_valid_input(dataType, inputMessage, errorMessage):
while True:
value = input(inputMessage)
try:
value = dataType(value)
break
except ValueError:
print(errorMessage)
You would call it like this:
floatvalue = get_valid_input(float, "enter a float value: ", "that is an invalid float")
intvalue = get_valid_input(int, "enter an integer value: ", "that is an invalid integer")
I am obviously unable to pass a keyword as an argument.
Not sure why you're saying that, but you can! :)
Also no need for error message, just catch all Exceptions (Not recommended but since you are just printing out the error it seems fine here)
The message strings aren't really needed, try using the name of the dataType and the exception's message like this:
def get_valid_data(dataType):
while True:
variableInput = input(f"Put in data of type {dataType.__name__}: ")
try:
variableInput = dataType(variableInput)
return variableInput
except Exception as e:
print(e)
get_valid_data(int)
>>> Put in data of type int: "hi"
>>> invalid literal for int() with base 10: '"hi"'
The runtime keeps telling me:
expected an indented block
But I don't want write nothing inside my except block, I just want it to catch and swallow the exception.
Just write
pass
as in
try:
# Do something illegal.
...
except:
# Pretend nothing happened.
pass
EDIT: #swillden brings up a good point, viz., this is a terrible idea in general. You should, at the least, say
except TypeError, DivideByZeroError:
or whatever kinds of errors you want to handle. Otherwise you can mask bigger problems.
For those who are very unclear as to why you would want to do this. Here is an example where I initially thought that an empty block would be a good idea:
def set_debug_dir(self, debug_dir=None):
if debug_dir is None:
debug_dir = self.__debug_dir
elif isinstance(debug_dir, (Path, str)):
debug_dir = debug_dir # this is my null operation
elif isinstance(debug_dir, list):
debug_dir = functools.reduce(os.path.join, debug_dir)
else:
raise TypeError('Unexpected type for debug_dir: {}'.format(type(debug_dir).__name__))
But it would be more clear to reorganize the statement:
def set_debug_dir(self, debug_dir=None):
if debug_dir is None:
debug_dir = self.__debug_dir
elif isinstance(debug_dir, list):
debug_dir = functools.reduce(os.path.join, debug_dir)
elif not isinstance(debug_dir, (Path, str)):
raise TypeError('Unexpected type for debug_dir: {}'.format(type(debug_dir).__name__))
I've never done this in more permanent code, but I frequently do it as a placeholder
if some_expression:
True
else:
do_something(blah)
Just sticking a True in there will stop the error. Not sure if there's anything bad about this.
The following snipped calls parse_args() to identify a parameter --num and that tests that the value is acceptable in separate code after parsing.
import argparse
def cmd_line_opts(cmdline):
parser = argparse.ArgumentParser(description="blah blah",)
parser.add_argument('--num', default=None, type=int,)
return parser.parse_args(cmdline)
p = cmd_line_opts(['--num', '2'])
if p.num < 1:
raise ValueError('--num must be > 0')
p = cmd_line_opts(['--num', '0'])
if p.num < 1:
raise ValueError('--num must be > 0')
I am wondering if it would be possible to include the test and a suitable error message directly in the parsing. I suspect that this involves using the Action API but I can't figure out how to signal a failure when returning from the action.
You just need a custom type for the argument.
def positive_int(s):
try:
s = int(s)
if s <= 0:
raise ValueError()
except ValueError:
raise ArgumentTypeError("Not a valid positive integer: {}".format(s))
# ...
parser.add_argument("--num", type=positive_int, default=0)
The type argument is any callable that accepts a string and returns a value to use for the argument's value. It doesn't have to be an actual type (built-in or otherwise).
Full credit to #chepner for his answer, above. At least on my system you need qualify ArgumentTypeError. I put it in a comment but thought it would be helpful to someone who just wanted to copy and paste the code.
import argparse
def positive_int(s):
try:
s = int(s)
if s <= 0:
raise ValueError()
except ValueError:
raise argparse.ArgumentTypeError("Not a valid positive integer: {}".format(s))
def cmd_line_opts(cmdline):
parser = argparse.ArgumentParser(description="blah blah",)
parser.add_argument("--num", type=positive_int, default=0)
return parser.parse_args(cmdline)
p = cmd_line_opts(['--num', 'x'])
Thats my first question on Stackoverflow and im a totally Python beginner.
I want to write, to get firm with python, a small Backup-Programm, the main part is done, but now i want to make it a bit "portable" and use a Config file, which i want to Validate.
My class "getBackupOptions" should be give Back a validate dict which should be enriched with "GlobalOptions" and "BackupOption" so that i finally get an fully "BackupOption" dict when i call "getBackupOptions.BackupOptions".
My Question now is, (in this Example is it easy, because its only the Function which check if the Path should be Recursive searched or not) how to simplify my Code?
For each (possible) Error i must write a new "TryExcept" Block - Can i Simplify it?
Maybe is there another way to Validate Config Files/Arrays?
class getBackupOptions:
def __init__(self,BackupOption,GlobalOptions):
self.BackupOption = BackupOption
self.GlobalOptions = GlobalOptions
self.getRecusive()
def getRecusive(self):
try:
if self.BackupOption['recursive'] != None:
pass
else:
raise KeyError
except KeyError:
try:
if self.GlobalOptions['recursive'] != None:
self.BackupOption['recursive'] = self.GlobalOptions['recursive']
else:
raise KeyError
except KeyError:
print('Recusive in: ' + str(self.BackupOption) + ' and Global is not set!')
exit()
Actually i only catch an KeyError, but what if the the Key is there but there is something else than "True" or "False"?
Thanks a lot for you help!
You may try this
class getBackupOptions:
def __init__(self,BackupOption,GlobalOptions):
self.BackupOption = BackupOption
self.GlobalOptions = GlobalOptions
self.getRecusive()
def getRecusive(self):
if self.BackupOption.get('recursive') == 'True' and self.GlobalOptions.get('recursive') == 'True':
self.BackupOption['recursive'] = self.GlobalOptions['recursive']
else:
print('Recusive in: ' + str(self.BackupOption) + ' and Global is not set!')
exit()
Here get method is used, therefore KeyError will not be faced.
If any text other than True comes in the field it will be considered as False.
I want to create custom error messages for a function.
def tr( launch_speed , launch_angle_deg , num_samples ):
#Error displays
try:
launch_speed>0
except:
raise Exception("Launch speed has to be positive!")
try:
0<launch_angle_deg<90
except:
raise Exception("Launch angle has to be 0 to 90 degrees!")
try:
um_samples = int(input())
except:
raise Exception("Integer amount of samples!")
try:
num_samples >=2
except:
raise Exception("At least 2 samples!")
Essentially, what I want is to get an error message every time a wrong value has been written in the function variables, and I've tried creating these messages based on what I've gathered on the Internet, but it doesn't seem to work.
You can't use try: except: for everything; for example, launch_speed>0 will not raise an error for negative values. Instead, I think you want e.g.
if launch_speed < 0: # note spacing, and if not try
raise ValueError("Launch speed must be positive.") # note specific error
You should also test for and raise more specific errors (see "the evils of except"), e.g.:
try:
num_samples = int(raw_input()) # don't use input in 2.x
except ValueError: # note specific error
raise TypeError("Integer amount of samples!")
You can see the list of built-in errors in the documentation.
Why not go one step further and build your own exception types? There's a quick tutorial in the docs which could be used something like:
class Error(Exception):
"""Base class for exceptions defined in this module"""
pass
class LaunchError(Error):
"""Errors related to the launch"""
pass
class LaunchSpeedError(LaunchError):
"""Launch speed is wrong"""
pass
class LaunchAngleError(LaunchError):
"""Launch angle is wrong"""
pass
class SamplesError(Error):
"""Error relating to samples"""
pass
In this case the default functionality of Exception is fine, but you may be able to get finer granularity in what you catch by defining extra exceptions.
if launch_speed < 0:
raise LaunchSpeedError("Launch speed must be positive")
if 0 <= launch_angle < 90:
raise LaunchAngleError("Launch angle must be between 0 and 90")
um_samples = input()
try:
um_samples = int(um_samples)
except ValueError:
raise SampleError("Samples must be an integer, not {}".format(um_samples))
if um_samples < 2:
raise SampleError("Must include more than one sample, not {}".format(str(um_samples)))