]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Api docs and typing system made consistent
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 22 Nov 2020 16:16:12 +0000 (16:16 +0000)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 22 Nov 2020 16:16:12 +0000 (16:16 +0000)
Top-level objects are annotated as coming from the main package: this
way the documentation can link them consistently to where they are
documented (e.g. `Connection` is `psycopg3.Connection`, not
`psycopg3.connection.Connection`) and MyPy is happy too.

docs/connection.rst
docs/cursor.rst
psycopg3/psycopg3/__init__.py
psycopg3/psycopg3/connection.py
psycopg3/psycopg3/cursor.py
psycopg3/psycopg3/transaction.py

index 0f76c1b96d148e5938ed2a68a4719ce2ff545521..38cfed9817f19729171954df857a9c6d7ae60989 100644 (file)
@@ -70,7 +70,7 @@ The `!Connection` class
     .. automethod:: rollback()
     .. automethod:: transaction(savepoint_name: Optional[str] = None, force_rollback: bool = False) -> Transaction
 
-        It must be called as ``with conn.transaction() as tx: ...``
+        .. note:: it must be called as ``with conn.transaction() as tx: ...``
 
         Inside a transaction block it will not be possible to call `commit()`
         or `rollback()`.
@@ -147,7 +147,7 @@ The `!AsyncConnection` class
 
     .. automethod:: transaction(savepoint_name: Optional[str] = None, force_rollback: bool = False) -> AsyncTransaction
 
-        It must be called as ``async with conn.transaction() as tx: ...``.
+        .. note:: it must be called as ``async with conn.transaction() as tx: ...``.
 
     .. automethod:: notifies
     .. automethod:: set_client_encoding
@@ -160,7 +160,7 @@ Connection support objects
 .. autoclass:: Notify()
     :members: channel, payload, pid
 
-    The objet is usually returned by `Connection.notifies()`.
+    The object is usually returned by `Connection.notifies()`.
 
 
 .. rubric:: Objects involved in :ref:`transactions`
index 83a24f1ecf97affe3bd12c4da43dfdcd5f25e6ff..c60bb522efb24b56404eaca7bf02400bf629334e 100644 (file)
@@ -31,6 +31,11 @@ The `!Cursor` class
     further operation will not be possible. Closing a cursor will not
     terminate a transaction or a session though.
 
+    .. attribute:: connection
+        :type: Connection
+
+        The connection this cursor is using.
+
     .. automethod:: close
 
         .. note:: you can use :ref:`with conn.cursor(): ...<with-statement>`
@@ -41,15 +46,25 @@ The `!Cursor` class
 
     .. rubric:: Methods to send commands
 
-    .. automethod:: execute
+    .. automethod:: execute(query: Query, vars: Optional[Args]=None) -> Cursor
+
+        :param query: The query to execute
+        :type query: `!str`, `!bytes`, or `sql.Composable`
+        :param vars: The parameters to pass to the query, if any
+        :type vars: Mapping, Sequence
 
         Return the cursor itself, so that it will be possible to chain a fetch
-        operation after the call
+        operation after the call.
 
         See :ref:`query-parameters` for all the details about executing
         queries.
 
