]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Make the row_maker non-optional
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 24 Feb 2021 14:23:23 +0000 (15:23 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 24 Feb 2021 14:23:23 +0000 (15:23 +0100)
Use the `tuple` type as return value for `tuple_row()`, which has a
valid interface and can also be used in the Cython code to fast-path the
case where the tuples created internally are good enough.

psycopg3/psycopg3/_transform.py
psycopg3/psycopg3/proto.py
psycopg3/psycopg3/rows.py
psycopg3_c/psycopg3_c/_psycopg3.pyi
psycopg3_c/psycopg3_c/_psycopg3/transform.pyx

index b4aa732b04c2a4d86b2476d3f57485f5e4d6c402..10ce79b72cc0d93ac065cfb19fde2a06bb616fc0 100644 (file)
@@ -38,7 +38,7 @@ class Transformer(AdaptContext):
     __module__ = "psycopg3.adapt"
     _adapters: "AdaptersMap"
     _pgresult: Optional["PGresult"] = None
-    make_row: Optional[RowMaker] = None
+    make_row: RowMaker = tuple
 
     def __init__(self, context: Optional[AdaptContext] = None):
 
@@ -172,19 +172,14 @@ class Transformer(AdaptContext):
                 f"rows must be included between 0 and {self._ntuples}"
             )
 
-        records: List[Row]
-        records = [None] * (row1 - row0)  # type: ignore[list-item]
-        if self.make_row:
-            mkrow = self.make_row
-        else:
-            mkrow = tuple
+        records: List[Row] = []
         for row in range(row0, row1):
             record: List[Any] = [None] * self._nfields
             for col in range(self._nfields):
                 val = res.get_value(row, col)
                 if val is not None:
                     record[col] = self._row_loaders[col](val)
-            records[row - row0] = mkrow(record)
+            records.append(self.make_row(record))
 
         return records
 
@@ -202,7 +197,7 @@ class Transformer(AdaptContext):
             if val is not None:
                 record[col] = self._row_loaders[col](val)
 
-        return self.make_row(record) if self.make_row else tuple(record)
+        return self.make_row(record)  # type: ignore[no-any-return]
 
     def load_sequence(
         self, record: Sequence[Optional[bytes]]
index acf04bdf68aed877ca3f724f6acc419b4e44ff2f..a63e3efd56d9a015618a009270f9dbf527275eb7 100644 (file)
@@ -56,7 +56,7 @@ class RowMaker(Protocol):
 
 
 class RowFactory(Protocol):
-    def __call__(self, __cursor: "BaseCursor[Any]") -> Optional[RowMaker]:
+    def __call__(self, __cursor: "BaseCursor[Any]") -> RowMaker:
         ...
 
 
@@ -86,11 +86,11 @@ class AdaptContext(Protocol):
 
 
 class Transformer(Protocol):
-    make_row: Optional[RowMaker] = None
-
     def __init__(self, context: Optional[AdaptContext] = None):
         ...
 
+    make_row: RowMaker
+
     @property
     def connection(self) -> Optional["BaseConnection"]:
         ...
index 452d8a3f3be9a634210863db57756308cd978d9f..a730c5961aa847c0b9bec81c9f40a50735f3ecc7 100644 (file)
@@ -7,7 +7,7 @@ psycopg3 row factories
 import functools
 import re
 from collections import namedtuple
-from typing import Any, Callable, Dict, Sequence, Type, NamedTuple
+from typing import Any, Callable, Dict, NamedTuple, Sequence, Tuple, Type
 from typing import TYPE_CHECKING
 
 from . import errors as e
@@ -16,14 +16,16 @@ if TYPE_CHECKING:
     from .cursor import BaseCursor
 
 
-def tuple_row(cursor: "BaseCursor[Any]") -> None:
+def tuple_row(
+    cursor: "BaseCursor[Any]",
+) -> Callable[[Sequence[Any]], Tuple[Any, ...]]:
     """Row factory to represent rows as simple tuples.
 
     This is the default factory.
     """
-    # Implementation detail: just return None instead of a callable because
-    # the Transformer knows how to use this value.
-    return None
+    # Implementation detail: make sure this is the tuple type itself, not an
+    # equivalent function, because the C code fast-paths on it.
+    return tuple
 
 
 def dict_row(
index 756c34e63ff0085447064c5b94884d43b7685f74..bd111aea115e5a9d05cc1e74dca7b63fd4ea0f01 100644 (file)
@@ -17,15 +17,12 @@ from psycopg3.pq.proto import PGconn, PGresult
 
 class Transformer(proto.AdaptContext):
     def __init__(self, context: Optional[proto.AdaptContext] = None): ...
+    make_row: proto.RowMaker
     @property
     def connection(self) -> Optional[BaseConnection]: ...
     @property
     def adapters(self) -> AdaptersMap: ...
     @property
-    def make_row(self) -> Optional[proto.RowMaker]: ...
-    @make_row.setter
-    def make_row(self, row_maker: proto.RowMaker) -> None: ...
-    @property
     def pgresult(self) -> Optional[PGresult]: ...
     def set_pgresult(
         self, result: Optional["PGresult"], set_loaders: bool = True
index ce88491509e2092c8f6c27705510ac1e47263023..1aff27eb8c6e308f42ab0b6ba92c6a0b2ec03fd5 100644 (file)
@@ -83,7 +83,7 @@ cdef class Transformer:
     cdef int _nfields, _ntuples
     cdef list _row_dumpers
     cdef list _row_loaders
-    cdef object _make_row
+    cdef public object make_row
 
     def __cinit__(self, context: Optional["AdaptContext"] = None):
         if context is not None:
@@ -94,14 +94,6 @@ cdef class Transformer:
             self.adapters = global_adapters
             self.connection = None
 
-    @property
-    def make_row(self) -> Optional[RowMaker]:
-        return self._make_row
-
-    @make_row.setter
-    def make_row(self, row_maker: Optional[RowMaker]) -> None:
-        self._make_row = row_maker
-
     @property
     def pgresult(self) -> Optional[PGresult]:
         return self._pgresult
@@ -342,8 +334,10 @@ cdef class Transformer:
                     Py_INCREF(pyval)
                     PyTuple_SET_ITEM(<object>brecord, col, pyval)
 
-        if self.make_row:
-            return list(map(self.make_row, records))
+        cdef object make_row = self.make_row
+        if make_row is not tuple:
+            for i in range(len(records)):
+                records[i] = make_row(records[i])
         return records
 
     def load_row(self, int row) -> Optional[Row]:
@@ -385,8 +379,9 @@ cdef class Transformer:
             Py_INCREF(pyval)
             PyTuple_SET_ITEM(record, col, pyval)
 
-        if self.make_row:
-            return self.make_row(record)
+        cdef object make_row = self.make_row
+        if make_row is not tuple:
+            record = make_row(record)
         return record
 
     cpdef object load_sequence(self, record: Sequence[Optional[bytes]]):