From: Daniele Varrazzo Date: Fri, 25 Jun 2021 17:17:45 +0000 (+0100) Subject: Stop using the psycopg3.types module as facade for all the types X-Git-Tag: 3.0.dev0~17^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b2fd09b7448707a95f7588e9bc9da94e3c9e0dbb;p=thirdparty%2Fpsycopg.git Stop using the psycopg3.types module as facade for all the types Drop the psycopg3.wrappers package too and define the interface where to take the wrapper to be psycopg3.types.MODULE --- diff --git a/docs/basic/adapt.rst b/docs/basic/adapt.rst index 22af60848..ad4d6fc60 100644 --- a/docs/basic/adapt.rst +++ b/docs/basic/adapt.rst @@ -266,7 +266,7 @@ either `psycopg3.types.Json` or `~psycopg3.types.Jsonb`. .. code:: python - from psycopg3.types import Jsonb + from psycopg3.types.json import Jsonb thing = {"foo": ["bar", 42]} conn.execute("insert into mytable values (%s)", [Jsonb(thing)]) @@ -275,8 +275,9 @@ By default `!psycopg3` uses the standard library `json.dumps()`__ and `json.loads()`__ functions to serialize and de-serialize Python objects to JSON. If you want to customise globally how serialization happens, for instance changing serialization parameters or using a different JSON library, -you can specify your own functions using the `psycopg3.types.set_json_dumps()` -and `~psycopg3.types.set_json_loads()` functions. +you can specify your own functions using the +`psycopg3.types.json.set_json_dumps()` and +`~psycopg3.types.json.set_json_loads()` functions. .. weird: intersphinx doesn't work @@ -287,7 +288,7 @@ and `~psycopg3.types.set_json_loads()` functions. .. code:: python from functools import partial - from psycopg3.types import Jsonb, set_json_dumps, set_json_loads + from psycopg3.types.json import Jsonb, set_json_dumps, set_json_loads import ujson # Use a faster dump function diff --git a/psycopg3/psycopg3/types/__init__.py b/psycopg3/psycopg3/types/__init__.py index b455ea12c..f81c87709 100644 --- a/psycopg3/psycopg3/types/__init__.py +++ b/psycopg3/psycopg3/types/__init__.py @@ -4,34 +4,15 @@ psycopg3 types package # Copyright (C) 2020-2021 The Psycopg Team -from ..oids import INVALID_OID -from ..proto import AdaptContext -from .array import register_all_arrays -from . import range as _range +from typing import TYPE_CHECKING -# Wrapper objects -from ..wrappers.numeric import ( - Int2 as Int2, - Int4 as Int4, - Int8 as Int8, - IntNumeric as IntNumeric, - Oid as Oid, -) -from .json import Json as Json, Jsonb as Jsonb -from .range import Range as Range +from . import json as _json +from . import array as _array +from . import range as _range +from . import numeric as _numeric # Database types descriptors -from .._typeinfo import ( - TypeInfo as TypeInfo, - RangeInfo as RangeInfo, - CompositeInfo as CompositeInfo, -) - -# Json global registrations -from .json import ( - set_json_dumps as set_json_dumps, - set_json_loads as set_json_loads, -) +from .._typeinfo import TypeInfo as TypeInfo # exported here # Adapter objects from .text import ( @@ -176,8 +157,14 @@ from .composite import ( CompositeBinaryLoader as CompositeBinaryLoader, ) +if TYPE_CHECKING: + from ..proto import AdaptContext + + +def register_default_globals(ctx: "AdaptContext") -> None: + + from ..oids import INVALID_OID -def register_default_globals(ctx: AdaptContext) -> None: # 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 @@ -212,15 +199,15 @@ def register_default_globals(ctx: AdaptContext) -> None: # (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) + 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) @@ -265,10 +252,10 @@ 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) + 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) @@ -296,8 +283,8 @@ def register_default_globals(ctx: AdaptContext) -> None: CidrLoader.register("cidr", ctx) CidrBinaryLoader.register("cidr", ctx) - RangeBinaryDumper.register(Range, ctx) - RangeDumper.register(Range, 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) @@ -330,4 +317,4 @@ def register_default_globals(ctx: AdaptContext) -> None: RecordLoader.register("record", ctx) RecordBinaryLoader.register("record", ctx) - register_all_arrays(ctx) + _array.register_all_arrays(ctx) diff --git a/psycopg3/psycopg3/types/composite.py b/psycopg3/psycopg3/types/composite.py index 5245e9d2c..c8b4256b2 100644 --- a/psycopg3/psycopg3/types/composite.py +++ b/psycopg3/psycopg3/types/composite.py @@ -15,7 +15,7 @@ from ..oids import TEXT_OID from ..adapt import Format, RecursiveDumper, RecursiveLoader from ..proto import AdaptContext, Buffer from .._struct import unpack_len -from .._typeinfo import CompositeInfo +from .._typeinfo import CompositeInfo as CompositeInfo # exported here _struct_oidlen = struct.Struct("!Ii") _unpack_oidlen = cast( diff --git a/psycopg3/psycopg3/types/numeric.py b/psycopg3/psycopg3/types/numeric.py index a940841a1..8974ded0b 100644 --- a/psycopg3/psycopg3/types/numeric.py +++ b/psycopg3/psycopg3/types/numeric.py @@ -18,11 +18,35 @@ 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 from .._struct import pack_float8, unpack_float4, unpack_float8 -from ..wrappers.numeric import Int2, Int4, Int8, IntNumeric # Wrappers to force numbers to be cast as specific PostgreSQL types +class Int2(int): + def __new__(cls, arg: int) -> "Int2": + return super().__new__(cls, arg) + + +class Int4(int): + def __new__(cls, arg: int) -> "Int4": + return super().__new__(cls, arg) + + +class Int8(int): + def __new__(cls, arg: int) -> "Int8": + return super().__new__(cls, arg) + + +class IntNumeric(int): + def __new__(cls, arg: int) -> "IntNumeric": + return super().__new__(cls, arg) + + +class Oid(int): + def __new__(cls, arg: int) -> "Oid": + return super().__new__(cls, arg) + + class NumberDumper(Dumper): format = Format.TEXT diff --git a/psycopg3/psycopg3/types/range.py b/psycopg3/psycopg3/types/range.py index 3a618be3c..3a2efb465 100644 --- a/psycopg3/psycopg3/types/range.py +++ b/psycopg3/psycopg3/types/range.py @@ -16,7 +16,7 @@ from ..adapt import Dumper, RecursiveDumper, RecursiveLoader from ..adapt import Format as Pg3Format from ..proto import AdaptContext, Buffer from .._struct import pack_len, unpack_len -from .._typeinfo import RangeInfo +from .._typeinfo import RangeInfo as RangeInfo # exported here from .composite import SequenceDumper, BaseCompositeLoader diff --git a/psycopg3/psycopg3/wrappers/__init__.py b/psycopg3/psycopg3/wrappers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/psycopg3/psycopg3/wrappers/numeric.py b/psycopg3/psycopg3/wrappers/numeric.py deleted file mode 100644 index 74a7e9361..000000000 --- a/psycopg3/psycopg3/wrappers/numeric.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Wrappers to force numbers to be cast as specific PostgreSQL types -""" - -# Copyright (C) 2020-2021 The Psycopg Team - - -class Int2(int): - def __new__(cls, arg: int) -> "Int2": - return super().__new__(cls, arg) - - -class Int4(int): - def __new__(cls, arg: int) -> "Int4": - return super().__new__(cls, arg) - - -class Int8(int): - def __new__(cls, arg: int) -> "Int8": - return super().__new__(cls, arg) - - -class IntNumeric(int): - def __new__(cls, arg: int) -> "IntNumeric": - return super().__new__(cls, arg) - - -class Oid(int): - def __new__(cls, arg: int) -> "Oid": - return super().__new__(cls, arg) diff --git a/psycopg3_c/psycopg3_c/types/numeric.pyx b/psycopg3_c/psycopg3_c/types/numeric.pyx index 1c80f9eff..82f05766d 100644 --- a/psycopg3_c/psycopg3_c/types/numeric.pyx +++ b/psycopg3_c/psycopg3_c/types/numeric.pyx @@ -22,7 +22,7 @@ from decimal import Decimal, Context, DefaultContext from psycopg3_c._psycopg3 cimport endian from psycopg3 import errors as e -from psycopg3.wrappers.numeric import Int2, Int4, Int8, IntNumeric +from psycopg3.types.numeric import Int2, Int4, Int8, IntNumeric cdef extern from "Python.h": # work around https://github.com/cython/cython/issues/3909 diff --git a/tests/fix_faker.py b/tests/fix_faker.py index 7b69d4779..4b552af5f 100644 --- a/tests/fix_faker.py +++ b/tests/fix_faker.py @@ -13,7 +13,7 @@ import psycopg3 from psycopg3 import sql from psycopg3.adapt import Format from psycopg3.types.range import Range -from psycopg3.wrappers.numeric import Int4, Int8 +from psycopg3.types.numeric import Int4, Int8 @pytest.fixture diff --git a/tests/test_copy.py b/tests/test_copy.py index 17db186f2..be5051aac 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -12,7 +12,7 @@ from psycopg3 import sql from psycopg3 import errors as e from psycopg3.pq import Format from psycopg3.adapt import Format as PgFormat -from psycopg3.types import Int4 +from psycopg3.types.numeric import Int4 from .utils import gc_collect diff --git a/tests/types/test_composite.py b/tests/types/test_composite.py index 078e4f3b4..da02e80be 100644 --- a/tests/types/test_composite.py +++ b/tests/types/test_composite.py @@ -4,7 +4,7 @@ from psycopg3 import pq from psycopg3.sql import Identifier from psycopg3.oids import postgres_types as builtins from psycopg3.adapt import Format, global_adapters -from psycopg3.types import CompositeInfo +from psycopg3.types.composite import CompositeInfo tests_str = [ diff --git a/tests/types/test_json.py b/tests/types/test_json.py index a903e8517..f1a5d0948 100644 --- a/tests/types/test_json.py +++ b/tests/types/test_json.py @@ -6,9 +6,8 @@ import pytest import psycopg3.types from psycopg3 import pq from psycopg3 import sql -from psycopg3.types import Json, Jsonb from psycopg3.adapt import Format -from psycopg3.types import set_json_dumps, set_json_loads +from psycopg3.types.json import Json, Jsonb, set_json_dumps, set_json_loads samples = [ "null", @@ -69,7 +68,7 @@ def test_json_load_copy(conn, val, jtype, fmt_out): @pytest.mark.parametrize("fmt_in", [Format.AUTO, Format.TEXT, Format.BINARY]) @pytest.mark.parametrize("wrapper", ["Json", "Jsonb"]) def test_json_dump_customise(conn, wrapper, fmt_in): - wrapper = getattr(psycopg3.types, wrapper) + wrapper = getattr(psycopg3.types.json, wrapper) obj = {"foo": "bar"} cur = conn.cursor() @@ -85,10 +84,10 @@ def test_json_dump_customise(conn, wrapper, fmt_in): @pytest.mark.parametrize("wrapper", ["Json", "Jsonb"]) def test_json_dump_subclass(conn, wrapper, fmt_in): JDumper = getattr( - psycopg3.types, + psycopg3.types.json, f"{wrapper}{'Binary' if fmt_in != Format.TEXT else ''}Dumper", ) - wrapper = getattr(psycopg3.types, wrapper) + wrapper = getattr(psycopg3.types.json, wrapper) class MyJsonDumper(JDumper): def get_dumps(self): @@ -121,7 +120,7 @@ def test_json_load_customise(conn, binary, pgtype): @pytest.mark.parametrize("pgtype", ["json", "jsonb"]) def test_json_load_subclass(conn, binary, pgtype): JLoader = getattr( - psycopg3.types, + psycopg3.types.json, f"{pgtype.title()}{'Binary' if binary else ''}Loader", ) diff --git a/tests/types/test_range.py b/tests/types/test_range.py index fe6c940ca..def7d112a 100644 --- a/tests/types/test_range.py +++ b/tests/types/test_range.py @@ -8,7 +8,7 @@ import psycopg3.errors from psycopg3 import pq from psycopg3.sql import Identifier from psycopg3.adapt import Format -from psycopg3.types import Range, RangeInfo +from psycopg3.types.range import Range, RangeInfo type2sub = {