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__
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
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:
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
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)
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)
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))
from psycopg3 import pq
from psycopg3 import sql
from psycopg3.adapt import Format
+from psycopg3 import Binary
eur = "\u20ac"
@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):