]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Make register_composite(), register_range() the public interface
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 26 Aug 2021 17:46:53 +0000 (19:46 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 26 Aug 2021 18:46:41 +0000 (20:46 +0200)
Drop subclassing of `TypeInfo.register()`, leaving it only for the base
task of registering type info and array. This makes them consistent with
other types which don't have a TypeInfo subclass of their own and only
expose a `register_*()` function (e.g. hstore).

docs/api/abc.rst
docs/api/adapt.rst
docs/api/types.rst
psycopg/psycopg/_typeinfo.py
psycopg/psycopg/types/composite.py
psycopg/psycopg/types/hstore.py
psycopg/psycopg/types/range.py
tests/types/test_composite.py
tests/types/test_range.py

index ad20f26e8ee500fda845b90c2021dec838b546d7..0740e9c76f8de4245c143e1820f4620c99225b52 100644 (file)
@@ -77,3 +77,6 @@ checking.
 
 .. autoclass:: AdaptContext
     :members:
+
+    .. seealso:: :ref:`adaptation` for an explanation about how contexts are
+        connected.
index 66f8ffbca86d9cf3dcaf11c068d388244be2f023..3d7b34843e36f6724397a86365a14b0d26dbdeef 100644 (file)
@@ -53,6 +53,9 @@ Other objects used in adaptations
 
 .. autoclass:: AdaptersMap
 
+   .. seealso:: :ref:`adaptation` for an explanation about how contexts are
+       connected.
+
    .. automethod:: register_dumper
    .. automethod:: register_loader
 
index bf792bb82b8ff36cbdf5760a031e963dcab04f66..6269cb7b1630c432bc3abe3d62e69a11cfd323f1 100644 (file)
@@ -65,36 +65,19 @@ can extend the behaviour of the adapters: if you create a loader for
         database as a list of the base type.
 
 
-.. autoclass:: TypesRegistry
-
-
 The following `!TypeInfo` subclasses allow to fetch more specialised
-information from certain class of PostgreSQL types and to create more
-specialised adapters configurations.
-
+information from certain class of PostgreSQL types.
 
 .. autoclass:: psycopg.types.composite.CompositeInfo
 
-    .. automethod:: register
-
-        Using `!CompositeInfo.register()` will also register a specialised
-        loader to fetch the composite type as a Python named tuple, or a
-        custom object if *factory* is specified.
-
-
 .. autoclass:: psycopg.types.range.RangeInfo
 
-    .. automethod:: register
 
-        Using `!RangeInfo.register()` will also register a specialised loaders
-        and dumpers. For instance, if you create a PostgreSQL range on the
-        type :sql:`inet`, loading these object with the database will use the
-        loader for the :sql:`inet` type to parse the range bounds - either the
-        builtin ones or any one you might have configured.
+`!TypeInfo` objects are collected in `TypesRegistry` instances, which help type
+information lookup. Every `~psycopg.adapt.AdaptersMap` expose its type map on
+its `~psycopg.adapt.AdaptersMap.types` attribute.
 
-        The type information will also be used by the `Range` dumper so that
-        if you dump a `!Range(address1, address2)` object it will use the
-        correct oid for your :sql:`inetrange` type.
+.. autoclass:: TypesRegistry
 
 
 .. _numeric-wrappers:
index 0f7ff2026a5da937ddfb78da2b95b1898e47703d..991f1c74a59a10598485a925da96f36b3051ccf3 100644 (file)
@@ -7,7 +7,7 @@ information to the adapters if needed.
 
 # Copyright (C) 2020-2021 The Psycopg Team
 
-from typing import Any, Callable, Dict, Iterator, Optional
+from typing import Any, Dict, Iterator, Optional
 from typing import Sequence, Type, TypeVar, Union, TYPE_CHECKING
 
 from . import errors as e
@@ -159,13 +159,6 @@ class RangeInfo(TypeInfo):
         super().__init__(name, oid, array_oid)
         self.subtype_oid = subtype_oid
 
-    def register(self, context: Optional[AdaptContext] = None) -> None:
-        super().register(context)
-
-        from .types.range import register_range
-
-        register_range(self, context)
-
     _info_query = """\
 SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid,
     r.rngsubtype AS subtype_oid
@@ -194,17 +187,6 @@ class CompositeInfo(TypeInfo):
         # Will be set by register() if the `factory` is a type
         self.python_type: Optional[type] = None
 
-    def register(
-        self,
-        context: Optional[AdaptContext] = None,
-        factory: Optional[Callable[..., Any]] = None,
-    ) -> None:
-        super().register(context)
-
-        from .types.composite import register_composite
-
-        register_composite(self, context, factory)
-
     _info_query = """\
 SELECT
     t.typname AS name, t.oid AS oid, t.typarray AS array_oid,
index e1a84394662274bc94b6fd035e676e25034cd93d..ac223c7573b0de95e17c883dc53847a18dff5c98 100644 (file)
@@ -188,6 +188,10 @@ def register_composite(
     context: Optional[AdaptContext] = None,
     factory: Optional[Callable[..., Any]] = None,
 ) -> None:
+
+    # Register arrays and type info
+    info.register(context)
+
     if not factory:
         factory = namedtuple(info.name, info.field_names)  # type: ignore
 
index 59a5013b7e60b8db72ebc6ec897eb648165fc6a1..675e1f4b9d3ac73715f45b216593cbdd8308c022 100644 (file)
@@ -109,6 +109,7 @@ def register_hstore(
     info: TypeInfo, context: Optional[AdaptContext] = None
 ) -> None:
 
+    # Register arrays and type info
     info.register(context)
 
     adapters = context.adapters if context else postgres.adapters
index 44e1af4252ed81902c1351e89cd0ed25bdc40961..f68cdac36f50e5cdbe00d3a69ffe83591c40b220 100644 (file)
@@ -445,6 +445,10 @@ def register_range(
     right subtype. Dumping the range just works, navigating from tye Python
     type to the type oid, to the range oid.
     """
+
+    # Register arrays and type info
+    info.register(context)
+
     adapters = context.adapters if context else postgres.adapters
 
     # generate and register a customized text loader
index 952959d93c9e885f8c9effe02ea190f5a8177901..8b18b76c22b6da149f5f1ffa61c864c57521596c 100644 (file)
@@ -4,8 +4,8 @@ from psycopg import pq, postgres
 from psycopg.sql import Identifier
 from psycopg.adapt import PyFormat as Format
 from psycopg.postgres import types as builtins
-from psycopg.types.composite import CompositeInfo, TupleDumper
-
+from psycopg.types.composite import CompositeInfo, register_composite
+from psycopg.types.composite import TupleDumper
 
 tests_str = [
     ("", ()),
@@ -39,7 +39,7 @@ def test_dump_tuple(conn, rec, obj):
         """
     )
     info = CompositeInfo.fetch(conn, "tmptype")
-    info.register(context=conn)
+    register_composite(info, conn)
 
     res = conn.execute("select %s::tmptype", [obj]).fetchone()[0]
     assert res == obj
@@ -172,7 +172,7 @@ def test_dump_composite_all_chars(conn, fmt_in, testcomp):
 @pytest.mark.parametrize("fmt_out", [pq.Format.TEXT, pq.Format.BINARY])
 def test_load_composite(conn, testcomp, fmt_out):
     info = CompositeInfo.fetch(conn, "testcomp")
-    info.register(conn)
+    register_composite(info, conn)
 
     cur = conn.cursor(binary=fmt_out)
     res = cur.execute("select row('hello', 10, 20)::testcomp").fetchone()[0]
@@ -197,7 +197,7 @@ def test_load_composite_factory(conn, testcomp, fmt_out):
         def __init__(self, *args):
             self.foo, self.bar, self.baz = args
 
-    info.register(conn, factory=MyThing)
+    register_composite(info, conn, factory=MyThing)
     assert info.python_type is MyThing
 
     cur = conn.cursor(binary=fmt_out)
@@ -216,7 +216,7 @@ def test_load_composite_factory(conn, testcomp, fmt_out):
 
 def test_register_scope(conn, testcomp):
     info = CompositeInfo.fetch(conn, "testcomp")
-    info.register()
+    register_composite(info)
     for fmt in (pq.Format.TEXT, pq.Format.BINARY):
         for oid in (info.oid, info.array_oid):
             assert postgres.adapters._loaders[fmt].pop(oid)
@@ -227,14 +227,14 @@ def test_register_scope(conn, testcomp):
     assert info.python_type not in postgres.adapters._dumpers[Format.BINARY]
 
     cur = conn.cursor()
-    info.register(cur)
+    register_composite(info, cur)
     for fmt in (pq.Format.TEXT, pq.Format.BINARY):
         for oid in (info.oid, info.array_oid):
             assert oid not in postgres.adapters._loaders[fmt]
             assert oid not in conn.adapters._loaders[fmt]
             assert oid in cur.adapters._loaders[fmt]
 
-    info.register(conn)
+    register_composite(info, conn)
     for fmt in (pq.Format.TEXT, pq.Format.BINARY):
         for oid in (info.oid, info.array_oid):
             assert oid not in postgres.adapters._loaders[fmt]
@@ -243,7 +243,7 @@ def test_register_scope(conn, testcomp):
 
 def test_type_dumper_registered(conn, testcomp):
     info = CompositeInfo.fetch(conn, "testcomp")
-    info.register(conn)
+    register_composite(info, conn)
     assert issubclass(info.python_type, tuple)
     assert info.python_type.__name__ == "testcomp"
     d = conn.adapters.get_dumper(info.python_type, "s")
@@ -261,7 +261,7 @@ def test_callable_dumper_not_registered(conn, testcomp):
     def fac(*args):
         return args + (args[-1],)
 
-    info.register(conn, factory=fac)
+    register_composite(info, conn, factory=fac)
     assert info.python_type is None
 
     # but the loader is registered
index 3ac0c11fe1c930ad545f176868818407cb5d3635..97a67f97ba15c3b139d531c3ed73460d53e75a56 100644 (file)
@@ -9,7 +9,7 @@ from psycopg import pq
 from psycopg.sql import Identifier
 from psycopg.adapt import PyFormat as Format
 from psycopg.types import range as range_module
-from psycopg.types.range import Range, RangeInfo
+from psycopg.types.range import Range, RangeInfo, register_range
 
 
 type2sub = {
@@ -326,7 +326,7 @@ async def test_fetch_info_not_found_async(aconn):
 
 def test_dump_custom_empty(conn, testrange):
     info = RangeInfo.fetch(conn, "testrange")
-    info.register(conn)
+    register_range(info, conn)
 
     r = Range(empty=True)
     cur = conn.execute("select 'empty'::testrange = %s", (r,))
@@ -335,7 +335,7 @@ def test_dump_custom_empty(conn, testrange):
 
 def test_dump_quoting(conn, testrange):
     info = RangeInfo.fetch(conn, "testrange")
-    info.register(conn)
+    register_range(info, conn)
     cur = conn.cursor()
     for i in range(1, 254):
         cur.execute(
@@ -351,7 +351,7 @@ def test_dump_quoting(conn, testrange):
 @pytest.mark.parametrize("fmt_out", [pq.Format.TEXT, pq.Format.BINARY])
 def test_load_custom_empty(conn, testrange, fmt_out):
     info = RangeInfo.fetch(conn, "testrange")
-    info.register(conn)
+    register_range(info, conn)
 
     cur = conn.cursor(binary=fmt_out)
     (got,) = cur.execute("select 'empty'::testrange").fetchone()
@@ -362,7 +362,7 @@ def test_load_custom_empty(conn, testrange, fmt_out):
 @pytest.mark.parametrize("fmt_out", [pq.Format.TEXT, pq.Format.BINARY])
 def test_load_quoting(conn, testrange, fmt_out):
     info = RangeInfo.fetch(conn, "testrange")
-    info.register(conn)
+    register_range(info, conn)
     cur = conn.cursor(binary=fmt_out)
     for i in range(1, 254):
         cur.execute(