Python - Returning Exception in unittest - python

im starting to learn TDD and got the Bowling Game kata as exercise.
I have completed some of the regular score test, but i want to add more just to practice and one idea was to raise an exception if i roll a negative number.
The hole code is not relevant because this is a simple validation
class BowlingGame(object):
def __init__(self):
pass
def roll(self, pins):
if pins < 0:
#Want to Return Value Exception
class BowlingGameTest(unittest.TestCase):
def setUp(self):
self._game = BowlingGame()
def test_roll_negative(self):
self.game.roll(-1)
#Want to catch exception here with self.assert or except
The problem is that if i return for example 0/0 the exception is raised in the BowlingGame class and not in the BowlingGameTest class (there are in two diferent files).
If i do return ValueError (BowlingGame Class) with self.assertRaises(ValueError): (BowlingGameTest Class) i got AssertionError: ValueError not raised
Any ideas?

You need to raise ValueError instead of returning it, i.e.,
def roll(self, pins):
if pins < 0:
raise ValueError
Returning an exception actually returns the class object, but if you raise an exception, it will throw an error like you want.
It sounds like you're using self.assertRaises correctly - just in case though - it should look like this:
def test_roll_negative(self):
with self.assertRaises(ValueError):
self.game.roll(-1)

something like this ..
try:
self.game.roll(-1)
except ValueError:
pass

Related

How does it help to subclass an exception?

Instead of calling the exception directly, I have seen it is subclassed with nothing in it or a pass statement. How does it help Python internally to subclass a base class, in this manner? Does it change namespace or signature? How?
class ACustomException(Exception):
pass
class BCustomException(Exception):
pass
Raising Exception is like telling the doctor "Something's wrong" and then refusing to answer any questions. Compare:
try:
with open("foo.json", "rt") as r:
new_count = json.load(r)["count"] + 1
except Exception:
# Is the file missing?
# Is the file there, but not readable?
# Is the file readable, but does not contain valid JSON?
# Is the file format okay, but the data's not a dict with `count`?
# Is the entry `count` there, but is not a number?
print("Something's wrong")
# I don't care. You figure it out.
and
try:
with open("data.json", "rt") as r:
new_count = json.load(r)["count"] + 1
except FileNotFoundError:
print("File is missing.")
except PermissionError:
print("File not readable.")
except json.decoder.JSONDecoderError:
print("File is not valid JSON.")
except KeyError:
print("Cannot find count.")
except TypeError:
print("Count is not a number.")
If you are making a library, you can use the predefined exception classes where appropriate — but sometimes you need to communicate errors that Python creators never thought about, or you need to make a finer distinction than the existing exceptions do. This is when you'd create a custom exception.
For example, Django will define django.contrib.auth.models.User.DoesNotExist exception to communicate that the code tried to look for a User in the database, but no User matching the given criteria could be found. Being able to catch django.contrib.auth.models.User.DoesNotExist is like being a doctor, and getting a patient that not only tells you what hurts, but brings X-rays and a printed family history with them.
When you're handling exceptions with try-except, you're catching them by name, so having specific names helps you handle them.
For example, if a function raises Exception for any error, the catching logic gets complicated:
def foobar():
if FOO:
raise Exception('FOO happened')
elif BAR:
raise Exception('BAR happened')
try:
foobar()
except Exception as e:
if e.args == ('FOO happened',):
print('Handling FOO')
elif e.args == ('BAR happened',):
print('Handling BAR')
else:
raise
On the other hand if you have subclassed exceptions, the catching logic is simple:
class FooError(Exception):
pass
class BarError(Exception):
pass
def function():
if FOO:
raise FooError('FOO happened')
elif BAR:
raise BarError('BAR happened')
try:
function()
except FooError:
print('Handling FOO')
except BarError:
print('Handling BAR')
It helps with determining 'what' the traceback issue is referring to in case of maybe a web service that you maybe running, so it's not low-level or the generic errors you normally get back rather the exception class that would be used.
To be more specific with an example:
val = int(input('Enter a number:'))
try:
val *= val
except ValueError as e:
raise e
print(val)
### ValueError will be raised if user inputs something other than a number
### this raise e will return the actual error message saying
### ValueError: invalid literal for int() with base 10: 'ok'
In your case, you could still raise your exception keeping ValueError as the except to be handled for, like this:
val = int(input('Enter a number:'))
try:
val *= val
except ValueError as e:
raise ACustomException('some debug statement referring to the cause of the error')
print(val)
### now this will raise your exception class besides the ValueError exception, with a debug statement if you choose to have one in it.

