Repository: falconry/falcon
Pull request #1094 (2017-08-04 19:45:00)

fix(constants): Clean up charset params in MEDIA_* and add MEDIA_GIF

codecov[bot]: # [Codecov](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=h1) Report
> Merging [#1094](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=desc) into [master](https://codecov.io/gh/falconry/falcon/commit/5036cd0baba2e5de30b8858853c8f73e52c6fcc4?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/falconry/falcon/pull/1094/graphs/tree.svg?width=650&height=150&src=pr&token=zOtkfNQ3h6)](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master   #1094   +/-   ##
======================================
  Coverage     100%    100%           
======================================
  Files          38      38           
  Lines        2417    2418    +1     
  Branches      343     343           
======================================
+ Hits         2417    2418    +1
```


| [Impacted Files](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [falcon/response.py](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=tree#diff-ZmFsY29uL3Jlc3BvbnNlLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [falcon/constants.py](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=tree#diff-ZmFsY29uL2NvbnN0YW50cy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [falcon/bench/queues/api.py](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=tree#diff-ZmFsY29uL2JlbmNoL3F1ZXVlcy9hcGkucHk=) | `100% <0%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=footer). Last update [5036cd0...af1e065](https://codecov.io/gh/falconry/falcon/pull/1094?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/docs/user/tutorial.rst b/docs/user/tutorial.rst
index aad13d6..ff48ad5 100644
--- a/docs/user/tutorial.rst
+++ b/docs/user/tutorial.rst
@@ -378,10 +378,10 @@ realize a small performance gain by assigning directly to ``resp.data``.
 
 Also note the use of ``falcon.MEDIA_MSGPACK``. The ``falcon`` module
 provides a number of constants for common media types, including
-``falcon.MEDIA_JSON``, ``falcon.MEDIA_HTML``, ``falcon.MEDIA_JS``,
-``falcon.MEDIA_XML``, ``falcon.MEDIA_TEXT``, ``falcon.MEDIA_JPEG``,
-``falcon.MEDIA_PNG``, ``falcon.MEDIA_YAML`` and
-``falcon.MEDIA_MSGPACK``.
+``falcon.MEDIA_JSON``, ``falcon.MEDIA_MSGPACK``, ``falcon.MEDIA_YAML``,
+``falcon.MEDIA_XML``, ``falcon.MEDIA_HTML``, ``falcon.MEDIA_JS``,
+``falcon.MEDIA_TEXT``, ``falcon.MEDIA_JPEG``, ``falcon.MEDIA_PNG``,
+and ``falcon.MEDIA_GIF``.
 
 Restart Gunicorn (unless you're using ``--reload``), and then try
 sending a GET request to the revised resource:
diff --git a/falcon/api.py b/falcon/api.py
index 0806fad..725d5d1 100644
--- a/falcon/api.py
+++ b/falcon/api.py
@@ -39,7 +39,8 @@ class API(object):
             value for the Content-Type header on responses (default
             'application/json'). The ``falcon`` module provides a
             number of constants for common media types, such as
-            ``falcon.MEDIA_YAML``, ``falcon.MEDIA_XML``, etc.
+            ``falcon.MEDIA_MSGPACK``, ``falcon.MEDIA_YAML``,
+            ``falcon.MEDIA_XML``, etc.
         middleware(object or list, optional): One or more objects
             (instantiated classes) that implement the following middleware
             component interface::
diff --git a/falcon/constants.py b/falcon/constants.py
index 4bdc7e9..216389e 100644
--- a/falcon/constants.py
+++ b/falcon/constants.py
@@ -10,14 +10,47 @@ HTTP_METHODS = (
     'TRACE',
 )
 
+# NOTE(kgriffs): According to RFC 7159, most JSON parsers assume
+# UTF-8 and so it is the recommended default charset going forward,
+# and indeed, other charsets should not be specified to ensure
+# maximum interoperability.
+#
+# TODO(kgriffs) In Falcon 2.0, omit the charset parameter
+# below.
 MEDIA_JSON = 'application/json; charset=UTF-8'
+
+# NOTE(kgriffs): An internet media type for MessagePack has not
+# yet been registered. 'application/x-msgpack' is commonly used,
+# but the use of the 'x-' prefix is discouraged by RFC 6838.
+MEDIA_MSGPACK = 'application/msgpack'
+
+# NOTE(kgriffs): An internet media type for YAML has not been
+# registered. RoR uses 'application/x-yaml', but since use of
+# 'x-' is discouraged by RFC 6838, we don't use it in Falcon.
+#
+# The YAML specification requires that parsers deduce the character
+# encoding by examining the first few bytes of the document itself.
+# Therefore, it does not make sense to include the charset in the
+# media type string.
+MEDIA_YAML = 'application/yaml'
+
+# NOTE(kgriffs): According to RFC 7303, when the charset is
+# omitted, preference is given to the encoding specified in the
+# document itself (either via a BOM, or via the XML declaration). If
+# the document does not explicitly specify the encoding, UTF-8 is
+# assumed. We do not specify the charset here, because many parsers
+# ignore it anyway and just use what is specified in the document,
+# contrary to the RFCs.
+MEDIA_XML = 'application/xml'
+
+# NOTE(kgriffs): According to RFC 6838, most text media types should
+# include the charset parameter.
 MEDIA_HTML = 'text/html; charset=utf-8'
 MEDIA_JS = 'text/javascript; charset=utf-8'
-MEDIA_XML = 'application/xml'
 MEDIA_TEXT = 'text/plain; charset=utf-8'
+
 MEDIA_JPEG = 'image/jpeg'
 MEDIA_PNG = 'image/png'
-MEDIA_YAML = 'application/yaml'
-MEDIA_MSGPACK = 'application/msgpack'
+MEDIA_GIF = 'image/gif'
 
 DEFAULT_MEDIA_TYPE = MEDIA_JSON
diff --git a/falcon/response.py b/falcon/response.py
index 896522e..ae0b91b 100644
--- a/falcon/response.py
+++ b/falcon/response.py
@@ -671,10 +671,11 @@ class Response(object):
 
         The ``falcon`` module provides a number of constants for
         common media types, including ``falcon.MEDIA_JSON``,
-        ``falcon.MEDIA_HTML``, ``falcon.MEDIA_JS``,
-        ``falcon.MEDIA_XML``, ``falcon.MEDIA_TEXT``,
+        ``falcon.MEDIA_MSGPACK``, ``falcon.MEDIA_YAML``,
+        ``falcon.MEDIA_XML``, ``falcon.MEDIA_HTML``,
+        ``falcon.MEDIA_JS``, ``falcon.MEDIA_TEXT``,
         ``falcon.MEDIA_JPEG``, ``falcon.MEDIA_PNG``,
-        ``falcon.MEDIA_YAML`` and ``falcon.MEDIA_MSGPACK``.
+        and ``falcon.MEDIA_GIF``.
         """)
 
     etag = header_property(


Test patch:
diff --git a/tests/test_response_media.py b/tests/test_response_media.py
index 00a572f..f7a0cf7 100644
--- a/tests/test_response_media.py
+++ b/tests/test_response_media.py
@@ -22,7 +22,7 @@ def create_client(handlers=None):
 
 @pytest.mark.parametrize('media_type', [
     ('*/*'),
-    ('application/json'),
+    (falcon.MEDIA_JSON),
     ('application/json; charset=utf-8'),
 ])
 def test_json(media_type):
@@ -37,7 +37,7 @@ def test_json(media_type):
 
 
 @pytest.mark.parametrize('media_type', [
-    ('application/msgpack'),
+    (falcon.MEDIA_MSGPACK),
     ('application/msgpack; charset=utf-8'),
     ('application/x-msgpack'),
 ])