Return argument throwing exception in Python - python

If I've defined a class that takes in two or more parameters:
class SomeObject:
def __init__(self, int_param, str_param):
#if parameters are wrong type:
raise TypeError("wrong type")
...
if (__name__ == "__main__"):
try:
invalid_obj = SomeObject('two', 'string')
print (invalid_obj)
except TypeError as e:
print (e)
it'll print "wrong type", but is there a way for it to also return which argument is raising the exception? Can I get the output to be:
"wrong type 'two'"
? I've tried print (e.args), print (repr(e)), and simply print(e) but the invalid argument never gets printed. Just wondering if this is possible, thank you.
edit: It works with a custom exception type, and if I list each parameter being tested individually - I also have ValueError catching for both the int_param and str_param as well, so I wanted to see if I can condense the if statements to just:
#if params not right type:
raise TypeError
#if params contain invalid value:
raise ValueError
and still get it to return the specific invalid argument that's causing the error. I'll definitely keep the custom Exception type in mind for future assignments; unfortunately for this one the instructor has "raise TypeError" and "raise ValueError" as requirements for full marks. She doesn't require the invalid argument to be returned though, that was just me being curious if I could manage it. I ended up with:
#if int_param not int:
raise TypeError("int_param {0} given is invalid type".format(int_param))
#if str_param not int:
raise TypeError("str_param {0} given is invalid type".format(str_param))
#if int_param is an invalid value:
raise ValueError("int_param {0} given is invalid value".format(int_param))
....
and so on. If anyone can see a cleaner way to do this (without a custom Exception type), please let me know!

You can make your own exception:
class SomeObjectException(TypeError):
def __init__(self, msg, which):
TypeError.__init__(self, msg)
self.which = which
Then:
class SomeObject:
def __init__(self, int_param, str_param):
#if parameters are wrong type:
raise SomeObjectException("wrong type", int_param)
And:
if (__name__ == "__main__"):
try:
invalid_obj = SomeObject('two', 'string')
print (invalid_obj)
except SomeObjectException as e:
print (e, e.which)
Also see proper way to declare custom exceptions in modern Python.

class SomeObject:
def __init__(self, int_param, str_param):
if type(int_param) != int:
raise TypeError("int_param: wrong type")
if type(str_param) != str:
raise TypeError("str_param: wrong type")

Maybe you should look for the traceback module.
instead of raise TypeError("wrong type") wrap traceback.print_exc() in try, except and see if that's what you looking for.

Related

How to raise exception inside an exception without the traceback?

I am trying to raise an exception inside the exception, without getting an error message of the outer exception and the traceback and print the hey only. However, I am a quite stuck here if I put a string instead of k or m. Any ideas?
The output, which I would need without the traceback
def division(k, m):
try:
k / m
except TypeError:
raise ValueError ('hey') from None
return k / m
I'm not exactly sure what you are trying to achieve here, but why don't you just print the string "hey" when the TypeError is raised? Like this:
def division(k, m):
try:
k / m
except TypeError:
print("hey")
return None
return k / m
If you need to raise the ValueError for any reason, then you can catch the ValueError where you call the method, I guess:
def division(k, m):
try:
k / m
except TypeError:
raise ValueError
return k / m
try:
division("not_an_int", "could_be_an_int")
except ValueError:
print("hey")
From what I understand, You want a custom exception with a custom message format.
class CustomException(Exception):
def __init__(self, message):
self.message = message # You can also set it by default so you don't need to input any message
super().__init__(self.message)
def __eq__(self, other):
return self.message == other.message
def __str__(self):
return f'{self.message}' # In your case, just to display message.
# return f'Error message: {self.message}'
def division(k, m):
try:
k / m
except TypeError:
raise CustomException(message="hey")
return k / m
try:
division("not_an_int", "could_be_an_int")
except ValueError as e:
print(e)
It is not entirely clear what you are trying to achieve here. You don't get the error message because you raise the exception but because you don't catch it again. If you don't want the error message, you need to catch the exception. Then, if you just want to print the message 'hey' you can get it from the exception args.
try:
division('a', 2)
except ValueError as e:
print(e.args[0])
The raise ... from None already got rid of the first exception, so you are only seeing the ValueError you raise in the except block in division, but if an exception makes it all the way out to the command line, you have to be informed somehow, and Python will do so by printing the error message.
Now, you can change the default behaviour for uncaught exceptions if you want to. This, for example, will print the args[0] for all exceptions you do not explicitly catch.
import sys
def handle_exception(exc_type, exc_value, exc_traceback):
print('handler:', exc_value.args[0])
sys.excepthook = handle_exception
The sys.excepthook is a function Python will call for an uncaught exception. So if you do
try:
division('a', 2)
except ValueError as e:
print('caught:', e)
division('a', 2) # not caught
the first division exception is caught, and the handler isn't invoked, and the second isn't caught and the handler is used (and will just print the message 'hey').
It is not really a great idea to change the way all uncaught exceptions are handled, though. You probably want to handle only your own and use the default behaviour for anything else.
But, as I said, it is not entirely clear to me what you are trying to achieve, so all of the above might be entirely unrelated to the question.

Exception raising does not reflect in test case even though raised as seen in logs

