From: Daniele Varrazzo Date: Wed, 3 Jan 2024 00:44:22 +0000 (+0100) Subject: fix: define the Row TypeVar as defaulting to TupleRow X-Git-Tag: pool-3.2.1~7^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcdc8df2a873551277ae2860949d14cf5b9214d1;p=thirdparty%2Fpsycopg.git fix: define the Row TypeVar as defaulting to TupleRow This allows to return `Self` uniformly from the `Connection.connect()` class method, which in turns allows to subclass the connection without the need of redefining the complex signature. Close #308 --- diff --git a/psycopg/psycopg/connection.py b/psycopg/psycopg/connection.py index 4bafd5ea1..d0e6391a3 100644 --- a/psycopg/psycopg/connection.py +++ b/psycopg/psycopg/connection.py @@ -20,7 +20,7 @@ from . import errors as e from . import waiting from .abc import AdaptContext, Params, PQGen, PQGenConn, Query, RV from ._tpc import Xid -from .rows import Row, RowFactory, tuple_row, TupleRow, args_row +from .rows import Row, RowFactory, tuple_row, args_row from .adapt import AdaptersMap from ._enums import IsolationLevel from ._compat import Self @@ -84,10 +84,7 @@ class Connection(BaseConnection[Row]): cursor_factory: Optional[Type[Cursor[Row]]] = None, context: Optional[AdaptContext] = None, **kwargs: Union[None, int, str], - ) -> Connection[Row]: - # TODO: returned type should be Self. See #308. - # Unfortunately we cannot use Self[Row] as Self is not parametric. - # https://peps.python.org/pep-0673/#use-in-generic-classes + ) -> Self: ... @overload @@ -101,7 +98,7 @@ class Connection(BaseConnection[Row]): cursor_factory: Optional[Type[Cursor[Any]]] = None, context: Optional[AdaptContext] = None, **kwargs: Union[None, int, str], - ) -> Connection[TupleRow]: + ) -> Self: ... @classmethod # type: ignore[misc] # https://github.com/python/mypy/issues/11004 diff --git a/psycopg/psycopg/connection_async.py b/psycopg/psycopg/connection_async.py index 9d8dad873..ec487e483 100644 --- a/psycopg/psycopg/connection_async.py +++ b/psycopg/psycopg/connection_async.py @@ -17,7 +17,7 @@ from . import errors as e from . import waiting from .abc import AdaptContext, Params, PQGen, PQGenConn, Query, RV from ._tpc import Xid -from .rows import Row, AsyncRowFactory, tuple_row, TupleRow, args_row +from .rows import Row, AsyncRowFactory, tuple_row, args_row from .adapt import AdaptersMap from ._enums import IsolationLevel from ._compat import Self @@ -90,10 +90,7 @@ class AsyncConnection(BaseConnection[Row]): cursor_factory: Optional[Type[AsyncCursor[Row]]] = None, context: Optional[AdaptContext] = None, **kwargs: Union[None, int, str], - ) -> AsyncConnection[Row]: - # TODO: returned type should be Self. See #308. - # Unfortunately we cannot use Self[Row] as Self is not parametric. - # https://peps.python.org/pep-0673/#use-in-generic-classes + ) -> Self: ... @overload @@ -107,7 +104,7 @@ class AsyncConnection(BaseConnection[Row]): cursor_factory: Optional[Type[AsyncCursor[Any]]] = None, context: Optional[AdaptContext] = None, **kwargs: Union[None, int, str], - ) -> AsyncConnection[TupleRow]: + ) -> Self: ... @classmethod # type: ignore[misc] # https://github.com/python/mypy/issues/11004 diff --git a/psycopg/psycopg/crdb/connection.py b/psycopg/psycopg/crdb/connection.py index 49b7d5ffa..d88b63e46 100644 --- a/psycopg/psycopg/crdb/connection.py +++ b/psycopg/psycopg/crdb/connection.py @@ -5,12 +5,10 @@ CockroachDB-specific connections. # Copyright (C) 2022 The Psycopg Team import re -from typing import Any, Optional, Type, Union, overload, TYPE_CHECKING +from typing import Any, Optional, Union, TYPE_CHECKING from .. import errors as e -from ..abc import AdaptContext -from ..rows import Row, RowFactory, AsyncRowFactory, TupleRow -from .._compat import Self +from ..rows import Row from ..conninfo import ConnectionInfo from ..connection import Connection from .._adapters_map import AdaptersMap @@ -19,8 +17,6 @@ from ._types import adapters if TYPE_CHECKING: from ..pq.abc import PGconn - from ..cursor import Cursor - from ..cursor_async import AsyncCursor class _CrdbConnectionMixin: @@ -63,45 +59,6 @@ class CrdbConnection(_CrdbConnectionMixin, Connection[Row]): __module__ = "psycopg.crdb" - # TODO: this method shouldn't require re-definition if the base class - # implements a generic self. - # https://github.com/psycopg/psycopg/issues/308 - @overload - @classmethod - def connect( - cls, - conninfo: str = "", - *, - autocommit: bool = False, - row_factory: RowFactory[Row], - prepare_threshold: Optional[int] = 5, - cursor_factory: "Optional[Type[Cursor[Row]]]" = None, - context: Optional[AdaptContext] = None, - **kwargs: Union[None, int, str], - ) -> "CrdbConnection[Row]": - ... - - @overload - @classmethod - def connect( - cls, - conninfo: str = "", - *, - autocommit: bool = False, - prepare_threshold: Optional[int] = 5, - cursor_factory: "Optional[Type[Cursor[Any]]]" = None, - context: Optional[AdaptContext] = None, - **kwargs: Union[None, int, str], - ) -> "CrdbConnection[TupleRow]": - ... - - @classmethod - def connect(cls, conninfo: str = "", **kwargs: Any) -> Self: - """ - Connect to a database server and return a new `CrdbConnection` instance. - """ - return super().connect(conninfo, **kwargs) # type: ignore[return-value] - class AsyncCrdbConnection(_CrdbConnectionMixin, AsyncConnection[Row]): """ @@ -110,42 +67,6 @@ class AsyncCrdbConnection(_CrdbConnectionMixin, AsyncConnection[Row]): __module__ = "psycopg.crdb" - # TODO: this method shouldn't require re-definition if the base class - # implements a generic self. - # https://github.com/psycopg/psycopg/issues/308 - @overload - @classmethod - async def connect( - cls, - conninfo: str = "", - *, - autocommit: bool = False, - prepare_threshold: Optional[int] = 5, - row_factory: AsyncRowFactory[Row], - cursor_factory: "Optional[Type[AsyncCursor[Row]]]" = None, - context: Optional[AdaptContext] = None, - **kwargs: Union[None, int, str], - ) -> "AsyncCrdbConnection[Row]": - ... - - @overload - @classmethod - async def connect( - cls, - conninfo: str = "", - *, - autocommit: bool = False, - prepare_threshold: Optional[int] = 5, - cursor_factory: "Optional[Type[AsyncCursor[Any]]]" = None, - context: Optional[AdaptContext] = None, - **kwargs: Union[None, int, str], - ) -> "AsyncCrdbConnection[TupleRow]": - ... - - @classmethod - async def connect(cls, conninfo: str = "", **kwargs: Any) -> Self: - return await super().connect(conninfo, **kwargs) # type: ignore[no-any-return] - class CrdbConnectionInfo(ConnectionInfo): """ diff --git a/psycopg/psycopg/rows.py b/psycopg/psycopg/rows.py index d0d834864..4c2f7781b 100644 --- a/psycopg/psycopg/rows.py +++ b/psycopg/psycopg/rows.py @@ -29,7 +29,7 @@ T = TypeVar("T", covariant=True) # Row factories -Row = TypeVar("Row", covariant=True) +Row = TypeVar("Row", covariant=True, default="TupleRow") class RowMaker(Protocol[Row]): diff --git a/psycopg_pool/psycopg_pool/pool.py b/psycopg_pool/psycopg_pool/pool.py index 1e298518b..45e218447 100644 --- a/psycopg_pool/psycopg_pool/pool.py +++ b/psycopg_pool/psycopg_pool/pool.py @@ -625,7 +625,7 @@ class ConnectionPool(Generic[CT], BasePool): kwargs["connect_timeout"] = max(round(timeout), 1) t0 = monotonic() try: - conn: CT = cast(CT, self.connection_class.connect(self.conninfo, **kwargs)) + conn = self.connection_class.connect(self.conninfo, **kwargs) except Exception: self._stats[self._CONNECTIONS_ERRORS] += 1 raise diff --git a/psycopg_pool/psycopg_pool/pool_async.py b/psycopg_pool/psycopg_pool/pool_async.py index d53243ff9..e3f7e113c 100644 --- a/psycopg_pool/psycopg_pool/pool_async.py +++ b/psycopg_pool/psycopg_pool/pool_async.py @@ -669,9 +669,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool): kwargs["connect_timeout"] = max(round(timeout), 1) t0 = monotonic() try: - conn: ACT = cast( - ACT, await self.connection_class.connect(self.conninfo, **kwargs) - ) + conn = await self.connection_class.connect(self.conninfo, **kwargs) except Exception: self._stats[self._CONNECTIONS_ERRORS] += 1 raise diff --git a/tests/test_typing.py b/tests/test_typing.py index fff9cec25..efafd0bb4 100644 --- a/tests/test_typing.py +++ b/tests/test_typing.py @@ -409,7 +409,6 @@ reveal_type(ref) assert got == want -@pytest.mark.xfail(reason="https://github.com/psycopg/psycopg/issues/308") @pytest.mark.parametrize( "conn, type", [