-    .. automethod:: executemany
+    .. automethod:: executemany(query: Query, vars_seq: Sequence[Args]) -> Cursor
+
+        :param query: The query to execute
+        :type query: `!str`, `!bytes`, or `sql.Composable`
+        :param vars_seq: The parameters to pass to the query
+        :type vars_seq: Sequence of Mapping or Sequence
 
         This is more efficient than performing separate queries, but in case of
         several :sql:`INSERT` (and with some SQL creativity for massive
@@ -58,18 +73,16 @@ The `!Cursor` class
         See :ref:`query-parameters` for all the details about executing
         queries.
 
-    .. automethod:: copy
-
-        It must be called as ``with cur.copy() as copy: ...``
+    .. automethod:: copy(statement: Query, vars: Optional[Args]=None) -> Copy
 
-        See :ref:`copy` for information about :sql:`COPY`.
+        :param statement: The copy operation to execute
+        :type statement: `!str`, `!bytes`, or `sql.Composable`
+        :param args: The parameters to pass to the query, if any
+        :type args: Mapping, Sequence
 
-    .. automethod:: callproc
+        .. note:: it must be called as ``with cur.copy() as copy: ...``
 
-        This method exists for DBAPI compatibility but it's not much different
-        than calling `execute()` on a :sql:`SELECT myproc(%s, %s, ...)`, which
-        will give you more flexibility in passing arguments and retrieving
-        results. Don't bother...
+        See :ref:`copy` for information about :sql:`COPY`.
 
     .. rubric:: Methods to retrieve results
 
@@ -89,8 +102,15 @@ The `!Cursor` class
 
     .. rubric:: Information about the data
 
-    .. autoproperty:: description
-    .. autoproperty:: rowcount
+    .. attribute:: description
+        :type: Optional[List[Column]]
+
+        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
 
 
 The `!AsyncCursor` class
@@ -105,19 +125,21 @@ The `!AsyncCursor` class
     The following methods have the same behaviour of the matching `!Cursor`
     methods, but should be called using the `await` keyword.
 
+    .. attribute:: connection
+        :type: AsyncConnection
+
     .. automethod:: close
 
         .. note:: you can use ``async with`` to close the cursor
             automatically when the block is exited, but be careful about
             the async quirkness: see :ref:`with-statement` for details.
 
-    .. automethod:: execute
-    .. automethod:: executemany
-    .. automethod:: copy
+    .. automethod:: execute(query: Query, vars: Optional[Args]=None) -> AsyncCursor
+    .. automethod:: executemany(query: Query, vars_seq: Sequence[Args]) -> AsyncCursor
+    .. automethod:: copy(statement: Query, vars: Optional[Args]=None) -> AsyncCopy
 
-        It must be called as ``async with cur.copy() as copy: ...``
+        .. note:: it must be called as ``async with cur.copy() as copy: ...``
 
-    .. automethod:: callproc
     .. automethod:: fetchone
     .. automethod:: fetchmany
     .. automethod:: fetchall
index 13067887d7da389a092ec3b934cafd280a6036c8..c10859f52f6c956445c97745b7e43c47929e0ac7 100644 (file)
@@ -34,3 +34,21 @@ if pq.__impl__ == "c":
     from psycopg3_c import _psycopg3
 
     _psycopg3.register_builtin_c_loaders()
+
+
+# Note: defining the exported methods helps both Sphynx in documenting that
+# this is the canonical place to obtain them and should be used by MyPy too,
+# so that function signatures are consistent with the documentation.
+__all__ = [
+    "AsyncConnection",
+    "AsyncCopy",
+    "AsyncCursor",
+    "AsyncTransaction",
+    "Column",
+    "Connection",
+    "Copy",
+    "Cursor",
+    "Notify",
+    "Rollback",
+    "Transaction",
+]
index e308b6b927b1592d4d8ba8a4790835c6d15a9cd7..0d8bfe4c8ebe6d3c6c542235a7a4d24136c24a5a 100644 (file)
@@ -39,8 +39,8 @@ connect: Callable[[str], PQGen["PGconn"]]
 execute: Callable[["PGconn"], PQGen[List["PGresult"]]]
 
 if TYPE_CHECKING:
+    import psycopg3
     from .pq.proto import PGconn, PGresult
-    from .cursor import Cursor, AsyncCursor
 
 if pq.__impl__ == "c":
     from psycopg3_c import _psycopg3
@@ -69,7 +69,7 @@ class Notify(NamedTuple):
 
 
 NoticeHandler = Callable[[e.Diagnostic], None]
-NotifyHandler = Callable[[Notify], None]
+NotifyHandler = Callable[["psycopg3.Notify"], None]
 
 
 class BaseConnection:
@@ -96,7 +96,9 @@ class BaseConnection:
     ConnStatus = pq.ConnStatus
     TransactionStatus = pq.TransactionStatus
 
-    cursor_factory: Union[Type["Cursor"], Type["AsyncCursor"]]
+    cursor_factory: Union[
+        Type["psycopg3.Cursor"], Type["psycopg3.AsyncCursor"]
+    ]
 
     def __init__(self, pgconn: "PGconn"):
         self.pgconn = pgconn  # TODO: document this
@@ -227,7 +229,7 @@ class Connection(BaseConnection):
     Wrapper for a connection to the database.
     """
 
-    cursor_factory: Type[cursor.Cursor]
+    cursor_factory: Type["psycopg3.Cursor"]
 
     def __init__(self, pgconn: "PGconn"):
         super().__init__(pgconn)
@@ -273,7 +275,7 @@ class Connection(BaseConnection):
 
     def cursor(
         self, name: str = "", format: pq.Format = pq.Format.TEXT
-    ) -> cursor.Cursor:
+    ) -> "psycopg3.Cursor":
         """
         Return a new `Cursor` to send commands and queries to the connection.
         """
@@ -369,7 +371,7 @@ class Connection(BaseConnection):
                     result, encoding=self.client_encoding
                 )
 
-    def notifies(self) -> Iterator[Notify]:
+    def notifies(self) -> Iterator["psycopg3.Notify"]:
         """
         Yield `Notify` objects as soon as they are received from the database.
         """
@@ -393,7 +395,7 @@ class AsyncConnection(BaseConnection):
     Asynchronous wrapper for a connection to the database.
     """
 
-    cursor_factory: Type[cursor.AsyncCursor]
+    cursor_factory: Type["psycopg3.AsyncCursor"]
 
     def __init__(self, pgconn: "PGconn"):
         super().__init__(pgconn)
@@ -432,7 +434,7 @@ class AsyncConnection(BaseConnection):
 
     async def cursor(
         self, name: str = "", format: pq.Format = pq.Format.TEXT
-    ) -> cursor.AsyncCursor:
+    ) -> "psycopg3.AsyncCursor":
         """
         Return a new `AsyncCursor` to send commands and queries to the connection.
         """
@@ -528,7 +530,7 @@ class AsyncConnection(BaseConnection):
                     result, encoding=self.client_encoding
                 )
 
-    async def notifies(self) -> AsyncIterator[Notify]:
+    async def notifies(self) -> AsyncIterator["psycopg3.Notify"]:
         while 1:
             async with self.lock:
                 ns = await self.wait(notifies(self.pgconn))
index c66b50c5d03f1a791ab976459af1c42cff83c215..c08d1ed339a6a4357287f7b87582bc79098f07b0 100644 (file)
@@ -154,7 +154,7 @@ class Column(Sequence[Any]):
 
     @property
     def null_ok(self) -> Optional[bool]:
-        """Always `None`"""
+        """Always `!None`"""
         return None
 
 
@@ -509,7 +509,9 @@ class Cursor(BaseCursor["Connection"]):
 
     def fetchone(self) -> Optional[Sequence[Any]]:
         """
-        Return the next record from the current recordset, `None` if not available.
+        Return the next record from the current recordset.
+
+        Return `!None` the recordset is finished.
         """
         self._check_result()
         rv = self._transformer.load_row(self._pos)
@@ -564,7 +566,7 @@ class Cursor(BaseCursor["Connection"]):
         self, statement: Query, vars: Optional[Params] = None
     ) -> Iterator[Copy]:
         """
-        Initiate a :sql:`COPY` operation and return a `Copy` object to manage it.
+        Initiate a :sql:`COPY` operation and return an object to manage it.
         """
         with self._start_copy(statement, vars) as copy:
             yield copy
@@ -698,9 +700,6 @@ class AsyncCursor(BaseCursor["AsyncConnection"]):
     async def copy(
         self, statement: Query, vars: Optional[Params] = None
     ) -> AsyncIterator[AsyncCopy]:
-        """
-        Initiate a :sql:`COPY` operation and return an `AsyncCopy` object.
-        """
         copy = await self._start_copy(statement, vars)
         async with copy:
             yield copy
index 30b482c956f550bde3b35fd470e33f440b248b68..b42ed81ea6f9fc7e9bfece030712faf3eadff458 100644 (file)
@@ -57,7 +57,9 @@ class BaseTransaction(Generic[ConnectionType]):
 
     @property
     def savepoint_name(self) -> Optional[str]:
-        """The name of the savepoint; `None` if handling the main transaction."""
+        """
+        The name of the savepoint; `!None` if handling the main transaction.
+        """
         # Yes, it may change on __enter__. No, I don't care, because the
         # un-entered state is outside the public interface.
         return self._savepoint_name