Python 3 - raise statement

I am currently working through Learning Python by Mark Lutz and David Ascher and I have come across a section of code that keeps bringing up errors. I am aware that that book was written with Python 2 in mind unlike the Pyhton 3 I am using. I was wondering if anyone knew a solution to my problem as I have looked everywhere but I have been unable to find a solution .
.........................
MyBad = 'oops'
def stuff( ):
raise MyBad
try:
stuff( )
except MyBad:
print('got it')
Basically, MyBad is not an exception, and the raise statement can only be used with exceptions.
To make MyBad an exception, you must make it extend a subclass of Exception. For instance, the following will work:
class MyBad(Exception):
pass
def stuff( ):
raise MyBad
try:
stuff( )
except MyBad:
print('got it')
Output:
got it
However, it's better to raise an instance of an exception class, rather than the class itself, because it allows the use of parameters, usually describing the error. The following example illustrates this:
class MyBad(Exception):
def __init__(self, message):
super().__init__()
self.message = message
def stuff(message):
raise MyBad(message)
try:
stuff("Your bad")
except MyBad as error:
print('got it (message: {})'.format(error.message))
Output:
got it (Your bad)
You cannot raise a custom exception without creating a class (at least an empty one).
You can add custom text as you want by using also an __init__ function instead of pass:
class MyBad(Exception):
pass
# def __init__(self, txt):
# print(txt)
def stuff( ):
raise MyBad('test')
try:
stuff( )
except MyBad:
print('got it')
If you use pass, you will have :
got it
If you use the __init__() in comment, you will have
test and got it

Python - Implementing Custom exceptions

I have a project that I need to run and have no idea how to implement custom exceptions. It mostly does complicated scientific functions, to be vague.
Mostly it will be raising exceptions if something is not set. I've been given this as a starting example from runnables.
# Define a class inherit from an exception type
class CustomError(Exception):
def __init__(self, arg):
# Set some exception infomation
self.msg = arg
try:
# Raise an exception with argument
raise CustomError('This is a CustomError')
except CustomError, arg:
# Catch the custom exception
print 'Error: ', arg.msg
I have no idea how this is meant to work or how I am meant to implement my code. It's not very explicit.
To give an idea of a basic exception that needs created.
In a function:
if self.humidities is None:
print "ERROR: Humidities have not been set..."
return
Apparently this needs to raise/throw an exception instead.
A ValueError looks suitable for your humidities example.
if self.humidities is None:
raise ValueError('Humidities value required')
If you want to be specific:
class HumiditiesError(Exception):
pass
def set_humidities(humidities):
if humidities is None:
raise HumiditiesError('Value required')
try:
set_humidities(None)
except HumiditiesError as e:
print 'Humidities error:', e.message
This defines a subclass of Exception named HumiditiesError. The default behavior seems sufficient for your example, so the body of the class is empty (pass) as no additional nor modified functionality is required.
N.B. Python 2 assumed. In Python 3 you would access elements of the e.args tuple.

python calling custom exceptions from if-statement and try-except

