Python Behave raise test failure on except [duplicate] - python

I want to explicitly fail the step in behave when I encounter an exception
eg. I am writing the code according to behave documentation -
from behave import *
#when('verify test fails.*?(?P<param_dict>.*)')
def test_logger(context, param_dict):
try:
logger.info("testing the logger. this is info message")
logger.info(1/0)
except Exception as e:
logger.error("arrived at exception: "+str(e))
fail("failed with exception: "+str(e))
but it throws this error:
NameError: name 'fail' is not defined
I tried other ways too, but nothing works
eg. context.failed = True (did not work either)
If I do not try to fail explicitly, final test result becomes PASS even if it goes in exception block ...which is weird.

context.failed is only an attribute set by Behave and doesn't do anything as is. It's an information attribute, and while you can use it to determine a fail-case and throw an assertion error, it will not do anything on it's own. See context.failed
As for the fail method you've mentioned, it is probably from the unittest module, as seen here. This module is used in Behave's development tests (see their Github) as well. I'll agree though, that this should be clarified in their documentation.
To fix your error you'd need to import the unittest module. To explicitly fail the step, you'd just raise the exception after you've logged your message, something like this:
except Exception as e:
logger.error("arrived at exception: "+str(e))
fail("failed with exception: "+str(e))
raise

As #Verv mentioned in their answer, a behave step will be marked as failed whenever an exception is thrown, so you could just re-raise the exception.
However, behave will show the backtrace for normal exceptions, whereas you probably just want to show a specific failure message.
For that, raise an AssertionError. In your code, that would look like this:
except Exception as e:
logger.error("arrived at exception: " + str(e))
raise AssertionError("failed with exception: " + str(e))
If behave encounters an AssertionError, it will fail the step, display the message you instantiate the error with, but not display other exception stuff.

Related

Python catching errors from package, finding out which sublibrary exception belongs in

