From: Daniele Varrazzo Date: Wed, 5 Aug 2020 22:25:56 +0000 (+0100) Subject: Dropped use of plain functions to define dumpers X-Git-Tag: 3.0.dev0~458^2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6839ccffb1777c3f89fea9ffdc57d8291c0ecabe;p=thirdparty%2Fpsycopg.git Dropped use of plain functions to define dumpers --- diff --git a/psycopg3/psycopg3/adapt.py b/psycopg3/psycopg3/adapt.py index da173d6b7..ea70aba53 100644 --- a/psycopg3/psycopg3/adapt.py +++ b/psycopg3/psycopg3/adapt.py @@ -40,13 +40,9 @@ class Dumper: f"dumpers should be registered on classes, got {src} instead" ) - if not ( - callable(dumper) - or (isinstance(dumper, type) and issubclass(dumper, Dumper)) - ): + if not (isinstance(dumper, type) and issubclass(dumper, Dumper)): raise TypeError( - f"dumpers should be callable or Dumper subclasses," - f" got {dumper} instead" + f"dumpers should be Dumper subclasses, got {dumper} instead" ) where = context.dumpers if context is not None else Dumper.globals diff --git a/psycopg3/psycopg3/dbapi20.py b/psycopg3/psycopg3/dbapi20.py index 527a02159..2c0763478 100644 --- a/psycopg3/psycopg3/dbapi20.py +++ b/psycopg3/psycopg3/dbapi20.py @@ -51,12 +51,13 @@ class Binary: @Dumper.text(Binary) -def dump_Binary(obj: Binary) -> Tuple[bytes, int]: - rv = obj.obj - if not isinstance(rv, bytes): - rv = bytes(rv) +class TextBinaryDumper(Dumper): + def dump(self, obj: Binary) -> Tuple[bytes, int]: + rv = obj.obj + if not isinstance(rv, bytes): + rv = bytes(rv) - return rv, builtins["bytea"].oid + return rv, builtins["bytea"].oid def Date(year: int, month: int, day: int) -> dt.date: diff --git a/psycopg3/psycopg3/proto.py b/psycopg3/psycopg3/proto.py index 1a4ac3140..9b84e28d4 100644 --- a/psycopg3/psycopg3/proto.py +++ b/psycopg3/psycopg3/proto.py @@ -38,7 +38,7 @@ AdaptContext = Union[None, "BaseConnection", "BaseCursor", "Transformer"] MaybeOid = Union[Optional[bytes], Tuple[Optional[bytes], int]] DumpFunc = Callable[[Any], MaybeOid] -DumperType = Union[Type["Dumper"], DumpFunc] +DumperType = Type["Dumper"] DumpersMap = Dict[Tuple[type, Format], DumperType] LoadFunc = Callable[[bytes], Any] diff --git a/psycopg3/psycopg3/transform.py b/psycopg3/psycopg3/transform.py index 6ef1fca49..e8a1c714c 100644 --- a/psycopg3/psycopg3/transform.py +++ b/psycopg3/psycopg3/transform.py @@ -172,10 +172,7 @@ class Transformer: dumper = self.lookup_dumper(src, format) func: DumpFunc - if isinstance(dumper, type): - func = dumper(src, self).dump - else: - func = dumper + func = dumper(src, self).dump self._dump_funcs[key] = func return func diff --git a/psycopg3/psycopg3/types/numeric.py b/psycopg3/psycopg3/types/numeric.py index a16c82b0f..5c22561d5 100644 --- a/psycopg3/psycopg3/types/numeric.py +++ b/psycopg3/psycopg3/types/numeric.py @@ -14,6 +14,7 @@ from .oids import builtins FLOAT8_OID = builtins["float8"].oid NUMERIC_OID = builtins["numeric"].oid +BOOL_OID = builtins["bool"].oid _encode = codecs.lookup("ascii").encode _decode = codecs.lookup("ascii").decode @@ -27,20 +28,27 @@ _float8_struct = struct.Struct("!d") @Dumper.text(int) -def dump_int(obj: int) -> Tuple[bytes, int]: - # We don't know the size of it, so we have to return a type big enough - return _encode(str(obj))[0], NUMERIC_OID +class TextIntDumper(Dumper): + def dump(self, obj: int) -> Tuple[bytes, int]: + # We don't know the size of it, so we have to return a type big enough + return _encode(str(obj))[0], NUMERIC_OID @Dumper.text(float) -def dump_float(obj: float) -> Tuple[bytes, int]: - # Float can't be bigger than this instead - return _encode(str(obj))[0], FLOAT8_OID +class TextFloatDumper(Dumper): + def dump(self, obj: float) -> Tuple[bytes, int]: + # Float can't be bigger than this instead + return _encode(str(obj))[0], FLOAT8_OID @Dumper.text(Decimal) -def dump_decimal(obj: Decimal) -> Tuple[bytes, int]: - return _encode(str(obj))[0], NUMERIC_OID +class TextDecimalDumper(Dumper): + def dump(self, obj: Decimal) -> Tuple[bytes, int]: + return _encode(str(obj))[0], NUMERIC_OID + + @property + def oid(self) -> int: + return NUMERIC_OID _bool_dump = { @@ -54,13 +62,23 @@ _bool_binary_dump = { @Dumper.text(bool) -def dump_bool(obj: bool) -> Tuple[bytes, int]: - return _bool_dump[obj] +class TextBoolDumper(Dumper): + def dump(self, obj: bool) -> Tuple[bytes, int]: + return _bool_dump[obj] + + @property + def oid(self) -> int: + return BOOL_OID @Dumper.binary(bool) -def dump_bool_binary(obj: bool) -> Tuple[bytes, int]: - return _bool_binary_dump[obj] +class BinaryBoolDumper(Dumper): + def dump(self, obj: bool) -> Tuple[bytes, int]: + return _bool_binary_dump[obj] + + @property + def oid(self) -> int: + return BOOL_OID @Loader.text(builtins["int2"].oid) diff --git a/psycopg3/psycopg3/types/text.py b/psycopg3/psycopg3/types/text.py index e3ac114b3..11a147eca 100644 --- a/psycopg3/psycopg3/types/text.py +++ b/psycopg3/psycopg3/types/text.py @@ -95,8 +95,9 @@ class BytesDumper(Dumper): @Dumper.binary(bytes) -def dump_bytes(b: bytes) -> Tuple[bytes, int]: - return b, BYTEA_OID +class BinaryBytesDumper(Dumper): + def dump(self, b: bytes) -> Tuple[bytes, int]: + return b, BYTEA_OID @Loader.text(builtins["bytea"].oid) diff --git a/psycopg3_c/psycopg3_c/transform.pyx b/psycopg3_c/psycopg3_c/transform.pyx index 28411b64f..7b438fb6c 100644 --- a/psycopg3_c/psycopg3_c/transform.pyx +++ b/psycopg3_c/psycopg3_c/transform.pyx @@ -252,12 +252,7 @@ cdef class Transformer: pass dumper = self.lookup_dumper(src, format) - func: "DumpFunc" - if isinstance(dumper, type): - func = dumper(src, self).dump - else: - func = dumper - + func = dumper(src, self).dump self._dump_funcs[key] = func return func diff --git a/tests/test_adapt.py b/tests/test_adapt.py index a22c4e1ea..6a26fc89f 100644 --- a/tests/test_adapt.py +++ b/tests/test_adapt.py @@ -25,9 +25,19 @@ def test_dump(data, format, result, type): assert rv == result +def make_dumper(suffix): + """Create a test dumper appending a suffix to the bytes representation.""" + + class TestDumper(Dumper): + def dump(self, s): + return (s + suffix).encode("ascii") + + return TestDumper + + def test_dump_connection_ctx(conn): - Dumper.register(str, lambda s: s.encode("ascii") + b"t", conn) - Dumper.register_binary(str, lambda s: s.encode("ascii") + b"b", conn) + Dumper.register(str, make_dumper("t"), conn) + Dumper.register_binary(str, make_dumper("b"), conn) cur = conn.cursor() cur.execute("select %s, %b", ["hello", "world"]) @@ -35,12 +45,12 @@ def test_dump_connection_ctx(conn): def test_dump_cursor_ctx(conn): - Dumper.register(str, lambda s: s.encode("ascii") + b"t", conn) - Dumper.register_binary(str, lambda s: s.encode("ascii") + b"b", conn) + Dumper.register(str, make_dumper("t"), conn) + Dumper.register_binary(str, make_dumper("b"), conn) cur = conn.cursor() - Dumper.register(str, lambda s: s.encode("ascii") + b"tc", cur) - Dumper.register_binary(str, lambda s: s.encode("ascii") + b"bc", cur) + Dumper.register(str, make_dumper("tc"), cur) + Dumper.register_binary(str, make_dumper("bc"), cur) cur.execute("select %s, %b", ["hello", "world"]) assert cur.fetchone() == ("hellotc", "worldbc")