]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Drop TypeInfo.async_fetch(), use fetch() for both connection types
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 26 Aug 2021 18:58:05 +0000 (20:58 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 26 Aug 2021 19:37:54 +0000 (21:37 +0200)
docs/api/types.rst
psycopg/psycopg/_typeinfo.py
tests/test_copy_async.py
tests/test_typeinfo.py
tests/types/test_composite.py
tests/types/test_range.py

index 6269cb7b1630c432bc3abe3d62e69a11cfd323f1..94c73474315b4652331bdae90c3ff7757e7875c4 100644 (file)
@@ -52,12 +52,35 @@ can extend the behaviour of the adapters: if you create a loader for
 
 .. autoclass:: TypeInfo
 
-    .. automethod:: fetch
-    .. automethod:: fetch_async
+    .. method:: fetch(conn, name)
+        :classmethod:
+
+    .. method:: fetch(aconn, name)
+        :classmethod:
+        :async:
+        :noindex:
+
+        Query a system catalog to read information about a type.
+
+        :param conn: the connection to query
+        :type conn: ~psycopg.Connection or ~psycopg.AsyncConnection
+        :param name: the name of the type to query. It can include a schema
+            name.
+        :type name: `!str` or `~psycopg.sql.Identifier`
+        :return: a `!TypeInfo` object (or subclass) populated with the type
+            information, `!None` if not found.
+
+        If the connection is async the function will behave as a coroutine and
+        the caller will need to `await` on it to get the result::
+
+            t = await TypeInfo.fetch(aconn, "mytype")
+
     .. automethod:: register
 
-        The *context* can be a `~psycopg.Connection` or `~psycopg.Cursor`.
-        Specifying no context will register the `!TypeInfo` globally.
+        :param context: the context where the type is registered, for instance
+            a `~psycopg.Connection` or `~psycopg.Cursor`. `!None` registers
+            the `!TypeInfo` globally.
+        :type context: Optional[~psycopg.abc.AdaptContext]
 
         Registering the `TypeInfo` in a context allows the adapters of that
         context to look up type information: for instance it allows to
index 7accec54fceb7d0c6aed4a416004326c64da93eb..551d14f93fe41f7fb97794d945ee534761155dcb 100644 (file)
@@ -7,7 +7,7 @@ information to the adapters if needed.
 
 # Copyright (C) 2020-2021 The Psycopg Team
 
-from typing import Any, Dict, Iterator, Optional
+from typing import Any, Dict, Iterator, Optional, overload
 from typing import Sequence, Type, TypeVar, Union, TYPE_CHECKING
 
 from . import errors as e
@@ -49,20 +49,34 @@ class TypeInfo:
             f" {self.name} (oid: {self.oid}, array oid: {self.array_oid})>"
         )
 
+    @overload
     @classmethod
     def fetch(
         cls: Type[T], conn: "Connection[Any]", name: Union[str, "Identifier"]
     ) -> Optional[T]:
-        """
-        Query a system catalog to read information about a type.
+        ...
+
+    @overload
+    @classmethod
+    async def fetch(
+        cls: Type[T],
+        conn: "AsyncConnection[Any]",
+        name: Union[str, "Identifier"],
+    ) -> Optional[T]:
+        ...
+
+    @classmethod
+    def fetch(
+        cls: Type[T],
+        conn: "Union[Connection[Any], AsyncConnection[Any]]",
+        name: Union[str, "Identifier"],
+    ) -> Any:
+        """Query a system catalog to read information about a type."""
+        from .connection_async import AsyncConnection
+
+        if isinstance(conn, AsyncConnection):
+            return cls._fetch_async(conn, name)
 
-        :param conn: the connection to query
-        :param name: the name of the type to query. It can include a schema
-            name.
-        :type name: `!str` or `~psycopg.sql.Identifier`
-        :return: a `!TypeInfo` object populated with the type information,
-            `!None` if not found.
-        """
         from .sql import Composable
 
         if isinstance(name, Composable):
@@ -79,10 +93,10 @@ class TypeInfo:
             return None
 
         recs = cur.fetchall()
