python / python/mypy

metaclass instance variable should be seen as class ClassVar

Open
#16,967 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

When a metaclass has an instance variable, the class (that is an instance of the metaclass) should have that variable as a ClassVar

The class is an instance of the metaclass.

To Reproduce

from typing import Any
from typing_extensions import reveal_type


class M(type):
    """ ensure classes of this type have ClassVar `x` """
    x: list[int]

    def __new__(mcs, name: str, bases: tuple[type, ...], dct: dict[str, Any]) -> "M":
        # construct class
        new_class = super().__new__(mcs, name, bases, dct)
        if "x" not in dct:
            new_class.x = [2]
        return new_class


class C(metaclass=M):
    x = []  # mypy reports "need type annotation" when it should know "ClassVar[list[int]]"


class D(metaclass=M):
    pass

    def f(self) -> None:
        self.x = [5]  # no type error reported
        # should report assigning instance variable over class variable


class E(metaclass=M):
    x = 3  # no type error reported - expected '"Literal[3]" is incompatible with "list[int]"'


print(C.x)  # []
print(D.x)  # [2]
print(E.x)  # 3

reveal_type(C.x)  # mypy: correctly sees list[int]  pyright: list[Unknown]

reveal_type(D.x)  # list[int]

reveal_type(E.x)  # mypy: list[int]  pyright: int
# I don't think it matters what this reports,
# because there should be a type error at assignment above.

Expected Behavior

in code comments

Actual Behavior

in code comments

Your Environment

  • Mypy version used: 1.8.0
  • Mypy command-line flags: --strict
  • Python version used: 3.10

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

Run the provided reproducer with mypy 1.8.0 and --strict, then compare the diagnostics and revealed types with the expected results in the code comments. Trace the type-checking path for metaclass instance variables and class bodies; done means C.x, D.x, and E.x produce the intended ClassVar-related behavior and assignment errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.