python / python/mypy

Unable to make generic subclass using type variable with value restriction

Open
#10,130 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-type-variables
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Mypy reports some strange false positive errors when I try to define a generic subclass of a generic class where the type variable has a value restriction.

To Reproduce

I made this minimal example to reproduce the bug:

from typing import Generic, TypeVar

T = TypeVar("T", str, int)


class GenericSuperClass(Generic[T]):
    def __init__(self, value: T) -> None:
        # mypy complains if self.value is not annotated, for some reason
        self.value: T = value


class GenericSubClass(GenericSuperClass[T]):
    def __init__(self, value: T, flag: bool) -> None:
        super().__init__(value)
        self.flag = flag


instance = GenericSubClass("string", True)
reveal_type(instance.value)

This example is a bit simple, of course, and does not make use of the value restriction. But you could imagine that there is some logic here that assumes T is either a str or an int.

Expected Behavior

I would expect the above example to not report any errors with Mypy, and I would expect Mypy to infer that self.value is of type T.

I expect the revealed type to be builtins.str.

Actual Behavior

Mypy reports the following errors:

testing_inheriting_generics.py:14: error: Argument 1 to "__init__" of "GenericSuperClass" has incompatible type "str"; expected "T"
testing_inheriting_generics.py:14: error: Argument 1 to "__init__" of "GenericSuperClass" has incompatible type "int"; expected "T"
testing_inheriting_generics.py:19: note: Revealed type is 'builtins.str*'
Found 2 errors in 1 file (checked 1 source file)

Additionally, if self.value is not annotated, Mypy reports the error testing_inheriting_generics.py:9: error: Need type annotation for 'value'

The revealed type is correct, but I believe the errors are false positives?

If I replace T = TypeVar("T", str, int) with T = TypeVar("T"), everything works as expected, but then I would not be able to assume that T is either a str or an int.

Your Environment

  • Mypy version used: mypy 0.812
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files):
    [mypy]
    disallow_untyped_calls = True
    warn_redundant_casts = True
    warn_return_any = True
    warn_unused_configs = True
    warn_unused_ignores = True
    
    [mypy-responses.*]
    ignore_missing_imports = True
    
  • Python version used: Python 3.9.1
  • Operating system and version: macOS Catalina 10.15.7

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproducer in testing_inheriting_generics.py and run mypy with the reported Python 3.9 setup. Trace checking of the value-restricted TypeVar through GenericSubClass and GenericSuperClass. Done means the false-positive constructor errors and unnecessary attribute annotation error are gone, while reveal_type reports builtins.str.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.