-        return cls._fetch(name, recs)
+        return cls._from_records(name, recs)
 
     @classmethod
-    async def fetch_async(
+    async def _fetch_async(
         cls: Type[T],
         conn: "AsyncConnection[Any]",
         name: Union[str, "Identifier"],
@@ -105,13 +119,11 @@ class TypeInfo:
             return None
 
         recs = await cur.fetchall()
-        return cls._fetch(name, recs)
+        return cls._from_records(name, recs)
 
     @classmethod
-    def _fetch(
-        cls: Type[T],
-        name: str,
-        recs: Sequence[Dict[str, Any]],
+    def _from_records(
+        cls: Type[T], name: str, recs: Sequence[Dict[str, Any]]
     ) -> Optional[T]:
         if len(recs) == 1:
             return cls(**recs[0])
index fe5ac59f2d7f2014270589f8ecc60315d13f4a02..b118f64630ef151749fc1e96e752a462225d35d7 100644 (file)
@@ -104,7 +104,7 @@ async def test_set_custom_type(aconn, hstore):
 
     assert rows == [('"a"=>"1", "b"=>"2"',)]
 
-    register_hstore(await TypeInfo.fetch_async(aconn, "hstore"), cur)
+    register_hstore(await TypeInfo.fetch(aconn, "hstore"), cur)
     async with cur.copy(command) as copy:
         copy.set_types(["hstore"])
         rows = [row async for row in copy.rows()]
index 11b8b9f1f936026d2ebb9597a2690bdbc994a545..fd1367e3769c77dffafd7c5e2731e0547130cb81 100644 (file)
@@ -35,7 +35,7 @@ async def test_fetch_async(aconn, name, status):
         await aconn.execute("select 1")
 
     assert aconn.info.transaction_status == status
-    info = await TypeInfo.fetch_async(aconn, name)
+    info = await TypeInfo.fetch(aconn, name)
     assert aconn.info.transaction_status == status
 
     assert info.name == "text"
@@ -66,7 +66,7 @@ async def test_fetch_not_found_async(aconn, name, status):
         await aconn.execute("select 1")
 
     assert aconn.info.transaction_status == status
-    info = await TypeInfo.fetch_async(aconn, name)
+    info = await TypeInfo.fetch(aconn, name)
     assert aconn.info.transaction_status == status
 
     assert info is None
index 8b18b76c22b6da149f5f1ffa61c864c57521596c..5d3504f0eb38f1a7309986517ae0c0a617cdfb8e 100644 (file)
@@ -145,7 +145,7 @@ def test_fetch_info(conn, testcomp, name, fields):
 @pytest.mark.asyncio
 @pytest.mark.parametrize("name, fields", fetch_cases)
 async def test_fetch_info_async(aconn, testcomp, name, fields):
-    info = await CompositeInfo.fetch_async(aconn, name)
+    info = await CompositeInfo.fetch(aconn, name)
     assert info.name == "testcomp"
     assert info.oid > 0
     assert info.oid != info.array_oid > 0
index 97a67f97ba15c3b139d531c3ed73460d53e75a56..2d44ca009ad2e8c4be3c6c785454a046cf8b6cf1 100644 (file)
@@ -312,7 +312,7 @@ def test_fetch_info_not_found(conn):
 @pytest.mark.asyncio
 @pytest.mark.parametrize("name, subtype", fetch_cases)
 async def test_fetch_info_async(aconn, testrange, name, subtype):
-    info = await RangeInfo.fetch_async(aconn, name)
+    info = await RangeInfo.fetch(aconn, name)
     assert info.name == "testrange"
     assert info.oid > 0
     assert info.oid != info.array_oid > 0
@@ -321,7 +321,7 @@ async def test_fetch_info_async(aconn, testrange, name, subtype):
 
 @pytest.mark.asyncio
 async def test_fetch_info_not_found_async(aconn):
-    assert await RangeInfo.fetch_async(aconn, "nosuchrange") is None
+    assert await RangeInfo.fetch(aconn, "nosuchrange") is None
 
 
 def test_dump_custom_empty(conn, testrange):