sqltypes.Enum not generic enough

Ouverte
#11,597 0 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

  • #13492 par @waterWang — fermée sans fusion

Évaluation

Difficulté
3/5
Temps estimé
1-2 jours
Accessibilité débutants
45/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
À l'abandon
Stack technique
python
Domaine
databases

Piste de recherche

Commencez dans lib/sqlalchemy/sql/sqltypes.py, au niveau des définitions de String et Enum, puis lisez la discussion liée concernant l’erreur de pyright et les modifications de typage proposées. Vérifiez l’exemple utilisant Enum(MyEnum, native_enum=False) et column_property ; le travail est terminé lorsque le typage générique de Enum prend en charge cette utilisation sans la plainte pyright signalée.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

bug datatypes typing
Discussed in https://github.com/sqlalchemy/sqlalchemy/discussions/11548

The generic type for Enum needs to be a typevar for pyright:

from __future__ import annotations

import enum

from sqlalchemy import Enum
from sqlalchemy import func
from sqlalchemy.orm import column_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column

class MyEnum(enum.Enum):
    one = "one"
    two = "two"



class Base(DeclarativeBase):
    pass


class A(Base):
    __tablename__ = "a"

    id: Mapped[int] = mapped_column(primary_key=True)
    data: Mapped[MyEnum] = column_property(
        func.some_func(type_=Enum(MyEnum, native_enum=False))
    )


image

seems to pass in mypy

a quick fix looks like:

@@ -1179,8 +1186,9 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         elif dialect.name not in variant_mapping:
             return _we_are_the_impl(variant_mapping["_default"])
 
+_TEE = TypeVar("_TEE", bound=Union[str, enum.Enum])
 
-class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
+class Enum(String, SchemaType, Emulated, TypeEngine[_TEE]):
     """Generic Enum Type.
 
     The :class:`.Enum` type provides a set of possible string values
@@ -1483,7 +1491,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
             self.enum_class = None
             return enums, enums
 
-    def _resolve_for_literal(self, value: Any) -> Enum:
+    def _resolve_for_literal(self, value: Any) -> Enum[Any]:
         tv = type(value)
         typ = self._resolve_for_python_type(tv, tv, tv)
         assert typ is not None
@@ -1494,7 +1502,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
         python_type: Type[Any],
         matched_on: _MatchedOnType,
         matched_on_flattened: Type[Any],
-    ) -> Optional[Enum]:
+    ) -> Optional[Enum[Any]]:
         # "generic form" indicates we were placed in a type map
         # as ``sqlalchemy.Enum(enum.Enum)`` which indicates we need to
         # get enumerated values from the datatype
@@ -1538,7 +1546,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
 
         kw["length"] = NO_ARG if self.length == 0 else self.length
         return cast(
-            Enum,
+            Enum[Any],
             self._generic_type_affinity(_enums=enum_args, **kw),  # type: ignore  # noqa: E501
         )

to go further we might want to remove String from Enum's inherits, since pyright still complains about the signature

diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index c20df07a6..f948ee01d 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -256,6 +256,13 @@ class String(Concatenable, TypeEngine[str]):
         return dbapi.STRING
 
 
+if TYPE_CHECKING:
+    class StringNoGeneric(Concatenable):
+        pass
+else:
+    StringNoGeneric = String
+
+
 class Text(String):
     """A variably sized string type.
 
@@ -1179,8 +1186,9 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         elif dialect.name not in variant_mapping:
             return _we_are_the_impl(variant_mapping["_default"])
 
+_TEE = TypeVar("_TEE", bound=Union[str, enum.Enum])
 
-class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
+class Enum(StringNoGeneric, SchemaType, Emulated, TypeEngine[_TEE]):
     """Generic Enum Type.
 
     The :class:`.Enum` type provides a set of possible string values
@@ -1483,7 +1491,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
             self.enum_class = None
             return enums, enums
 
-    def _resolve_for_literal(self, value: Any) -> Enum:
+    def _resolve_for_literal(self, value: Any) -> Enum[Any]:
         tv = type(value)
         typ = self._resolve_for_python_type(tv, tv, tv)
         assert typ is not None
@@ -1494,7 +1502,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
         python_type: Type[Any],
         matched_on: _MatchedOnType,
         matched_on_flattened: Type[Any],
-    ) -> Optional[Enum]:
+    ) -> Optional[Enum[Any]]:
         # "generic form" indicates we were placed in a type map
         # as ``sqlalchemy.Enum(enum.Enum)`` which indicates we need to
         # get enumerated values from the datatype
@@ -1538,7 +1546,7 @@ class Enum(String, SchemaType, Emulated, TypeEngine[Union[str, enum.Enum]]):
 
         kw["length"] = NO_ARG if self.length == 0 else self.length
         return cast(
-            Enum,
+            Enum[Any],
             self._generic_type_affinity(_enums=enum_args, **kw),  # type: ignore  # noqa: E501
         )
 

Langage dominant
Python
Étoiles
12.3k
Forks
1.8k
Merge moyen
2 j 10 h
PR mergées (30 j)
9

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de sqlalchemy/sqlalchemy

Toutes les issues de sqlalchemy/sqlalchemy

Issues similaires

Plus d'issues Python

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.