I'm having some problems implementing an exception system in my program.
I found somewhere the following piece of code that I am trying to use for my program:
class InvalidProgramStateException(Exception):
def __init__(self, expr, msg):
self.expr = expr
self.msg = msg
I think msg must be a string message to be shown, but how do I fill the "expr" when I want to raise this exception? Do I have to write it by hand?
raise InvalidProgramStateException(what_here?, "there was an error")
Your custom exceptions don't actually need to take parameters at all. If you haven't got any particular error message or state to encapsulate in the Exception, this will work just fine:
class MyException(Exception):
pass
This would allow your program to catch cases of this exception by type:
try:
raise MyException()
except MyException:
print "Doing something with MyException"
except:
print "Some other error occurred... handling it differently"
If you want the Exception to have some meaningful string representation, or have properties that would provide your application greater details on what went wrong, that's when you pass additional arguments to the constructor. The number, name and type of these arguments is not really pre-defined by Python... they can be anything. Just be sure to provide a custom __str__ or __unicode__ method so you can provide a meaningful text depiction:
class MyException(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return "MyException with %s" % self.msg
In the case of the example you're quoting, the expr and msg parameters are specific to the fictional case of the example. A contrived scenario for how these might be used is:
def do_something(expr):
if 'foo' in expr:
raise InvalidProgramStateException(expr, "We don't allow foos here")
return 5
user_input = 'foo bar'
try:
do_something(user_input)
except InvalidProgramStateException, e:
print "%s (using expression %s)" % (e.msg, e.expr)
Since it doesn't appear that your application requires it, just drop the parameters you don't require.
Related
I am trying to execute a loop while ignoring exceptions. I think pass or continue will allow me to ignore exceptions in a loop. Where should I put the pass or continue?
class KucoinAPIException(Exception):
"""Exception class to handle general API Exceptions
`code` values
`message` format
"""
def __init__(self, response):
self.code = ''
self.message = 'Unknown Error'
try:
json_res = response.json()
except ValueError:
self.message = response.content
pass
else:
if 'error' in json_res:
self.message = json_res['error']
if 'msg' in json_res:
self.message = json_res['msg']
if 'message' in json_res and json_res['message'] != 'No message available':
self.message += ' - {}'.format(json_res['message'])
if 'code' in json_res:
self.code = json_res['code']
if 'data' in json_res:
try:
self.message += " " + json.dumps(json_res['data'])
except ValueError:
pass
self.status_code = response.status_code
self.response = response
self.request = getattr(response, 'request', None)
def __str__(self):
return 'KucoinAPIException {}: {}'.format(self.code, self.message)
And this doesn't work:
from kucoin.exceptions import KucoinAPIException, KucoinRequestException, KucoinResolutionException
for i in range(10):
# Do kucoin stuff, which might raise an exception.
continue
Quick solution:
Catching the exceptions inside your loop.
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except Exception as e:
print(e)
pass
Adopting best practices:
Note that it is generally considered bad practice to catch all exceptions that inherit from Exception. Instead, determine which exceptions might be raised and handle those. In this case, you probably want to handle your Kucoin exceptions. (KucoinAPIException, KucoinResolutionException, and KucoinRequestException. In which case your loop should look like this:
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except (KucoinAPIException, KucoinRequestException, KucoinResolutionException) as e:
print(e)
pass
We can make the except clause less verbose by refactoring your custom exception hierarchy to inherit from a custom exception class. Say, KucoinException.
class KucoinException(Exception):
pass
class KucoinAPIException(KucoinException):
# ...
class KucoinRequestException(KucoinException):
# ...
class KucoinResolutionException(KucoinException):
# ...
And then your loop would look like this:
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except KucoinException as e:
print(e)
pass
Exception classes aren't designed to handle exceptions. They shouldn't actually have any logic in them. Exception classes essentially function like enums to allow us to quickly and easily differentiate between different types of exceptions.
The logic you have to either raise or ignore an exception should be in your main code flow, not in the exception itself.
You can use finally block to execute the block no matter what.
for i in range(10):
try:
#do something
except:
#catch exceptions
finally:
#do something no matter what
Is that is what you were looking for?
use try except in main block where KucoinAPIException is thrown
for i in range(10):
try:
# do kucoin stuff
# .
# .
# .
except:
pass
Since you mentioned ignoring exceptions I am assuming you would pass all exceptions. So no need to mention individual exceptions at except: line.
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.
I've been thinking about switching from nose to behave for testing (mocha/chai etc have spoiled me). So far so good, but I can't seem to figure out any way of testing for exceptions besides:
#then("It throws a KeyError exception")
def step_impl(context):
try:
konfigure.load_env_mapping("baz", context.configs)
except KeyError, e:
assert (e.message == "No baz configuration found")
With nose I can annotate a test with
#raises(KeyError)
I can't find anything like this in behave (not in the source, not in the examples, not here). It sure would be grand to be able to specify exceptions that might be thrown in the scenario outlines.
Anyone been down this path?
I'm pretty new to BDD myself, but generally, the idea would be that the tests document what behaves the client can expect - not the step implementations. So I'd expect the canonical way to test this would be something like:
When I try to load config baz
Then it throws a KeyError with message "No baz configuration found"
With steps defined like:
#when('...')
def step(context):
try:
# do some loading here
context.exc = None
except Exception, e:
context.exc = e
#then('it throws a {type} with message "{msg}"')
def step(context, type, msg):
assert isinstance(context.exc, eval(type)), "Invalid exception - expected " + type
assert context.exc.message == msg, "Invalid message - expected " + msg
If that's a common pattern, you could just write your own decorator:
def catch_all(func):
def wrapper(context, *args, **kwargs):
try:
func(context, *args, **kwargs)
context.exc = None
except Exception, e:
context.exc = e
return wrapper
#when('... ...')
#catch_all
def step(context):
# do some loading here - same as before
This try/catch approach by Barry works, but I see some issues:
Adding a try/except to your steps means that errors will be hidden.
Adding an extra decorator is inelegant. I would like my decorator to be a modified #where
My suggestion is to
have the expect exception before the failing statement
in the try/catch, raise if the error was not expected
in the after_scenario, raise error if expected error not found.
use the modified given/when/then everywhere
Code:
def given(regexp):
return _wrapped_step(behave.given, regexp) #pylint: disable=no-member
def then(regexp):
return _wrapped_step(behave.then, regexp) #pylint: disable=no-member
def when(regexp):
return _wrapped_step(behave.when, regexp) #pylint: disable=no-member
def _wrapped_step(step_function, regexp):
def wrapper(func):
"""
This corresponds to, for step_function=given
#given(regexp)
#accept_expected_exception
def a_given_step_function(context, ...
"""
return step_function(regexp)(_accept_expected_exception(func))
return wrapper
def _accept_expected_exception(func):
"""
If an error is expected, check if it matches the error.
Otherwise raise it again.
"""
def wrapper(context, *args, **kwargs):
try:
func(context, *args, **kwargs)
except Exception, e: #pylint: disable=W0703
expected_fail = context.expected_fail
# Reset expected fail, only try matching once.
context.expected_fail = None
if expected_fail:
expected_fail.assert_exception(e)
else:
raise
return wrapper
class ErrorExpected(object):
def __init__(self, message):
self.message = message
def get_message_from_exception(self, exception):
return str(exception)
def assert_exception(self, exception):
actual_msg = self.get_message_from_exception(exception)
assert self.message == actual_msg, self.failmessage(exception)
def failmessage(self, exception):
msg = "Not getting expected error: {0}\nInstead got{1}"
msg = msg.format(self.message, self.get_message_from_exception(exception))
return msg
#given('the next step shall fail with')
def expect_fail(context):
if context.expected_fail:
msg = 'Already expecting failure:\n {0}'.format(context.expected_fail.message)
context.expected_fail = None
util.show_gherkin_error(msg)
context.expected_fail = ErrorExpected(context.text)
I import my modified given/then/when instead of behave, and add to my environment.py initiating context.expected fail before scenario and checking it after:
def after_scenario(context, scenario):
if context.expected_fail:
msg = "Expected failure not found: %s" % (context.expected_fail.message)
util.show_gherkin_error(msg)
The try / except approach you show is actually completely correct because it shows the way that you would actually use the code in real life. However, there's a reason that you don't completely like it. It leads to ugly problems with things like the following:
Scenario: correct password accepted
Given that I have a correct password
When I attempt to log in
Then I should get a prompt
Scenario: incorrect password rejected
Given that I have an incorrect password
When I attempt to log in
Then I should get an exception
If I write the step definition without try/except then the second scenario will fail. If I write it with try/except then the first scenario risks hiding an exception, especially if the exception happens after the prompt has already been printed.
Instead those scenarios should, IMHO, be written as something like
Scenario: correct password accepted
Given that I have a correct password
When I log in
Then I should get a prompt
Scenario: correct password accepted
Given that I have a correct password
When I try to log in
Then I should get an exception
The "I log in" step should not use try; The "I try to log in" matches neatly to try and gives away the fact that there might not be success.
Then there comes the question about code reuse between the two almost, but not quite identical steps. Probably we don't want to have two functions which both login. Apart from simply having a common other function you call, you could also do something like this near the end of your step file.
#when(u'{who} try to {what}')
def step_impl(context):
try:
context.execute_steps("when" + who + " " + what)
context.exception=None
except Exception as e:
context.exception=e
This will automatically convert all steps containing the word "try to" into steps with the same name but with try to deleted and then protect them with a try/except.
There are some questions about when you actually should deal with exceptions in BDD since they aren't user visible. It's not part of the answer to this question though so I've put them in a separate posting.
Behave is not in the assertion matcher business. Therefore, it does not provide a solution for this. There are already enough Python packages that solve this problem.
SEE ALSO: behave.example: Select an assertion matcher library
Hi im currently doing a program like this.
class MyError(Exception):
def __init__(self, text = "Correct")
self.text = text
def __str__(self):
return (self.kod)
class Atom(self):
.
.
.
try:
function()
else:
raise MyError("Incorrect use of function")
def main():
try:
a = Atom()
except:
# Here i want to print the error that was raised
What I think I understand is that the error is raised in an object created in Atom().
But I want to send it to my main program and do the print of the error MyError there.
Is it possible to do this and how should I write it so that the correct text of exception is printed since i will have several different error messages.
If i come to the except statement I would want to get the message "Incorrect use of function" printed.
It seems that you're pretty close:
class MyError(Exception):
def __init__(self, text = "Correct")
self.text = text
def __str__(self):
return (self.kod)
class Atom(self):
.
.
.
try:
function()
except: # try: ... else: raise ... seems a bit funky to me.
raise MyError("Incorrect use of function")
def main():
try:
a = Atom()
except Exception as err: # Possibly `except MyError as err` to be more specific
print err
The trick is that when you catch the error, you want to bind the exception instance to a name using the as clause. Then you can print it, look at it's attributes, re-raise or pretty much do anything you choose with it.
Please note that this code still isn't "clean". Generally, you want to limit exception handling as much as possible -- only catch exceptions that expect to see and that you know how to handle. Otherwise, you can sometimes mask hard to find bugs in your code. Because of this:
try:
do_something()
except:
...
is discouraged (it catches all sorts of things like KeyboardInterrupt and SystemExit) ... Instead:
try:
do_something()
except ExceptionIKnowHowToHandle:
...
is advised.
Firstly, never do a blank except. That will catch all errors, including things like KeyboardInterrupt - so you won't be able to ctrl-c out of your program. Here you should just catch MyError.
The except clause also allows you to assign the actual exception to a variable, which you can then print or do anything else with. So you can do:
try:
...
except MyError as e:
print e.text
I am customizing exceptions in my python code. I have inherited exception class in to other and now defining some custom errors as classes derived from my custom exception class like this:
class DataCollectorError(Exception): pass
class ParamNullError(DataCollectorError) : pass
class ParamInvalidTypeError(DataCollectorError) : pass
I am raising these exceptions in my python function like:
def READ_METER_DATA (regIndex, numRegisters, slaveUnit):
try:
if not regIndex:
raise ParamNullError, "register index is null"
if not numRegisters:
raise ParamNullError, "number of registers should not be null"
if not slaveUnit:
raise ParamNullError, "Meter Id should not be null"
and logging error like :
except DataCollectorError as d:
lgr.error('DataCollector Error(READ_METER_DATA): '+d.args[0])
print 'DataCollector Error:(READ_METER_DATA)', d.args[0]
except:
lgr.error('Unexpected Error: ', sys.exc_info())
print 'Unexpected Error: ', sys.exc_info()
pass
but this defeats purpose of unit testing script as it doesn't whether exception raised bcz it is being catched by my catch block before my unit test script knows it. so i wanted to log these errors in base class itself -
Class ParamNullError(DataCollectorError):
<----here----------->
pass
can anybody tell me how to fetch that string passed while raising exception?
Simply extend your error-class with an __init__ and an __str__ method.
Example:
class DataCollectorError(Exception):
def __init__(self, msg=''):
self.msg = msg
log(msg) # use your logging things here
def __str__(self):
return self.msg
Use msg='' because then you don't need to always specify a message.
Don't.
Factor out the calls you need to unit test, and move your exception handler out:
try:
testableFunctionCall()
except:
lgr.exception('Unexpected Error')
and test testableFunctionCall().
Alternatively, use the testfixtures library to test the logging itself:
from testfixtures import LogCapture
with LogCapture() as l:
callFunctionUnderTest()
l.check(
('packagename', 'ERROR', 'DataCollector Error(READ_METER_DATA): foobar'),
)