python / python/mypy

mypy doesn't like when I use type variables to subscript generic type

Ouverte
#13,619 7 commentaires 2 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

bug
Langage dominant
Python
Étoiles
20.6k
Forks
3.3k
Métriques de merge des PR
Métriques de PR en attente

Description

Bug Report

Hey, I'm trying to figure out if this mypy output is a bug or if I'm doing something incorrectly. I need to pass a type variable to a function to properly deserialize my model class. Versions 1 & 2 of my build_generic_* function work correctly, as visible in the code output, but mypy doesn't like what I'm doing there saying that I can't use a type variable this way. I created versions of this function both with Type and TypeAlias annotation just to check if mypy will be fine with either one.

from typing import Generic, Type, TypeAlias, TypeVar
from pydantic import BaseModel
from pydantic.generics import GenericModel


class SomeModel(BaseModel):
    a: int


T = TypeVar("T", bound=BaseModel)


class SomeGenericModel(GenericModel, Generic[T]):
    some_model_instance: T


def build_generic_type_from_str_1(some_generic_model_str: str,
                                  t_type: Type[T]) -> SomeGenericModel[T]:
    return SomeGenericModel[t_type].parse_raw(some_generic_model_str)


def build_generic_type_from_str_2(some_generic_model_str: str,
                                  t_type: TypeAlias) -> SomeGenericModel[T]:
    return SomeGenericModel[t_type].parse_raw(some_generic_model_str)


def build_generic_type_from_str_3(
        some_generic_model_str: str) -> SomeGenericModel[T]:
    return SomeGenericModel.parse_raw(some_generic_model_str)


def main():
    print(
        build_generic_type_from_str_1('{"some_model_instance": {"a": 1}}',
                                      SomeModel))
    print(
        build_generic_type_from_str_2('{"some_model_instance": {"a": 1}}',
                                      SomeModel))
    print(build_generic_type_from_str_3('{"some_model_instance": {"a": 1}}'))


if __name__ == "__main__":
    main()

carbon

Output from running this code & mypy:

$ python tests/mypy_typealias_problem.py
some_model_instance=SomeModel(a=1)
some_model_instance=SomeModel(a=1)
some_model_instance=BaseModel()

$ mypy tests/mypy_typealias_problem.py  
tests/mypy_typealias_problem.py:19: error: Variable "t_type" is not valid as a type
tests/mypy_typealias_problem.py:19: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
tests/mypy_typealias_problem.py:24: error: Variable "t_type" is not valid as a type
tests/mypy_typealias_problem.py:24: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
Found 2 errors in 1 file (checked 1 source file)

For comparison, pyright seems to suggest that the second approach with TypeAlias is incorrect.

$ pyright tests/mypy_typealias_problem.py                              
WARNING: there is a new pyright version available (v1.1.269 -> v1.1.274).
Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`

No configuration file found.
pyproject.toml file found at /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client.
Loading pyproject.toml file at /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/pyproject.toml
Assuming Python version 3.10
Assuming Python platform Darwin
Auto-excluding **/node_modules
Auto-excluding **/__pycache__
Auto-excluding **/.*
stubPath /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/typings is not a valid directory.
Searching for source files
Found 1 source file
pyright 1.1.269
/Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/tests/mypy_typealias_problem.py
  /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/tests/mypy_typealias_problem.py:24:29 - error: Expected class type but received "TypeAlias" (reportGeneralTypeIssues)
  /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/tests/mypy_typealias_problem.py:23:74 - warning: TypeVar "T" appears only once in generic function signature (reportInvalidTypeVarUse)
  /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/tests/mypy_typealias_problem.py:28:58 - warning: TypeVar "T" appears only once in generic function signature (reportInvalidTypeVarUse)
  /Users/dominikderen/dev/qomplx/argo-workflows/iostation-responders-client/tests/mypy_typealias_problem.py:38:39 - error: Argument of type "Type[SomeModel]" cannot be assigned to parameter "t_type" of type "TypeAlias" in function "build_generic_type_from_str_2"
    "Type[ModelMetaclass]" is incompatible with "Type[TypeAlias]" (reportGeneralTypeIssues)
2 errors, 2 warnings, 0 informations
Completed in 0.77sec

Versions:
Any suggestions on this would be greatly appreciated!

To Reproduce

Run the script provided above.

Expected Behavior

Either of the two approaches should not raise a mypy validation error.

Actual Behavior

Mypy is making case 1 & 2 as errors.

Your Environment

  • Mypy version used: mypy 0.971 (compiled: yes)

  • Mypy command-line flags: none, just providing a directory.

  • Mypy configuration options from mypy.ini (and other config files): none.

  • Python version used: 3.10.5

  • Operating system and version: MacOS Monterey 12.5.1

  • Pyright: 1.1.269

Guide de contribution

Ouvrir le guide de contribution

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.

Piste de recherche

Commencez par le reproducer dans tests/mypy_typealias_problem.py et exécutez la commande mypy indiquée sur les trois variantes de build_generic_type_from_str. Examinez la gestion de l’application des types génériques et des expressions TypeVar, puis comparez les diagnostics avec le comportement attendu décrit dans l’issue. Le travail est terminé lorsqu’une décision documentée sur le comportement a été prise et qu’un test de régression a été ajouté ou mis à jour si le comportement est confirmé comme étant un bug.

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

Évaluation

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

Recevez les nouvelles issues par e-mail

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