Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Make error initializers more consistent #1655

Merged
merged 29 commits into from Feb 15, 2020
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4d6873d
refactor(errors.py): unify init signature of the error classes
CaselIT Jan 25, 2020
137cee8
refactor(errors.py): remove NoRepresentation, HTTPRangeNotSatisfiable…
CaselIT Jan 25, 2020
2ac519f
refactor(errors.py): use py3 style super
CaselIT Jan 25, 2020
7bab132
test(errors): add tests to changes in errors, update other tests
CaselIT Jan 25, 2020
0ffb44b
chore(news): add news fragment for changelog
CaselIT Jan 25, 2020
c98c7f3
docs: remove references to NoRepresentation in documentation
CaselIT Jan 25, 2020
ea554a3
Merge branch 'master' into fix-777-errors
kgriffs Jan 26, 2020
8a95c65
Merge branch 'master' into fix-777-errors
vytas7 Jan 26, 2020
569cabf
refactor(errors): make the arguments kwonly
CaselIT Jan 26, 2020
6695d36
refactor(errors): ensure that the arguments of the error override the…
CaselIT Jan 26, 2020
a48e8c5
docs(errors): update error documentation adding kw arguments
CaselIT Jan 26, 2020
a55f940
refactor(error): use kw args when creating errors
CaselIT Jan 26, 2020
5e04469
chore(cython): fix errors on cython
CaselIT Jan 26, 2020
055cb04
refactor(errors): make the arguments kwonly in httperror
CaselIT Jan 26, 2020
992a2b3
docs(errors): update error documentation adding kw arguments to httpe…
CaselIT Jan 26, 2020
f3aefc4
chore(pep): fix pep errors
CaselIT Jan 26, 2020
2fef4e4
docs(news): update new for changelog
CaselIT Jan 26, 2020
c0b2ec6
fix(errors): allow a list of two tuples as the headers of the errors …
CaselIT Jan 29, 2020
af547cd
docs(error): add note about headers
CaselIT Feb 1, 2020
f1d1765
test(httperror): add missing test
CaselIT Feb 1, 2020
4109f27
Merge branch 'master' into fix-777-errors
CaselIT Feb 4, 2020
6969e0c
refactor(errors): deprecate positional arguments instead of making th…
CaselIT Feb 4, 2020
89e137a
style(pep8): fix pep8 errors
CaselIT Feb 5, 2020
e875d15
chore: add missing tests and address review
CaselIT Feb 5, 2020
ab3645a
docs: be polite
CaselIT Feb 5, 2020
c13bd66
docs(changelog): update changelog
CaselIT Feb 8, 2020
9fef3b3
docs(changelog): address review comments
CaselIT Feb 11, 2020
769de42
Merge branch 'master' into fix-777-errors
kgriffs Feb 12, 2020
8793055
Merge branch 'master' into fix-777-errors
kgriffs Feb 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 20 additions & 20 deletions README.rst
Expand Up @@ -455,8 +455,8 @@ bodies.
'database. It worked on my box.')

raise falcon.HTTPError(falcon.HTTP_725,
'Database Error',
description)
title='Database Error',
description=description)


class SinkAdapter:
Expand Down Expand Up @@ -488,18 +488,18 @@ bodies.
description = ('Please provide an auth token '
'as part of the request.')

