Wrap a function or code block in try/except and automatically call
        ``.captureException`` if it raises an exception, then the exception
        is reraised.

        By default, it will capture ``Exception``

        >>> @client.capture_exceptions
        >>> def foo():
        >>>     raise Exception()

        >>> with client.capture_exceptions():
        >>>    raise Exception()

        You can also specify exceptions to be caught specifically

        >>> @client.capture_exceptions((IOError, LookupError))
        >>> def bar():
        >>>     ...

        ``kwargs`` are passed through to ``.captureException``.

def capture_exceptions(self, f=None, exceptions=None):  # TODO: Ash fix kwargs in base
        """
        Wrap a function or code block in try/except and automatically call
        ``.captureException`` if it raises an exception, then the exception
        is reraised.

        By default, it will capture ``Exception``

        >>> @client.capture_exceptions
        >>> def foo():
        >>>     raise Exception()

        >>> with client.capture_exceptions():
        >>>    raise Exception()

        You can also specify exceptions to be caught specifically

        >>> @client.capture_exceptions((IOError, LookupError))
        >>> def bar():
        >>>     ...

        ``kwargs`` are passed through to ``.captureException``.
        """
        if not isinstance(f, FunctionType):
            # when the decorator has args which is not a function we except
            # f to be the exceptions tuple
            return functools.partial(self.capture_exceptions, exceptions=f)

        exceptions = exceptions or (Exception,)

        @functools.wraps(f)
        def wrapped(event, context, *args, **kwargs):
            try:
                return f(event, context, *args, **kwargs)
            except exceptions:
                self.captureException(event=event, context=context, **kwargs)
                self.context.clear()
                raise
        return wrapped