Source code for bag.web.exceptions
"""Exceptions for web development."""
[docs]class Problem(Exception):
"""Great exception class for application-level errors.
Service (or "action") layers should be independent of web frameworks;
however, often I feel I want the service layer to determine the
HTTP code returned by a web service, instead of the controller layer.
So I raise this exception in the service layer and capture it in the
controller layer.
Very useful when coupled with the
`ajax_view decorator <https://github.com/nandoflorestan/bag/blob/master/bag/web/pyramid/views.py>`_, which does the capture part.
When developing a user interface of any kind, it is great when all the
webservices respect a standardized interface for returning errors.
This class outputs these fields by convention:
- error_msg: the string to be displayed to the end user
- error_title: by default the HTTP error title
- error_debug: should NOT be shown to end users; for devs only
"""
HTTP = { # http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
# TODO Complete this map with the remaining 4xx and 5xx
# 4xx Client error
400: "Bad request",
401: "Unauthorized",
403: "Forbidden",
404: "Not found",
409: "Conflict",
410: "Gone",
413: "Request entity too large",
422: "Unprocessable entity",
# 5xx Server error
500: "Internal server error",
}
def __init__( # noqa
self, error_msg, status_int=400, error_title=None, error_debug=None, **kw
):
self.status_int = int(status_int)
assert str(self.status_int)[0] in ("4", "5")
kw["error_title"] = error_title or self.HTTP[self.status_int]
kw["error_msg"] = error_msg
kw["error_debug"] = error_debug
self.kw = kw
[docs] def to_dict(self): # noqa
return self.kw
@property
def error_msg(self): # noqa
return self.kw["error_msg"]
@property
def error_title(self): # noqa
return self.kw["error_title"]
@property
def error_debug(self): # noqa
return self.kw["error_debug"]
def __repr__(self):
return "<{} {}>".format(type(self).__name__, self.error_msg)
def __str__(self):
return self.error_msg
[docs]def ensure(condition, *a, **kw):
"""Use an assert-like syntax to raise Problem exceptions."""
if not condition:
raise Problem(*a, **kw)
[docs]class Unprocessable(Exception):
"""Exception that mimics Colander's Invalid.
...because both have an ``asdict()`` method. However, this one can be
instantiated without a schema. Example usage::
if not data.get('user_email'):
raise Unprocessable(user_email='This field is required.')
"""
def __init__(self, **adict): # noqa
self.adict = adict
[docs] def asdict(self): # noqa
return self.adict