raise falcon.HTTPUnauthorized('Auth token required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Auth token required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

if not self._token_is_valid(token, account_id):
description = ('The provided auth token is not valid. '
'Please request a new token and try again.')

raise falcon.HTTPUnauthorized('Authentication required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Authentication required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

def _token_is_valid(self, token, account_id):
Expand All @@ -511,13 +511,13 @@ bodies.
def process_request(self, req, resp):
if not req.client_accepts_json:
raise falcon.HTTPNotAcceptable(
'This API only supports responses encoded as JSON.',
title='This API only supports responses encoded as JSON.',
href='http://docs.examples.com/api/json')

if req.method in ('POST', 'PUT'):
if 'application/json' not in req.content_type:
raise falcon.HTTPUnsupportedMediaType(
'This API only supports requests encoded as JSON.',
title='This API only supports requests encoded as JSON.',
href='http://docs.examples.com/api/json')


Expand All @@ -537,16 +537,16 @@ bodies.

body = req.stream.read()
if not body:
raise falcon.HTTPBadRequest('Empty request body',
'A valid JSON document is required.')
raise falcon.HTTPBadRequest(title='Empty request body',
description='A valid JSON document is required.')

try:
req.context.doc = json.loads(body.decode('utf-8'))

except (ValueError, UnicodeDecodeError):
raise falcon.HTTPError(falcon.HTTP_753,
'Malformed JSON',
'Could not decode the request body. The '
title='Malformed JSON',
description='Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.')

Expand All @@ -566,7 +566,7 @@ bodies.
'exceed ' + str(limit) + ' bytes in length.')

raise falcon.HTTPPayloadTooLarge(
'Request body is too large', msg)
title='Request body is too large', description=msg)

return hook

Expand All @@ -591,9 +591,9 @@ bodies.
'We appreciate your patience.')

raise falcon.HTTPServiceUnavailable(
'Service Outage',
description,
30)
title='Service Outage',
description=description,
retry_after=30)

# NOTE: Normally you would use resp.media for this sort of thing;
# this example serves only to demonstrate how the context can be
Expand All @@ -610,8 +610,8 @@ bodies.
doc = req.context.doc
except AttributeError:
raise falcon.HTTPBadRequest(
'Missing thing',
'A thing must be submitted in the request body.')
title='Missing thing',
description='A thing must be submitted in the request body.')

proper_thing = self.db.add_thing(doc)

Expand Down
3 changes: 3 additions & 0 deletions docs/_newsfragments/777.feature.rst
@@ -0,0 +1,3 @@
The error classes in ``falcon.errors`` were updated to have the ``title`` and
``description`` keyword arguments and to correctly handle headers passed as
list of tuples
2 changes: 2 additions & 0 deletions docs/_newsfragments/777.misc.rst
@@ -0,0 +1,2 @@
Deprecate the use of positional arguments for the optional kw args of
the HTTPError subclasses
2 changes: 2 additions & 0 deletions docs/_newsfragments/777.removal.rst
@@ -0,0 +1,2 @@
The class :class:`~.falcon.http_error.NoRepresentation` was removed since
all :class:`~.falcon.HTTPError` have optional representation.
6 changes: 3 additions & 3 deletions docs/api/errors.rst
Expand Up @@ -54,8 +54,8 @@ All classes are available directly in the ``falcon`` package namespace::
# ...

raise falcon.HTTPBadRequest(
"TTL Out of Range",
"The message's TTL must be between 60 and 300 seconds, inclusive."
title="TTL Out of Range",
description="The message's TTL must be between 60 and 300 seconds, inclusive."
)

# ...
Expand All @@ -79,7 +79,7 @@ Base Class
Mixins
------

.. autoclass:: falcon.http_error.NoRepresentation
.. autoclass:: falcon.http_error.OptionalRepresentation
:members:

.. _predefined_errors:
Expand Down
4 changes: 2 additions & 2 deletions docs/api/hooks.rst
Expand Up @@ -15,7 +15,7 @@ an image resource:
def validate_image_type(req, resp, resource, params):
if req.content_type not in ALLOWED_IMAGE_TYPES:
msg = 'Image type not allowed. Must be PNG, JPEG, or GIF'
raise falcon.HTTPBadRequest('Bad request', msg)
raise falcon.HTTPBadRequest(title='Bad request', description=msg)

You would attach this hook to an ``on_post`` responder like so:

Expand Down Expand Up @@ -56,7 +56,7 @@ as needed:
def validate_image_type(req, resp, resource, params, allowed_types):
if req.content_type not in allowed_types:
msg = 'Image type not allowed.'
raise falcon.HTTPBadRequest('Bad request', msg)
raise falcon.HTTPBadRequest(title='Bad request', description=msg)

@falcon.before(validate_image_type, ['image/png'])
def on_post(self, req, resp):
Expand Down
40 changes: 20 additions & 20 deletions docs/user/quickstart.rst
Expand Up @@ -112,8 +112,8 @@ parameters, handling errors, and working with request and response bodies.
'database. It worked on my box.')

raise falcon.HTTPError(falcon.HTTP_725,
'Database Error',
description)
title='Database Error',
description=description)


class SinkAdapter:
Expand Down Expand Up @@ -145,18 +145,18 @@ parameters, handling errors, and working with request and response bodies.
description = ('Please provide an auth token '
'as part of the request.')

raise falcon.HTTPUnauthorized('Auth token required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Auth token required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

if not self._token_is_valid(token, account_id):
description = ('The provided auth token is not valid. '
'Please request a new token and try again.')

raise falcon.HTTPUnauthorized('Authentication required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Authentication required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

def _token_is_valid(self, token, account_id):
Expand All @@ -168,13 +168,13 @@ parameters, handling errors, and working with request and response bodies.
def process_request(self, req, resp):
if not req.client_accepts_json:
raise falcon.HTTPNotAcceptable(
'This API only supports responses encoded as JSON.',
title='This API only supports responses encoded as JSON.',
href='http://docs.examples.com/api/json')

if req.method in ('POST', 'PUT'):
if 'application/json' not in req.content_type:
raise falcon.HTTPUnsupportedMediaType(
'This API only supports requests encoded as JSON.',
title='This API only supports requests encoded as JSON.',
href='http://docs.examples.com/api/json')


Expand All @@ -194,16 +194,16 @@ parameters, handling errors, and working with request and response bodies.

body = req.stream.read()
if not body:
raise falcon.HTTPBadRequest('Empty request body',
'A valid JSON document is required.')
raise falcon.HTTPBadRequest(title='Empty request body',
description='A valid JSON document is required.')

try:
req.context.doc = json.loads(body.decode('utf-8'))

except (ValueError, UnicodeDecodeError):
raise falcon.HTTPError(falcon.HTTP_753,
'Malformed JSON',
'Could not decode the request body. The '
title='Malformed JSON',
description='Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.')

Expand All @@ -223,7 +223,7 @@ parameters, handling errors, and working with request and response bodies.
'exceed ' + str(limit) + ' bytes in length.')

raise falcon.HTTPPayloadTooLarge(
'Request body is too large', msg)
title='Request body is too large', description=msg)

return hook

Expand All @@ -248,9 +248,9 @@ parameters, handling errors, and working with request and response bodies.
'We appreciate your patience.')

raise falcon.HTTPServiceUnavailable(
'Service Outage',
description,
30)
title='Service Outage',
description=description,
retry_after=30)

# NOTE: Normally you would use resp.media for this sort of thing;
# this example serves only to demonstrate how the context can be
Expand All @@ -267,8 +267,8 @@ parameters, handling errors, and working with request and response bodies.
doc = req.context.doc
except AttributeError:
raise falcon.HTTPBadRequest(
'Missing thing',
'A thing must be submitted in the request body.')
title='Missing thing',
description='A thing must be submitted in the request body.')

proper_thing = self.db.add_thing(doc)

Expand Down
2 changes: 1 addition & 1 deletion docs/user/tutorial.rst
Expand Up @@ -1293,7 +1293,7 @@ message. Add this method below the definition of ``ALLOWED_IMAGE_TYPES``:
def validate_image_type(req, resp, resource, params):
if req.content_type not in ALLOWED_IMAGE_TYPES:
msg = 'Image type not allowed. Must be PNG, JPEG, or GIF'
raise falcon.HTTPBadRequest('Bad request', msg)
raise falcon.HTTPBadRequest(title='Bad request', description=msg)