I'm practicing TDD in Python and came across a problem in testing whether an exception is raised.
Here is my test_phonebook.py with test_add_empty_name_raises_exception which fails.
import unittest
import phonebook
class Test(unittest.TestCase):
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
unittest.main()
Below is my phonebook.py with the method add which adds the data into the dictionary.
import re
_phonebook = {}
file_name = "phonebook.txt"
def is_valid_name(name):
return re.search(r"([A-Z][a-z]*)([\\s\\\'-][A-Z][a-z]*)*", name) is not None
def is_valid_number(number):
return re.search(r"\+?[\d ]+$", number) is not None
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
if __name__ == '__main__':
pass
My problem is that the test fails even though it is seen in the console log that there was a ValueError raised within the add method.
Finding files... done.
Importing test modules ... done.
('Invalid arguments.', '', '1111111111')
======================================================================
FAIL: test_add_empty_name_raises_exception (path.to.phonebook.test_phonebook.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "path\to\phonebook\test_phonebook.py", line 13, in test_add_empty_name_raises_exception
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
AssertionError: ValueError not raised
----------------------------------------------------------------------
Ran 1 test in 0.002s
How do I solve this? I there something I forgot?
I also tried using the new format for handling exceptions in tests in Python 2.7 but it still hasn't caught the ValueError raising.
def test_add_empty_name_raises_exception(self):
with self.assertRaises(ValueError):
self.phonebook.add("", "1111111111)
I also changed the form of the test case into using lambdas but still no changes.
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, lambda: phonebook.add("", "1111111111"))
I also cleaned my directory and restarted Eclipse Luna and problem still persists.
Possible solution
I was reading the 8.Errors and Exceptions documentation and got to the "Raising Exceptions" part which states that:
If you need to determine whether an exception was raised but don’t intend to handle it,
a simpler form of the raise statement allows you to re-raise the exception:
I added this to the existing add method as such:
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
raise
Which caused the test case to pass.
Is this the correct way? To call raise again in the except block?
When you catch an exception (in your except ValueError as err: block), you prevent it from continuing back up the call stack to eventually terminate the program. Essentially, you're saying "I know how to handle this, so no need to panic anyone else."
Re-raising an exception is the proper thing to do if you caught the exception but didn't do so to actually fix anything, for instance, to log that it occurred. Typically, though, one catches an exception in order to correct it.
In your case, you're catching the exception almost immediately after you yourself raised it. Why not put your logging statement in the same else block as the raise? No need for a try: ... except: indent at all.
def add(name, number):
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
print "Invalid arguments.", name, number
raise ValueError("Invalid arguments.", name, number)
return

Why isn't my user defined exception being handled properly?

I'm wondering a user defined exception I've raised in my python program from within a class isn't being handled by the correct exception handler within my main(). Say I have a class:
class Pdbalog:
# Constructor
def __init__(self, logtype):
if logtype == 1 or logtype == 2:
# These are valid
self.logtypeV = logtype
...<continue processing>
else:
# Invalid
raise Exception("Invalid Logtype")
My main looks like:
from pdbalog import *
def main():
try:
mylog = Pdbalog(10)
...<other code here>
except "Invalid Logtype":
print('Exiting...')
except:
print('Unhandled exception')
raise
I would expect the when main is run that the line where I instantiate the Pdbalog object would raise an exception (Exception("Invalid Logtype")) and the exception handler in main (except "Invalid Logtype") would print the output string "Exiting...". However, it does not. It is being handled by the unhandled exception handler. What ends up happening is the string "Unhandled exception" is being output. Why isn't the
except "Invalid Logtype":
handling the exception?
I am using an old version of python (2.4).
Exception("Invalid Logtype") is still just an Exception, just now with an error message. "Invalid Logtype" isn't an error, just a str, so you can't catch it.
Try:
class InvalidLogtype(Exception): pass
try:
raise InvalidLogType
except InvalidLogType:
pass
Note that you can catch based on error messages by doing
except Exception, e:
if e.args == ("Invalid Logtype",):
...
else:
raise
Try this instead:
class InvalidLogType(Exception):
pass
then
raise InvalidLogType()
then
except InvalidLogType:
etc

Is there a reason to wrap kwargs.get() with a try except statement in python?

If I define a function, is it ever possible that an exception would be raised for kwargs.get? For example,
def func(**kwargs):
try:
a = kwargs.get("a")
except Exception as e:
raise ValueError("Would I ever see this error? \n ERROR: %s" % e )
No, kwargs.get('somestring') will not raise an exception; you are passed a standard Python dict type in that case.

Python: Custom Exception Class deriving from ValueError

My question seems rather simply, but I didn't find any post to this particular issue. I need my own custom exception class deriving from ValueError to print the expected type (standard error msg) as well as the type that was entered (with custom text).
class MyOwnException(ValueError):
...
try:
raise MyOwnException ( int('str') ) #not sure what to do here, as I only want to
#raise the exception if incorrect value type
except MyOwnException as e:
print "Error: Expected type", e.expType() #int
print "Error: Entered type", e.entType() #string
To add to the above and raising my custom exception via the built-in ValueError:
class MyOwnException(ValueError):
def __init__(self, value):
self.value = value
print "Error: Expected type", type(self.value) #int
print "Error type", self.value #how to return expected value type?
try:
int('str')
except ValueError as e:
raise MyOwnException(e)
I would very much appreatiate any help in this regard. Thanks very much!
Cheers, Manuel
It's generally the case that when raising custom exceptions, you have to catch a more generic exception and re-raise a different one. So for example,
>>> class MoofiError(ValueError):
... pass
...
>>> try:
... int('a')
... except ValueError:
... raise MoofiError, 'you did something wrong, fool'
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
__main__.MoofiError: you did something wrong, fool
The int function will always return a ValueError, rather than your custom type.
In order to throw a different exception, you would have to wrap int to catch ValueError and then raise an exception of your choice (which could include the failing value, as you want).
This code creates a new exception class
class MyOwnException(ValueError): pass
However nothing will make someone else's code raise your exception - you can only raise it in yours.

Categories

Resources