diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f15edb22..d6a25a71 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.4.5 +current_version = 2.4.6 [bumpversion:file:.env] diff --git a/.env b/.env index a92dd495..dff052fb 100644 --- a/.env +++ b/.env @@ -11,7 +11,7 @@ fi export PROJECT_NAME=$OPEN_PROJECT_NAME export PROJECT_DIR="$PWD" -export PROJECT_VERSION="2.4.5" +export PROJECT_VERSION="2.4.6" if [ ! -d "venv" ]; then if ! hash pyvenv 2>/dev/null; then diff --git a/CHANGELOG.md b/CHANGELOG.md index dd940c51..fa62c25a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ Ideally, within a virtual environment. Changelog ========= +### 2.4.6 - March 25, 2019 +- Fixed issue #753 - 404 not found does not respect default output format. +- Documented the `--without-cython` option in `CONTRIBUTING.md` +- Extended documentation for output formats + ### 2.4.4 - March 21, 2019 - Added the ability to change the default output format for CLI endpoints both at the API and global level. - Added the ablity to extend CLI APIs in addition to HTTP APIs issue #744. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2b57035..24ed0dbc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,20 @@ Once you have verified that you system matches the base requirements you can sta - If you don't have autoenv set-up, run `source .env` to set up the local environment. You will need to run this script every time you want to work on the project - though it will not cause the entire set up process to re-occur. 4. Run `test` to verify your everything is set up correctly. If the tests all pass, you have successfully set up hug for local development! If not, you can ask for help diagnosing the error [here](https://gitter.im/timothycrosley/hug). +At step 3, you can skip using autoenv and the `.env` script, +and create your development virtul environment manually instead +using e.g. [`python3 -m venv`](https://docs.python.org/3/library/venv.html) +or `mkvirtualenv` (from [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)). + +Install dependencies by running `pip install -r requirements/release.txt`, +and optional build or development dependencies +by running `pip install -r requirements/build.txt` +or `pip install -r requirements/build.txt`. + +Install Hug itself with `pip install .` or `pip install -e .` (for editable mode). +This will compile all modules with [Cython](https://cython.org/) if it's installed in the environment. +You can skip Cython compilation using `pip install --without-cython .` (this works with `-e` as well). + Making a contribution ========= Congrats! You're now ready to make a contribution! Use the following as a guide to help you reach a successful pull-request: diff --git a/documentation/OUTPUT_FORMATS.md b/documentation/OUTPUT_FORMATS.md index 5b16c355..2d2cf920 100644 --- a/documentation/OUTPUT_FORMATS.md +++ b/documentation/OUTPUT_FORMATS.md @@ -3,7 +3,7 @@ hug output formats Every endpoint that is exposed through an externally facing interface will need to return data in a standard, easily understandable format. -The default output format for all hug APIs is JSON. However, you may explicitly specify a different default output_format: +The default output format for all hug APIs is JSON. However, you may explicitly specify a different default output_format for a particular API: hug.API(__name__).http.output_format = hug.output_format.html @@ -13,7 +13,14 @@ or: def my_output_formatter(data, request, response): # Custom output formatting code -Or, to specify an output_format for a specific endpoint, simply specify the output format within its router: +By default, this only applies to the output format of HTTP responses. +To change the output format of the command line interface: + + @hug.default_output_format(cli=True, http=False) + def my_output_formatter(data, request, response): + # Custom output formatting code + +To specify an output_format for a specific endpoint, simply specify the output format within its router: @hug.get(output=hug.output_format.html) def my_endpoint(): @@ -42,6 +49,29 @@ Finally, an output format may be a collection of different output formats that g In this case, if the endpoint is accessed via my_endpoint.js, the output type will be JSON; however if it's accessed via my_endoint.html, the output type will be HTML. +You can also change the default output format globally for all APIs with either: + + @hug.default_output_format(apply_globally=True, cli=True, http=True) + def my_output_formatter(data, request, response): + # Custom output formatting code + +or: + + hug.defaults.output_format = hug.output_format.html # for HTTP + hug.defaults.cli_output_format = hug.output_format.html # for the CLI + +Note that when extending APIs, changing the default output format globally must be done before importing the modules of any of the sub-APIs: + + hug.defaults.cli_output_format = hug.output_format.html + + from my_app import my_sub_api + + @hug.extend_api() + def extended(): + return [my_sub_api] + + + Built-in hug output formats =================== diff --git a/hug/_version.py b/hug/_version.py index 5217fecd..85d39a45 100644 --- a/hug/_version.py +++ b/hug/_version.py @@ -21,4 +21,4 @@ """ from __future__ import absolute_import -current = "2.4.5" +current = "2.4.6" diff --git a/hug/api.py b/hug/api.py index 09d74ef7..2a006a1f 100644 --- a/hug/api.py +++ b/hug/api.py @@ -305,9 +305,16 @@ def handle_404(request, response, *args, **kwargs): "Here's a definition of the API to help you get going :)") to_return['documentation'] = self.documentation(base_url, self.determine_version(request, False), prefix=url_prefix) - response.data = hug.output_format.json(to_return, indent=4, separators=(',', ': ')) + + if self.output_format == hug.output_format.json: + response.data = hug.output_format.json(to_return, indent=4, separators=(',', ': ')) + response.content_type = 'application/json; charset=utf-8' + else: + response.data = self.output_format(to_return) + response.content_type = self.output_format.content_type + response.status = falcon.HTTP_NOT_FOUND - response.content_type = 'application/json; charset=utf-8' + handle_404.interface = True return handle_404 diff --git a/setup.py b/setup.py index 6aaf8b0d..d756c7f9 100755 --- a/setup.py +++ b/setup.py @@ -75,7 +75,7 @@ def list_modules(dirname): setup( name='hug', - version='2.4.5', + version='2.4.6', description='A Python framework that makes developing APIs ' 'as simple as possible, but no simpler.', long_description=long_description, diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 6e5b110d..1c1896b8 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -307,30 +307,32 @@ def accepts_get_and_post(): assert 'method not allowed' in hug.test.trace(api, 'accepts_get_and_post').status.lower() -def test_not_found(): +def test_not_found(hug_api): """Test to ensure the not_found decorator correctly routes 404s to the correct handler""" - @hug.not_found() + @hug.not_found(api=hug_api) def not_found_handler(): return "Not Found" - result = hug.test.get(api, '/does_not_exist/yet') + result = hug.test.get(hug_api, '/does_not_exist/yet') assert result.data == "Not Found" assert result.status == falcon.HTTP_NOT_FOUND - @hug.not_found(versions=10) # noqa + @hug.not_found(versions=10, api=hug_api) # noqa def not_found_handler(response): response.status = falcon.HTTP_OK return {'look': 'elsewhere'} - result = hug.test.get(api, '/v10/does_not_exist/yet') + result = hug.test.get(hug_api, '/v10/does_not_exist/yet') assert result.data == {'look': 'elsewhere'} assert result.status == falcon.HTTP_OK - result = hug.test.get(api, '/does_not_exist/yet') + result = hug.test.get(hug_api, '/does_not_exist/yet') assert result.data == "Not Found" assert result.status == falcon.HTTP_NOT_FOUND - del api.http._not_found_handlers + hug_api.http.output_format = hug.output_format.text + result = hug.test.get(hug_api, '/v10/does_not_exist/yet') + assert result.data == "{'look': 'elsewhere'}" def test_not_found_with_extended_api():