]> git.ipfire.org Git - thirdparty/psycopg.git/commit
Make Cursor generic on Row
authorDenis Laxalde <denis.laxalde@dalibo.com>
Thu, 15 Apr 2021 15:49:04 +0000 (17:49 +0200)
committerDenis Laxalde <denis.laxalde@dalibo.com>
Mon, 26 Apr 2021 13:56:10 +0000 (15:56 +0200)
commit749f3ff784320edd59af2098c59397cd2958bccd
tree4e9046660bbd9cb4099eee0a0a14d76de0a0e023
parente8b8fdc848c615baa90fbb250c75fec486af58b4
Make Cursor generic on Row

We make RowMaker, RowFactory and Cursor types generic on a Row type
variable thus making type inference work on cursor's fetch*() methods.

For example:

    R = TypeVar("R")
    def my_row_factory(cursor: BaseCursor[Any, R]) -> Callable[[Sequence[Any]], R]:
        ...

    with conn.cursor(row_factory=my_row_factory) as cur:
        cur.execute("select 1")
        reveal_type(cur)
        # Revealed type is 'psycopg3.cursor.Cursor[R`-1]'
        r = cur.fetchone()
        reveal_type(r)
        # Revealed type is 'Union[R`-1, None]'

The definition of RowMaker and RowFactory protocols needs two distinct
type variable because the former is covariant on Row (using 'Row_co'
type variable) and the latter is invariant on Row.

In Cursor.__init__(), row_factory argument is now required as we remove
its default value 'tuple_row'; this is helpful in order to keep Cursor
definition generic on Row, which would be more difficult when specifying
a concrete RowFactory by default binding Row to Tuple.

The Connection is not (yet) generic on Row, so we use RowFactory[Any].
Still, in cursor() methods, we get a fully typed Cursor value when a
row_factory argument is passed. We add two overloaded variants of these
cursor() methods depending on whether row_factory is passed or not (in
the former case, we return a Cursor[Row], in the latter case, a
Cursor[Any]).

A noticeable improvement is that we no longer need to explicitly declare
or ignore types in Transformer's load_row() and load_rows() as this is
not correctly inferred. Similarly, type annotations are not needed
anymore in callers of these methods (Cursor's fetch*() methods).
In TypeInfo's fetch*() method, we can drop superfluous type annotations.
psycopg3/psycopg3/_column.py
psycopg3/psycopg3/_transform.py
psycopg3/psycopg3/_typeinfo.py
psycopg3/psycopg3/connection.py
psycopg3/psycopg3/copy.py
psycopg3/psycopg3/cursor.py
psycopg3/psycopg3/proto.py
psycopg3/psycopg3/rows.py
psycopg3/psycopg3/server_cursor.py
psycopg3_c/psycopg3_c/_psycopg3.pyi