So, I've created a custom exception that I want to call in 2 different ways (a if/else statement, and a try/except statement). Here is the custom exception:
class CustomException(Exception):
def __init__(self, value=None, *args, **kwargs):
self.parameter = value
for key, value in kwargs.items():
setattr(self, key, value)
for key, value in self.__dict__.items():
print "%s => %s" % ( key, value )
def __str__(self):
return repr(self.parameter)
Here is how I am wanting to implement the custom exception:
try:
if something:
#make an error
;lsdfj
else:
raise CustomException('this is my custom message', file='somefile.txt', var2='something')
except Exception, e:
raise CustomException(e)
My issues, I believe, are two fold:
1: When the standard NameError that is thrown in the try/except block (due to ;lsdfj), I want to pass CustomExceptions some extra parameters like 'file', just like the if/else implementation; how would I do that?
2: When the custom exception is raised (from the if/else statement being false), the CustomExceptions class ends up being called twice, because I raise it in the if/else block then it gets raised again within the except: section. I don't know how to get around this.
So, in the above case, I want to call CustomException when the if-statement is not true, and I want to call it when there is a standard exception thrown inside the code block... but currently, if something: evaluates to false then the CustomException will be raised twice...
So I want the custom exception to be used unilaterally throughout my code for if/else conditions, and standard python exceptions...
I know this explanation was convoluted but I'm not sure how else to explain what I'm after... Any help would be much appreciated! Thanks in advance!
In order not to raise the exception twice, you should wrap the try/except block around the if statemnt only, like so:
if something:
try:
#make an error
;fdsfas
except Exception, e:
raise CustomException(e.message, file='somefile.txt', var2='something')
else:
raise CustomException('this is my custom message', file='somefile.txt', var2='something')
And in order to pass the custom exception some parameters you must provide that parameters to the constructor of the class just like you did in the if/else statement.
You could in the except block use:
if not isinstance(e, CustomException): raise CustomException(e)
Edit:
A sys.exc_info() before the raise inside the except will successfully remove the traceback to the source of the exception i.e. NameError.

Invalid argument raise exception

How do I test my parameter if it will raise an exception without actually raising it, using try and except?
class MyClass:
def function(parameter):
pass
parameter is an ambiguous function that may raise 1 or more of any exception, for example:
parameter = pow("5", 5)
A TypeError is raised as soon as the function is called and before the function can execute its statements.
In a comment to another answer you said: "parameter is another function; take for example: parameter = pow("5", 5) which raises a TypeError, but it could be any type of function and any type of exception."
If you want to catch the exeption inside your function you have to call the paramenter (which I'm assuming is callable) inside that function:
def function(callable, args=()):
try:
callable(*args)
except:
print('Ops!')
Example:
>>> function(pow, args=("5", 5))
Ops!
This is if you really need to call your "paramenter" inside the function. Otherwise your should manage its behaviour outside, maybe with something like:
>>> try:
... param = pow('5', 5)
... except:
... param = 10
...
>>> param
10
>>> function(param)
In this example, to raise an exception is pow not function, so it's a good practice to separate the the two different call, and wrap with a try-except statement the code that might fail.
From what I can understand, you want to handle the exceptions raised and also inspect what sort of errors were raised for further inspection? Here is one way of doing it.
class Foo(object):
def find_errors(arg):
errors = []
try:
# do something
except TypeError as e:
errors.append(e)
# handle exception somehow
except ValueError as e:
errors.append(e)
# handle exception somehow
# and so on ...
finally:
pass #something here
return errors, ans
Now you can inspect errors and find out what exceptions have been raised.
If you expect the parameter to be a certain type, you can use type(paramter) is parametertype.
For example, if you wanted to verify that 'i' is an int, run instructions if(type(i) is int):
By edit:
try:
pow("5",5)
return 0
except Exception, err:
sys.stderr.write('ERROR: %s\n' % str(err))
return 1
Perhaps what you mean is how to catch the TypeError exceptions caused by invalid function calls?
Like this:
def foo(bar):
pass
foo(1, 2)
You don't catch them in the function and certainly not in the def foo(bar): line.
It's the caller of the function that made an error so that's where you catch the exception:
try:
foo(1, 2)
except TypeError:
print('call failed')

Categories