What is this about?

behave is a behavior-driven-development (BDD) tool for python that tests whether you have properly implemented the features you have defined in your features file(s). In their tutorial they tell you how you can set it up so that it will drop into ipdb (ipython debugger) when a test fails, but I use pudb and the fish shell (not bash) so this documents what I had to do to get it to work.

How do you do it then?

The first thing to do is create a file named environment.py in the same folder as the features file. Inside of it put the following:
from distutils.util import strtobool as _bool
import os

BEHAVE_DEBUG_ON_ERROR = _bool(os.environ.get("BEHAVE_DEBUG_ON_ERROR",
"no"))
def after_step(context, step):
if BEHAVE_DEBUG_ON_ERROR and step.status == 'failed':
import pudb
pudb.post_mortem(tb=step.exc_traceback,
e_type=None,
e_value=None)
return
This is more-or-less exactly what was in the tutorial except I swapped out pudb for pdb. This code tells behave to run the pudb.post_mortem after a step is finished (a step corresponds to one of the functions you define to implement the tests) if the step failed and your shell has an environment variable named BEHAVE_DEBUG_ON_ERROR and it is set to something that strtobool recognizes as True. This is from the docstring documentation for strtobool:
distutils.util.strtobool(val)
Convert a string representation of truth to true (1) or false (0).
  • True values are y, yes, t, true, on and 1
  • false values are n, no, f, false, off and 0
  • Raises ValueError if val is anything else.
The 'no' in the os.environ.get function means that it won't execute by default. To have it run you need to set the environment variable to one of the 'true' values. In fish this would be:
set -x BEHAVE_DEBUG_ON_ERROR yes
Now when you run behave it will drop into pudb when a test fails.

So, what then?

Using this has so far been less useful than I thought it would be, since it tends to drop me into the pyhamcrest call that failed and although I've managed to step through to the behave code I haven't managed to figure out how to get to my own code. It is still useful, though, since behave will not stop when it encounters a failed test so this makes it easier to figure out what has failed.
Even though the pudb-behave combination is less exciting than I thought it would be, there were several things I learned that I want to document here for later.

Setting an environment variable in fish

To set a fish environment variable:
set -x <variable> <value>
And then unset it:
set -e <variable>
I've done this before to set my PATH variable but for some reason when I tried to search for it this time I got some false-starts at first.

Python's String to Boolean

I also learned that python has a built in way to translate strings to booleans. This isn't really a hard thing to do on your own, but it was an interesting discovery. I don't think I would have looked in distutils for it.

pudb's post_mortem function

Another interesting thing to find out was that pudb has a post_mortem function. I like pudb but it doesn't seem to be well documented. The readme does say that it displays the same interface as python's pdb so I suppose I could just read their documentation, but it seems like one of those things where you have to know what you don't know to know to look for it. In this case I figured out how to call it by looking at the code (it's defined in pudb.__init__.py).

Using environment variables for debugging

Probably the most interesting thing was the way they used os.environ to change the behavior of the code. I normally use command-line options to enable debugging but this might be a better pattern since it pulls it out of the user interface. This means that it won't be as obvious to the user, but I suppose if they're going to debug my code they had better read the documentation and not just rely on --help anyway. I think I'll probably get rid of in in the environment.py file, though, since I want it to run pretty much all the time, but it's an interesting idea anyway.

Conclusion

This was a translation of how to set up a post-mortem debugger for behave using pudb instead of ipdb and fish instead of bash. It is primarily meant to be a record for me to look at in the future, since I don't set up my behave environment on a regular basis and tend to have a hard time re-searching for things (possibly because I use DuckDuckGo so my search history isn't being used). I think the most valuable thing I got out of it was the pattern for setting up debuggers that I think I'll steal (use) for my own code.