]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Fix DB API Binary wrapper
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 10 Jun 2021 10:25:47 +0000 (11:25 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 14 Jun 2021 09:37:07 +0000 (10:37 +0100)
psycopg3/psycopg3/__init__.py
psycopg3/psycopg3/dbapi20.py
tests/fix_faker.py
tests/types/test_text.py

index b1c651903bc610b53a90e6ce0039d1215c7471ed..4d5cc8846c9ce555913f29b80d828ffcd19845b4 100644 (file)
@@ -20,8 +20,9 @@ from .connection import BaseConnection, AsyncConnection, Connection, Notify
 from .transaction import Rollback, Transaction, AsyncTransaction
 from .server_cursor import AsyncServerCursor, ServerCursor
 
-from .dbapi20 import BINARY, DATETIME, NUMBER, ROWID, STRING, BinaryDumper
-from .dbapi20 import Binary, Date, DateFromTicks, Time, TimeFromTicks
+from .dbapi20 import BINARY, DATETIME, NUMBER, ROWID, STRING
+from .dbapi20 import Binary, BinaryTextDumper, BinaryBinaryDumper
+from .dbapi20 import Date, DateFromTicks, Time, TimeFromTicks
 from .dbapi20 import Timestamp, TimestampFromTicks
 
 from .version import __version__
@@ -39,7 +40,8 @@ connect = Connection.connect
 apilevel = "2.0"
 threadsafety = 2
 paramstyle = "pyformat"
-BinaryDumper.register(Binary, global_adapters)  # dbapi20
+BinaryTextDumper.register(Binary, global_adapters)  # dbapi20
+BinaryBinaryDumper.register(Binary, global_adapters)  # dbapi20
 
 
 # Note: defining the exported methods helps both Sphynx in documenting that
index dc7e55156350e7e73f3715ee5e05c598537a6962..cc62664f888f9d3c75bec41b74e431a571b750e3 100644 (file)
@@ -7,11 +7,12 @@ Compatibility objects with DBAPI 2.0
 import time
 import datetime as dt
 from math import floor
-from typing import Any, Sequence
+from typing import Any, Optional, Sequence
 
-from .pq import Format
+from .pq import Format, Escaping
 from .oids import postgres_types as builtins
 from .adapt import Dumper
+from .proto import AdaptContext
 
 
 class DBAPITypeObject:
@@ -50,11 +51,17 @@ class Binary:
     def __init__(self, obj: Any):
         self.obj = obj
 
+    def __repr__(self):
+        sobj = repr(self.obj)
+        if len(sobj) > 40:
+            sobj = f"{sobj[:35]} ... ({len(sobj)} byteschars)"
+        return f"{self.__class__.__name__}({sobj})"
 
-class BinaryDumper(Dumper):
 
-    format = Format.TEXT
-    oid = builtins["bytea"].oid
+class BinaryBinaryDumper(Dumper):
+
+    format = Format.BINARY
+    _oid = builtins["bytea"].oid
 
     def dump(self, obj: Binary) -> bytes:
         wrapped = obj.obj
@@ -64,6 +71,21 @@ class BinaryDumper(Dumper):
             return bytes(wrapped)
 
 
+class BinaryTextDumper(BinaryBinaryDumper):
+
+    format = Format.TEXT
+
+    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+        super().__init__(cls, context)
+        self._esc = Escaping(
+            self.connection.pgconn if self.connection else None
+        )
+
+    def dump(self, obj: Binary) -> bytes:
+        data = super().dump(obj)
+        return self._esc.escape_bytea(data)
+
+
 def Date(year: int, month: int, day: int) -> dt.date:
     return dt.date(year, month, day)
 
index b57a1945b6f955e48f7b2f365a14066ab0509316..9257cf49bad2a28c024f84c7b6a1cf5794777243 100644 (file)
@@ -216,8 +216,6 @@ class Faker:
 
         return None
 
-    # methods to implement specific objects
-
     def make(self, spec):
         # spec can be a type or a list [type] or a tuple (spec, spec, ...)
         return self.get_maker(spec)(spec)
@@ -225,6 +223,14 @@ class Faker:
     def match_any(self, spec, got, want):
         assert got == want
 
+    # methods to generate samples of specific types
+
+    def make_Binary(self, spec):
+        return self.make_bytes(spec)
+
+    def match_Binary(self, spec, got, want):
+        return want.obj == got
+
     def make_bool(self, spec):
         return choice((True, False))
 
index 998afb1b8ddd3a5af29a41ca10753dd0f9b693bf..e9e0696c1fb356b1f4ade3dc3e96d889857d2ae6 100644 (file)
@@ -4,6 +4,7 @@ import psycopg3
 from psycopg3 import pq
 from psycopg3 import sql
 from psycopg3.adapt import Format
+from psycopg3 import Binary
 
 eur = "\u20ac"
 
@@ -206,7 +207,7 @@ def test_text_array_ascii(conn, fmt_in, fmt_out):
 
 
 @pytest.mark.parametrize("fmt_in", [Format.AUTO, Format.TEXT, Format.BINARY])
-@pytest.mark.parametrize("pytype", [bytes, bytearray, memoryview])
+@pytest.mark.parametrize("pytype", [bytes, bytearray, memoryview, Binary])
 def test_dump_1byte(conn, fmt_in, pytype):
     cur = conn.cursor()
     for i in range(0, 256):