From aeed523d394ddf8888a6861b7804806096d97cf3 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Thu, 26 Aug 2021 20:58:05 +0200 Subject: [PATCH] Drop TypeInfo.async_fetch(), use fetch() for both connection types --- docs/api/types.rst | 31 ++++++++++++++++++++--- psycopg/psycopg/_typeinfo.py | 46 ++++++++++++++++++++++------------- tests/test_copy_async.py | 2 +- tests/test_typeinfo.py | 4 +-- tests/types/test_composite.py | 2 +- tests/types/test_range.py | 4 +-- 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/docs/api/types.rst b/docs/api/types.rst index 6269cb7b1..94c734743 100644 --- a/docs/api/types.rst +++ b/docs/api/types.rst @@ -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 diff --git a/psycopg/psycopg/_typeinfo.py b/psycopg/psycopg/_typeinfo.py index 7accec54f..551d14f93 100644 --- a/psycopg/psycopg/_typeinfo.py +++ b/psycopg/psycopg/_typeinfo.py @@ -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]) diff --git a/tests/test_copy_async.py b/tests/test_copy_async.py index fe5ac59f2..b118f6463 100644 --- a/tests/test_copy_async.py +++ b/tests/test_copy_async.py @@ -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()] diff --git a/tests/test_typeinfo.py b/tests/test_typeinfo.py index 11b8b9f1f..fd1367e37 100644 --- a/tests/test_typeinfo.py +++ b/tests/test_typeinfo.py @@ -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 diff --git a/tests/types/test_composite.py b/tests/types/test_composite.py index 8b18b76c2..5d3504f0e 100644 --- a/tests/types/test_composite.py +++ b/tests/types/test_composite.py @@ -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 diff --git a/tests/types/test_range.py b/tests/types/test_range.py index 97a67f97b..2d44ca009 100644 --- a/tests/types/test_range.py +++ b/tests/types/test_range.py @@ -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): -- 2.47.3