From: Daniele Varrazzo Date: Fri, 16 Apr 2021 18:01:02 +0000 (+0100) Subject: Use automatic type hints in docs X-Git-Tag: 3.0.dev0~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e20aede1bff8aef9af2c44cbefb572cdc1897ab5;p=thirdparty%2Fpsycopg.git Use automatic type hints in docs The result is not perfect but it can be improved. Better than redefining all the types. --- diff --git a/docs/advanced/adapt.rst b/docs/advanced/adapt.rst index f5fae47c7..f4a14b2b9 100644 --- a/docs/advanced/adapt.rst +++ b/docs/advanced/adapt.rst @@ -159,7 +159,6 @@ Objects involved in types adaptation your cake. Don't tell me I didn't warn you. .. autoattribute:: oid - :annotation: int .. admonition:: todo diff --git a/docs/api/connections.rst b/docs/api/connections.rst index 6976c20a1..32ccd45de 100644 --- a/docs/api/connections.rst +++ b/docs/api/connections.rst @@ -62,10 +62,7 @@ The `!Connection` class close the connection automatically when the block is exited. .. autoattribute:: closed - :annotation: bool - .. autoattribute:: broken - :annotation: bool .. method:: cursor(*, binary: bool = False, row_factory: Optional[RowFactory] = None) -> Cursor @@ -115,7 +112,7 @@ The `!Connection` class .. automethod:: commit() .. automethod:: rollback() - .. automethod:: transaction(savepoint_name: Optional[str] = None, force_rollback: bool = False) -> Transaction + .. automethod:: transaction .. note:: It must be called as ``with conn.transaction() as tx: ...`` @@ -123,7 +120,6 @@ The `!Connection` class or `rollback()`. .. autoattribute:: autocommit - :annotation: bool The property is writable for sync connections, read-only for async ones: you should call ``await`` `~AsyncConnection.set_autocommit`\ @@ -132,7 +128,6 @@ The `!Connection` class .. rubric:: Checking and configuring the connection state .. autoattribute:: client_encoding - :annotation: str The property is writable for sync connections, read-only for async ones: you should call ``await`` `~AsyncConnection.set_client_encoding`\ @@ -168,17 +163,14 @@ The `!Connection` class TODO - .. automethod:: fileno .. autoattribute:: prepare_threshold - :annotation: Optional[int] See :ref:`prepared-statements` for details. .. autoattribute:: prepared_max - :annotation: int If more queries need to be prepared, old ones are deallocated__. @@ -187,6 +179,8 @@ The `!Connection` class .. rubric:: Methods you can use to do something cool + .. automethod:: cancel + .. automethod:: notifies Notifies are recevied after using :sql:`LISTEN` in a connection, when @@ -194,15 +188,17 @@ The `!Connection` class listened channels. .. automethod:: add_notify_handler + + :param callback: a callable taking a `Notify` parameter. + .. automethod:: remove_notify_handler See :ref:`async-notify` for details. - .. automethod:: cancel .. automethod:: add_notice_handler - The argument of the callback is a `~psycopg3.errors.Diagnostic` object - containing all the details about the notice. + :param callback: a callable taking a `~psycopg3.errors.Diagnostic` + object containing all the details about the notice. .. automethod:: remove_notice_handler @@ -237,7 +233,7 @@ The `!AsyncConnection` class .. automethod:: commit .. automethod:: rollback - .. automethod:: transaction(savepoint_name: Optional[str] = None, force_rollback: bool = False) -> AsyncTransaction + .. automethod:: transaction .. note:: It must be called as ``async with conn.transaction() as tx: ...``. @@ -261,10 +257,11 @@ Connection support objects .. autoproperty:: savepoint_name .. autoattribute:: connection - :annotation: Connection .. autoclass:: AsyncTransaction() + .. autoattribute:: connection + .. autoexception:: Rollback It can be used as diff --git a/docs/api/cursors.rst b/docs/api/cursors.rst index 128bf4b28..089e56755 100644 --- a/docs/api/cursors.rst +++ b/docs/api/cursors.rst @@ -46,7 +46,6 @@ The `!Cursor` class to close the cursor automatically when the block is exited. .. autoattribute:: closed - :annotation: bool .. rubric:: Methods to send commands @@ -127,6 +126,14 @@ The `!Cursor` class .. note:: cursors are iterable objects, so just using ``for record in cursor`` syntax will iterate on the records in the current recordset. + .. autoproperty:: row_factory + + The property affects the objects returned by the `fetchone()`, + `fetchmany()`, `fetchall()` methods. The default + (`~psycopg3.rows.tuple_row`) returns a tuple for each record fetched. + + See :ref:`row-factories` for details. + .. automethod:: fetchone .. automethod:: fetchmany .. automethod:: fetchall @@ -141,28 +148,22 @@ The `!Cursor` class .. rubric:: Information about the data - .. attribute:: description - :type: Optional[List[Column]] + .. autoattribute:: description A list of objects describing each column of the current queryset. `!None` if the last operation didn't return a queryset. .. autoattribute:: rowcount - :annotation: int - .. autoattribute:: rownumber - :annotation: int .. autoattribute:: query - :annotation: Optional[bytes] The query will be in PostgreSQL format (with ``$1``, ``$2``... parameters), the parameters will *not* be merged to the query: see `params`. .. autoattribute:: params - :annotation: Optional[List[Optional[bytes]]] The parameters are adapted to PostgreSQL format. @@ -185,7 +186,6 @@ The `!ServerCursor` class documented the differences: .. autoattribute:: name - :annotation: str .. automethod:: close @@ -239,7 +239,6 @@ The `!ServerCursor` class batches of `itersize` to reduce the number of server roundtrips. .. autoattribute:: itersize - :annotation: int Number of records to fetch at time when iterating on the cursor. The default is 100. diff --git a/docs/api/pq.rst b/docs/api/pq.rst index cfc95e9cb..5a445eeed 100644 --- a/docs/api/pq.rst +++ b/docs/api/pq.rst @@ -57,7 +57,6 @@ Module content -------------- .. autodata:: __impl__ - :annotation: str: The choice of implementation is automatic but can be forced setting the :envvar:`PSYCOPG3_IMPL` env var. diff --git a/docs/conf.py b/docs/conf.py index 7060245a9..1829a15ce 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -37,6 +37,7 @@ release = "UNRELEASED" extensions = [ "sphinx.ext.autodoc", "sphinx.ext.intersphinx", + "sphinx_autodoc_typehints", "sql_role", "pg3_docs", "libpq_docs", diff --git a/docs/lib/pg3_docs.py b/docs/lib/pg3_docs.py index b580d2eb8..cf6e67700 100644 --- a/docs/lib/pg3_docs.py +++ b/docs/lib/pg3_docs.py @@ -6,6 +6,7 @@ Customisation for docs generation. import os import re +import logging import importlib from typing import Dict from collections import deque @@ -39,6 +40,12 @@ def setup(app): recover_defined_module(psycopg3) monkeypatch_autodoc() + # Disable warnings in sphinx_autodoc_typehints because it doesn't seem that + # there is a workaround for: "WARNING: Cannot resolve forward reference in + # type annotations" + logger = logging.getLogger("sphinx.sphinx_autodoc_typehints") + logger.setLevel(logging.ERROR) + # Classes which may have __module__ overwritten recovered_classes: Dict[type, str] = {} diff --git a/docs/requirements.txt b/docs/requirements.txt index a6049581d..2f7344f62 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ Sphinx >= 3.3, < 3.4 docutils >= 0.16, < 0.17 +sphinx-autodoc-typehints >= 1.12, < 1.13 furo diff --git a/psycopg3/psycopg3/adapt.py b/psycopg3/psycopg3/adapt.py index afa82b1fa..62f08e263 100644 --- a/psycopg3/psycopg3/adapt.py +++ b/psycopg3/psycopg3/adapt.py @@ -39,7 +39,7 @@ class Dumper(ABC): context.connection if context else None ) - self.oid = self._oid + self.oid: int = self._oid """The oid to pass to the server, if known.""" @abstractmethod diff --git a/psycopg3/psycopg3/connection.py b/psycopg3/psycopg3/connection.py index 51e7c1720..7492d753c 100644 --- a/psycopg3/psycopg3/connection.py +++ b/psycopg3/psycopg3/connection.py @@ -564,6 +564,7 @@ class Connection(BaseConnection): transaction. If `!None`, one will be chosen automatically. :param force_rollback: Roll back the transaction at the end of the block even if there were no error (e.g. to try a no-op process). + :rtype: Transaction """ with Transaction(self, savepoint_name, force_rollback) as tx: yield tx @@ -736,6 +737,8 @@ class AsyncConnection(BaseConnection): ) -> AsyncIterator[AsyncTransaction]: """ Start a context block with a new transaction or nested transaction. + + :rtype: AsyncTransaction """ tx = AsyncTransaction(self, savepoint_name, force_rollback) async with tx: diff --git a/psycopg3/psycopg3/cursor.py b/psycopg3/psycopg3/cursor.py index 2a8ad986d..d678338d8 100644 --- a/psycopg3/psycopg3/cursor.py +++ b/psycopg3/psycopg3/cursor.py @@ -175,6 +175,7 @@ class BaseCursor(Generic[ConnectionType]): @property def row_factory(self) -> RowFactory: + """Writable attribute to control how result rows are formed.""" return self._row_factory @row_factory.setter @@ -538,6 +539,8 @@ class Cursor(BaseCursor["Connection"]): Return the next record from the current recordset. Return `!None` the recordset is finished. + + :rtype: Optional[Row], with Row defined by `row_factory` """ self._check_result() record = self._tx.load_row(self._pos) @@ -545,11 +548,13 @@ class Cursor(BaseCursor["Connection"]): self._pos += 1 return record # type: ignore[no-any-return] - def fetchmany(self, size: int = 0) -> Sequence[Row]: + def fetchmany(self, size: int = 0) -> List[Row]: """ Return the next *size* records from the current recordset. *size* default to `!self.arraysize` if not specified. + + :rtype: Sequence[Row], with Row defined by `row_factory` """ self._check_result() assert self.pgresult @@ -562,9 +567,11 @@ class Cursor(BaseCursor["Connection"]): self._pos += len(records) return records - def fetchall(self) -> Sequence[Row]: + def fetchall(self) -> List[Row]: """ Return all the remaining records from the current recordset. + + :rtype: Sequence[Row], with Row defined by `row_factory` """ self._check_result() assert self.pgresult @@ -601,6 +608,8 @@ class Cursor(BaseCursor["Connection"]): def copy(self, statement: Query) -> Iterator[Copy]: """ Initiate a :sql:`COPY` operation and return an object to manage it. + + :rtype: Copy """ with self._conn.lock: self._conn.wait(self._start_copy_gen(statement)) @@ -704,6 +713,9 @@ class AsyncCursor(BaseCursor["AsyncConnection"]): @asynccontextmanager async def copy(self, statement: Query) -> AsyncIterator[AsyncCopy]: + """ + :rtype: AsyncCopy + """ async with self._conn.lock: await self._conn.wait(self._start_copy_gen(statement)) diff --git a/psycopg3/psycopg3/server_cursor.py b/psycopg3/psycopg3/server_cursor.py index 1ce78a5cf..9cf4d3253 100644 --- a/psycopg3/psycopg3/server_cursor.py +++ b/psycopg3/psycopg3/server_cursor.py @@ -179,7 +179,7 @@ class ServerCursor(BaseCursor["Connection"]): super().__init__(connection, format=format, row_factory=row_factory) self._helper: ServerCursorHelper["Connection"] self._helper = ServerCursorHelper(name) - self.itersize = DEFAULT_ITERSIZE + self.itersize: int = DEFAULT_ITERSIZE def __del__(self) -> None: if not self._closed: @@ -300,7 +300,7 @@ class AsyncServerCursor(BaseCursor["AsyncConnection"]): super().__init__(connection, format=format, row_factory=row_factory) self._helper: ServerCursorHelper["AsyncConnection"] self._helper = ServerCursorHelper(name) - self.itersize = DEFAULT_ITERSIZE + self.itersize: int = DEFAULT_ITERSIZE def __del__(self) -> None: if not self._closed: diff --git a/psycopg3/psycopg3/transaction.py b/psycopg3/psycopg3/transaction.py index cdc2b7b65..ef05a921a 100644 --- a/psycopg3/psycopg3/transaction.py +++ b/psycopg3/psycopg3/transaction.py @@ -54,11 +54,6 @@ class BaseTransaction(Generic[ConnectionType]): self.force_rollback = force_rollback self._entered = self._exited = False - @property - def connection(self) -> ConnectionType: - """The connection the object is managing.""" - return self._conn - @property def savepoint_name(self) -> Optional[str]: """ @@ -183,6 +178,11 @@ class Transaction(BaseTransaction["Connection"]): __module__ = "psycopg3" + @property + def connection(self) -> "Connection": + """The connection the object is managing.""" + return self._conn + def __enter__(self) -> "Transaction": with self._conn.lock: self._conn.wait(self._enter_gen()) @@ -205,6 +205,10 @@ class AsyncTransaction(BaseTransaction["AsyncConnection"]): __module__ = "psycopg3" + @property + def connection(self) -> "AsyncConnection": + return self._conn + async def __aenter__(self) -> "AsyncTransaction": async with self._conn.lock: await self._conn.wait(self._enter_gen())