We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Clarify that `TestClient` does not use the app's JSON handlers
As I'm writing pytest tests for my ASGI app, I'm using the TestClient as a fixture as described in the docs:

```python
@pytest.fixture
def falcon_test_client():
    return TestClient(get_app())
```

`get_app()` is a function that creates and configures my app including some custom Json handlers (which as you can see below I also use for `application/x-www-form-urlencoded`):
```python
def get_app():
    app = App()

    json_handler = JSONHandler(
        dumps=partial(json.dumps, cls=CustomJsonEncoder),
        loads=partial(json.loads, cls=CustomJsonEncoder),
    )

    extra_handlers = {
        falcon.MEDIA_JSON: json_handler,
        falcon.MEDIA_URLENCODED: json_handler,
    }

    app.req_options.media_handlers.update(extra_handlers)
    app.resp_options.media_handlers.update(extra_handlers)

    # ... routes ...

    return app
```

`CustomJsonEncoder` is an encoder that can handle `UUID` and `datetime` objects; testing it with `json.dumps()` works so I know the problem is not there.

The problem is that when I try to give some data that includes a `UUID` to `simulate_post()`, it fails with `TypeError: Object of type UUID is not JSON serializable`, and I can see from pytest's traceback that at the moment of the exception, `self` is `json.encoder.JSONEncoder`, namely not the custom encoder I defined.

This is the simple test I'm trying this with:

```python
def test_(falcon_test_client):
    response = falcon_test_client.simulate_post(
        "/my/endpoint",
        json={
            "data": {},  # Just a dict with str keys and a UUID as value
        },
    )
```

I'm either forgetting something or I got something wrong, but I'm not sure what and how.

Also, I was rather confused when I was looking for ways to simulate and receive `x-www-form-urlencoded` data: if I set the `content_type` accordingly in something like `simulate_post()` and put the data in `body` as a dict¹, `req.get_media()` in the route handler seems to receive it as plain text.  
If I put the data in the `json` parameter, as stated in the docs, the `content_type` is forced to `application/json`, making my test subtly different from reality, and since there doesn't seem to be a way to avoid this behaviour, I'd rather use an alternative that keeps the content type intact. How should I handle this?

