From: Daniele Varrazzo Date: Mon, 10 Apr 2023 20:55:44 +0000 (+0200) Subject: fix(json): allow to register json dumpers on dict or other objects X-Git-Tag: 3.1.9~1^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c487ae8bec79b05d737dea28e870429899752134;p=thirdparty%2Fpsycopg.git fix(json): allow to register json dumpers on dict or other objects --- diff --git a/docs/news.rst b/docs/news.rst index 2798a39ac..f5492ebeb 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -17,6 +17,8 @@ Psycopg 3.1.9 (unreleased) (:ticket:`#503`). - Fix "filedescriptor out of range" using a large number of files open in Python implementation (:ticket:`#532`). +- Allow JSON dumpers to be registered on `!dict` or any other object, as was + possible in psycopg2 (:ticket:`#541`). - Fix canceling running queries on process interruption in async connections (:ticket:`#543`). - Fix loading ROW values with different types in the same query using the diff --git a/psycopg/psycopg/types/json.py b/psycopg/psycopg/types/json.py index 31e6495e3..b3323cf0c 100644 --- a/psycopg/psycopg/types/json.py +++ b/psycopg/psycopg/types/json.py @@ -126,9 +126,13 @@ class _JsonDumper(Dumper): super().__init__(cls, context) self.dumps = self.__class__._dumps - def dump(self, obj: _JsonWrapper) -> bytes: - dumps = obj.dumps or self.dumps - return dumps(obj.obj).encode() + def dump(self, obj: Any) -> bytes: + if isinstance(obj, _JsonWrapper): + dumps = obj.dumps or self.dumps + obj = obj.obj + else: + dumps = self.dumps + return dumps(obj).encode() class JsonDumper(_JsonDumper): @@ -148,9 +152,8 @@ class JsonbBinaryDumper(_JsonDumper): format = Format.BINARY oid = postgres.types["jsonb"].oid - def dump(self, obj: _JsonWrapper) -> bytes: - dumps = obj.dumps or self.dumps - return b"\x01" + dumps(obj.obj).encode() + def dump(self, obj: Any) -> bytes: + return b"\x01" + super().dump(obj) class _JsonLoader(Loader): diff --git a/tests/types/test_json.py b/tests/types/test_json.py index 50e8ce32f..24970c712 100644 --- a/tests/types/test_json.py +++ b/tests/types/test_json.py @@ -47,6 +47,24 @@ def test_dump(conn, val, wrapper, fmt_in): assert cur.fetchone()[0] is True +@pytest.mark.parametrize( + "fmt_in, type, dumper_name", + [ + ("t", "json", "JsonDumper"), + ("b", "json", "JsonBinaryDumper"), + ("t", "jsonb", "JsonbDumper"), + ("b", "jsonb", "JsonbBinaryDumper"), + ], +) +def test_dump_dict(conn, fmt_in, type, dumper_name): + obj = {"foo": "bar"} + cur = conn.cursor() + cur.adapters.register_dumper(dict, getattr(psycopg.types.json, dumper_name)) + cur.execute(f"select %{fmt_in}", (obj,)) + assert cur.fetchone()[0] == obj + assert cur.description[0].type_code == conn.adapters.types[type].oid + + @pytest.mark.crdb_skip("json array") @pytest.mark.parametrize("val", samples) @pytest.mark.parametrize("wrapper", ["Json", "Jsonb"])