]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix(json): allow to register json dumpers on dict or other objects
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 10 Apr 2023 20:55:44 +0000 (22:55 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 2 May 2023 10:18:06 +0000 (12:18 +0200)
docs/news.rst
psycopg/psycopg/types/json.py
tests/types/test_json.py

index 2798a39ac28c74a2914a40b0651274807da89333..f5492ebebaf5e20442b61580caf2954e3ca1095b 100644 (file)
@@ -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
index 31e6495e3afd52d97ba891e865621dc94eeddc23..b3323cf0c2de71f12e1ff9ad5f531dc219c7ad8e 100644 (file)
@@ -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):
index 50e8ce32fde39aa5de1a178eeba6e15b178f5d53..24970c7121343e7b9a25c39a280ec7d2bde9d7e6 100644 (file)
@@ -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"])