¹ I know that that is basically JSON, but my app needs to receive webhooks from an app which sends JSON-like data as `x-www-form-urlencoded`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `falcon/media/json.py`
Content:
```
1 from functools import partial
2 import json
3 
4 from falcon import errors
5 from falcon import http_error
6 from falcon.media.base import BaseHandler
7 from falcon.media.base import TextBaseHandlerWS
8 
9 
10 class JSONHandler(BaseHandler):
11     """JSON media handler.
12 
13     This handler uses Python's standard :py:mod:`json` library by default, but
14     can be easily configured to use any of a number of third-party JSON
15     libraries, depending on your needs. For example, you can often
16     realize a significant performance boost under CPython by using an
17     alternative library. Good options in this respect include `orjson`,
18     `python-rapidjson`, and `mujson`.
19 
20     This handler will raise a :class:`falcon.MediaNotFoundError` when attempting
21     to parse an empty body, or a :class:`falcon.MediaMalformedError`
22     if an error happens while parsing the body.
23 
24     Note:
25         If you are deploying to PyPy, we recommend sticking with the standard
26         library's JSON implementation, since it will be faster in most cases
27         as compared to a third-party library.
28 
29     .. rubric:: Custom JSON library
30 
31     You can replace the default JSON handler by using a custom JSON library
32     (see also: :ref:`custom_media_handlers`). Overriding the default JSON
33     implementation is simply a matter of specifying the desired ``dumps`` and
34     ``loads`` functions::
35 
36         import falcon
37         from falcon import media
38 
39         import rapidjson
40 
41         json_handler = media.JSONHandler(
42             dumps=rapidjson.dumps,
43             loads=rapidjson.loads,
44         )
45         extra_handlers = {
46             'application/json': json_handler,
47         }
48 
49         app = falcon.App()
50         app.req_options.media_handlers.update(extra_handlers)
51         app.resp_options.media_handlers.update(extra_handlers)
52 
53     .. rubric:: Custom serialization parameters
54 
55     Even if you decide to stick with the stdlib's :any:`json.dumps` and
56     :any:`json.loads`, you can wrap them using :any:`functools.partial` to
57     provide custom serialization or deserialization parameters supported by the
58     ``dumps`` and ``loads`` functions, respectively
59     (see also: :ref:`prettifying-json-responses`)::
60 
61         import falcon
62         from falcon import media
63 
64         from functools import partial
65 
66         json_handler = media.JSONHandler(
67             dumps=partial(
68                 json.dumps,
69                 default=str,
70                 sort_keys=True,
71             ),
72         )
73         extra_handlers = {
74             'application/json': json_handler,
75         }
76 
77         app = falcon.App()
78         app.req_options.media_handlers.update(extra_handlers)
79         app.resp_options.media_handlers.update(extra_handlers)
80 
81     By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.
82     If you override the ``dumps`` function, you will need to explicitly set
83     ``ensure_ascii`` to ``False`` in order to enable the serialization of
84     Unicode characters to UTF-8. This is easily done by using
85     :any:`functools.partial` to apply the desired keyword argument. As also
86     demonstrated in the previous paragraph, you can use this same technique to
87     customize any option supported by the ``dumps`` and ``loads`` functions::
88 
89         from functools import partial
90 
91         from falcon import media
92         import rapidjson
93 
94         json_handler = media.JSONHandler(
95             dumps=partial(
96                 rapidjson.dumps,
97                 ensure_ascii=False, sort_keys=True
98             ),
99         )
100 
101     .. _custom-media-json-encoder:
102 
103     .. rubric:: Custom JSON encoder
104 
105     You can also override the default :class:`~json.JSONEncoder` by using a
106     custom Encoder and updating the media handlers for ``application/json``
107     type to use that::
108 
109         import json
110         from datetime import datetime
111         from functools import partial
112 
113         import falcon
114         from falcon import media
115 
116         class DatetimeEncoder(json.JSONEncoder):
117             \"\"\"Json Encoder that supports datetime objects.\"\"\"
118 
119             def default(self, obj):
120                 if isinstance(obj, datetime):
121                     return obj.isoformat()
122                 return super().default(obj)
123 
124         app = falcon.App()
125 
126         json_handler = media.JSONHandler(
127             dumps=partial(json.dumps, cls=DatetimeEncoder),
128         )
129         extra_handlers = {
130             'application/json': json_handler,
131         }
132 
133         app.req_options.media_handlers.update(extra_handlers)
134         app.resp_options.media_handlers.update(extra_handlers)
135 
136 
137     Keyword Arguments:
138         dumps (func): Function to use when serializing JSON responses.
139         loads (func): Function to use when deserializing JSON requests.
140     """
141 
142     def __init__(self, dumps=None, loads=None):
143         self._dumps = dumps or partial(json.dumps, ensure_ascii=False)
144         self._loads = loads or json.loads
145 
146         # PERF(kgriffs): Test dumps once up front so we can set the
147         #     proper serialize implementation.
148         result = self._dumps({'message': 'Hello World'})
149         if isinstance(result, str):
150             self.serialize = self._serialize_s
151             self.serialize_async = self._serialize_async_s
152         else:
153             self.serialize = self._serialize_b
154             self.serialize_async = self._serialize_async_b
155 
156         # NOTE(kgriffs): To be safe, only enable the optimized protocol when
157         #   not subclassed.
158         if type(self) is JSONHandler:
159             self._serialize_sync = self.serialize
160             self._deserialize_sync = self._deserialize
161 
162     def _deserialize(self, data):
163         if not data:
164             raise errors.MediaNotFoundError('JSON')
165         try:
166             return self._loads(data.decode())
167         except ValueError as err:
168             raise errors.MediaMalformedError('JSON') from err
169 
170     def deserialize(self, stream, content_type, content_length):
171         return self._deserialize(stream.read())
172 
173     async def deserialize_async(self, stream, content_type, content_length):
174         return self._deserialize(await stream.read())
175 
176     # NOTE(kgriffs): Make content_type a kwarg to support the
177     #   Request.render_body() shortcut optimization.
178     def _serialize_s(self, media, content_type=None) -> bytes:
179         return self._dumps(media).encode()
180 
181     async def _serialize_async_s(self, media, content_type) -> bytes:
182         return self._dumps(media).encode()
183 
184     def _serialize_b(self, media, content_type) -> bytes:
185         return self._dumps(media)
186 
187     async def _serialize_async_b(self, media, content_type) -> bytes:
188         return self._dumps(media)
189 
190 
191 class JSONHandlerWS(TextBaseHandlerWS):
192     """WebSocket media handler for de(serializing) JSON to/from TEXT payloads.
193 
194     This handler uses Python's standard :py:mod:`json` library by default, but
195     can be easily configured to use any of a number of third-party JSON
196     libraries, depending on your needs. For example, you can often
197     realize a significant performance boost under CPython by using an
198     alternative library. Good options in this respect include `orjson`,
199     `python-rapidjson`, and `mujson`.
200 
201     Note:
202         If you are deploying to PyPy, we recommend sticking with the standard
203         library's JSON implementation, since it will be faster in most cases
204         as compared to a third-party library.
205 
206     Overriding the default JSON implementation is simply a matter of specifying
207     the desired ``dumps`` and ``loads`` functions::
208 
209         import falcon
210         from falcon import media
211 
212         import rapidjson
213 
214         json_handler = media.JSONHandlerWS(
215             dumps=rapidjson.dumps,
216             loads=rapidjson.loads,
217         )
218 
219         app = falcon.asgi.App()
220         app.ws_options.media_handlers[falcon.WebSocketPayloadType.TEXT] = json_handler
221 
222     By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.
223     If you override the ``dumps`` function, you will need to explicitly set
224     ``ensure_ascii`` to ``False`` in order to enable the serialization of
225     Unicode characters to UTF-8. This is easily done by using
226     :any:`functools.partial` to apply the desired keyword argument. In fact, you
227     can use this same technique to customize any option supported by the
228     ``dumps`` and ``loads`` functions::
229 
230         from functools import partial
231 
232         from falcon import media
233         import rapidjson
234 
235         json_handler = media.JSONHandlerWS(
236             dumps=partial(
237                 rapidjson.dumps,
238                 ensure_ascii=False, sort_keys=True
239             ),
240         )
241 
242     Keyword Arguments:
243         dumps (func): Function to use when serializing JSON.
244         loads (func): Function to use when deserializing JSON.
245     """
246 
247     __slots__ = ['dumps', 'loads']
248 
249     def __init__(self, dumps=None, loads=None):
250         self._dumps = dumps or partial(json.dumps, ensure_ascii=False)
251         self._loads = loads or json.loads
252 
253     def serialize(self, media: object) -> str:
254         return self._dumps(media)
255 
256     def deserialize(self, payload: str) -> object:
257         return self._loads(payload)
258 
259 
260 http_error._DEFAULT_JSON_HANDLER = _DEFAULT_JSON_HANDLER = JSONHandler()  # type: ignore
261
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/falcon/media/json.py b/falcon/media/json.py
--- a/falcon/media/json.py
+++ b/falcon/media/json.py
@@ -133,6 +133,15 @@
         app.req_options.media_handlers.update(extra_handlers)
         app.resp_options.media_handlers.update(extra_handlers)
 
+    .. note:: When testing an application employing a custom JSON encoder, bear
+        in mind that :class:`~.testing.TestClient` is decoupled from the app,
+        and it simulates requests as if they were performed by a third-party
+        client (just sans network). Therefore, passing the **json** parameter
+        to :ref:`simulate_* <testing_standalone_methods>` methods will
+        effectively use the stdlib's :func:`json.dumps`. If you want to
+        serialize custom objects for testing, you will need to dump them into a
+        string yourself, and pass it using the **body** parameter instead
+        (accompanied by the ``application/json`` content type header).
 
     Keyword Arguments:
         dumps (func): Function to use when serializing JSON responses.

{"golden_diff": "diff --git a/falcon/media/json.py b/falcon/media/json.py\n--- a/falcon/media/json.py\n+++ b/falcon/media/json.py\n@@ -133,6 +133,15 @@\n         app.req_options.media_handlers.update(extra_handlers)\n         app.resp_options.media_handlers.update(extra_handlers)\n \n+    .. note:: When testing an application employing a custom JSON encoder, bear\n+        in mind that :class:`~.testing.TestClient` is decoupled from the app,\n+        and it simulates requests as if they were performed by a third-party\n+        client (just sans network). Therefore, passing the **json** parameter\n+        to :ref:`simulate_* <testing_standalone_methods>` methods will\n+        effectively use the stdlib's :func:`json.dumps`. If you want to\n+        serialize custom objects for testing, you will need to dump them into a\n+        string yourself, and pass it using the **body** parameter instead\n+        (accompanied by the ``application/json`` content type header).\n \n     Keyword Arguments:\n         dumps (func): Function to use when serializing JSON responses.\n", "issue": "Clarify that `TestClient` does not use the app's JSON handlers\nAs I'm writing pytest tests for my ASGI app, I'm using the TestClient as a fixture as described in the docs:\r\n\r\n```python\r\n@pytest.fixture\r\ndef falcon_test_client():\r\n    return TestClient(get_app())\r\n```\r\n\r\n`get_app()` is a function that creates and configures my app including some custom Json handlers (which as you can see below I also use for `application/x-www-form-urlencoded`):\r\n```python\r\ndef get_app():\r\n    app = App()\r\n\r\n    json_handler = JSONHandler(\r\n        dumps=partial(json.dumps, cls=CustomJsonEncoder),\r\n        loads=partial(json.loads, cls=CustomJsonEncoder),\r\n    )\r\n\r\n    extra_handlers = {\r\n        falcon.MEDIA_JSON: json_handler,\r\n        falcon.MEDIA_URLENCODED: json_handler,\r\n    }\r\n\r\n    app.req_options.media_handlers.update(extra_handlers)\r\n    app.resp_options.media_handlers.update(extra_handlers)\r\n\r\n    # ... routes ...\r\n\r\n    return app\r\n```\r\n\r\n`CustomJsonEncoder` is an encoder that can handle `UUID` and `datetime` objects; testing it with `json.dumps()` works so I know the problem is not there.\r\n\r\nThe problem is that when I try to give some data that includes a `UUID` to `simulate_post()`, it fails with `TypeError: Object of type UUID is not JSON serializable`, and I can see from pytest's traceback that at the moment of the exception, `self` is `json.encoder.JSONEncoder`, namely not the custom encoder I defined.\r\n\r\nThis is the simple test I'm trying this with:\r\n\r\n```python\r\ndef test_(falcon_test_client):\r\n    response = falcon_test_client.simulate_post(\r\n        \"/my/endpoint\",\r\n        json={\r\n            \"data\": {},  # Just a dict with str keys and a UUID as value\r\n        },\r\n    )\r\n```\r\n\r\nI'm either forgetting something or I got something wrong, but I'm not sure what and how.\r\n\r\nAlso, I was rather confused when I was looking for ways to simulate and receive `x-www-form-urlencoded` data: if I set the `content_type` accordingly in something like `simulate_post()` and put the data in `body` as a dict\u00b9, `req.get_media()` in the route handler seems to receive it as plain text.  \r\nIf I put the data in the `json` parameter, as stated in the docs, the `content_type` is forced to `application/json`, making my test subtly different from reality, and since there doesn't seem to be a way to avoid this behaviour, I'd rather use an alternative that keeps the content type intact. How should I handle this?\r\n\r\n\u00b9 I know that that is basically JSON, but my app needs to receive webhooks from an app which sends JSON-like data as `x-www-form-urlencoded`.\n", "before_files": [{"content": "from functools import partial\nimport json\n\nfrom falcon import errors\nfrom falcon import http_error\nfrom falcon.media.base import BaseHandler\nfrom falcon.media.base import TextBaseHandlerWS\n\n\nclass JSONHandler(BaseHandler):\n    \"\"\"JSON media handler.\n\n    This handler uses Python's standard :py:mod:`json` library by default, but\n    can be easily configured to use any of a number of third-party JSON\n    libraries, depending on your needs. For example, you can often\n    realize a significant performance boost under CPython by using an\n    alternative library. Good options in this respect include `orjson`,\n    `python-rapidjson`, and `mujson`.\n\n    This handler will raise a :class:`falcon.MediaNotFoundError` when attempting\n    to parse an empty body, or a :class:`falcon.MediaMalformedError`\n    if an error happens while parsing the body.\n\n    Note:\n        If you are deploying to PyPy, we recommend sticking with the standard\n        library's JSON implementation, since it will be faster in most cases\n        as compared to a third-party library.\n\n    .. rubric:: Custom JSON library\n\n    You can replace the default JSON handler by using a custom JSON library\n    (see also: :ref:`custom_media_handlers`). Overriding the default JSON\n    implementation is simply a matter of specifying the desired ``dumps`` and\n    ``loads`` functions::\n\n        import falcon\n        from falcon import media\n\n        import rapidjson\n\n        json_handler = media.JSONHandler(\n            dumps=rapidjson.dumps,\n            loads=rapidjson.loads,\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app = falcon.App()\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n    .. rubric:: Custom serialization parameters\n\n    Even if you decide to stick with the stdlib's :any:`json.dumps` and\n    :any:`json.loads`, you can wrap them using :any:`functools.partial` to\n    provide custom serialization or deserialization parameters supported by the\n    ``dumps`` and ``loads`` functions, respectively\n    (see also: :ref:`prettifying-json-responses`)::\n\n        import falcon\n        from falcon import media\n\n        from functools import partial\n\n        json_handler = media.JSONHandler(\n            dumps=partial(\n                json.dumps,\n                default=str,\n                sort_keys=True,\n            ),\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app = falcon.App()\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n    By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.\n    If you override the ``dumps`` function, you will need to explicitly set\n    ``ensure_ascii`` to ``False`` in order to enable the serialization of\n    Unicode characters to UTF-8. This is easily done by using\n    :any:`functools.partial` to apply the desired keyword argument. As also\n    demonstrated in the previous paragraph, you can use this same technique to\n    customize any option supported by the ``dumps`` and ``loads`` functions::\n\n        from functools import partial\n\n        from falcon import media\n        import rapidjson\n\n        json_handler = media.JSONHandler(\n            dumps=partial(\n                rapidjson.dumps,\n                ensure_ascii=False, sort_keys=True\n            ),\n        )\n\n    .. _custom-media-json-encoder:\n\n    .. rubric:: Custom JSON encoder\n\n    You can also override the default :class:`~json.JSONEncoder` by using a\n    custom Encoder and updating the media handlers for ``application/json``\n    type to use that::\n\n        import json\n        from datetime import datetime\n        from functools import partial\n\n        import falcon\n        from falcon import media\n\n        class DatetimeEncoder(json.JSONEncoder):\n            \\\"\\\"\\\"Json Encoder that supports datetime objects.\\\"\\\"\\\"\n\n            def default(self, obj):\n                if isinstance(obj, datetime):\n                    return obj.isoformat()\n                return super().default(obj)\n\n        app = falcon.App()\n\n        json_handler = media.JSONHandler(\n            dumps=partial(json.dumps, cls=DatetimeEncoder),\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n\n    Keyword Arguments:\n        dumps (func): Function to use when serializing JSON responses.\n        loads (func): Function to use when deserializing JSON requests.\n    \"\"\"\n\n    def __init__(self, dumps=None, loads=None):\n        self._dumps = dumps or partial(json.dumps, ensure_ascii=False)\n        self._loads = loads or json.loads\n\n        # PERF(kgriffs): Test dumps once up front so we can set the\n        #     proper serialize implementation.\n        result = self._dumps({'message': 'Hello World'})\n        if isinstance(result, str):\n            self.serialize = self._serialize_s\n            self.serialize_async = self._serialize_async_s\n        else:\n            self.serialize = self._serialize_b\n            self.serialize_async = self._serialize_async_b\n\n        # NOTE(kgriffs): To be safe, only enable the optimized protocol when\n        #   not subclassed.\n        if type(self) is JSONHandler:\n            self._serialize_sync = self.serialize\n            self._deserialize_sync = self._deserialize\n\n    def _deserialize(self, data):\n        if not data:\n            raise errors.MediaNotFoundError('JSON')\n        try:\n            return self._loads(data.decode())\n        except ValueError as err:\n            raise errors.MediaMalformedError('JSON') from err\n\n    def deserialize(self, stream, content_type, content_length):\n        return self._deserialize(stream.read())\n\n    async def deserialize_async(self, stream, content_type, content_length):\n        return self._deserialize(await stream.read())\n\n    # NOTE(kgriffs): Make content_type a kwarg to support the\n    #   Request.render_body() shortcut optimization.\n    def _serialize_s(self, media, content_type=None) -> bytes:\n        return self._dumps(media).encode()\n\n    async def _serialize_async_s(self, media, content_type) -> bytes:\n        return self._dumps(media).encode()\n\n    def _serialize_b(self, media, content_type) -> bytes:\n        return self._dumps(media)\n\n    async def _serialize_async_b(self, media, content_type) -> bytes:\n        return self._dumps(media)\n\n\nclass JSONHandlerWS(TextBaseHandlerWS):\n    \"\"\"WebSocket media handler for de(serializing) JSON to/from TEXT payloads.\n\n    This handler uses Python's standard :py:mod:`json` library by default, but\n    can be easily configured to use any of a number of third-party JSON\n    libraries, depending on your needs. For example, you can often\n    realize a significant performance boost under CPython by using an\n    alternative library. Good options in this respect include `orjson`,\n    `python-rapidjson`, and `mujson`.\n\n    Note:\n        If you are deploying to PyPy, we recommend sticking with the standard\n        library's JSON implementation, since it will be faster in most cases\n        as compared to a third-party library.\n\n    Overriding the default JSON implementation is simply a matter of specifying\n    the desired ``dumps`` and ``loads`` functions::\n\n        import falcon\n        from falcon import media\n\n        import rapidjson\n\n        json_handler = media.JSONHandlerWS(\n            dumps=rapidjson.dumps,\n            loads=rapidjson.loads,\n        )\n\n        app = falcon.asgi.App()\n        app.ws_options.media_handlers[falcon.WebSocketPayloadType.TEXT] = json_handler\n\n    By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.\n    If you override the ``dumps`` function, you will need to explicitly set\n    ``ensure_ascii`` to ``False`` in order to enable the serialization of\n    Unicode characters to UTF-8. This is easily done by using\n    :any:`functools.partial` to apply the desired keyword argument. In fact, you\n    can use this same technique to customize any option supported by the\n    ``dumps`` and ``loads`` functions::\n\n        from functools import partial\n\n        from falcon import media\n        import rapidjson\n\n        json_handler = media.JSONHandlerWS(\n            dumps=partial(\n                rapidjson.dumps,\n                ensure_ascii=False, sort_keys=True\n            ),\n        )\n\n    Keyword Arguments:\n        dumps (func): Function to use when serializing JSON.\n        loads (func): Function to use when deserializing JSON.\n    \"\"\"\n\n    __slots__ = ['dumps', 'loads']\n\n    def __init__(self, dumps=None, loads=None):\n        self._dumps = dumps or partial(json.dumps, ensure_ascii=False)\n        self._loads = loads or json.loads\n\n    def serialize(self, media: object) -> str:\n        return self._dumps(media)\n\n    def deserialize(self, payload: str) -> object:\n        return self._loads(payload)\n\n\nhttp_error._DEFAULT_JSON_HANDLER = _DEFAULT_JSON_HANDLER = JSONHandler()  # type: ignore\n", "path": "falcon/media/json.py"}], "after_files": [{"content": "from functools import partial\nimport json\n\nfrom falcon import errors\nfrom falcon import http_error\nfrom falcon.media.base import BaseHandler\nfrom falcon.media.base import TextBaseHandlerWS\n\n\nclass JSONHandler(BaseHandler):\n    \"\"\"JSON media handler.\n\n    This handler uses Python's standard :py:mod:`json` library by default, but\n    can be easily configured to use any of a number of third-party JSON\n    libraries, depending on your needs. For example, you can often\n    realize a significant performance boost under CPython by using an\n    alternative library. Good options in this respect include `orjson`,\n    `python-rapidjson`, and `mujson`.\n\n    This handler will raise a :class:`falcon.MediaNotFoundError` when attempting\n    to parse an empty body, or a :class:`falcon.MediaMalformedError`\n    if an error happens while parsing the body.\n\n    Note:\n        If you are deploying to PyPy, we recommend sticking with the standard\n        library's JSON implementation, since it will be faster in most cases\n        as compared to a third-party library.\n\n    .. rubric:: Custom JSON library\n\n    You can replace the default JSON handler by using a custom JSON library\n    (see also: :ref:`custom_media_handlers`). Overriding the default JSON\n    implementation is simply a matter of specifying the desired ``dumps`` and\n    ``loads`` functions::\n\n        import falcon\n        from falcon import media\n\n        import rapidjson\n\n        json_handler = media.JSONHandler(\n            dumps=rapidjson.dumps,\n            loads=rapidjson.loads,\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app = falcon.App()\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n    .. rubric:: Custom serialization parameters\n\n    Even if you decide to stick with the stdlib's :any:`json.dumps` and\n    :any:`json.loads`, you can wrap them using :any:`functools.partial` to\n    provide custom serialization or deserialization parameters supported by the\n    ``dumps`` and ``loads`` functions, respectively\n    (see also: :ref:`prettifying-json-responses`)::\n\n        import falcon\n        from falcon import media\n\n        from functools import partial\n\n        json_handler = media.JSONHandler(\n            dumps=partial(\n                json.dumps,\n                default=str,\n                sort_keys=True,\n            ),\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app = falcon.App()\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n    By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.\n    If you override the ``dumps`` function, you will need to explicitly set\n    ``ensure_ascii`` to ``False`` in order to enable the serialization of\n    Unicode characters to UTF-8. This is easily done by using\n    :any:`functools.partial` to apply the desired keyword argument. As also\n    demonstrated in the previous paragraph, you can use this same technique to\n    customize any option supported by the ``dumps`` and ``loads`` functions::\n\n        from functools import partial\n\n        from falcon import media\n        import rapidjson\n\n        json_handler = media.JSONHandler(\n            dumps=partial(\n                rapidjson.dumps,\n                ensure_ascii=False, sort_keys=True\n            ),\n        )\n\n    .. _custom-media-json-encoder:\n\n    .. rubric:: Custom JSON encoder\n\n    You can also override the default :class:`~json.JSONEncoder` by using a\n    custom Encoder and updating the media handlers for ``application/json``\n    type to use that::\n\n        import json\n        from datetime import datetime\n        from functools import partial\n\n        import falcon\n        from falcon import media\n\n        class DatetimeEncoder(json.JSONEncoder):\n            \\\"\\\"\\\"Json Encoder that supports datetime objects.\\\"\\\"\\\"\n\n            def default(self, obj):\n                if isinstance(obj, datetime):\n                    return obj.isoformat()\n                return super().default(obj)\n\n        app = falcon.App()\n\n        json_handler = media.JSONHandler(\n            dumps=partial(json.dumps, cls=DatetimeEncoder),\n        )\n        extra_handlers = {\n            'application/json': json_handler,\n        }\n\n        app.req_options.media_handlers.update(extra_handlers)\n        app.resp_options.media_handlers.update(extra_handlers)\n\n    .. note:: When testing an application employing a custom JSON encoder, bear\n        in mind that :class:`~.testing.TestClient` is decoupled from the app,\n        and it simulates requests as if they were performed by a third-party\n        client (just sans network). Therefore, passing the **json** parameter\n        to :ref:`simulate_* <testing_standalone_methods>` methods will\n        effectively use the stdlib's :func:`json.dumps`. If you want to\n        serialize custom objects for testing, you will need to dump them into a\n        string yourself, and pass it using the **body** parameter instead\n        (accompanied by the ``application/json`` content type header).\n\n    Keyword Arguments:\n        dumps (func): Function to use when serializing JSON responses.\n        loads (func): Function to use when deserializing JSON requests.\n    \"\"\"\n\n    def __init__(self, dumps=None, loads=None):\n        self._dumps = dumps or partial(json.dumps, ensure_ascii=False)\n        self._loads = loads or json.loads\n\n        # PERF(kgriffs): Test dumps once up front so we can set the\n        #     proper serialize implementation.\n        result = self._dumps({'message': 'Hello World'})\n        if isinstance(result, str):\n            self.serialize = self._serialize_s\n            self.serialize_async = self._serialize_async_s\n        else:\n            self.serialize = self._serialize_b\n            self.serialize_async = self._serialize_async_b\n\n        # NOTE(kgriffs): To be safe, only enable the optimized protocol when\n        #   not subclassed.\n        if type(self) is JSONHandler:\n            self._serialize_sync = self.serialize\n            self._deserialize_sync = self._deserialize\n\n    def _deserialize(self, data):\n        if not data:\n            raise errors.MediaNotFoundError('JSON')\n        try:\n            return self._loads(data.decode())\n        except ValueError as err:\n            raise errors.MediaMalformedError('JSON') from err\n\n    def deserialize(self, stream, content_type, content_length):\n        return self._deserialize(stream.read())\n\n    async def deserialize_async(self, stream, content_type, content_length):\n        return self._deserialize(await stream.read())\n\n    # NOTE(kgriffs): Make content_type a kwarg to support the\n    #   Request.render_body() shortcut optimization.\n    def _serialize_s(self, media, content_type=None) -> bytes:\n        return self._dumps(media).encode()\n\n    async def _serialize_async_s(self, media, content_type) -> bytes:\n        return self._dumps(media).encode()\n\n    def _serialize_b(self, media, content_type) -> bytes:\n        return self._dumps(media)\n\n    async def _serialize_async_b(self, media, content_type) -> bytes:\n        return self._dumps(media)\n\n\nclass JSONHandlerWS(TextBaseHandlerWS):\n    \"\"\"WebSocket media handler for de(serializing) JSON to/from TEXT payloads.\n\n    This handler uses Python's standard :py:mod:`json` library by default, but\n    can be easily configured to use any of a number of third-party JSON\n    libraries, depending on your needs. For example, you can often\n    realize a significant performance boost under CPython by using an\n    alternative library. Good options in this respect include `orjson`,\n    `python-rapidjson`, and `mujson`.\n\n    Note:\n        If you are deploying to PyPy, we recommend sticking with the standard\n        library's JSON implementation, since it will be faster in most cases\n        as compared to a third-party library.\n\n    Overriding the default JSON implementation is simply a matter of specifying\n    the desired ``dumps`` and ``loads`` functions::\n\n        import falcon\n        from falcon import media\n\n        import rapidjson\n\n        json_handler = media.JSONHandlerWS(\n            dumps=rapidjson.dumps,\n            loads=rapidjson.loads,\n        )\n\n        app = falcon.asgi.App()\n        app.ws_options.media_handlers[falcon.WebSocketPayloadType.TEXT] = json_handler\n\n    By default, ``ensure_ascii`` is passed to the ``json.dumps`` function.\n    If you override the ``dumps`` function, you will need to explicitly set\n    ``ensure_ascii`` to ``False`` in order to enable the serialization of\n    Unicode characters to UTF-8. This is easily done by using\n    :any:`functools.partial` to apply the desired keyword argument. In fact, you\n    can use this same technique to customize any option supported by the\n    ``dumps`` and ``loads`` functions::\n\n        from functools import partial\n\n        from falcon import media\n        import rapidjson\n\n        json_handler = media.JSONHandlerWS(\n            dumps=partial(\n                rapidjson.dumps,\n                ensure_ascii=False, sort_keys=True\n            ),\n        )\n\n    Keyword Arguments:\n        dumps (func): Function to use when serializing JSON.\n        loads (func): Function to use when deserializing JSON.\n    \"\"\"\n\n    __slots__ = ['dumps', 'loads']\n\n    def __init__(self, dumps=None, loads=None):\n        self._dumps = dumps or partial(json.dumps, ensure_ascii=False)\n        self._loads = loads or json.loads\n\n    def serialize(self, media: object) -> str:\n        return self._dumps(media)\n\n    def deserialize(self, payload: str) -> object:\n        return self._loads(payload)\n\n\nhttp_error._DEFAULT_JSON_HANDLER = _DEFAULT_JSON_HANDLER = JSONHandler()  # type: ignore\n", "path": "falcon/media/json.py"}]}