I've encountered several times now that I want to catch an exception that was raised by some library, but that it takes some time to actually find where that exception resides.
Example
Suppose I want to read some csv-file, except the seperator can be one of 2 values. I'd use:
import pandas
try:
mydf=pandas.read_csv('Somefile.csv', sep=';')
if not someValidityChecks(mydf): raise myExc.NotValidError
except:
mydf=pandas.read_csv('Somefile.csv', sep=',')
Now this code catches any and all exceptions, which is not really what I want (it's not Zen).
What I actually want, is to catch NotValidError, and the exception that is thrown by pandas if it encounters some invalid csv: ParserError.
But except myExc.NotValidError, ParserError won't work, because ParserError is not defined in my context. Instead, it should be pandas.errors.ParserError.
The question
Is there some quick way to find out where an exception is defined?
That there is a ParserError that I should catch, is easy enough to find out by simply letting it be thrown, the errormessage clearly shows that. Yet to find out where that error comes from, I have to dig into the stacktrace, and look at all the imports where it could be defined.
Now pandas doesn't have the most complicated structure, and guessing that the error could be in pandas.errors isn't that hard, but it still takes some time checking. Other libraries might have defined their exceptions at some more unexpected place, or spread all around. It should be easy enough to find out what actual error (including package) was thrown, right?
Environment
I'm working with Anaconda/Spyder 3.3.2, with Python 3.7
The quick way to do this is to print the module of the exception and it's qualified name:
try:
# thing that generates exception
raise pd.errors.ParserError
except Exception as e:
print(type(e).__module__, type(e).__qualname__)
pandas.errors ParserError

Python Exception Handle a Lib

I've been playing around with this but I can't quite seem to figure out the syntax. I'm trying to exception handle a specific exception thrown from an Amazon API lib.
It throws the exception:
class 'amazon.api.AsinNotFound'
I've tried:
except AsinNotFound
and
except amazon.api.AsinNotFound
I can handle it with just an except but I want to be able to catch this specific case if possible. If it's not I could look for the text in sys.exc_info() but that doesn't seem like a neat way of doing it.
Example:
try:
DoSomethingWithASIN
except amazon.api.AsinNotFound:
print "No ASIN"
except:
print "this part triggers instead"

How to handle ConnectionError in Python

Currently I have the problem that I get a NameError for the following code:
try:
# some network programming raising an exception
except ConnectionError:
# some error handling
This does not work, because you have to import ConnectionError from some module, which is not mentioned in the documentation (maybe I'm just blind?).
All I found is this, but it refers to another request library.
All of the exceptions in the standard library that are expected to be "generally usable" are built-ins, and are documented in the Built-in Exceptions part of the library reference.
In 3.3, that includes this one:
exception ConnectionError
A base class for connection-related issues.
Subclasses are BrokenPipeError, ConnectionAbortedError, ConnectionRefusedError and ConnectionResetError.
But this is a built-in. So this should work:
except ConnectionError:
In 3.0-3.2, there is no such exception as ConnectionError. Nothing in the stdlib raises anything of that name. So there's no point in trying to handle it. (See PEP 3151 for an explanation of how OSError and IOError were reorganized between 3.2 and 3.3.)
The 3.2 equivalent of ConnectionError is OSError with certain errno values. So, what you want is something like:
except OSError as e:
if e.errno not in (EPIPE, ESHUTDOWN, ECONNABORTED, ECONNREFUSED, ECONNRESET):
raise
# whatever you wanted to do for ConnectionError.
Meanwhile, in the future, when you don't know what kind of exception you need to handle, it's pretty easy to test. First, write some test code that handles any exception by logging the qualified name of the exception type. Then take the type out of the log and use that in your real code.
try:
code_that_raises()
except Exception as e:
print(type(e), type(e).__qualname__, whatever_else_looks_useful(e))

Test that fails if exception is rised?

How to write a unit test that is considered failed if an exception is risen?
I've found the assertRaises here but it seems to be doing the exact opposite.
Example from Django
If something is wrong with the database the entry.save() will rises an exception.
class TestModel(TestCase):
def test_model_creation(self):
try:
entry = MyModel(name='Bob')
entry.save()
except Exception:
self.assertEqual(0, 1)
The self.assertEqual(0, 1) is just a bad hack for the test to fail if there is an exception. What would be the right way of doing it?
No need to try and except. If a test raises an error then it fails anyway.
Otherwise, see this post about the same thing.

what does the error "no exception supplied" mean?

My Django app is currently throwing this error on one of my pages, does anyone know what it eans? I would supply more detail but I don't know what this error means so I'm not sure what the relevant files are and Django apps are rather large in the amount of code spread around so I'll post some code once I can get an idea of what this means. Thanks in advance for any help.
EDIT: I tried capturing the error and printing it like so:
EDIT: I've entered the code that's throwing the error
jobIDs is a dict containing all of the IDs of the records I want to modify
for i in jobIDs:
dateToRun = request.POST['dateToRun']
timeToRun = request.POST['timeToRun']
try:
if len(request.POST['dateToRun']) <= 0:
dateToRun = Job.objects.filter(id=jobIDs[i]).values()['whenToRun'].split(' ')[0]
if len(request.POST['timeToRun']) <= 0:
timeToRun = Job.objects.filter(id=jobIDs[i]).values()['whenToRun'].split(' ')[1]
except BaseException, e:
print str(e)
whenToRun = dateToRun + ' ' + timeToRun
Job.objects.filter(id=jobIDs[i]).update(whenToRun=whenToRun)
This produces a blank line of output (from the print in the except block), am I misunderstanding how to print out the error?
Are you executing a piece of code that may throw an exception? Perhaps a database query for something that does not exist? If so, you will need to wrap the block of code in a try/except clause. For example, if the exception is indeed a query for something that does not exist:
try:
#Block of code that throws exception
except Object.DoesNotExist:
#Handle error
Perhaps it's because you're using BaseException instead of just Exception? Try this:
try:
# Your code that may throw an exception
except Exception, e:
print str(e)
As per the Python Exception docs on BaseException:
exception BaseException
directly inherited by user-defined classes (for that, use Exception)The base class for all built-in exceptions. It is not meant to be directly inherited by user-defined classes (for that, use Exception).

Categories

Resources