From: Daniele Varrazzo Date: Sat, 26 Jun 2021 00:59:35 +0000 (+0100) Subject: Don't expose all the adapters in the types package X-Git-Tag: 3.0.dev0~17^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=75c9409882c62167b68bab811a610a6488c0bca4;p=thirdparty%2Fpsycopg.git Don't expose all the adapters in the types package --- diff --git a/docs/advanced/adapt.rst b/docs/advanced/adapt.rst index 27e8e4be6..bed85f572 100644 --- a/docs/advanced/adapt.rst +++ b/docs/advanced/adapt.rst @@ -81,7 +81,7 @@ cursor): from datetime import date from psycopg3.oids import postgres_types as builtins - from psycopg3.types import DateLoader, DateDumper + from psycopg3.types.date import DateLoader, DateDumper class InfDateDumper(DateDumper): def dump(self, obj): diff --git a/docs/api/types.rst b/docs/api/types.rst index 40ff77213..c85ad4ee3 100644 --- a/docs/api/types.rst +++ b/docs/api/types.rst @@ -71,7 +71,7 @@ information from certain class of PostgreSQL types and to create more specialised adapters configurations. -.. autoclass:: CompositeInfo +.. autoclass:: psycopg3.types.composite.CompositeInfo .. automethod:: register @@ -80,7 +80,7 @@ specialised adapters configurations. custom object if *factory* is specified. -.. autoclass:: RangeInfo +.. autoclass:: psycopg3.types.range.RangeInfo .. automethod:: register @@ -112,6 +112,8 @@ Objects wrappers JSON adapters ------------- +.. currentmodule:: psycopg3.types.json + .. autoclass:: Json .. autoclass:: Jsonb diff --git a/psycopg3/psycopg3/types/__init__.py b/psycopg3/psycopg3/types/__init__.py index f81c87709..158eee8a3 100644 --- a/psycopg3/psycopg3/types/__init__.py +++ b/psycopg3/psycopg3/types/__init__.py @@ -6,315 +6,34 @@ psycopg3 types package from typing import TYPE_CHECKING -from . import json as _json -from . import array as _array -from . import range as _range -from . import numeric as _numeric +from . import date +from . import json +from . import text +from . import uuid +from . import array +from . import range +from . import network +from . import numeric +from . import composite +from . import singletons -# Database types descriptors from .._typeinfo import TypeInfo as TypeInfo # exported here -# Adapter objects -from .text import ( - StringDumper as StringDumper, - StringBinaryDumper as StringBinaryDumper, - TextLoader as TextLoader, - TextBinaryLoader as TextBinaryLoader, - BytesDumper as BytesDumper, - BytesBinaryDumper as BytesBinaryDumper, - ByteaLoader as ByteaLoader, - ByteaBinaryLoader as ByteaBinaryLoader, -) -from .numeric import ( - IntDumper as IntDumper, - IntBinaryDumper as IntBinaryDumper, - FloatDumper as FloatDumper, - FloatBinaryDumper as FloatBinaryDumper, - DecimalDumper as DecimalDumper, - DecimalBinaryDumper as DecimalBinaryDumper, - Int2Dumper as Int2Dumper, - Int4Dumper as Int4Dumper, - Int8Dumper as Int8Dumper, - IntNumericDumper as IntNumericDumper, - OidDumper as OidDumper, - Int2BinaryDumper as Int2BinaryDumper, - Int4BinaryDumper as Int4BinaryDumper, - Int8BinaryDumper as Int8BinaryDumper, - OidBinaryDumper as OidBinaryDumper, - IntLoader as IntLoader, - Int2BinaryLoader as Int2BinaryLoader, - Int4BinaryLoader as Int4BinaryLoader, - Int8BinaryLoader as Int8BinaryLoader, - OidBinaryLoader as OidBinaryLoader, - FloatLoader as FloatLoader, - Float4BinaryLoader as Float4BinaryLoader, - Float8BinaryLoader as Float8BinaryLoader, - NumericLoader as NumericLoader, - NumericBinaryLoader as NumericBinaryLoader, -) -from .singletons import ( - BoolDumper as BoolDumper, - BoolBinaryDumper as BoolBinaryDumper, - NoneDumper as NoneDumper, - BoolLoader as BoolLoader, - BoolBinaryLoader as BoolBinaryLoader, -) -from .date import ( - DateDumper as DateDumper, - DateBinaryDumper as DateBinaryDumper, - TimeDumper as TimeDumper, - TimeBinaryDumper as TimeBinaryDumper, - TimeTzDumper as TimeTzDumper, - TimeTzBinaryDumper as TimeTzBinaryDumper, - DateTimeTzDumper as DateTimeTzDumper, - DateTimeTzBinaryDumper as DateTimeTzBinaryDumper, - DateTimeDumper as DateTimeDumper, - DateTimeBinaryDumper as DateTimeBinaryDumper, - TimeDeltaDumper as TimeDeltaDumper, - TimeDeltaBinaryDumper as TimeDeltaBinaryDumper, - DateLoader as DateLoader, - DateBinaryLoader as DateBinaryLoader, - TimeLoader as TimeLoader, - TimeBinaryLoader as TimeBinaryLoader, - TimetzLoader as TimetzLoader, - TimetzBinaryLoader as TimetzBinaryLoader, - TimestampLoader as TimestampLoader, - TimestampBinaryLoader as TimestampBinaryLoader, - TimestamptzLoader as TimestamptzLoader, - TimestamptzBinaryLoader as TimestamptzBinaryLoader, - IntervalLoader as IntervalLoader, - IntervalBinaryLoader as IntervalBinaryLoader, -) -from .json import ( - JsonDumper as JsonDumper, - JsonBinaryDumper as JsonBinaryDumper, - JsonbDumper as JsonbDumper, - JsonbBinaryDumper as JsonbBinaryDumper, - JsonLoader as JsonLoader, - JsonBinaryLoader as JsonBinaryLoader, - JsonbLoader as JsonbLoader, - JsonbBinaryLoader as JsonbBinaryLoader, -) -from .uuid import ( - UUIDDumper as UUIDDumper, - UUIDBinaryDumper as UUIDBinaryDumper, - UUIDLoader as UUIDLoader, - UUIDBinaryLoader as UUIDBinaryLoader, -) -from .network import ( - InterfaceDumper as InterfaceDumper, - NetworkDumper as NetworkDumper, - IPv4AddressBinaryDumper as IPv4AddressBinaryDumper, - IPv6AddressBinaryDumper as IPv6AddressBinaryDumper, - IPv4InterfaceBinaryDumper as IPv4InterfaceBinaryDumper, - IPv6InterfaceBinaryDumper as IPv6InterfaceBinaryDumper, - IPv4NetworkBinaryDumper as IPv4NetworkBinaryDumper, - IPv6NetworkBinaryDumper as IPv6NetworkBinaryDumper, - InetLoader as InetLoader, - InetBinaryLoader as InetBinaryLoader, - CidrLoader as CidrLoader, - CidrBinaryLoader as CidrBinaryLoader, -) -from .range import ( - RangeDumper as RangeDumper, - Int4RangeDumper as Int4RangeDumper, - Int8RangeDumper as Int8RangeDumper, - NumericRangeDumper as NumericRangeDumper, - DateRangeDumper as DateRangeDumper, - TimestampRangeDumper as TimestampRangeDumper, - TimestamptzRangeDumper as TimestamptzRangeDumper, - RangeBinaryDumper as RangeBinaryDumper, - Int4RangeBinaryDumper as Int4RangeBinaryDumper, - Int8RangeBinaryDumper as Int8RangeBinaryDumper, - NumericRangeBinaryDumper as NumericRangeBinaryDumper, - DateRangeBinaryDumper as DateRangeBinaryDumper, - TimestampRangeBinaryDumper as TimestampRangeBinaryDumper, - TimestamptzRangeBinaryDumper as TimestamptzRangeBinaryDumper, - RangeLoader as RangeLoader, - Int4RangeLoader as Int4RangeLoader, - Int8RangeLoader as Int8RangeLoader, - NumericRangeLoader as NumericRangeLoader, - DateRangeLoader as DateRangeLoader, - TimestampRangeLoader as TimestampRangeLoader, - TimestampTZRangeLoader as TimestampTZRangeLoader, - RangeBinaryLoader as RangeBinaryLoader, - Int4RangeBinaryLoader as Int4RangeBinaryLoader, - Int8RangeBinaryLoader as Int8RangeBinaryLoader, - NumericRangeBinaryLoader as NumericRangeBinaryLoader, - DateRangeBinaryLoader as DateRangeBinaryLoader, - TimestampRangeBinaryLoader as TimestampRangeBinaryLoader, - TimestampTZRangeBinaryLoader as TimestampTZRangeBinaryLoader, -) -from .array import ( - ListDumper as ListDumper, - ListBinaryDumper as ListBinaryDumper, -) -from .composite import ( - TupleDumper as TupleDumper, - RecordLoader as RecordLoader, - RecordBinaryLoader as RecordBinaryLoader, - CompositeLoader as CompositeLoader, - CompositeBinaryLoader as CompositeBinaryLoader, -) - if TYPE_CHECKING: from ..proto import AdaptContext def register_default_globals(ctx: "AdaptContext") -> None: - - from ..oids import INVALID_OID - - # NOTE: the order the dumpers are registered is relevant. - # The last one registered becomes the default for each type. - # Normally, binary is the default dumper, except for text (which plays - # the role of unknown, so it can be cast automatically to other types). - StringBinaryDumper.register(str, ctx) - StringDumper.register(str, ctx) - TextLoader.register(INVALID_OID, ctx) - TextLoader.register("bpchar", ctx) - TextLoader.register("name", ctx) - TextLoader.register("text", ctx) - TextLoader.register("varchar", ctx) - TextBinaryLoader.register("bpchar", ctx) - TextBinaryLoader.register("name", ctx) - TextBinaryLoader.register("text", ctx) - TextBinaryLoader.register("varchar", ctx) - - BytesDumper.register(bytes, ctx) - BytesDumper.register(bytearray, ctx) - BytesDumper.register(memoryview, ctx) - BytesBinaryDumper.register(bytes, ctx) - BytesBinaryDumper.register(bytearray, ctx) - BytesBinaryDumper.register(memoryview, ctx) - ByteaLoader.register("bytea", ctx) - ByteaBinaryLoader.register(INVALID_OID, ctx) - ByteaBinaryLoader.register("bytea", ctx) - - IntDumper.register(int, ctx) - IntBinaryDumper.register(int, ctx) - FloatDumper.register(float, ctx) - FloatBinaryDumper.register(float, ctx) - # The binary dumper is currently some 30% slower, so default to text - # (see tests/scripts/testdec.py for a rough benchmark) - DecimalBinaryDumper.register("decimal.Decimal", ctx) - DecimalDumper.register("decimal.Decimal", ctx) - Int2Dumper.register(_numeric.Int2, ctx) - Int4Dumper.register(_numeric.Int4, ctx) - Int8Dumper.register(_numeric.Int8, ctx) - IntNumericDumper.register(_numeric.IntNumeric, ctx) - OidDumper.register(_numeric.Oid, ctx) - Int2BinaryDumper.register(_numeric.Int2, ctx) - Int4BinaryDumper.register(_numeric.Int4, ctx) - Int8BinaryDumper.register(_numeric.Int8, ctx) - OidBinaryDumper.register(_numeric.Oid, ctx) - IntLoader.register("int2", ctx) - IntLoader.register("int4", ctx) - IntLoader.register("int8", ctx) - IntLoader.register("oid", ctx) - Int2BinaryLoader.register("int2", ctx) - Int4BinaryLoader.register("int4", ctx) - Int8BinaryLoader.register("int8", ctx) - OidBinaryLoader.register("oid", ctx) - FloatLoader.register("float4", ctx) - FloatLoader.register("float8", ctx) - Float4BinaryLoader.register("float4", ctx) - Float8BinaryLoader.register("float8", ctx) - NumericLoader.register("numeric", ctx) - NumericBinaryLoader.register("numeric", ctx) - - BoolDumper.register(bool, ctx) - BoolBinaryDumper.register(bool, ctx) - NoneDumper.register(type(None), ctx) - BoolLoader.register("bool", ctx) - BoolBinaryLoader.register("bool", ctx) - - DateDumper.register("datetime.date", ctx) - DateBinaryDumper.register("datetime.date", ctx) - TimeDumper.register("datetime.time", ctx) - TimeBinaryDumper.register("datetime.time", ctx) - DateTimeTzDumper.register("datetime.datetime", ctx) - DateTimeTzBinaryDumper.register("datetime.datetime", ctx) - TimeDeltaDumper.register("datetime.timedelta", ctx) - TimeDeltaBinaryDumper.register("datetime.timedelta", ctx) - DateLoader.register("date", ctx) - DateBinaryLoader.register("date", ctx) - TimeLoader.register("time", ctx) - TimeBinaryLoader.register("time", ctx) - TimetzLoader.register("timetz", ctx) - TimetzBinaryLoader.register("timetz", ctx) - TimestampLoader.register("timestamp", ctx) - TimestampBinaryLoader.register("timestamp", ctx) - TimestamptzLoader.register("timestamptz", ctx) - TimestamptzBinaryLoader.register("timestamptz", ctx) - IntervalLoader.register("interval", ctx) - IntervalBinaryLoader.register("interval", ctx) - - # Currently json binary format is nothing different than text, maybe with - # an extra memcopy we can avoid. - JsonBinaryDumper.register(_json.Json, ctx) - JsonDumper.register(_json.Json, ctx) - JsonbBinaryDumper.register(_json.Jsonb, ctx) - JsonbDumper.register(_json.Jsonb, ctx) - JsonLoader.register("json", ctx) - JsonbLoader.register("jsonb", ctx) - JsonBinaryLoader.register("json", ctx) - JsonbBinaryLoader.register("jsonb", ctx) - - UUIDDumper.register("uuid.UUID", ctx) - UUIDBinaryDumper.register("uuid.UUID", ctx) - UUIDLoader.register("uuid", ctx) - UUIDBinaryLoader.register("uuid", ctx) - - InterfaceDumper.register("ipaddress.IPv4Address", ctx) - InterfaceDumper.register("ipaddress.IPv6Address", ctx) - InterfaceDumper.register("ipaddress.IPv4Interface", ctx) - InterfaceDumper.register("ipaddress.IPv6Interface", ctx) - NetworkDumper.register("ipaddress.IPv4Network", ctx) - NetworkDumper.register("ipaddress.IPv6Network", ctx) - IPv4AddressBinaryDumper.register("ipaddress.IPv4Address", ctx) - IPv6AddressBinaryDumper.register("ipaddress.IPv6Address", ctx) - IPv4InterfaceBinaryDumper.register("ipaddress.IPv4Interface", ctx) - IPv6InterfaceBinaryDumper.register("ipaddress.IPv6Interface", ctx) - IPv4NetworkBinaryDumper.register("ipaddress.IPv4Network", ctx) - IPv6NetworkBinaryDumper.register("ipaddress.IPv6Network", ctx) - InetLoader.register("inet", ctx) - InetBinaryLoader.register("inet", ctx) - CidrLoader.register("cidr", ctx) - CidrBinaryLoader.register("cidr", ctx) - - RangeBinaryDumper.register(_range.Range, ctx) - RangeDumper.register(_range.Range, ctx) - Int4RangeDumper.register(_range.Int4Range, ctx) - Int8RangeDumper.register(_range.Int8Range, ctx) - NumericRangeDumper.register(_range.NumericRange, ctx) - DateRangeDumper.register(_range.DateRange, ctx) - TimestampRangeDumper.register(_range.TimestampRange, ctx) - TimestamptzRangeDumper.register(_range.TimestamptzRange, ctx) - Int4RangeBinaryDumper.register(_range.Int4Range, ctx) - Int8RangeBinaryDumper.register(_range.Int8Range, ctx) - NumericRangeBinaryDumper.register(_range.NumericRange, ctx) - DateRangeBinaryDumper.register(_range.DateRange, ctx) - TimestampRangeBinaryDumper.register(_range.TimestampRange, ctx) - TimestamptzRangeBinaryDumper.register(_range.TimestamptzRange, ctx) - Int4RangeLoader.register("int4range", ctx) - Int8RangeLoader.register("int8range", ctx) - NumericRangeLoader.register("numrange", ctx) - DateRangeLoader.register("daterange", ctx) - TimestampRangeLoader.register("tsrange", ctx) - TimestampTZRangeLoader.register("tstzrange", ctx) - Int4RangeBinaryLoader.register("int4range", ctx) - Int8RangeBinaryLoader.register("int8range", ctx) - NumericRangeBinaryLoader.register("numrange", ctx) - DateRangeBinaryLoader.register("daterange", ctx) - TimestampRangeBinaryLoader.register("tsrange", ctx) - TimestampTZRangeBinaryLoader.register("tstzrange", ctx) - - ListDumper.register(list, ctx) - ListBinaryDumper.register(list, ctx) - - TupleDumper.register(tuple, ctx) - RecordLoader.register("record", ctx) - RecordBinaryLoader.register("record", ctx) - - _array.register_all_arrays(ctx) + date.register_default_globals(ctx) + json.register_default_globals(ctx) + text.register_default_globals(ctx) + uuid.register_default_globals(ctx) + array.register_default_globals(ctx) + range.register_default_globals(ctx) + network.register_default_globals(ctx) + numeric.register_default_globals(ctx) + composite.register_default_globals(ctx) + singletons.register_default_globals(ctx) + + # Must come after all the types are registered + array.register_all_arrays(ctx) diff --git a/psycopg3/psycopg3/types/array.py b/psycopg3/psycopg3/types/array.py index 5090eb593..85b2c7fcf 100644 --- a/psycopg3/psycopg3/types/array.py +++ b/psycopg3/psycopg3/types/array.py @@ -328,6 +328,11 @@ def register_adapters( loader.register(info.array_oid, context=context) +def register_default_globals(ctx: AdaptContext) -> None: + ListDumper.register(list, ctx) + ListBinaryDumper.register(list, ctx) + + def register_all_arrays(ctx: AdaptContext) -> None: """ Associate the array oid of all the types in Loader.globals. diff --git a/psycopg3/psycopg3/types/composite.py b/psycopg3/psycopg3/types/composite.py index c8b4256b2..07b3a2c94 100644 --- a/psycopg3/psycopg3/types/composite.py +++ b/psycopg3/psycopg3/types/composite.py @@ -208,3 +208,9 @@ def register_adapters( {"factory": factory}, ) loader.register(info.oid, context=context) + + +def register_default_globals(ctx: AdaptContext) -> None: + TupleDumper.register(tuple, ctx) + RecordLoader.register("record", ctx) + RecordBinaryLoader.register("record", ctx) diff --git a/psycopg3/psycopg3/types/date.py b/psycopg3/psycopg3/types/date.py index 262ec23d7..505356dd1 100644 --- a/psycopg3/psycopg3/types/date.py +++ b/psycopg3/psycopg3/types/date.py @@ -737,3 +737,26 @@ _month_abbr = { # Pad to get microseconds from a fraction of seconds _uspad = [0, 100_000, 10_000, 1_000, 100, 10, 1] + + +def register_default_globals(ctx: AdaptContext) -> None: + DateDumper.register("datetime.date", ctx) + DateBinaryDumper.register("datetime.date", ctx) + TimeDumper.register("datetime.time", ctx) + TimeBinaryDumper.register("datetime.time", ctx) + DateTimeTzDumper.register("datetime.datetime", ctx) + DateTimeTzBinaryDumper.register("datetime.datetime", ctx) + TimeDeltaDumper.register("datetime.timedelta", ctx) + TimeDeltaBinaryDumper.register("datetime.timedelta", ctx) + DateLoader.register("date", ctx) + DateBinaryLoader.register("date", ctx) + TimeLoader.register("time", ctx) + TimeBinaryLoader.register("time", ctx) + TimetzLoader.register("timetz", ctx) + TimetzBinaryLoader.register("timetz", ctx) + TimestampLoader.register("timestamp", ctx) + TimestampBinaryLoader.register("timestamp", ctx) + TimestamptzLoader.register("timestamptz", ctx) + TimestamptzBinaryLoader.register("timestamptz", ctx) + IntervalLoader.register("interval", ctx) + IntervalBinaryLoader.register("interval", ctx) diff --git a/psycopg3/psycopg3/types/json.py b/psycopg3/psycopg3/types/json.py index 528fc78b0..206ca12e6 100644 --- a/psycopg3/psycopg3/types/json.py +++ b/psycopg3/psycopg3/types/json.py @@ -162,3 +162,16 @@ class JsonbBinaryLoader(_JsonLoader): if isinstance(data, memoryview): data = bytes(data) return self._loads(data) + + +def register_default_globals(ctx: AdaptContext) -> None: + # Currently json binary format is nothing different than text, maybe with + # an extra memcopy we can avoid. + JsonBinaryDumper.register(Json, ctx) + JsonDumper.register(Json, ctx) + JsonbBinaryDumper.register(Jsonb, ctx) + JsonbDumper.register(Jsonb, ctx) + JsonLoader.register("json", ctx) + JsonbLoader.register("jsonb", ctx) + JsonBinaryLoader.register("json", ctx) + JsonbBinaryLoader.register("jsonb", ctx) diff --git a/psycopg3/psycopg3/types/network.py b/psycopg3/psycopg3/types/network.py index 7248323bd..bd9942fb4 100644 --- a/psycopg3/psycopg3/types/network.py +++ b/psycopg3/psycopg3/types/network.py @@ -207,3 +207,22 @@ class CidrBinaryLoader(_LazyIpaddress): return IPv6Network((packed, prefix)) return ip_network(data.decode("utf8")) + + +def register_default_globals(ctx: AdaptContext) -> None: + InterfaceDumper.register("ipaddress.IPv4Address", ctx) + InterfaceDumper.register("ipaddress.IPv6Address", ctx) + InterfaceDumper.register("ipaddress.IPv4Interface", ctx) + InterfaceDumper.register("ipaddress.IPv6Interface", ctx) + NetworkDumper.register("ipaddress.IPv4Network", ctx) + NetworkDumper.register("ipaddress.IPv6Network", ctx) + IPv4AddressBinaryDumper.register("ipaddress.IPv4Address", ctx) + IPv6AddressBinaryDumper.register("ipaddress.IPv6Address", ctx) + IPv4InterfaceBinaryDumper.register("ipaddress.IPv4Interface", ctx) + IPv6InterfaceBinaryDumper.register("ipaddress.IPv6Interface", ctx) + IPv4NetworkBinaryDumper.register("ipaddress.IPv4Network", ctx) + IPv6NetworkBinaryDumper.register("ipaddress.IPv6Network", ctx) + InetLoader.register("inet", ctx) + InetBinaryLoader.register("inet", ctx) + CidrLoader.register("cidr", ctx) + CidrBinaryLoader.register("cidr", ctx) diff --git a/psycopg3/psycopg3/types/numeric.py b/psycopg3/psycopg3/types/numeric.py index 8974ded0b..9a9074350 100644 --- a/psycopg3/psycopg3/types/numeric.py +++ b/psycopg3/psycopg3/types/numeric.py @@ -14,6 +14,7 @@ from ..pq import Format from ..oids import postgres_types as builtins from ..adapt import Buffer, Dumper, Loader from ..adapt import Format as Pg3Format +from ..proto import AdaptContext from .._struct import pack_int2, pack_uint2, unpack_int2 from .._struct import pack_int4, pack_uint4, unpack_int4, unpack_uint4 from .._struct import pack_int8, unpack_int8 @@ -450,3 +451,37 @@ class DecimalBinaryDumper(Dumper): out += pack_uint2(pgdigit) return out + + +def register_default_globals(ctx: AdaptContext) -> None: + IntDumper.register(int, ctx) + IntBinaryDumper.register(int, ctx) + FloatDumper.register(float, ctx) + FloatBinaryDumper.register(float, ctx) + # The binary dumper is currently some 30% slower, so default to text + # (see tests/scripts/testdec.py for a rough benchmark) + DecimalBinaryDumper.register("decimal.Decimal", ctx) + DecimalDumper.register("decimal.Decimal", ctx) + Int2Dumper.register(Int2, ctx) + Int4Dumper.register(Int4, ctx) + Int8Dumper.register(Int8, ctx) + IntNumericDumper.register(IntNumeric, ctx) + OidDumper.register(Oid, ctx) + Int2BinaryDumper.register(Int2, ctx) + Int4BinaryDumper.register(Int4, ctx) + Int8BinaryDumper.register(Int8, ctx) + OidBinaryDumper.register(Oid, ctx) + IntLoader.register("int2", ctx) + IntLoader.register("int4", ctx) + IntLoader.register("int8", ctx) + IntLoader.register("oid", ctx) + Int2BinaryLoader.register("int2", ctx) + Int4BinaryLoader.register("int4", ctx) + Int8BinaryLoader.register("int8", ctx) + OidBinaryLoader.register("oid", ctx) + FloatLoader.register("float4", ctx) + FloatLoader.register("float8", ctx) + Float4BinaryLoader.register("float4", ctx) + Float8BinaryLoader.register("float8", ctx) + NumericLoader.register("numeric", ctx) + NumericBinaryLoader.register("numeric", ctx) diff --git a/psycopg3/psycopg3/types/range.py b/psycopg3/psycopg3/types/range.py index 3a2efb465..212a4460e 100644 --- a/psycopg3/psycopg3/types/range.py +++ b/psycopg3/psycopg3/types/range.py @@ -569,3 +569,32 @@ class TimestampRangeBinaryLoader(RangeBinaryLoader[datetime]): class TimestampTZRangeBinaryLoader(RangeBinaryLoader[datetime]): subtype_oid = builtins["timestamptz"].oid + + +def register_default_globals(ctx: AdaptContext) -> None: + RangeBinaryDumper.register(Range, ctx) + RangeDumper.register(Range, ctx) + Int4RangeDumper.register(Int4Range, ctx) + Int8RangeDumper.register(Int8Range, ctx) + NumericRangeDumper.register(NumericRange, ctx) + DateRangeDumper.register(DateRange, ctx) + TimestampRangeDumper.register(TimestampRange, ctx) + TimestamptzRangeDumper.register(TimestamptzRange, ctx) + Int4RangeBinaryDumper.register(Int4Range, ctx) + Int8RangeBinaryDumper.register(Int8Range, ctx) + NumericRangeBinaryDumper.register(NumericRange, ctx) + DateRangeBinaryDumper.register(DateRange, ctx) + TimestampRangeBinaryDumper.register(TimestampRange, ctx) + TimestamptzRangeBinaryDumper.register(TimestamptzRange, ctx) + Int4RangeLoader.register("int4range", ctx) + Int8RangeLoader.register("int8range", ctx) + NumericRangeLoader.register("numrange", ctx) + DateRangeLoader.register("daterange", ctx) + TimestampRangeLoader.register("tsrange", ctx) + TimestampTZRangeLoader.register("tstzrange", ctx) + Int4RangeBinaryLoader.register("int4range", ctx) + Int8RangeBinaryLoader.register("int8range", ctx) + NumericRangeBinaryLoader.register("numrange", ctx) + DateRangeBinaryLoader.register("daterange", ctx) + TimestampRangeBinaryLoader.register("tsrange", ctx) + TimestampTZRangeBinaryLoader.register("tstzrange", ctx) diff --git a/psycopg3/psycopg3/types/singletons.py b/psycopg3/psycopg3/types/singletons.py index 539c15052..9db920c0c 100644 --- a/psycopg3/psycopg3/types/singletons.py +++ b/psycopg3/psycopg3/types/singletons.py @@ -7,6 +7,7 @@ Adapters for None and boolean. from ..pq import Format from ..oids import postgres_types as builtins from ..adapt import Buffer, Dumper, Loader +from ..proto import AdaptContext class BoolDumper(Dumper): @@ -59,3 +60,11 @@ class BoolBinaryLoader(Loader): def load(self, data: Buffer) -> bool: return data != b"\x00" + + +def register_default_globals(ctx: AdaptContext) -> None: + BoolDumper.register(bool, ctx) + BoolBinaryDumper.register(bool, ctx) + NoneDumper.register(type(None), ctx) + BoolLoader.register("bool", ctx) + BoolBinaryLoader.register("bool", ctx) diff --git a/psycopg3/psycopg3/types/text.py b/psycopg3/psycopg3/types/text.py index c298b1cc4..af405f206 100644 --- a/psycopg3/psycopg3/types/text.py +++ b/psycopg3/psycopg3/types/text.py @@ -130,3 +130,33 @@ class ByteaBinaryLoader(Loader): def load(self, data: Buffer) -> bytes: return data + + +def register_default_globals(ctx: "AdaptContext") -> None: + from ..oids import INVALID_OID + + # NOTE: the order the dumpers are registered is relevant. + # The last one registered becomes the default for each type. + # Normally, binary is the default dumper, except for text (which plays + # the role of unknown, so it can be cast automatically to other types). + StringBinaryDumper.register(str, ctx) + StringDumper.register(str, ctx) + TextLoader.register(INVALID_OID, ctx) + TextLoader.register("bpchar", ctx) + TextLoader.register("name", ctx) + TextLoader.register("text", ctx) + TextLoader.register("varchar", ctx) + TextBinaryLoader.register("bpchar", ctx) + TextBinaryLoader.register("name", ctx) + TextBinaryLoader.register("text", ctx) + TextBinaryLoader.register("varchar", ctx) + + BytesDumper.register(bytes, ctx) + BytesDumper.register(bytearray, ctx) + BytesDumper.register(memoryview, ctx) + BytesBinaryDumper.register(bytes, ctx) + BytesBinaryDumper.register(bytearray, ctx) + BytesBinaryDumper.register(memoryview, ctx) + ByteaLoader.register("bytea", ctx) + ByteaBinaryLoader.register(INVALID_OID, ctx) + ByteaBinaryLoader.register("bytea", ctx) diff --git a/psycopg3/psycopg3/types/uuid.py b/psycopg3/psycopg3/types/uuid.py index 67987322b..0767c4880 100644 --- a/psycopg3/psycopg3/types/uuid.py +++ b/psycopg3/psycopg3/types/uuid.py @@ -62,3 +62,10 @@ class UUIDBinaryLoader(UUIDLoader): if isinstance(data, memoryview): data = bytes(data) return UUID(bytes=data) + + +def register_default_globals(ctx: AdaptContext) -> None: + UUIDDumper.register("uuid.UUID", ctx) + UUIDBinaryDumper.register("uuid.UUID", ctx) + UUIDLoader.register("uuid", ctx) + UUIDBinaryLoader.register("uuid", ctx) diff --git a/tests/test_adapt.py b/tests/test_adapt.py index 374521568..9c6cc856d 100644 --- a/tests/test_adapt.py +++ b/tests/test_adapt.py @@ -1,4 +1,5 @@ import datetime as dt +from types import ModuleType import pytest @@ -93,7 +94,7 @@ def test_dump_subclass(conn, fmt_out): def test_subclass_dumper(conn): # This might be a C fast object: make sure that the Python code is called - from psycopg3.types import StringDumper + from psycopg3.types.text import StringDumper class MyStringDumper(StringDumper): def dump(self, obj): @@ -105,7 +106,7 @@ def test_subclass_dumper(conn): def test_subclass_loader(conn): # This might be a C fast object: make sure that the Python code is called - from psycopg3.types import TextLoader + from psycopg3.types.text import TextLoader class MyTextLoader(TextLoader): def load(self, data): @@ -291,9 +292,8 @@ def test_no_cast_needed(conn, fmt_in): assert cur.fetchone()[0] == 20 +@pytest.mark.skipif(psycopg3.pq.__impl__ == "python", reason="C module test") def test_optimised_adapters(): - if psycopg3.pq.__impl__ == "python": - pytest.skip("test C module only") from psycopg3_c import _psycopg3 @@ -330,15 +330,16 @@ def test_optimised_adapters(): # Check that every optimised adapter is the optimised version of a Py one for n in dir(psycopg3.types): - obj = getattr(psycopg3.types, n) - if not isinstance(obj, type): - continue - if not issubclass(obj, (Dumper, Loader)): + mod = getattr(psycopg3.types, n) + if not isinstance(mod, ModuleType): continue - c_adapters.pop(obj.__name__, None) - - # TODO: This dumper is not registered yet as not implemented - del c_adapters["IntNumericBinaryDumper"] + for n1 in dir(mod): + obj = getattr(mod, n1) + if not isinstance(obj, type): + continue + if not issubclass(obj, (Dumper, Loader)): + continue + c_adapters.pop(obj.__name__, None) assert not c_adapters diff --git a/tests/test_copy.py b/tests/test_copy.py index be5051aac..034de90c8 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -259,9 +259,9 @@ def test_copy_in_empty(conn, format): @pytest.mark.parametrize("format", [Format.TEXT, Format.BINARY]) def test_subclass_adapter(conn, format): if format == Format.TEXT: - from psycopg3.types import StringDumper as BaseDumper + from psycopg3.types.text import StringDumper as BaseDumper else: - from psycopg3.types import StringBinaryDumper as BaseDumper + from psycopg3.types.text import StringBinaryDumper as BaseDumper class MyStringDumper(BaseDumper): def dump(self, obj): diff --git a/tests/types/test_date.py b/tests/types/test_date.py index b58302115..3e420af7a 100644 --- a/tests/types/test_date.py +++ b/tests/types/test_date.py @@ -583,7 +583,7 @@ class TestInterval: # NOTE: this is an example in the docs. Make sure it doesn't regress when # adding binary datetime adapters from psycopg3.oids import postgres_types as builtins - from psycopg3.types import DateLoader, DateDumper + from psycopg3.types.date import DateLoader, DateDumper class InfDateDumper(DateDumper): def dump(self, obj):