]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix)composite): rename make_instance to make_object
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 30 Nov 2025 21:33:36 +0000 (22:33 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 1 Dec 2025 01:38:19 +0000 (02:38 +0100)
The name feels more idiomatic.

Also clean up the related documentation.

docs/basic/pgtypes.rst
psycopg/psycopg/types/composite.py
tests/types/test_composite.py

index a15e8d1a3e0e41cc18aebe42a72b2c7a989cd8dc..886c1b0eef581dc2ab3bce6887c6fc5fd639d28d 100644 (file)
@@ -26,8 +26,7 @@ Composite types adaptation
 
 Psycopg can adapt PostgreSQL composite types (either created with the |CREATE
 TYPE|_ command or implicitly defined after a table row type) to and from
-Python tuples, `~collections.namedtuple`, or any other suitable object
-configured.
+Python tuples, `~collections.namedtuple`, or any suitably configured object.
 
 .. |CREATE TYPE| replace:: :sql:`CREATE TYPE`
 .. _CREATE TYPE: https://www.postgresql.org/docs/current/static/sql-createtype.html
@@ -39,13 +38,13 @@ using `~psycopg.types.composite.register_composite()`.
 .. autoclass:: psycopg.types.composite.CompositeInfo
 
    `!CompositeInfo` is a `~psycopg.types.TypeInfo` subclass: check its
-   documentation for the generic usage, especially the
+   documentation for the general usage, especially the
    `~psycopg.types.TypeInfo.fetch()` method.
 
    .. attribute:: python_type
 
-       After `register_composite()` is called, it will contain the python type
-       mapping to the registered composite.
+       After `register_composite()` is called, it will contain the Python type
+       adapting the registered composite.
 
 .. autofunction:: psycopg.types.composite.register_composite
 
@@ -58,16 +57,20 @@ using `~psycopg.types.composite.register_composite()`.
 
    If the `!factory` is a type (and not a generic callable) then dumpers for
    such type are created and registered too, so that passing objects of that
-   type to a query will adapt them to the registered type. This assumes that
-   the `!factory` is a sequence; if this is not the case you can specify the
-   `!make_sequence` parameter. See :ref:`composite-generic`.
+   type to a query will adapt them to the registered composite type. This
+   assumes that `!factory` is a sequence; if this is not the case you can
+   specify the `!make_sequence` parameter: a function taking the object to
+   dump and the list of field names of the composite and returning a sequence
+   of values. See :ref:`composite-non-sequence`.
 
    The `!factory` callable will be called with the sequence of value from the
    composite. If passing the sequence of positional arguments is not suitable
-   you can specify a `!make_instance` callable.
+   you can specify a `!make_object` callable, which takes the sequence of
+   composite values and field names and which should return a new instance of
+   the object to load. See :ref:`composite-non-sequence`.
 
    .. versionadded:: 3.3
-        the `!make_instance` and `!make_sequence` parameters.
+        the `!make_object` and `!make_sequence` parameters.
 
 
 .. _composite-sequence:
@@ -110,16 +113,16 @@ composite components are registered as well::
     card_back(face=card(value=8, suit='hearts'), back='blue')
 
 
-.. _composite-generic:
+.. _composite-non-sequence:
 
-Example: Generic Python object
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Example: non-sequence Python object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. versionadded:: 3.3
 
 If your Python type takes keyword arguments, or if the sequence of value
 coming from the PostgreSQL type is not suitable for it, it is possible to
-specify a :samp:`make_instance({values}, {names})` function to adapt the
+specify a :samp:`make_object({values}, {names})` function to adapt the
 values from the composite to the right type requirements. For example::
 
     >>> from dataclasses import dataclass
@@ -133,7 +136,7 @@ values from the composite to the right type requirements. For example::
     >>> def card_from_db(values: Sequence[Any], names: Sequence[str]) -> Card:
     ...     return Card(**dict(zip(names, values)))
 
-    >>> register_composite(info, conn, make_instance=card_from_db)
+    >>> register_composite(info, conn, make_object=card_from_db)
     >>> conn.execute("select '(1,spades)'::card").fetchone()[0]
     Card(suit='spades', value=1)
 
@@ -149,7 +152,7 @@ a sequence matching the composite fields::
 
     >>> register_composite(
     ...     info, conn, factory=Card,
-    ...     make_instance=card_from_db, make_sequence=card_to_db)
+    ...     make_object=card_from_db, make_sequence=card_to_db)
 
     >>> conn.execute(
     ...     "select %(card)s.value + 1, %(card)s.suit",
@@ -287,7 +290,7 @@ multirange type with its subtype and make it work like the builtin ones.
 .. autoclass:: psycopg.types.multirange.MultirangeInfo
 
    `!MultirangeInfo` is a `~psycopg.types.TypeInfo` subclass: check its
-   documentation for generic details, especially the
+   documentation for general details, especially the
    `~psycopg.types.TypeInfo.fetch()` method.
 
 .. autofunction:: psycopg.types.multirange.register_multirange
index d1cdbc6743db83dc7f1cba054178ebb4e8541240..17bf643870926c4f845cb072206261d962c73b22 100644 (file)
@@ -35,7 +35,7 @@ _unpack_oidlen = cast(
 )
 
 T = TypeVar("T")
-InstanceMaker: TypeAlias = Callable[[Sequence[Any], Sequence[str]], T]
+ObjectMaker: TypeAlias = Callable[[Sequence[Any], Sequence[str]], T]
 SequenceMaker: TypeAlias = Callable[[T, Sequence[str]], Sequence[Any]]
 
 
@@ -240,11 +240,11 @@ class _CompositeLoader(Loader, Generic[T], ABC):
             args = ()
         else:
             args = self._tx.load_sequence(tuple(_parse_text_record(data[1:-1])))
-        return type(self).make_instance(args, self.fields_names)
+        return type(self).make_object(args, self.fields_names)
 
     @staticmethod
     @abstractmethod
-    def make_instance(args: Sequence[Any], names: Sequence[str]) -> T: ...
+    def make_object(args: Sequence[Any], names: Sequence[str]) -> T: ...
 
 
 class _CompositeBinaryLoader(Loader, Generic[T], ABC):
@@ -268,18 +268,18 @@ class _CompositeBinaryLoader(Loader, Generic[T], ABC):
     def load(self, data: abc.Buffer) -> T:
         brecord, _ = _parse_binary_record(data)  # assume oids == self.fields_types
         record = self._tx.load_sequence(brecord)
-        return type(self).make_instance(record, self.fields_names)
+        return type(self).make_object(record, self.fields_names)
 
     @staticmethod
     @abstractmethod
-    def make_instance(args: Sequence[Any], names: Sequence[str]) -> T: ...
+    def make_object(args: Sequence[Any], names: Sequence[str]) -> T: ...
 
 
 def register_composite(
     info: CompositeInfo,
     context: abc.AdaptContext | None = None,
     factory: Callable[..., T] | None = None,
-    make_instance: InstanceMaker[T] | None = None,
+    make_object: ObjectMaker[T] | None = None,
     make_sequence: SequenceMaker[T] | None = None,
 ) -> None:
     """Register the adapters to load and dump a composite type.
@@ -292,11 +292,11 @@ def register_composite(
     :param factory: Callable to create a Python object from the sequence of
         attributes read from the composite.
     :type factory: `!Callable[..., T]` | `!None`
-    :param make_instance: optional function taking values and names as input and
-        returning the new type.
-    :type make_instance: `!Callable[[Sequence[Any], Sequence[str]], T]` | `!None`
-    :param make_sequence: optional function taking an instance and names as
-        input and returning the fields to dump.
+    :param make_object: optional function to use on load, to adapt the
+        composite's sequence of values to a Python object
+    :type make_object: `!Callable[[Sequence[Any], Sequence[str]], T]` | `!None`
+    :param make_sequence: optional function to use on dump, to adapt an object
+        to the composite's sequence of values
     :type make_sequence: `!Callable[[T, Sequence[str]], Sequence[Any]]` | `!None`
 
     .. note::
@@ -318,9 +318,9 @@ def register_composite(
     if not factory:
         factory = cast("Callable[..., T]", _nt_from_info(info))
 
-    if not make_instance:
+    if not make_object:
 
-        def make_instance(values: Sequence[Any], types: Sequence[str]) -> T:
+        def make_object(values: Sequence[Any], types: Sequence[str]) -> T:
             return factory(*values)
 
     adapters = context.adapters if context else postgres.adapters
@@ -330,13 +330,13 @@ def register_composite(
 
     # generate and register a customized text loader
     loader: type[_CompositeLoader[T]] = _make_loader(
-        info.name, field_names, field_types, make_instance
+        info.name, field_names, field_types, make_object
     )
     adapters.register_loader(info.oid, loader)
 
     # generate and register a customized binary loader
     binary_loader: type[_CompositeBinaryLoader[T]] = _make_binary_loader(
-        info.name, field_names, field_types, make_instance
+        info.name, field_names, field_types, make_object
     )
     adapters.register_loader(info.oid, binary_loader)
 
@@ -527,14 +527,14 @@ def _make_loader(
     name: str,
     field_names: tuple[str, ...],
     field_types: tuple[int, ...],
-    make_instance: InstanceMaker[T],
+    make_object: ObjectMaker[T],
 ) -> type[_CompositeLoader[T]]:
     doc = f"Text loader for the '{name}' composite."
     d = {
         "__doc__": doc,
         "fields_types": field_types,
         "fields_names": field_names,
-        "make_instance": make_instance,
+        "make_object": make_object,
     }
     return type(f"{name.title()}Loader", (_CompositeLoader,), d)
 
@@ -544,14 +544,14 @@ def _make_binary_loader(
     name: str,
     field_names: tuple[str, ...],
     field_types: tuple[int, ...],
-    make_instance: InstanceMaker[T],
+    make_object: ObjectMaker[T],
 ) -> type[_CompositeBinaryLoader[T]]:
     doc = f"Binary loader for the '{name}' composite."
     d = {
         "__doc__": doc,
         "fields_names": field_names,
         "fields_types": field_types,
-        "make_instance": make_instance,
+        "make_object": make_object,
     }
     return type(f"{name.title()}BinaryLoader", (_CompositeBinaryLoader,), d)
 
index de808b840d05489bedb3793ddc1609413b79438f..16cc058ea5c5addaffe56fd6980413c033f692bc 100644 (file)
@@ -355,10 +355,10 @@ class MyKeywordThing:
 def test_load_keyword_composite_factory(conn, testcomp, fmt_out):
     info = CompositeInfo.fetch(conn, "testcomp")
 
-    def make_instance(values, names):
+    def make_object(values, names):
         return MyKeywordThing(**dict(zip(names, values)))
 
-    register_composite(info, conn, factory=MyKeywordThing, make_instance=make_instance)
+    register_composite(info, conn, factory=MyKeywordThing, make_object=make_object)
     assert info.python_type is MyKeywordThing
 
     cur = conn.cursor(binary=fmt_out)