From: Daniele Varrazzo Date: Sun, 27 Jun 2021 01:40:41 +0000 (+0100) Subject: Update json documentation to describe the new interfaces X-Git-Tag: 3.0.dev0~14^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dc87984b767950668aa72aa040e7c7170445b13c;p=thirdparty%2Fpsycopg.git Update json documentation to describe the new interfaces --- diff --git a/docs/api/types.rst b/docs/api/types.rst index fca2e85e5..74d08ac63 100644 --- a/docs/api/types.rst +++ b/docs/api/types.rst @@ -103,7 +103,6 @@ Objects wrappers Document the various objects wrappers - Int2, Int4, Int8, ... - - Json, Jsonb - Range @@ -112,6 +111,8 @@ Objects wrappers JSON adapters ------------- +See :ref:`adapt-json` for details. + .. currentmodule:: psycopg.types.json .. autoclass:: Json @@ -121,40 +122,9 @@ Wrappers to signal to convert *obj* to a json or jsonb PostgreSQL value. Any object supported by the underlying `!dumps()` function can be wrapped. +If a *dumps* function is passed to the wrapper, use it to dump the wrapped +object. Otherwise use the function specified by `set_json_dumps()`. + .. autofunction:: set_json_dumps .. autofunction:: set_json_loads - -.. autoclass:: JsonDumper - - .. automethod:: get_dumps - -.. autoclass:: JsonBinaryDumper -.. autoclass:: JsonbDumper -.. autoclass:: JsonbBinaryDumper - -`~psycopg.adapt.Dumper` subclasses using the function provided by -`set_json_dumps()` function to serialize the Python object wrapped by -`Json`/`Jsonb`. - -If you need to specify different `!dumps()` functions in different contexts -you can subclass one/some of these functions to override the -`~JsonDumper.get_dumps()` method and `~psycopg.adapt.Dumper.register()` them -on the right connection or cursor. - -.. autoclass:: JsonLoader - - .. automethod:: get_loads - -.. autoclass:: JsonBinaryLoader -.. autoclass:: JsonbLoader -.. autoclass:: JsonbBinaryLoader - -`~psycopg.adapt.Loader` subclasses using the function provided by -`set_json_loads()` function to de-serialize :sql:`json`/:sql:`jsonb` -PostgreSQL values to Python objects. - -If you need to specify different `!loads()` functions in different contexts -you can subclass one/some of these functions to override the -`~JsonLoader.get_loads()` method and `~psycopg.adapt.Loader.register()` them -on the right connection or cursor. diff --git a/docs/basic/adapt.rst b/docs/basic/adapt.rst index e033e4d84..2e851b60e 100644 --- a/docs/basic/adapt.rst +++ b/docs/basic/adapt.rst @@ -271,19 +271,13 @@ either `psycopg.types.json.Json` or `~psycopg.types.json.Jsonb`. thing = {"foo": ["bar", 42]} conn.execute("insert into mytable values (%s)", [Jsonb(thing)]) -By default Psycopg uses the standard library `json.dumps()`__ and -`json.loads()`__ functions to serialize and de-serialize Python objects to -JSON. If you want to customise globally how serialization happens, for -instance changing serialization parameters or using a different JSON library, -you can specify your own functions using the -`psycopg.types.json.set_json_dumps()` and -`~psycopg.types.json.set_json_loads()` functions. - -.. - weird: intersphinx doesn't work - -.. __: https://docs.python.org/3/library/json.html#json.dumps -.. __: https://docs.python.org/3/library/json.html#json.loads +By default Psycopg uses the standard library `json.dumps` and `json.loads` +functions to serialize and de-serialize Python objects to JSON. If you want to +customise how serialization happens, for instance changing serialization +parameters or using a different JSON library, you can specify your own +functions using the `psycopg.types.json.set_json_dumps()` and +`~psycopg.types.json.set_json_loads()` functions, to apply either globally or +to a specific context (connection or cursor). .. code:: python @@ -294,15 +288,34 @@ you can specify your own functions using the # Use a faster dump function set_json_dumps(ujson.dumps) - # Return floating point values as Decimal - set_json_loads(partial(json.loads, parse_float=Decimal)) + # Return floating point values as Decimal, just in one connection + set_json_loads(partial(json.loads, parse_float=Decimal), conn) conn.execute("select %s", [Jsonb({"value": 123.45})]).fetchone()[0] # {'value': Decimal('123.45')} -If you need a more precise customisation, such as per-connection instead of -global, you can subclass and register the JSON adapters in the right context: -see :ref:`json-adapters`. +If you need an even more specific dump customisation only for certain objects +(including different configurations in the same query) you can specify a +*dumps* parameter in the +`~psycopg.types.json.Json`/`~psycopg.types.json.Jsonb` wrapper, which will +take precedence over what specified by `!set_json_dumps()`. + +.. code:: python + + from uuid import UUID, uuid4 + + class UUIDEncoder(json.JSONEncoder): + """A JSON encoder which can dump UUID.""" + def default(self, obj): + if isinstance(obj, UUID): + return str(obj) + return json.JSONEncoder.default(self, obj) + + uuid_dumps = partial(json.dumps, cls=UUIDEncoder) + obj = {"uuid": uuid4()} + cnn.execute("insert into objs values %s", [Json(obj, dumps=uuid_dumps)]) + # will insert: {'uuid': '0a40799d-3980-4c65-8315-2956b18ab0e1'} + .. _adapt-date: .. _adapt-list: diff --git a/psycopg/psycopg/types/json.py b/psycopg/psycopg/types/json.py index 74a2e142b..7f194635f 100644 --- a/psycopg/psycopg/types/json.py +++ b/psycopg/psycopg/types/json.py @@ -21,10 +21,19 @@ def set_json_dumps( dumps: JsonDumpsFunction, context: Optional[AdaptContext] = None ) -> None: """ - Set a global JSON serialisation function to use by default by JSON dumpers. + Set the JSON serialisation function to store JSON objects in the database. - By default dumping JSON uses the builtin `json.dumps()`. You can override + :param dumps: The dump function to use. + :type dumps: `!Callable[[Any], str]` + :param context: Where to use the *dumps* function. If not specified, use it + globally. + :type context: `~psycopg.Connection` or `~psycopg.Cursor` + + By default dumping JSON uses the builtin `json.dumps`. You can override it to use a different JSON library or to use customised arguments. + + If the `Json` wrapper specified a *dumps* function, use it in precedence + of the one set by this function. """ if context is None: # If changing load function globally, just change the default on the @@ -49,9 +58,15 @@ def set_json_loads( loads: JsonLoadsFunction, context: Optional[AdaptContext] = None ) -> None: """ - Set a global JSON parsing function to use by default by the JSON loaders. + Set the JSON parsing function to fetch JSON objects from the database. + + :param loads: The load function to use. + :type loads: `!Callable[[bytes], Any]` + :param context: Where to use the *loads* function. If not specified, use it + globally. + :type context: `~psycopg.Connection` or `~psycopg.Cursor` - By default loading JSON uses the builtin `json.loads()`. You can override + By default loading JSON uses the builtin `json.loads`. You can override it to use a different JSON library or to use customised arguments. """ if context is None: