From 17bfce4baffa7b48db59d3258e3efd60133bc677 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Mon, 18 Apr 2022 19:23:32 +0200 Subject: [PATCH] refactor(enum): rename python_type -> enum, enum_labels -> labels on EnumInfo The previous name were lifted from the composite adapters. However, that class would have had a more ambiguous "type" attribute, and "types" for the fields, hence the decision of using "python_" and "fields_" prefix to disambiguate. In the enum adapters context, enum is not ambiguous, so a more natural name seems preferred. --- docs/basic/adapt.rst | 8 +++---- psycopg/psycopg/_typeinfo.py | 8 +++---- psycopg/psycopg/types/enum.py | 39 +++++++++++++++-------------------- tests/types/test_enum.py | 18 ++++++++-------- 4 files changed, 34 insertions(+), 39 deletions(-) diff --git a/docs/basic/adapt.rst b/docs/basic/adapt.rst index 139c5effc..d19881418 100644 --- a/docs/basic/adapt.rst +++ b/docs/basic/adapt.rst @@ -395,11 +395,11 @@ using `~psycopg.types.enum.register_enum()`. documentation for the generic usage, especially the `~psycopg.types.TypeInfo.fetch()` method. - .. attribute:: enum_labels + .. attribute:: labels Contains labels available in the PostgreSQL enum type. - .. attribute:: python_type + .. attribute:: enum After `register_enum()` is called, it will contain the python type mapping to the registered enum. @@ -409,7 +409,7 @@ using `~psycopg.types.enum.register_enum()`. After registering, fetching data of the registered enum will cast PostgreSQL enum labels into corresponding Python enum labels. - If no ``python_type`` is specified, a `Enum` is created based on + If no `!enum` is specified, a new `Enum` is created based on PostgreSQL enum labels. Example:: @@ -427,7 +427,7 @@ Example:: >>> info = EnumInfo.fetch(conn, "user_role") >>> register_enum(info, UserRole, conn) - >>> some_editor = info.python_type.EDITOR + >>> some_editor = info.enum.EDITOR >>> some_editor diff --git a/psycopg/psycopg/_typeinfo.py b/psycopg/psycopg/_typeinfo.py index dfe770edc..933cb4798 100644 --- a/psycopg/psycopg/_typeinfo.py +++ b/psycopg/psycopg/_typeinfo.py @@ -295,12 +295,12 @@ class EnumInfo(TypeInfo): name: str, oid: int, array_oid: int, - enum_labels: Sequence[str], + labels: Sequence[str], ): super().__init__(name, oid, array_oid) - self.enum_labels = enum_labels + self.labels = labels # Will be set by register_enum() - self.python_type: Optional[Type[Enum]] = None + self.enum: Optional[Type[Enum]] = None @classmethod def _get_info_query( @@ -309,7 +309,7 @@ class EnumInfo(TypeInfo): return """\ SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, - array_agg(x.enumlabel) AS enum_labels + array_agg(x.enumlabel) AS labels FROM pg_type t LEFT JOIN ( SELECT e.enumtypid, e.enumlabel diff --git a/psycopg/psycopg/types/enum.py b/psycopg/psycopg/types/enum.py index aa99ab52f..c71fc19e3 100644 --- a/psycopg/psycopg/types/enum.py +++ b/psycopg/psycopg/types/enum.py @@ -18,7 +18,7 @@ E = TypeVar("E", bound=Enum) class EnumLoader(Loader, Generic[E]): _encoding = "utf-8" - python_type: Type[E] + enum: Type[E] def __init__(self, oid: int, context: Optional[AdaptContext] = None): super().__init__(oid, context) @@ -32,7 +32,7 @@ class EnumLoader(Loader, Generic[E]): else: label = data.decode(self._encoding) - return self.python_type[label] + return self.enum[label] class EnumBinaryLoader(EnumLoader[E]): @@ -59,14 +59,14 @@ class EnumBinaryDumper(EnumDumper): def register_enum( info: EnumInfo, - python_type: Optional[Type[E]] = None, + enum: Optional[Type[E]] = None, context: Optional[AdaptContext] = None, ) -> None: """Register the adapters to load and dump a enum type. :param info: The object with the information about the enum to register. - :param python_type: Python enum type matching to the Postgres one. If `!None`, - the type will be generated and put into info.python_type. + :param enum: Python enum type matching to the Postgres one. If `!None`, + a new enum will be generated and exposed as `EnumInfo.enum`. :param context: The context where to register the adapters. If `!None`, register it globally. """ @@ -74,39 +74,34 @@ def register_enum( if not info: raise TypeError("no info passed. Is the requested enum available?") - if python_type is None: - python_type = cast( - Type[E], - Enum(info.name.title(), {label: label for label in info.enum_labels}), - ) + if enum is None: + enum = cast(Type[E], Enum(info.name.title(), info.labels, module=__name__)) - info.python_type = python_type + info.enum = enum adapters = context.adapters if context else postgres.adapters info.register(context) - attribs: Dict[str, Any] = {"python_type": info.python_type} + attribs: Dict[str, Any] = {"enum": info.enum} loader_base = EnumLoader - name = f"{info.name.title()}{loader_base.__name__}" + name = f"{info.name.title()}Loader" loader = type(name, (loader_base,), attribs) adapters.register_loader(info.oid, loader) loader_base = EnumBinaryLoader - name = f"{info.name.title()}{loader_base.__name__}" + name = f"{info.name.title()}BinaryLoader" loader = type(name, (loader_base,), attribs) adapters.register_loader(info.oid, loader) attribs = {"oid": info.oid} - dumper_base: Type[Dumper] = EnumBinaryDumper - name = f"{info.name.title()}{dumper_base.__name__}" - dumper = type(name, (dumper_base,), attribs) - adapters.register_dumper(info.python_type, dumper) + name = f"{enum.__name__}BinaryDumper" + dumper = type(name, (EnumBinaryDumper,), attribs) + adapters.register_dumper(info.enum, dumper) - dumper_base = EnumDumper - name = f"{info.name.title()}{dumper_base.__name__}" - dumper = type(name, (dumper_base,), attribs) - adapters.register_dumper(info.python_type, dumper) + name = f"{enum.__name__}Dumper" + dumper = type(name, (EnumDumper,), attribs) + adapters.register_dumper(info.enum, dumper) def register_default_adapters(context: AdaptContext) -> None: diff --git a/tests/types/test_enum.py b/tests/types/test_enum.py index eda761ee5..7301ce0f9 100644 --- a/tests/types/test_enum.py +++ b/tests/types/test_enum.py @@ -59,18 +59,18 @@ def test_fetch_info(conn, testenum): assert info.name == name assert info.oid > 0 assert info.oid != info.array_oid > 0 - assert len(info.enum_labels) == len(labels) - assert info.enum_labels == labels + assert len(info.labels) == len(labels) + assert info.labels == labels def test_register_makes_a_type(conn, testenum): name, enum, labels = testenum info = EnumInfo.fetch(conn, name) assert info - assert info.python_type is None + assert info.enum is None register_enum(info, context=conn) - assert info.python_type is not None - assert [e.name for e in info.python_type] == [e.name for e in enum] + assert info.enum is not None + assert [e.name for e in info.enum] == [e.name for e in enum] @pytest.mark.parametrize("encoding", encodings) @@ -143,7 +143,7 @@ def test_generic_enum_loader(conn, testenum, encoding, fmt_in, fmt_out): for label in labels: cur = conn.execute(f"select %{fmt_in}::{name}", [label], binary=fmt_out) - assert cur.fetchone()[0] == info.python_type(label) + assert cur.fetchone()[0] == info.enum(label) @pytest.mark.parametrize("encoding", encodings) @@ -183,7 +183,7 @@ def test_generic_enum_array_loader(conn, testenum, encoding, fmt_in, fmt_out): register_enum(info, enum, conn) cur = conn.execute(f"select %{fmt_in}::{name}[]", [labels], binary=fmt_out) - assert cur.fetchone()[0] == list(info.python_type) + assert cur.fetchone()[0] == list(info.enum) @pytest.mark.asyncio @@ -194,8 +194,8 @@ async def test_fetch_info_async(aconn, testenum): assert info.name == name assert info.oid > 0 assert info.oid != info.array_oid > 0 - assert len(info.enum_labels) == len(labels) - assert info.enum_labels == labels + assert len(info.labels) == len(labels) + assert info.labels == labels @pytest.mark.asyncio -- 2.47.2