API: initially commit for error handling

~~**NOT READY FOR MERGE**~~

This PR contains the initial error handling API that is fairly similar to numpy's system, and includes a context manager. Currently, only empty table is defined, but adding other error types is easy. In addition, (and I didn't know numpy had this until today), you can define callbacks for errors. I have not incorporated this yet into `Table`, and of course more tests and examples are necessary to add. 

I wanted to get this in now to check if this seems like a viable solution to handling empty tables and other error types. @gregcaporaso @jairideout, I wanted to flag you on this too as this may be more generally useful for use in scikit-bio, though it may be useful to define multiple profiles (e.g., one for `DistanceMatrix`, `TreeNode`, etc). 

Examples of what should be possible with this code once adopted by `Table`:

```python
>>> from biom import example_table
>>> from biom.err import seterr, seterrcall, errstate 
>>> seterr(emptytable='ignore')
>>> # filter to an empty table
>>> t = example_table.filter(lambda v, i, md: v.sum() > 100000000, inplace=False)
>>> # raise if we create an empty table
>>> with errstate(emptytable='raise'):
...    t = example_table.filter(lambda v, i, md: v.sum() > 100000000, inplace=False)
Traceback (most recent call last):
...
biom.exception.TableException: All data was filtered out!
>>> # our original 'ignore' state is back to being valid
>>> t = example_table.filter(lambda v, i, md: v.sum() > 100000000, inplace=False)
>>> # show example of a callback
>>> def callback():
...    print "damnit"
>>> seterrcall('emptytable', callback)   # may want this to be kwarg like seterr
>>> seterr(emptytable='call')
>>> t = example_table.filter(lambda v, i, md: v.sum() > 100000000, inplace=False)
damnit
```
How they are defined are the functions associated with each error type and
state (e.g., 'ignore' has effectively a noop). The handling is the actual
calling of the function if an error is observed. Perhaps it would be better
if the language was changed to "...and performs the actual handling..."?


On Tue, Aug 5, 2014 at 11:05 AM, adamrp <notifications@github.com> wrote:

> In biom/err.py:
>
> > +
> > +
> > +def _create_error_states(msg, callback, exception):
> > +    """Create an error states"""
> > +    return {'ignore': lambda x: None,
> > +            'warn': lambda x: warn(msg),
> > +            'raise': lambda x: exception(msg),
> > +            'call': callback if callback is not None else lambda x: None,
> > +            'print': lambda x: stdout.write(msg + '\n')}
> > +
> > +
> > +class ErrorProfile(object):
> > +    """An error profile
> > +
> > +    The error profile defines the types of errors that can be optionally
> > +    handled, how those errors are handled, and the actual handling of the
>
> What's the difference between how they are handled, and the actual
> handling of them?
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/biocore/biom-format/pull/525/files#r15826225>.
>