And then attach the hook to the ``on_post()`` responder:

Expand Down
40 changes: 20 additions & 20 deletions examples/things_advanced.py
Expand Up @@ -26,8 +26,8 @@ def handle(ex, req, resp, params):
'database. It worked on my box.')

raise falcon.HTTPError(falcon.HTTP_725,
'Database Error',
description)
title='Database Error',
description=description)


class SinkAdapter:
Expand Down Expand Up @@ -59,18 +59,18 @@ def process_request(self, req, resp):
description = ('Please provide an auth token '
'as part of the request.')

raise falcon.HTTPUnauthorized('Auth token required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Auth token required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

if not self._token_is_valid(token, account_id):
description = ('The provided auth token is not valid. '
'Please request a new token and try again.')

raise falcon.HTTPUnauthorized('Authentication required',
description,
challenges,
raise falcon.HTTPUnauthorized(title='Authentication required',
description=description,
challenges=challenges,
href='http://docs.example.com/auth')

def _token_is_valid(self, token, account_id):
Expand All @@ -82,13 +82,13 @@ class RequireJSON:
def process_request(self, req, resp):
if not req.client_accepts_json:
raise falcon.HTTPNotAcceptable(
'This API only supports responses encoded as JSON.',
title='This API only supports responses encoded as JSON.',
href='http://docs.examples.com/api/json')

if req.method in ('POST', 'PUT'):
if 'application/json' not in req.content_type:
raise falcon.HTTPUnsupportedMediaType(
'This API only supports requests encoded as JSON.',
title='This API only supports requests encoded as JSON.',
href='http://docs.examples.com/api/json')


Expand All @@ -108,16 +108,16 @@ def process_request(self, req, resp):

body = req.stream.read()
if not body:
raise falcon.HTTPBadRequest('Empty request body',
'A valid JSON document is required.')
raise falcon.HTTPBadRequest(title='Empty request body',
description='A valid JSON document is required.')

try:
req.context.doc = json.loads(body.decode('utf-8'))

except (ValueError, UnicodeDecodeError):
raise falcon.HTTPError(falcon.HTTP_753,
'Malformed JSON',
'Could not decode the request body. The '
title='Malformed JSON',
description='Could not decode the request body. The '
'JSON was incorrect or not encoded as '
'UTF-8.')

Expand All @@ -137,7 +137,7 @@ def hook(req, resp, resource, params):
'exceed ' + str(limit) + ' bytes in length.')

raise falcon.HTTPPayloadTooLarge(
'Request body is too large', msg)
title='Request body is too large', description=msg)

return hook

Expand All @@ -162,9 +162,9 @@ def on_get(self, req, resp, user_id):
'We appreciate your patience.')

raise falcon.HTTPServiceUnavailable(
'Service Outage',
description,
30)
title='Service Outage',
description=description,
retry_after=30)

# NOTE: Normally you would use resp.media for this sort of thing;
# this example serves only to demonstrate how the context can be
Expand All @@ -181,8 +181,8 @@ def on_post(self, req, resp, user_id):
doc = req.context.doc
except AttributeError:
raise falcon.HTTPBadRequest(
'Missing thing',
'A thing must be submitted in the request body.')
title='Missing thing',
description='A thing must be submitted in the request body.')

proper_thing = self.db.add_thing(doc)

Expand Down
3 changes: 2 additions & 1 deletion falcon/app.py
Expand Up @@ -732,7 +732,8 @@ def set_error_serializer(self, serializer):
The default serializer will not render any response body for
:class:`~.HTTPError` instances where the `has_representation`
property evaluates to ``False`` (such as in the case of types
that subclass :class:`falcon.http_error.NoRepresentation`).
that subclass :class:`falcon.http_error.OptionalRepresentation`
and do not provide a description).
However a custom serializer will be called regardless of the
property value, and it may choose to override the
representation logic.
Expand Down