From 38cac12073e6e9f9b408b183ec0eaad2f2228d85 Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Fri, 2 Jun 2023 15:05:38 +0200 Subject: [PATCH 1/6] Explicit decorated __new__, __class_getitem__ and __init_subclass__ --- mypy/checker.py | 5 +- mypy/semanal.py | 6 +- mypy/typeops.py | 4 +- ...eck-special-class--and-static-methods.test | 1391 +++++++++++++++++ test-data/unit/fixtures/__init_subclass__.pyi | 1 + test-data/unit/fixtures/__new__.pyi | 1 + test-data/unit/fixtures/dict.pyi | 2 + .../fixtures/object_with_init_subclass.pyi | 1 + test-data/unit/fixtures/primitives.pyi | 2 + test-data/unit/fixtures/tuple.pyi | 1 + 10 files changed, 1408 insertions(+), 6 deletions(-) create mode 100644 test-data/unit/check-special-class--and-static-methods.test diff --git a/mypy/checker.py b/mypy/checker.py index c1c31538b7de..040857d34336 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1159,11 +1159,10 @@ def check_func_def( isinstance(defn, FuncDef) and ref_type is not None and i == 0 - and not defn.is_static + and (not defn.is_static or defn.name == "__new__") and typ.arg_kinds[0] not in [nodes.ARG_STAR, nodes.ARG_STAR2] ): - isclass = defn.is_class or defn.name in ("__new__", "__init_subclass__") - if isclass: + if defn.is_class or defn.name == "__new__": ref_type = mypy.types.TypeType.make_normalized(ref_type) erased = get_proper_type(erase_to_bound(arg_type)) if not is_subtype(ref_type, erased, ignore_type_params=True): diff --git a/mypy/semanal.py b/mypy/semanal.py index 8934dc9321b7..a1afcf855f3b 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -959,9 +959,11 @@ def remove_unpack_kwargs(self, defn: FuncDef, typ: CallableType) -> CallableType def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type: bool) -> None: """Check basic signature validity and tweak annotation of self/cls argument.""" - # Only non-static methods are special. + # Only non-static methods are special, as well as __new__. functype = func.type - if not func.is_static: + if func.name == "__new__": + func.is_static = True + if not func.is_static or func.name == "__new__": if func.name in ["__init_subclass__", "__class_getitem__"]: func.is_class = True if not func.arguments: diff --git a/mypy/typeops.py b/mypy/typeops.py index ee544c6740bb..feaab0e04730 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -704,7 +704,9 @@ def callable_type( fdef: FuncItem, fallback: Instance, ret_type: Type | None = None ) -> CallableType: # TODO: somewhat unfortunate duplication with prepare_method_signature in semanal - if fdef.info and not fdef.is_static and fdef.arg_names: + if fdef.name == "__new__": + fdef.is_static = True + if fdef.info and (not fdef.is_static or fdef.name == "__new__") and fdef.arg_names: self_type: Type = fill_typevars(fdef.info) if fdef.is_class or fdef.name == "__new__": self_type = TypeType.make_normalized(self_type) diff --git a/test-data/unit/check-special-class--and-static-methods.test b/test-data/unit/check-special-class--and-static-methods.test new file mode 100644 index 000000000000..cded49cc59ce --- /dev/null +++ b/test-data/unit/check-special-class--and-static-methods.test @@ -0,0 +1,1391 @@ +-- Explicitly decorated __new__, __init_subclass__ and __class_getitem_ +-- Ref. https://github.com/python/mypy/issues/15080 +-- -------------------------------------------------------------------- + +-- Variants of tests in check-classes.test +-- --------------------------------------- + +[case testOverride__new__WithDifferentSignature_explicit] + +class A: + @staticmethod + def __new__(cls, x: int) -> A: + pass + +class B(A): + def __new__(cls) -> B: + pass + +class C(A): + @staticmethod + def __new__(cls) -> C: + pass + +[builtins fixtures/staticmethod.pyi] + +[case testOverride__new__AndCallObject_explicit] +from typing import TypeVar, Generic + +class A: + @staticmethod + def __new__(cls, x: int) -> 'A': + return object.__new__(cls) + +T = TypeVar('T') +class B(Generic[T]): + @staticmethod + def __new__(cls, foo: T) -> 'B[T]': + x = object.__new__(cls) + # object.__new__ doesn't have a great type :( + reveal_type(x) # N: Revealed type is "Any" + return x + +[builtins fixtures/__new__.pyi] + +[case testOverride__init_subclass__WithDifferentSignature_explicit] +class A: + @classmethod + def __init_subclass__(cls, x: int) -> None: pass + +class B(A): # E: Missing positional argument "x" in call to "__init_subclass__" of "A" + @classmethod + def __init_subclass__(cls) -> None: pass + +[builtins fixtures/classmethod.pyi] + +[case testInitSubclassWithReturnValueType_explicit] +import typing +class A: + @classmethod + def __init_subclass__(cls) -> 'A': pass # E: The return type of "__init_subclass__" must be None + +[builtins fixtures/classmethod.pyi] + +[case testInitSubclassWithImplicitReturnValueType_explicit] +import typing + +class A: + @classmethod + def __init_subclass__(cls, x: int=1): pass + +[builtins fixtures/classmethod.pyi] + +[case testDecoratedInitSubclassWithImplicitReturnValueType_explicit] +import typing +from typing import Callable + +def deco(fn: Callable) -> Callable: + return fn + +class A: + @deco + @classmethod + def __init_subclass__(cls, x: int=1): pass + +[builtins fixtures/classmethod.pyi] + +[case testOverloadedInitSubclassWithImplicitReturnValueType_explicit] +from typing import overload +from foo import * +[file foo.pyi] +from typing import overload +class Foo: + @overload + @classmethod + def __init_subclass__(cls, a: int): + pass + + @overload + @classmethod + def __init_subclass__(cls, a: str): + pass + +[builtins fixtures/classmethod.pyi] + +[case testInitSubclassWithAnyReturnValueType_explicit] +import typing +from typing import Any + +class A: + @classmethod + def __init_subclass__(cls) -> Any: pass # E: The return type of "__init_subclass__" must be None + +[builtins fixtures/classmethod.pyi] + +[case testOverloadedInitSubclassWithAnyReturnValueType_explicit] +from foo import * +[file foo.pyi] +from typing import overload, Any +class Foo: + @overload + @classmethod + def __init_subclass__(cls, a: int) -> Any: # E: The return type of "__init_subclass__" must be None + pass + + @overload + @classmethod + def __init_subclass__(cls, a: str) -> Any: # E: The return type of "__init_subclass__" must be None + pass + +[builtins fixtures/classmethod.pyi] + +[case testConstructInstanceWith__new___explitit] +from typing import Optional +class C: + @staticmethod + def __new__(cls, foo: Optional[int] = None) -> 'C': + obj = object.__new__(cls) + return obj + +x = C(foo=12) +x.a # E: "C" has no attribute "a" +C(foo='') # E: Argument "foo" to "C" has incompatible type "str"; expected "Optional[int]" + +[builtins fixtures/__new__.pyi] + +[case testClassWith__new__AndCompatibilityWithType_explicit] +class C: + @staticmethod + def __new__(cls, foo: int = None) -> 'C': + obj = object.__new__(cls) + return obj + +def f(x: type) -> None: pass +def g(x: int) -> None: pass + +f(C) +g(C) # E: Argument 1 to "g" has incompatible type "Type[C]"; expected "int" + +[builtins fixtures/__new__.pyi] + +[case testClassWith__new__AndCompatibilityWithType2_explicit] +class C: + @staticmethod + def __new__(cls, foo): + obj = object.__new__(cls) + return obj + +def f(x: type) -> None: pass +def g(x: int) -> None: pass + +f(C) +g(C) # E: Argument 1 to "g" has incompatible type "Type[C]"; expected "int" + +[builtins fixtures/__new__.pyi] + +[case testGenericClassWith__new___explicit] +from typing import TypeVar, Generic +T = TypeVar('T') + +class C(Generic[T]): + @staticmethod + def __new__(cls, foo: T) -> 'C[T]': + obj = object.__new__(cls) + return obj + def set(self, x: T) -> None: pass +c = C('') +c.set('') +c.set(1) # E: Argument 1 to "set" of "C" has incompatible type "int"; expected "str" + +[builtins fixtures/__new__.pyi] + +[case testOverloaded__new___explicit] +from foo import * +[file foo.pyi] +from typing import overload + +class C: + @overload + @staticmethod + def __new__(cls, foo: int) -> 'C': + obj = object.__new__(cls) + return obj + @overload + @staticmethod + def __new__(cls, x: str, y: str) -> 'C': + obj = object.__new__(cls) + return obj +c = C(1) +c.a # E: "C" has no attribute "a" +C('', '') +C('') # E: No overload variant of "C" matches argument type "str" \ + # N: Possible overload variants: \ + # N: def __new__(cls, foo: int) -> C \ + # N: def __new__(cls, x: str, y: str) -> C + +[builtins fixtures/__new__.pyi] + +[case testNewAndInit1_explicit] +class A: + def __init__(self, x: int) -> None: + pass + +class C(A): + @staticmethod + def __new__(cls) -> C: + pass + +C() + +[builtins fixtures/staticmethod.pyi] + +[case testNewAndInit2_explicit] +from typing import Any + +class A: + @staticmethod + def __new__(cls, *args: Any) -> 'A': + ... + +class B(A): + def __init__(self, x: int) -> None: + pass + +reveal_type(B) # N: Revealed type is "def (x: builtins.int) -> __main__.B" + +[builtins fixtures/tuple.pyi] + +[case testNewAndInit3_explicit] +from typing import Any + +class A: + @staticmethod + def __new__(cls, *args: Any) -> 'A': + ... + def __init__(self, x: int) -> None: + pass + +reveal_type(A) # N: Revealed type is "def (x: builtins.int) -> __main__.A" + +[builtins fixtures/tuple.pyi] + +[case testDecoratedConstructors_explicit] +from typing import TypeVar, Callable, Any + +F = TypeVar('F', bound=Callable[..., Any]) + +def dec(f: F) -> F: ... + +class A: + @dec + def __init__(self, x: int) -> None: ... + +class B: + @dec + @staticmethod + def __new__(cls, x: int) -> B: ... + +reveal_type(A) # N: Revealed type is "def (x: builtins.int) -> __main__.A" +reveal_type(B) # N: Revealed type is "def (x: builtins.int) -> __main__.B" + +[builtins fixtures/staticmethod.pyi] + +[case testDecoratedConstructorsBad_explicit] +from typing import Callable, Any + +def dec(f: Callable[[Any, int], Any]) -> int: ... + +class A: + @dec # E: Unsupported decorated constructor type + def __init__(self, x: int) -> None: ... + +class B: + @dec # E: Unsupported decorated constructor type + @staticmethod + def __new__(cls, x: int) -> B: ... + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType1_explicit] +class A: + @staticmethod + def __new__(cls) -> B: + pass + +class B(A): pass + +reveal_type(A()) # N: Revealed type is "__main__.B" +reveal_type(B()) # N: Revealed type is "__main__.B" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType2_explicit] +from typing import Any + +# make sure that __new__ method that return Any are ignored when +# determining the return type +class A: + @staticmethod + def __new__(cls): + pass + +class B: + @staticmethod + def __new__(cls) -> Any: + pass + +reveal_type(A()) # N: Revealed type is "__main__.A" +reveal_type(B()) # N: Revealed type is "__main__.B" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType3_explicit] + +# Check for invalid __new__ typing + +class A: + @staticmethod + def __new__(cls) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "A") + pass + +reveal_type(A()) # N: Revealed type is "__main__.A" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType4_explicit] +from typing import TypeVar, Type + +# Check for __new__ using type vars + +TX = TypeVar('TX', bound='X') +class X: + @staticmethod + def __new__(lol: Type[TX], x: int) -> TX: + pass +class Y(X): pass + +reveal_type(X(20)) # N: Revealed type is "__main__.X" +reveal_type(Y(20)) # N: Revealed type is "__main__.Y" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType5_explicit] +from typing import Any, TypeVar, Generic, overload + +T = TypeVar('T') +class O(Generic[T]): + @overload + @staticmethod + def __new__(cls) -> O[int]: + pass + @overload + @staticmethod + def __new__(cls, x: int) -> O[str]: + pass + @staticmethod + def __new__(cls, x: int = 0) -> O[Any]: + pass + +reveal_type(O()) # N: Revealed type is "__main__.O[builtins.int]" +reveal_type(O(10)) # N: Revealed type is "__main__.O[builtins.str]" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType6_explicit] +from typing import Tuple, Optional + +# Check for some cases that aren't allowed + +class X: + @staticmethod + def __new__(cls) -> Optional[Y]: # E: "__new__" must return a class instance (got "Optional[Y]") + pass +class Y: + @staticmethod + def __new__(cls) -> Optional[int]: # E: "__new__" must return a class instance (got "Optional[int]") + pass + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType7_explicit] +from typing import NamedTuple + +# ... test __new__ returning tuple type +class A: + @staticmethod + def __new__(cls) -> 'B': + pass + +N = NamedTuple('N', [('x', int)]) +class B(A, N): pass + +reveal_type(A()) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.B]" + +[builtins fixtures/tuple.pyi] + +[case testNewReturnType8_explicit] +from typing import TypeVar, Any + +# test type var from a different argument +TX = TypeVar('TX', bound='X') +class X: + @staticmethod + def __new__(cls, x: TX) -> TX: # E: "__new__" must return a class instance (got "TX") + pass + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType9_explicit] +class A: + @staticmethod + def __new__(cls) -> A: + pass + +class B(A): + pass + +reveal_type(B()) # N: Revealed type is "__main__.B" + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType10_explicit] +# https://github.com/python/mypy/issues/11398 +from typing import Type + +class MyMetaClass(type): + @staticmethod + def __new__(cls, name, bases, attrs) -> Type['MyClass']: + pass + +class MyClass(metaclass=MyMetaClass): + pass + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType11_explicit] +# https://github.com/python/mypy/issues/11398 +class MyMetaClass(type): + @staticmethod + def __new__(cls, name, bases, attrs) -> type: + pass + +class MyClass(metaclass=MyMetaClass): + pass + +[builtins fixtures/staticmethod.pyi] + +[case testNewReturnType12_explicit] +# https://github.com/python/mypy/issues/11398 +from typing import Type + +class MyMetaClass(type): + @staticmethod + def __new__(cls, name, bases, attrs) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "type") + pass + +class MyClass(metaclass=MyMetaClass): + pass + +[builtins fixtures/staticmethod.pyi] + +[case testInitSubclassWrongType_explicit] +class Base: + default_name: str + + @classmethod + def __init_subclass__(cls, default_name: str): + super().__init_subclass__() + cls.default_name = default_name + return + +class Child(Base, default_name=5): # E: Argument "default_name" to "__init_subclass__" of "Base" has incompatible type "int"; expected "str" + pass + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassTooFewArgs_explicit] +class Base: + default_name: str + + @classmethod + def __init_subclass__(cls, default_name: str, **kwargs): + super().__init_subclass__() + cls.default_name = default_name + return + +class Child(Base): # E: Missing positional argument "default_name" in call to "__init_subclass__" of "Base" + pass + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassTooFewArgs2_explicit] +class Base: + default_name: str + + @classmethod + def __init_subclass__(cls, default_name: str, thing: int): + super().__init_subclass__() + cls.default_name = default_name + return +# TODO implement this, so that no error is raised? +e = {"default_name": "abc", "thing": 0} +class Child(Base, **e): # E: Missing positional arguments "default_name", "thing" in call to "__init_subclass__" of "Base" + pass + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassOK_explicit] +class Base: + default_name: str + thing: int + + @classmethod + def __init_subclass__(cls, default_name: str, thing:int, **kwargs): + super().__init_subclass__() + cls.default_name = default_name + return + +class Child(Base, thing=5, default_name=""): + pass + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassWithMetaclassOK_explicit] +class Base: + thing: int + + @classmethod + def __init_subclass__(cls, thing: int): + cls.thing = thing + +class Child(Base, metaclass=type, thing=0): + pass + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassWithImports_explicit] +from init_subclass.a import Base +class Child(Base, thing=5): # E: Missing positional argument "default_name" in call to "__init_subclass__" of "Base" + pass + +[file init_subclass/a.py] +class Base: + default_name: str + thing: int + + @classmethod + def __init_subclass__(cls, default_name: str, thing:int, **kwargs): + pass + +[file init_subclass/__init__.py] +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassWithImportsOK_explicit] +from init_subclass.a import MidBase +class Main(MidBase, test=True): pass +[file init_subclass/a.py] +class Base: + @classmethod + def __init_subclass__(cls, **kwargs) -> None: pass +class MidBase(Base): pass + +[file init_subclass/__init__.py] +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassUnannotated_explicit] +class A: + @classmethod + def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) + +class B(A): + pass + +reveal_type(A.__init_subclass__) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> Any" + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testInitSubclassUnannotatedMulti_explicit] +from typing import ClassVar, List, Type + +class A: + registered_classes: ClassVar[List[Type[A]]] = [] + @classmethod + def __init_subclass__(cls, *args, register=True, **kwargs): + if register: + cls.registered_classes.append(cls) + super().__init_subclass__(*args, **kwargs) + +class B(A): ... +class C(A, register=False): ... +class D(C): ... + +[builtins fixtures/object_with_init_subclass.pyi] + +[case testClassMethodUnannotated_explicit] +class C: + @staticmethod + def __new__(cls): ... + @classmethod + def meth(cls): ... + +reveal_type(C.meth) # N: Revealed type is "def () -> Any" +reveal_type(C.__new__) # N: Revealed type is "def (cls: Type[__main__.C]) -> Any" + +[builtins fixtures/classmethod.pyi] + +[case testNewAndInitNoReturn_explicit] +from typing import NoReturn + +class A: + @staticmethod + def __new__(cls) -> NoReturn: ... + +class B: + @staticmethod + def __new__(cls) -> "B": ... + def __init__(self) -> NoReturn: ... + +class C: + @staticmethod + def __new__(cls) -> NoReturn: ... + def __init__(self) -> NoReturn: ... + +reveal_type(A()) # N: Revealed type is "" +reveal_type(B()) # N: Revealed type is "" +reveal_type(C()) # N: Revealed type is "" + +[builtins fixtures/staticmethod.pyi] + +[case testOverloadedNewAndInitNoReturn_explicit] +from typing import NoReturn, overload + +class A: + @overload + @staticmethod + def __new__(cls) -> NoReturn: ... + @overload + @staticmethod + def __new__(cls, a: int) -> "A": ... + @staticmethod + def __new__(cls, a: int = ...) -> "A": ... + +class B: + @staticmethod + def __new__(cls, a: int = ...) -> "B": ... + @overload + def __init__(self) -> NoReturn: ... + @overload + def __init__(self, a: int) -> None: ... + def __init__(self, a: int = ...) -> None: ... + +class C: + @overload + @staticmethod + def __new__(cls) -> NoReturn: ... + @overload + @staticmethod + def __new__(cls, a: int) -> "C": ... + @staticmethod + def __new__(cls, a: int = ...) -> "C": ... + @overload + def __init__(self) -> NoReturn: ... + @overload + def __init__(self, a: int) -> None: ... + def __init__(self, a: int = ...) -> None: ... + +reveal_type(A()) # N: Revealed type is "" +reveal_type(A(1)) # N: Revealed type is "__main__.A" +reveal_type(B()) # N: Revealed type is "" +reveal_type(B(1)) # N: Revealed type is "__main__.B" +reveal_type(C()) # N: Revealed type is "" +reveal_type(C(1)) # N: Revealed type is "__main__.C" + +[builtins fixtures/staticmethod.pyi] + +-- Variants of tests in check-class-namedtuple.test +-- ------------------------------------------------ + +[case testNewNamedTupleIllegalNames_explicit] +from typing import NamedTuple + +class MagicalFields(NamedTuple): + x: int + def __slots__(self) -> None: pass + @staticmethod + def __new__(cls) -> MagicalFields: pass + def _source(self) -> int: pass + __annotations__ = {'x': float} + +[out] +main:5: error: Cannot overwrite NamedTuple attribute "__slots__" +main:6: error: Cannot overwrite NamedTuple attribute "__new__" +main:8: error: Cannot overwrite NamedTuple attribute "_source" +main:9: error: NamedTuple field name cannot start with an underscore: __annotations__ +main:9: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" +main:9: error: Cannot overwrite NamedTuple attribute "__annotations__" + +[builtins fixtures/tuple.pyi] + +-- Variants of tests in check-dataclass-transform.test +-- --------------------------------------------------- + +[case testDataclassTransformParametersMustBeBoolLiterals_explicit] +# flags: --python-version 3.11 +from typing import dataclass_transform, Callable, Type + +@dataclass_transform() +def my_dataclass(*, eq: bool = True, order: bool = False) -> Callable[[Type], Type]: + def transform(cls: Type) -> Type: + return cls + return transform +@dataclass_transform() +class BaseClass: + @classmethod + def __init_subclass__(cls, *, eq: bool): ... +@dataclass_transform() +class Metaclass(type): ... + +BOOL_CONSTANT = True +@my_dataclass(eq=BOOL_CONSTANT) # E: "eq" argument must be a True or False literal +class A: ... +@my_dataclass(order=not False) # E: "order" argument must be a True or False literal +class B: ... +class C(BaseClass, eq=BOOL_CONSTANT): ... # E: "eq" argument must be a True or False literal +class D(metaclass=Metaclass, order=not False): ... # E: "order" argument must be a True or False literal + +[typing fixtures/typing-full.pyi] +[builtins fixtures/dataclasses.pyi] + +[case testDataclassTransformViaBaseClass_explicit] +# flags: --python-version 3.11 +from typing import dataclass_transform + +@dataclass_transform(frozen_default=True) +class Dataclass: + @classmethod + def __init_subclass__(cls, *, kw_only: bool = False): ... + +class Person(Dataclass, kw_only=True): + name: str + age: int + +reveal_type(Person) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> __main__.Person" +Person('Jonh', 21) # E: Too many positional arguments for "Person" +person = Person(name='John', age=32) +person.name = "John Smith" # E: Property "name" defined in "Person" is read-only + +class Contact(Person): + email: str + +reveal_type(Contact) # N: Revealed type is "def (email: builtins.str, *, name: builtins.str, age: builtins.int) -> __main__.Contact" +Contact('john@john.com', name='John', age=32) + +[typing fixtures/typing-full.pyi] +[builtins fixtures/dataclasses.pyi] + +-- Variants of tests in check-enum.test +-- ------------------------------------ + +[case testNewSetsUnexpectedValueType_explicit] +from enum import Enum + +class bytes: + @staticmethod + def __new__(cls): pass + +class Foo(bytes, Enum): + def __new__(cls, value: int) -> 'Foo': + obj = bytes.__new__(cls) + obj._value_ = "Number %d" % value + return obj + A = 1 + B = 2 + +a = Foo.A +reveal_type(a.value) # N: Revealed type is "Any" +reveal_type(a._value_) # N: Revealed type is "Any" + +class Bar(bytes, Enum): + @staticmethod + def __new__(cls, value: int) -> 'Bar': + obj = bytes.__new__(cls) + obj._value_ = "Number %d" % value + return obj + A = 1 + B = 2 + +b = Bar.B +reveal_type(b.value) # N: Revealed type is "Any" +reveal_type(b._value_) # N: Revealed type is "Any" + +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testValueTypeWithNewInParentClass_explicit] +from enum import Enum + +class bytes: + @staticmethod + def __new__(cls): pass + +class Foo1(bytes, Enum): + def __new__(cls, value: int) -> 'Foo1': + obj = bytes.__new__(cls) + obj._value_ = "Number %d" % value + return obj + +class Bar1(Foo1): + A = 1 + B = 2 + +a = Bar1.A +reveal_type(a.value) # N: Revealed type is "Any" +reveal_type(a._value_) # N: Revealed type is "Any" + +class Foo2(bytes, Enum): + @staticmethod + def __new__(cls, value: int) -> 'Foo2': + obj = bytes.__new__(cls) + obj._value_ = "Number %d" % value + return obj + +class Bar2(Foo2): + A = 1 + B = 2 + +b = Bar2.B +reveal_type(b.value) # N: Revealed type is "Any" +reveal_type(b._value_) # N: Revealed type is "Any" + +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-medium.pyi] + +[case testEnumBaseClassesOrder_explicit] +import enum + +# Base types: + +class First: + @staticmethod + def __new__(cls, val): + pass + +class Second: + @staticmethod + def __new__(cls, val): + pass + +class Third: + @staticmethod + def __new__(cls, val): + pass + +class Mixin: + pass + +class EnumWithCustomNew1(enum.Enum): + def __new__(cls, val): + pass + +class EnumWithCustomNew2(enum.Enum): + @staticmethod + def __new__(cls, val): + pass + +class SecondEnumWithCustomNew1(enum.Enum): + def __new__(cls, val): + pass + +class SecondEnumWithCustomNew2(enum.Enum): + @staticmethod + def __new__(cls, val): + pass + +# Correct Enums: + +class Correct0(enum.Enum): + pass + +class Correct1(Mixin, First, enum.Enum): + pass + +class Correct2(First, enum.Enum): + pass + +class Correct3(Mixin, enum.Enum): + pass + +class RegularClass(Mixin, First, Second): + pass + +class Correct5(enum.Enum): + pass + +# Correct inheritance: + +class _InheritingDataAndMixin(Correct1): + pass + +class _CorrectWithData(First, Correct0): + pass + +class _CorrectWithDataAndMixin(Mixin, First, Correct0): + pass + +class _CorrectWithMixin(Mixin, Correct2): + pass + +class _CorrectMultipleEnumBases(Correct0, Correct5): + pass + +class _MultipleEnumBasesAndMixin(int, Correct0, enum.Flag): + pass + +class _MultipleEnumBasesWithCustomNew1(int, EnumWithCustomNew1, SecondEnumWithCustomNew1): + pass + +class _MultipleEnumBasesWithCustomNew2(int, EnumWithCustomNew1, SecondEnumWithCustomNew2): + pass + +class _MultipleEnumBasesWithCustomNew3(int, EnumWithCustomNew2, SecondEnumWithCustomNew1): + pass + +class _MultipleEnumBasesWithCustomNew4(int, EnumWithCustomNew2, SecondEnumWithCustomNew2): + pass + +# Wrong Enums: + +class TwoDataTypesViaInheritance(Second, Correct2): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" + pass + +class TwoDataTypesViaInheritanceAndMixin(Second, Correct2, Mixin): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" + pass + +class MixinAfterEnum1(enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" + pass + +class MixinAfterEnum2(First, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" + pass + +class TwoDataTypes(First, Second, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class TwoDataTypesAndIntEnumMixin(First, Second, enum.IntEnum, Mixin): # E: No non-enum mixin classes are allowed after "enum.IntEnum" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class ThreeDataTypes(First, Second, Third, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" + pass + +class ThreeDataTypesAndMixin(First, Second, Third, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" + pass + +class FromEnumAndOther1(Correct2, Second, enum.Enum): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass + +class FromEnumAndOther2(Correct2, Second): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ + # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" + pass +[builtins fixtures/tuple.pyi] + +[case testEnumWithNewHierarchy_explicit] +import enum + +class A1: + def __new__(cls, val): ... +class A2: + @staticmethod + def __new__(cls, val): ... +class B1(A1): + @staticmethod + def __new__(cls, val): ... +class B2(A2): + def __new__(cls, val): ... +class B3(A2): + @staticmethod + def __new__(cls, val): ... + +class C1: + def __new__(cls, val): ... +class C2: + @staticmethod + def __new__(cls, val): ... + +class E1(A2, enum.Enum): ... +class E2(B1, enum.Enum): ... +class E3(B2, enum.Enum): ... +class E4(B3, enum.Enum): ... + +# Errors: + +class W1(C1, E1): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E1" +class W2(C1, E2): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E2" +class W3(C1, E3): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E3" +class W4(C1, E4): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E4" +class W7(C2, E1): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E1" +class W8(C2, E2): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E2" +class W9(C2, E3): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E3" +class W10(C2, E4): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E4" +[builtins fixtures/tuple.pyi] + +-- Variants of tests in check-expressions.test +-- ------------------------------------------- + +[case testAssertTypeGeneric_explicit] +from typing import assert_type, TypeVar, Generic +from typing_extensions import Literal +T = TypeVar("T") +def f(x: T) -> T: return x +assert_type(f(1), int) +class Gen(Generic[T]): + @staticmethod + def __new__(cls, obj: T) -> Gen[T]: ... +assert_type(Gen(1), Gen[int]) +# With type context, it infers Gen[Literal[1]] instead. +y: Gen[Literal[1]] = assert_type(Gen(1), Gen[Literal[1]]) + +[builtins fixtures/tuple.pyi] + +-- Variants of tests in check-final.test +-- ------------------------------------- + +[case testFinalOverridingMethodInitNew_explicit] +from typing import final + +class B1: + @final + def __init__(self) -> None: ... + @final + def __new__(cls) -> B1: ... +class B2: + @final + def __init__(self) -> None: ... + @final + @staticmethod + def __new__(cls) -> B2: ... +class C1(B2): + def __init__(self) -> None: ... + def __new__(cls) -> C1: ... +class C2(B1): + def __init__(self) -> None: ... + @staticmethod + def __new__(cls) -> C2: ... +class C3(B2): + def __init__(self) -> None: ... + @staticmethod + def __new__(cls) -> C3: ... + +[out] +main:15: error: Cannot override final attribute "__init__" (previously declared in base class "B2") +main:16: error: Cannot override final attribute "__new__" (previously declared in base class "B2") +main:18: error: Cannot override final attribute "__init__" (previously declared in base class "B1") +main:19: error: Cannot override final attribute "__new__" (previously declared in base class "B1") +main:22: error: Cannot override final attribute "__init__" (previously declared in base class "B2") +main:23: error: Cannot override final attribute "__new__" (previously declared in base class "B2") + +[builtins fixtures/staticmethod.pyi] + +-- Variants of tests in check-generics.test +-- ---------------------------------------- + +# TODO: enable this when #7935 is fixed. +[case testGenericClassInGenericFunctionOverloadedConstructor_explicit-skip] +from typing import TypeVar, Generic, overload + +T = TypeVar('T') + +class C(Generic[T]): + @overload + @staticmethod + def __new__(cls) -> C[None]: ... + @overload + @staticmethod + def __new__(cls, item: T) -> C[T]: ... + @staticmethod + def __new__(cls, item=None): + ... + @classmethod + def f(cls, x: T) -> T: + return x + +def foo(x: T, y: int) -> T: + C.f(y) + C(y) # OK + C[T](y) # E: Argument 1 to "C" has incompatible type "int"; expected "T" + C[T].f(y) # E: Argument 1 to "f" of "C" has incompatible type "int"; expected "T" + C[T].f(x) # OK + return x +[builtins fixtures/classmethod.pyi] + +-- Variants of tests in check-multiple-inheritance.test +-- ---------------------------------------------------- + +[case testMultipleInheritance_NestedClassesWithSameNameOverloadedNew_explicit] +from mixins import Mixin1, Mixin2 +class A(Mixin1, Mixin2): + pass +[file mixins.py] +class Mixin1: + class Meta: + pass +class Mixin2: + class Meta: + pass +[file mixins.pyi] +from typing import overload, Any, Mapping, Dict +class Mixin1: + class Meta: + @overload + @staticmethod + def __new__(cls, *args, **kwargs: None) -> Mixin1.Meta: + pass + @overload + @staticmethod + def __new__(cls, *args, **kwargs: Dict[str, Any]) -> Mixin1.Meta: + pass +class Mixin2: + class Meta: + pass +[builtins fixtures/dict.pyi] +[out] +main:2: error: Definition of "Meta" in base class "Mixin1" is incompatible with definition in base class "Mixin2" + +[case testMultipleInheritance_ReferenceToSubclassesFromSameMROOverloadedNew_explicit] +from mixins import A, B +class Base1: + NestedVar = A +class Base2: + NestedVar = B +class Combo(Base2, Base1): ... +[file mixins.py] +class A: + pass +class B(A): + pass +[file mixins.pyi] +from typing import overload, Dict, Any +class A: + @overload + @staticmethod + def __new__(cls, *args, **kwargs: None) -> A: + pass + @overload + @staticmethod + def __new__(cls, *args, **kwargs: Dict[str, Any]) -> A: + pass +class B: + pass +[builtins fixtures/dict.pyi] +[out] +main:6: error: Definition of "NestedVar" in base class "Base2" is incompatible with definition in base class "Base1" + +-- Variants of tests in check-namedtuple.test +-- ------------------------------------------ + +[case testNamedTupleNew_explicit] +from typing import NamedTuple + +Base = NamedTuple('Base', [('param', int)]) + +class Child(Base): + @staticmethod + def __new__(cls, param: int = 1) -> 'Child': + return Base.__new__(cls, param) + +Base(param=10) +Child(param=10) +[builtins fixtures/tuple.pyi] + +-- Variants of tests in check-selftype.test + +[case testSelfTypeNew_explicit] +from typing import TypeVar, Type + +T = TypeVar('T', bound='A') +class A: + @staticmethod + def __new__(cls: Type[T]) -> T: + return cls() + + @classmethod + def __init_subclass__(cls: Type[T]) -> None: + pass + +class B: + @staticmethod + def __new__(cls: Type[T]) -> T: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" + return cls() + + @classmethod + def __init_subclass__(cls: Type[T]) -> None: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" + pass + +class C: + @staticmethod + def __new__(cls: Type[C]) -> C: + return cls() + + @classmethod + def __init_subclass__(cls: Type[C]) -> None: + pass + +class D: + @staticmethod + def __new__(cls: D) -> D: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" + return cls + + @classmethod + def __init_subclass__(cls: D) -> None: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" + pass + +class E: + @staticmethod + def __new__(cls) -> E: + reveal_type(cls) # N: Revealed type is "Type[__main__.E]" + return cls() + + @classmethod + def __init_subclass__(cls) -> None: + reveal_type(cls) # N: Revealed type is "Type[__main__.E]" + +[builtins fixtures/classmethod.pyi] + +[case testSelfTypeInGenericClassUsedFromAnotherGenericClass1_explicit] +from typing import TypeVar, Generic, Iterator, List, Tuple + +_T_co = TypeVar("_T_co", covariant=True) +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +S = TypeVar("S") + +class Z(Iterator[_T_co]): + @staticmethod + def __new__(cls, + __iter1: List[_T1], + __iter2: List[_T2]) -> Z[Tuple[_T1, _T2]]: ... + def __iter__(self: S) -> S: ... + def __next__(self) -> _T_co: ... + +T = TypeVar('T') + +class C(Generic[T]): + a: List[T] + b: List[str] + + def f(self) -> None: + for x, y in Z(self.a, self.b): + reveal_type((x, y)) # N: Revealed type is "Tuple[T`1, builtins.str]" + +[builtins fixtures/tuple.pyi] + +-- Variants of tests in check-serialize.test +-- ----------------------------------------- + +[case testSerialize__new___explicit] +import a +[file a.py] +import b +[file a.py.2] +from b import A +A('') +[file b.py] +class A: + @staticmethod + def __new__(cls, x: int) -> 'A': pass + +[out2] +tmp/a.py:2: error: Argument 1 to "A" has incompatible type "str"; expected "int" + +[builtins fixtures/staticmethod.pyi] + +-- Variants of tests in check-super.test +-- ------------------------------------- + +[case testSuperWithNew_explicit] +class A1: + def __new__(cls, x: int) -> 'A1': + return object.__new__(cls) + +class A2: + @staticmethod + def __new__(cls, x: int) -> 'A2': + return object.__new__(cls) + +class B1(A1): + @staticmethod + def __new__(cls, x: int, y: str = '') -> 'B1': + super().__new__(cls, 1) + super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A1" + return None + +class B2(A2): + def __new__(cls, x: int, y: str = '') -> 'B2': + super().__new__(cls, 1) + super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A2" + return None + +class B3(A2): + @staticmethod + def __new__(cls, x: int, y: str = '') -> 'B3': + super().__new__(cls, 1) + super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A2" + return None + +B1('') # E: Argument 1 to "B1" has incompatible type "str"; expected "int" +B2('') # E: Argument 1 to "B2" has incompatible type "str"; expected "int" +B3('') # E: Argument 1 to "B3" has incompatible type "str"; expected "int" +B1(1) +B2(1) +B3(1) +B1(1, 'x') +B2(1, 'x') +B3(1, 'x') +[builtins fixtures/__new__.pyi] + +reveal_type(C.a) # N: Revealed type is "Any" +[out] + +[case testSuperWithTypeTypeAsSecondArgument_explicit] +class B: + def f(self) -> None: pass + +class C(B): + @staticmethod + def __new__(cls) -> 'C': + super(C, cls).f + return C() + +[builtins fixtures/staticmethod.pyi] + +[case testSuperInInitSubclass_explicit] +class A: + @classmethod + def __init_subclass__(cls) -> None: + super().__init_subclass__() +[builtins fixtures/__init_subclass__.pyi] + +[case testSuperClassGetItem_explicit] +from typing import TypeVar, Type, Any + +T1 = TypeVar("T1", bound="B1") +T2 = TypeVar("T2", bound="B2") +T3 = TypeVar("T3", bound="B3") + +class A1: + def __class_getitem__(cls, item) -> None: pass + +class A2: + @classmethod + def __class_getitem__(cls, item) -> None: pass + +class B1(A1): + @classmethod + def __class_getitem__(cls: Type[T1], item: Any) -> None: + super(B1, cls).__class_getitem__(item) + +class B2(A2): + def __class_getitem__(cls: Type[T2], item: Any) -> None: + super(B2, cls).__class_getitem__(item) + +class B3(A2): + @classmethod + def __class_getitem__(cls: Type[T3], item: Any) -> None: + super(B3, cls).__class_getitem__(item) + +[builtins fixtures/classmethod.pyi] diff --git a/test-data/unit/fixtures/__init_subclass__.pyi b/test-data/unit/fixtures/__init_subclass__.pyi index b4618c28249e..1976e401ac80 100644 --- a/test-data/unit/fixtures/__init_subclass__.pyi +++ b/test-data/unit/fixtures/__init_subclass__.pyi @@ -12,3 +12,4 @@ class bool: pass class str: pass class function: pass class dict: pass +class classmethod: pass diff --git a/test-data/unit/fixtures/__new__.pyi b/test-data/unit/fixtures/__new__.pyi index 401de6fb9cd1..b9aee479a97c 100644 --- a/test-data/unit/fixtures/__new__.pyi +++ b/test-data/unit/fixtures/__new__.pyi @@ -17,3 +17,4 @@ class bool: pass class str: pass class function: pass class dict: pass +class staticmethod: pass diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index 19d175ff79ab..b83d1fc95e4e 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -60,6 +60,8 @@ class bool(int): pass class ellipsis: __class__: object +class classmethod: pass +class staticmethod: pass def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass class BaseException: pass diff --git a/test-data/unit/fixtures/object_with_init_subclass.pyi b/test-data/unit/fixtures/object_with_init_subclass.pyi index da062349a204..204107492076 100644 --- a/test-data/unit/fixtures/object_with_init_subclass.pyi +++ b/test-data/unit/fixtures/object_with_init_subclass.pyi @@ -33,6 +33,7 @@ class bytearray: pass class tuple(Generic[T]): pass class function: pass class ellipsis: pass +class classmethod: pass # copy-pasted from list.pyi class list(Sequence[T]): diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index b74252857d6f..f5c02942b9fc 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -58,6 +58,8 @@ class frozenset(Iterable[T]): def __iter__(self) -> Iterator[T]: pass class function: pass class ellipsis: pass +class classmethod: pass +class staticmethod: pass class range(Sequence[int]): def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass diff --git a/test-data/unit/fixtures/tuple.pyi b/test-data/unit/fixtures/tuple.pyi index e270f3d79d3e..0dd7bf9c5fea 100644 --- a/test-data/unit/fixtures/tuple.pyi +++ b/test-data/unit/fixtures/tuple.pyi @@ -28,6 +28,7 @@ class function: __name__: str class ellipsis: pass class classmethod: pass +class staticmethod: pass # We need int and slice for indexing tuples. class int: From 3064f3b996117c8e6810e7f9764682534671c3ea Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Fri, 9 Jun 2023 13:42:17 +0200 Subject: [PATCH 2/6] Fix primer error, minor polish. --- mypy/checkmember.py | 6 +----- mypy/nodes.py | 2 +- mypy/semanal.py | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index c2c6b3555805..371f9c68fd26 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -319,11 +319,7 @@ def analyze_instance_member_access( mx.msg.cant_assign_to_method(mx.context) signature = function_type(method, mx.named_type("builtins.function")) signature = freshen_all_functions_type_vars(signature) - if name == "__new__" or method.is_static: - # __new__ is special and behaves like a static method -- don't strip - # the first argument. - pass - else: + if not method.is_static: if name != "__call__": # TODO: use proper treatment of special methods on unions instead # of this hack here and below (i.e. mx.self_type). diff --git a/mypy/nodes.py b/mypy/nodes.py index 8457e39b6aa1..e5b132b36626 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -510,7 +510,7 @@ class FuncBase(Node): "info", "is_property", "is_class", # Uses "@classmethod" (explicit or implicit) - "is_static", # Uses "@staticmethod" + "is_static", # Uses "@staticmethod" (explicit or implicit) "is_final", # Uses "@final" "is_explicit_override", # Uses "@override" "_fullname", diff --git a/mypy/semanal.py b/mypy/semanal.py index a1afcf855f3b..897fffef69dd 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1383,7 +1383,7 @@ def analyze_function_body(self, defn: FuncItem) -> None: # The first argument of a non-static, non-class method is like 'self' # (though the name could be different), having the enclosing class's # instance type. - if is_method and not defn.is_static and defn.arguments: + if is_method and (not defn.is_static or defn.name == "__new__") and defn.arguments: if not defn.is_class: defn.arguments[0].variable.is_self = True else: From 65efb01394a231a3b1fa10aa87a6988fd9b1c8cb Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Tue, 4 Jul 2023 11:48:44 +0200 Subject: [PATCH 3/6] Reduce unit tests to just the ones failing before this patch --- test-data/unit/check-selftype.test | 52 + ...eck-special-class--and-static-methods.test | 1391 ----------------- 2 files changed, 52 insertions(+), 1391 deletions(-) delete mode 100644 test-data/unit/check-special-class--and-static-methods.test diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 96d5b2306427..69a7da17220c 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -509,6 +509,58 @@ class E: def __init_subclass__(cls) -> None: reveal_type(cls) # N: Revealed type is "Type[__main__.E]" +[case testSelfTypeNew_explicit] +from typing import TypeVar, Type + +T = TypeVar('T', bound='A') +class A: + @staticmethod + def __new__(cls: Type[T]) -> T: + return cls() + + @classmethod + def __init_subclass__(cls: Type[T]) -> None: + pass + +class B: + @staticmethod + def __new__(cls: Type[T]) -> T: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" + return cls() + + @classmethod + def __init_subclass__(cls: Type[T]) -> None: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" + pass + +class C: + @staticmethod + def __new__(cls: Type[C]) -> C: + return cls() + + @classmethod + def __init_subclass__(cls: Type[C]) -> None: + pass + +class D: + @staticmethod + def __new__(cls: D) -> D: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" + return cls + + @classmethod + def __init_subclass__(cls: D) -> None: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" + pass + +class E: + @staticmethod + def __new__(cls) -> E: + reveal_type(cls) # N: Revealed type is "Type[__main__.E]" + return cls() + + @classmethod + def __init_subclass__(cls) -> None: + reveal_type(cls) # N: Revealed type is "Type[__main__.E]" + +[builtins fixtures/classmethod.pyi] + [case testSelfTypePropertyUnion] from typing import Union class A: diff --git a/test-data/unit/check-special-class--and-static-methods.test b/test-data/unit/check-special-class--and-static-methods.test deleted file mode 100644 index cded49cc59ce..000000000000 --- a/test-data/unit/check-special-class--and-static-methods.test +++ /dev/null @@ -1,1391 +0,0 @@ --- Explicitly decorated __new__, __init_subclass__ and __class_getitem_ --- Ref. https://github.com/python/mypy/issues/15080 --- -------------------------------------------------------------------- - --- Variants of tests in check-classes.test --- --------------------------------------- - -[case testOverride__new__WithDifferentSignature_explicit] - -class A: - @staticmethod - def __new__(cls, x: int) -> A: - pass - -class B(A): - def __new__(cls) -> B: - pass - -class C(A): - @staticmethod - def __new__(cls) -> C: - pass - -[builtins fixtures/staticmethod.pyi] - -[case testOverride__new__AndCallObject_explicit] -from typing import TypeVar, Generic - -class A: - @staticmethod - def __new__(cls, x: int) -> 'A': - return object.__new__(cls) - -T = TypeVar('T') -class B(Generic[T]): - @staticmethod - def __new__(cls, foo: T) -> 'B[T]': - x = object.__new__(cls) - # object.__new__ doesn't have a great type :( - reveal_type(x) # N: Revealed type is "Any" - return x - -[builtins fixtures/__new__.pyi] - -[case testOverride__init_subclass__WithDifferentSignature_explicit] -class A: - @classmethod - def __init_subclass__(cls, x: int) -> None: pass - -class B(A): # E: Missing positional argument "x" in call to "__init_subclass__" of "A" - @classmethod - def __init_subclass__(cls) -> None: pass - -[builtins fixtures/classmethod.pyi] - -[case testInitSubclassWithReturnValueType_explicit] -import typing -class A: - @classmethod - def __init_subclass__(cls) -> 'A': pass # E: The return type of "__init_subclass__" must be None - -[builtins fixtures/classmethod.pyi] - -[case testInitSubclassWithImplicitReturnValueType_explicit] -import typing - -class A: - @classmethod - def __init_subclass__(cls, x: int=1): pass - -[builtins fixtures/classmethod.pyi] - -[case testDecoratedInitSubclassWithImplicitReturnValueType_explicit] -import typing -from typing import Callable - -def deco(fn: Callable) -> Callable: - return fn - -class A: - @deco - @classmethod - def __init_subclass__(cls, x: int=1): pass - -[builtins fixtures/classmethod.pyi] - -[case testOverloadedInitSubclassWithImplicitReturnValueType_explicit] -from typing import overload -from foo import * -[file foo.pyi] -from typing import overload -class Foo: - @overload - @classmethod - def __init_subclass__(cls, a: int): - pass - - @overload - @classmethod - def __init_subclass__(cls, a: str): - pass - -[builtins fixtures/classmethod.pyi] - -[case testInitSubclassWithAnyReturnValueType_explicit] -import typing -from typing import Any - -class A: - @classmethod - def __init_subclass__(cls) -> Any: pass # E: The return type of "__init_subclass__" must be None - -[builtins fixtures/classmethod.pyi] - -[case testOverloadedInitSubclassWithAnyReturnValueType_explicit] -from foo import * -[file foo.pyi] -from typing import overload, Any -class Foo: - @overload - @classmethod - def __init_subclass__(cls, a: int) -> Any: # E: The return type of "__init_subclass__" must be None - pass - - @overload - @classmethod - def __init_subclass__(cls, a: str) -> Any: # E: The return type of "__init_subclass__" must be None - pass - -[builtins fixtures/classmethod.pyi] - -[case testConstructInstanceWith__new___explitit] -from typing import Optional -class C: - @staticmethod - def __new__(cls, foo: Optional[int] = None) -> 'C': - obj = object.__new__(cls) - return obj - -x = C(foo=12) -x.a # E: "C" has no attribute "a" -C(foo='') # E: Argument "foo" to "C" has incompatible type "str"; expected "Optional[int]" - -[builtins fixtures/__new__.pyi] - -[case testClassWith__new__AndCompatibilityWithType_explicit] -class C: - @staticmethod - def __new__(cls, foo: int = None) -> 'C': - obj = object.__new__(cls) - return obj - -def f(x: type) -> None: pass -def g(x: int) -> None: pass - -f(C) -g(C) # E: Argument 1 to "g" has incompatible type "Type[C]"; expected "int" - -[builtins fixtures/__new__.pyi] - -[case testClassWith__new__AndCompatibilityWithType2_explicit] -class C: - @staticmethod - def __new__(cls, foo): - obj = object.__new__(cls) - return obj - -def f(x: type) -> None: pass -def g(x: int) -> None: pass - -f(C) -g(C) # E: Argument 1 to "g" has incompatible type "Type[C]"; expected "int" - -[builtins fixtures/__new__.pyi] - -[case testGenericClassWith__new___explicit] -from typing import TypeVar, Generic -T = TypeVar('T') - -class C(Generic[T]): - @staticmethod - def __new__(cls, foo: T) -> 'C[T]': - obj = object.__new__(cls) - return obj - def set(self, x: T) -> None: pass -c = C('') -c.set('') -c.set(1) # E: Argument 1 to "set" of "C" has incompatible type "int"; expected "str" - -[builtins fixtures/__new__.pyi] - -[case testOverloaded__new___explicit] -from foo import * -[file foo.pyi] -from typing import overload - -class C: - @overload - @staticmethod - def __new__(cls, foo: int) -> 'C': - obj = object.__new__(cls) - return obj - @overload - @staticmethod - def __new__(cls, x: str, y: str) -> 'C': - obj = object.__new__(cls) - return obj -c = C(1) -c.a # E: "C" has no attribute "a" -C('', '') -C('') # E: No overload variant of "C" matches argument type "str" \ - # N: Possible overload variants: \ - # N: def __new__(cls, foo: int) -> C \ - # N: def __new__(cls, x: str, y: str) -> C - -[builtins fixtures/__new__.pyi] - -[case testNewAndInit1_explicit] -class A: - def __init__(self, x: int) -> None: - pass - -class C(A): - @staticmethod - def __new__(cls) -> C: - pass - -C() - -[builtins fixtures/staticmethod.pyi] - -[case testNewAndInit2_explicit] -from typing import Any - -class A: - @staticmethod - def __new__(cls, *args: Any) -> 'A': - ... - -class B(A): - def __init__(self, x: int) -> None: - pass - -reveal_type(B) # N: Revealed type is "def (x: builtins.int) -> __main__.B" - -[builtins fixtures/tuple.pyi] - -[case testNewAndInit3_explicit] -from typing import Any - -class A: - @staticmethod - def __new__(cls, *args: Any) -> 'A': - ... - def __init__(self, x: int) -> None: - pass - -reveal_type(A) # N: Revealed type is "def (x: builtins.int) -> __main__.A" - -[builtins fixtures/tuple.pyi] - -[case testDecoratedConstructors_explicit] -from typing import TypeVar, Callable, Any - -F = TypeVar('F', bound=Callable[..., Any]) - -def dec(f: F) -> F: ... - -class A: - @dec - def __init__(self, x: int) -> None: ... - -class B: - @dec - @staticmethod - def __new__(cls, x: int) -> B: ... - -reveal_type(A) # N: Revealed type is "def (x: builtins.int) -> __main__.A" -reveal_type(B) # N: Revealed type is "def (x: builtins.int) -> __main__.B" - -[builtins fixtures/staticmethod.pyi] - -[case testDecoratedConstructorsBad_explicit] -from typing import Callable, Any - -def dec(f: Callable[[Any, int], Any]) -> int: ... - -class A: - @dec # E: Unsupported decorated constructor type - def __init__(self, x: int) -> None: ... - -class B: - @dec # E: Unsupported decorated constructor type - @staticmethod - def __new__(cls, x: int) -> B: ... - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType1_explicit] -class A: - @staticmethod - def __new__(cls) -> B: - pass - -class B(A): pass - -reveal_type(A()) # N: Revealed type is "__main__.B" -reveal_type(B()) # N: Revealed type is "__main__.B" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType2_explicit] -from typing import Any - -# make sure that __new__ method that return Any are ignored when -# determining the return type -class A: - @staticmethod - def __new__(cls): - pass - -class B: - @staticmethod - def __new__(cls) -> Any: - pass - -reveal_type(A()) # N: Revealed type is "__main__.A" -reveal_type(B()) # N: Revealed type is "__main__.B" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType3_explicit] - -# Check for invalid __new__ typing - -class A: - @staticmethod - def __new__(cls) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "A") - pass - -reveal_type(A()) # N: Revealed type is "__main__.A" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType4_explicit] -from typing import TypeVar, Type - -# Check for __new__ using type vars - -TX = TypeVar('TX', bound='X') -class X: - @staticmethod - def __new__(lol: Type[TX], x: int) -> TX: - pass -class Y(X): pass - -reveal_type(X(20)) # N: Revealed type is "__main__.X" -reveal_type(Y(20)) # N: Revealed type is "__main__.Y" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType5_explicit] -from typing import Any, TypeVar, Generic, overload - -T = TypeVar('T') -class O(Generic[T]): - @overload - @staticmethod - def __new__(cls) -> O[int]: - pass - @overload - @staticmethod - def __new__(cls, x: int) -> O[str]: - pass - @staticmethod - def __new__(cls, x: int = 0) -> O[Any]: - pass - -reveal_type(O()) # N: Revealed type is "__main__.O[builtins.int]" -reveal_type(O(10)) # N: Revealed type is "__main__.O[builtins.str]" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType6_explicit] -from typing import Tuple, Optional - -# Check for some cases that aren't allowed - -class X: - @staticmethod - def __new__(cls) -> Optional[Y]: # E: "__new__" must return a class instance (got "Optional[Y]") - pass -class Y: - @staticmethod - def __new__(cls) -> Optional[int]: # E: "__new__" must return a class instance (got "Optional[int]") - pass - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType7_explicit] -from typing import NamedTuple - -# ... test __new__ returning tuple type -class A: - @staticmethod - def __new__(cls) -> 'B': - pass - -N = NamedTuple('N', [('x', int)]) -class B(A, N): pass - -reveal_type(A()) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.B]" - -[builtins fixtures/tuple.pyi] - -[case testNewReturnType8_explicit] -from typing import TypeVar, Any - -# test type var from a different argument -TX = TypeVar('TX', bound='X') -class X: - @staticmethod - def __new__(cls, x: TX) -> TX: # E: "__new__" must return a class instance (got "TX") - pass - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType9_explicit] -class A: - @staticmethod - def __new__(cls) -> A: - pass - -class B(A): - pass - -reveal_type(B()) # N: Revealed type is "__main__.B" - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType10_explicit] -# https://github.com/python/mypy/issues/11398 -from typing import Type - -class MyMetaClass(type): - @staticmethod - def __new__(cls, name, bases, attrs) -> Type['MyClass']: - pass - -class MyClass(metaclass=MyMetaClass): - pass - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType11_explicit] -# https://github.com/python/mypy/issues/11398 -class MyMetaClass(type): - @staticmethod - def __new__(cls, name, bases, attrs) -> type: - pass - -class MyClass(metaclass=MyMetaClass): - pass - -[builtins fixtures/staticmethod.pyi] - -[case testNewReturnType12_explicit] -# https://github.com/python/mypy/issues/11398 -from typing import Type - -class MyMetaClass(type): - @staticmethod - def __new__(cls, name, bases, attrs) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "type") - pass - -class MyClass(metaclass=MyMetaClass): - pass - -[builtins fixtures/staticmethod.pyi] - -[case testInitSubclassWrongType_explicit] -class Base: - default_name: str - - @classmethod - def __init_subclass__(cls, default_name: str): - super().__init_subclass__() - cls.default_name = default_name - return - -class Child(Base, default_name=5): # E: Argument "default_name" to "__init_subclass__" of "Base" has incompatible type "int"; expected "str" - pass - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassTooFewArgs_explicit] -class Base: - default_name: str - - @classmethod - def __init_subclass__(cls, default_name: str, **kwargs): - super().__init_subclass__() - cls.default_name = default_name - return - -class Child(Base): # E: Missing positional argument "default_name" in call to "__init_subclass__" of "Base" - pass - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassTooFewArgs2_explicit] -class Base: - default_name: str - - @classmethod - def __init_subclass__(cls, default_name: str, thing: int): - super().__init_subclass__() - cls.default_name = default_name - return -# TODO implement this, so that no error is raised? -e = {"default_name": "abc", "thing": 0} -class Child(Base, **e): # E: Missing positional arguments "default_name", "thing" in call to "__init_subclass__" of "Base" - pass - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassOK_explicit] -class Base: - default_name: str - thing: int - - @classmethod - def __init_subclass__(cls, default_name: str, thing:int, **kwargs): - super().__init_subclass__() - cls.default_name = default_name - return - -class Child(Base, thing=5, default_name=""): - pass - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassWithMetaclassOK_explicit] -class Base: - thing: int - - @classmethod - def __init_subclass__(cls, thing: int): - cls.thing = thing - -class Child(Base, metaclass=type, thing=0): - pass - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassWithImports_explicit] -from init_subclass.a import Base -class Child(Base, thing=5): # E: Missing positional argument "default_name" in call to "__init_subclass__" of "Base" - pass - -[file init_subclass/a.py] -class Base: - default_name: str - thing: int - - @classmethod - def __init_subclass__(cls, default_name: str, thing:int, **kwargs): - pass - -[file init_subclass/__init__.py] -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassWithImportsOK_explicit] -from init_subclass.a import MidBase -class Main(MidBase, test=True): pass -[file init_subclass/a.py] -class Base: - @classmethod - def __init_subclass__(cls, **kwargs) -> None: pass -class MidBase(Base): pass - -[file init_subclass/__init__.py] -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassUnannotated_explicit] -class A: - @classmethod - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - -class B(A): - pass - -reveal_type(A.__init_subclass__) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> Any" - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testInitSubclassUnannotatedMulti_explicit] -from typing import ClassVar, List, Type - -class A: - registered_classes: ClassVar[List[Type[A]]] = [] - @classmethod - def __init_subclass__(cls, *args, register=True, **kwargs): - if register: - cls.registered_classes.append(cls) - super().__init_subclass__(*args, **kwargs) - -class B(A): ... -class C(A, register=False): ... -class D(C): ... - -[builtins fixtures/object_with_init_subclass.pyi] - -[case testClassMethodUnannotated_explicit] -class C: - @staticmethod - def __new__(cls): ... - @classmethod - def meth(cls): ... - -reveal_type(C.meth) # N: Revealed type is "def () -> Any" -reveal_type(C.__new__) # N: Revealed type is "def (cls: Type[__main__.C]) -> Any" - -[builtins fixtures/classmethod.pyi] - -[case testNewAndInitNoReturn_explicit] -from typing import NoReturn - -class A: - @staticmethod - def __new__(cls) -> NoReturn: ... - -class B: - @staticmethod - def __new__(cls) -> "B": ... - def __init__(self) -> NoReturn: ... - -class C: - @staticmethod - def __new__(cls) -> NoReturn: ... - def __init__(self) -> NoReturn: ... - -reveal_type(A()) # N: Revealed type is "" -reveal_type(B()) # N: Revealed type is "" -reveal_type(C()) # N: Revealed type is "" - -[builtins fixtures/staticmethod.pyi] - -[case testOverloadedNewAndInitNoReturn_explicit] -from typing import NoReturn, overload - -class A: - @overload - @staticmethod - def __new__(cls) -> NoReturn: ... - @overload - @staticmethod - def __new__(cls, a: int) -> "A": ... - @staticmethod - def __new__(cls, a: int = ...) -> "A": ... - -class B: - @staticmethod - def __new__(cls, a: int = ...) -> "B": ... - @overload - def __init__(self) -> NoReturn: ... - @overload - def __init__(self, a: int) -> None: ... - def __init__(self, a: int = ...) -> None: ... - -class C: - @overload - @staticmethod - def __new__(cls) -> NoReturn: ... - @overload - @staticmethod - def __new__(cls, a: int) -> "C": ... - @staticmethod - def __new__(cls, a: int = ...) -> "C": ... - @overload - def __init__(self) -> NoReturn: ... - @overload - def __init__(self, a: int) -> None: ... - def __init__(self, a: int = ...) -> None: ... - -reveal_type(A()) # N: Revealed type is "" -reveal_type(A(1)) # N: Revealed type is "__main__.A" -reveal_type(B()) # N: Revealed type is "" -reveal_type(B(1)) # N: Revealed type is "__main__.B" -reveal_type(C()) # N: Revealed type is "" -reveal_type(C(1)) # N: Revealed type is "__main__.C" - -[builtins fixtures/staticmethod.pyi] - --- Variants of tests in check-class-namedtuple.test --- ------------------------------------------------ - -[case testNewNamedTupleIllegalNames_explicit] -from typing import NamedTuple - -class MagicalFields(NamedTuple): - x: int - def __slots__(self) -> None: pass - @staticmethod - def __new__(cls) -> MagicalFields: pass - def _source(self) -> int: pass - __annotations__ = {'x': float} - -[out] -main:5: error: Cannot overwrite NamedTuple attribute "__slots__" -main:6: error: Cannot overwrite NamedTuple attribute "__new__" -main:8: error: Cannot overwrite NamedTuple attribute "_source" -main:9: error: NamedTuple field name cannot start with an underscore: __annotations__ -main:9: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" -main:9: error: Cannot overwrite NamedTuple attribute "__annotations__" - -[builtins fixtures/tuple.pyi] - --- Variants of tests in check-dataclass-transform.test --- --------------------------------------------------- - -[case testDataclassTransformParametersMustBeBoolLiterals_explicit] -# flags: --python-version 3.11 -from typing import dataclass_transform, Callable, Type - -@dataclass_transform() -def my_dataclass(*, eq: bool = True, order: bool = False) -> Callable[[Type], Type]: - def transform(cls: Type) -> Type: - return cls - return transform -@dataclass_transform() -class BaseClass: - @classmethod - def __init_subclass__(cls, *, eq: bool): ... -@dataclass_transform() -class Metaclass(type): ... - -BOOL_CONSTANT = True -@my_dataclass(eq=BOOL_CONSTANT) # E: "eq" argument must be a True or False literal -class A: ... -@my_dataclass(order=not False) # E: "order" argument must be a True or False literal -class B: ... -class C(BaseClass, eq=BOOL_CONSTANT): ... # E: "eq" argument must be a True or False literal -class D(metaclass=Metaclass, order=not False): ... # E: "order" argument must be a True or False literal - -[typing fixtures/typing-full.pyi] -[builtins fixtures/dataclasses.pyi] - -[case testDataclassTransformViaBaseClass_explicit] -# flags: --python-version 3.11 -from typing import dataclass_transform - -@dataclass_transform(frozen_default=True) -class Dataclass: - @classmethod - def __init_subclass__(cls, *, kw_only: bool = False): ... - -class Person(Dataclass, kw_only=True): - name: str - age: int - -reveal_type(Person) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> __main__.Person" -Person('Jonh', 21) # E: Too many positional arguments for "Person" -person = Person(name='John', age=32) -person.name = "John Smith" # E: Property "name" defined in "Person" is read-only - -class Contact(Person): - email: str - -reveal_type(Contact) # N: Revealed type is "def (email: builtins.str, *, name: builtins.str, age: builtins.int) -> __main__.Contact" -Contact('john@john.com', name='John', age=32) - -[typing fixtures/typing-full.pyi] -[builtins fixtures/dataclasses.pyi] - --- Variants of tests in check-enum.test --- ------------------------------------ - -[case testNewSetsUnexpectedValueType_explicit] -from enum import Enum - -class bytes: - @staticmethod - def __new__(cls): pass - -class Foo(bytes, Enum): - def __new__(cls, value: int) -> 'Foo': - obj = bytes.__new__(cls) - obj._value_ = "Number %d" % value - return obj - A = 1 - B = 2 - -a = Foo.A -reveal_type(a.value) # N: Revealed type is "Any" -reveal_type(a._value_) # N: Revealed type is "Any" - -class Bar(bytes, Enum): - @staticmethod - def __new__(cls, value: int) -> 'Bar': - obj = bytes.__new__(cls) - obj._value_ = "Number %d" % value - return obj - A = 1 - B = 2 - -b = Bar.B -reveal_type(b.value) # N: Revealed type is "Any" -reveal_type(b._value_) # N: Revealed type is "Any" - -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testValueTypeWithNewInParentClass_explicit] -from enum import Enum - -class bytes: - @staticmethod - def __new__(cls): pass - -class Foo1(bytes, Enum): - def __new__(cls, value: int) -> 'Foo1': - obj = bytes.__new__(cls) - obj._value_ = "Number %d" % value - return obj - -class Bar1(Foo1): - A = 1 - B = 2 - -a = Bar1.A -reveal_type(a.value) # N: Revealed type is "Any" -reveal_type(a._value_) # N: Revealed type is "Any" - -class Foo2(bytes, Enum): - @staticmethod - def __new__(cls, value: int) -> 'Foo2': - obj = bytes.__new__(cls) - obj._value_ = "Number %d" % value - return obj - -class Bar2(Foo2): - A = 1 - B = 2 - -b = Bar2.B -reveal_type(b.value) # N: Revealed type is "Any" -reveal_type(b._value_) # N: Revealed type is "Any" - -[builtins fixtures/primitives.pyi] -[typing fixtures/typing-medium.pyi] - -[case testEnumBaseClassesOrder_explicit] -import enum - -# Base types: - -class First: - @staticmethod - def __new__(cls, val): - pass - -class Second: - @staticmethod - def __new__(cls, val): - pass - -class Third: - @staticmethod - def __new__(cls, val): - pass - -class Mixin: - pass - -class EnumWithCustomNew1(enum.Enum): - def __new__(cls, val): - pass - -class EnumWithCustomNew2(enum.Enum): - @staticmethod - def __new__(cls, val): - pass - -class SecondEnumWithCustomNew1(enum.Enum): - def __new__(cls, val): - pass - -class SecondEnumWithCustomNew2(enum.Enum): - @staticmethod - def __new__(cls, val): - pass - -# Correct Enums: - -class Correct0(enum.Enum): - pass - -class Correct1(Mixin, First, enum.Enum): - pass - -class Correct2(First, enum.Enum): - pass - -class Correct3(Mixin, enum.Enum): - pass - -class RegularClass(Mixin, First, Second): - pass - -class Correct5(enum.Enum): - pass - -# Correct inheritance: - -class _InheritingDataAndMixin(Correct1): - pass - -class _CorrectWithData(First, Correct0): - pass - -class _CorrectWithDataAndMixin(Mixin, First, Correct0): - pass - -class _CorrectWithMixin(Mixin, Correct2): - pass - -class _CorrectMultipleEnumBases(Correct0, Correct5): - pass - -class _MultipleEnumBasesAndMixin(int, Correct0, enum.Flag): - pass - -class _MultipleEnumBasesWithCustomNew1(int, EnumWithCustomNew1, SecondEnumWithCustomNew1): - pass - -class _MultipleEnumBasesWithCustomNew2(int, EnumWithCustomNew1, SecondEnumWithCustomNew2): - pass - -class _MultipleEnumBasesWithCustomNew3(int, EnumWithCustomNew2, SecondEnumWithCustomNew1): - pass - -class _MultipleEnumBasesWithCustomNew4(int, EnumWithCustomNew2, SecondEnumWithCustomNew2): - pass - -# Wrong Enums: - -class TwoDataTypesViaInheritance(Second, Correct2): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" - pass - -class TwoDataTypesViaInheritanceAndMixin(Second, Correct2, Mixin): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Correct2" - pass - -class MixinAfterEnum1(enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" - pass - -class MixinAfterEnum2(First, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" - pass - -class TwoDataTypes(First, Second, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" - pass - -class TwoDataTypesAndIntEnumMixin(First, Second, enum.IntEnum, Mixin): # E: No non-enum mixin classes are allowed after "enum.IntEnum" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" - pass - -class ThreeDataTypes(First, Second, Third, enum.Enum): # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" - pass - -class ThreeDataTypesAndMixin(First, Second, Third, enum.Enum, Mixin): # E: No non-enum mixin classes are allowed after "enum.Enum" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Third" - pass - -class FromEnumAndOther1(Correct2, Second, enum.Enum): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" - pass - -class FromEnumAndOther2(Correct2, Second): # E: No non-enum mixin classes are allowed after "__main__.Correct2" \ - # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.Second" - pass -[builtins fixtures/tuple.pyi] - -[case testEnumWithNewHierarchy_explicit] -import enum - -class A1: - def __new__(cls, val): ... -class A2: - @staticmethod - def __new__(cls, val): ... -class B1(A1): - @staticmethod - def __new__(cls, val): ... -class B2(A2): - def __new__(cls, val): ... -class B3(A2): - @staticmethod - def __new__(cls, val): ... - -class C1: - def __new__(cls, val): ... -class C2: - @staticmethod - def __new__(cls, val): ... - -class E1(A2, enum.Enum): ... -class E2(B1, enum.Enum): ... -class E3(B2, enum.Enum): ... -class E4(B3, enum.Enum): ... - -# Errors: - -class W1(C1, E1): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E1" -class W2(C1, E2): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E2" -class W3(C1, E3): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E3" -class W4(C1, E4): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E4" -class W7(C2, E1): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E1" -class W8(C2, E2): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E2" -class W9(C2, E3): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E3" -class W10(C2, E4): ... # E: Only a single data type mixin is allowed for Enum subtypes, found extra "__main__.E4" -[builtins fixtures/tuple.pyi] - --- Variants of tests in check-expressions.test --- ------------------------------------------- - -[case testAssertTypeGeneric_explicit] -from typing import assert_type, TypeVar, Generic -from typing_extensions import Literal -T = TypeVar("T") -def f(x: T) -> T: return x -assert_type(f(1), int) -class Gen(Generic[T]): - @staticmethod - def __new__(cls, obj: T) -> Gen[T]: ... -assert_type(Gen(1), Gen[int]) -# With type context, it infers Gen[Literal[1]] instead. -y: Gen[Literal[1]] = assert_type(Gen(1), Gen[Literal[1]]) - -[builtins fixtures/tuple.pyi] - --- Variants of tests in check-final.test --- ------------------------------------- - -[case testFinalOverridingMethodInitNew_explicit] -from typing import final - -class B1: - @final - def __init__(self) -> None: ... - @final - def __new__(cls) -> B1: ... -class B2: - @final - def __init__(self) -> None: ... - @final - @staticmethod - def __new__(cls) -> B2: ... -class C1(B2): - def __init__(self) -> None: ... - def __new__(cls) -> C1: ... -class C2(B1): - def __init__(self) -> None: ... - @staticmethod - def __new__(cls) -> C2: ... -class C3(B2): - def __init__(self) -> None: ... - @staticmethod - def __new__(cls) -> C3: ... - -[out] -main:15: error: Cannot override final attribute "__init__" (previously declared in base class "B2") -main:16: error: Cannot override final attribute "__new__" (previously declared in base class "B2") -main:18: error: Cannot override final attribute "__init__" (previously declared in base class "B1") -main:19: error: Cannot override final attribute "__new__" (previously declared in base class "B1") -main:22: error: Cannot override final attribute "__init__" (previously declared in base class "B2") -main:23: error: Cannot override final attribute "__new__" (previously declared in base class "B2") - -[builtins fixtures/staticmethod.pyi] - --- Variants of tests in check-generics.test --- ---------------------------------------- - -# TODO: enable this when #7935 is fixed. -[case testGenericClassInGenericFunctionOverloadedConstructor_explicit-skip] -from typing import TypeVar, Generic, overload - -T = TypeVar('T') - -class C(Generic[T]): - @overload - @staticmethod - def __new__(cls) -> C[None]: ... - @overload - @staticmethod - def __new__(cls, item: T) -> C[T]: ... - @staticmethod - def __new__(cls, item=None): - ... - @classmethod - def f(cls, x: T) -> T: - return x - -def foo(x: T, y: int) -> T: - C.f(y) - C(y) # OK - C[T](y) # E: Argument 1 to "C" has incompatible type "int"; expected "T" - C[T].f(y) # E: Argument 1 to "f" of "C" has incompatible type "int"; expected "T" - C[T].f(x) # OK - return x -[builtins fixtures/classmethod.pyi] - --- Variants of tests in check-multiple-inheritance.test --- ---------------------------------------------------- - -[case testMultipleInheritance_NestedClassesWithSameNameOverloadedNew_explicit] -from mixins import Mixin1, Mixin2 -class A(Mixin1, Mixin2): - pass -[file mixins.py] -class Mixin1: - class Meta: - pass -class Mixin2: - class Meta: - pass -[file mixins.pyi] -from typing import overload, Any, Mapping, Dict -class Mixin1: - class Meta: - @overload - @staticmethod - def __new__(cls, *args, **kwargs: None) -> Mixin1.Meta: - pass - @overload - @staticmethod - def __new__(cls, *args, **kwargs: Dict[str, Any]) -> Mixin1.Meta: - pass -class Mixin2: - class Meta: - pass -[builtins fixtures/dict.pyi] -[out] -main:2: error: Definition of "Meta" in base class "Mixin1" is incompatible with definition in base class "Mixin2" - -[case testMultipleInheritance_ReferenceToSubclassesFromSameMROOverloadedNew_explicit] -from mixins import A, B -class Base1: - NestedVar = A -class Base2: - NestedVar = B -class Combo(Base2, Base1): ... -[file mixins.py] -class A: - pass -class B(A): - pass -[file mixins.pyi] -from typing import overload, Dict, Any -class A: - @overload - @staticmethod - def __new__(cls, *args, **kwargs: None) -> A: - pass - @overload - @staticmethod - def __new__(cls, *args, **kwargs: Dict[str, Any]) -> A: - pass -class B: - pass -[builtins fixtures/dict.pyi] -[out] -main:6: error: Definition of "NestedVar" in base class "Base2" is incompatible with definition in base class "Base1" - --- Variants of tests in check-namedtuple.test --- ------------------------------------------ - -[case testNamedTupleNew_explicit] -from typing import NamedTuple - -Base = NamedTuple('Base', [('param', int)]) - -class Child(Base): - @staticmethod - def __new__(cls, param: int = 1) -> 'Child': - return Base.__new__(cls, param) - -Base(param=10) -Child(param=10) -[builtins fixtures/tuple.pyi] - --- Variants of tests in check-selftype.test - -[case testSelfTypeNew_explicit] -from typing import TypeVar, Type - -T = TypeVar('T', bound='A') -class A: - @staticmethod - def __new__(cls: Type[T]) -> T: - return cls() - - @classmethod - def __init_subclass__(cls: Type[T]) -> None: - pass - -class B: - @staticmethod - def __new__(cls: Type[T]) -> T: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" - return cls() - - @classmethod - def __init_subclass__(cls: Type[T]) -> None: # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "Type[__main__.B]" - pass - -class C: - @staticmethod - def __new__(cls: Type[C]) -> C: - return cls() - - @classmethod - def __init_subclass__(cls: Type[C]) -> None: - pass - -class D: - @staticmethod - def __new__(cls: D) -> D: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" - return cls - - @classmethod - def __init_subclass__(cls: D) -> None: # E: The erased type of self "__main__.D" is not a supertype of its class "Type[__main__.D]" - pass - -class E: - @staticmethod - def __new__(cls) -> E: - reveal_type(cls) # N: Revealed type is "Type[__main__.E]" - return cls() - - @classmethod - def __init_subclass__(cls) -> None: - reveal_type(cls) # N: Revealed type is "Type[__main__.E]" - -[builtins fixtures/classmethod.pyi] - -[case testSelfTypeInGenericClassUsedFromAnotherGenericClass1_explicit] -from typing import TypeVar, Generic, Iterator, List, Tuple - -_T_co = TypeVar("_T_co", covariant=True) -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -S = TypeVar("S") - -class Z(Iterator[_T_co]): - @staticmethod - def __new__(cls, - __iter1: List[_T1], - __iter2: List[_T2]) -> Z[Tuple[_T1, _T2]]: ... - def __iter__(self: S) -> S: ... - def __next__(self) -> _T_co: ... - -T = TypeVar('T') - -class C(Generic[T]): - a: List[T] - b: List[str] - - def f(self) -> None: - for x, y in Z(self.a, self.b): - reveal_type((x, y)) # N: Revealed type is "Tuple[T`1, builtins.str]" - -[builtins fixtures/tuple.pyi] - --- Variants of tests in check-serialize.test --- ----------------------------------------- - -[case testSerialize__new___explicit] -import a -[file a.py] -import b -[file a.py.2] -from b import A -A('') -[file b.py] -class A: - @staticmethod - def __new__(cls, x: int) -> 'A': pass - -[out2] -tmp/a.py:2: error: Argument 1 to "A" has incompatible type "str"; expected "int" - -[builtins fixtures/staticmethod.pyi] - --- Variants of tests in check-super.test --- ------------------------------------- - -[case testSuperWithNew_explicit] -class A1: - def __new__(cls, x: int) -> 'A1': - return object.__new__(cls) - -class A2: - @staticmethod - def __new__(cls, x: int) -> 'A2': - return object.__new__(cls) - -class B1(A1): - @staticmethod - def __new__(cls, x: int, y: str = '') -> 'B1': - super().__new__(cls, 1) - super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A1" - return None - -class B2(A2): - def __new__(cls, x: int, y: str = '') -> 'B2': - super().__new__(cls, 1) - super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A2" - return None - -class B3(A2): - @staticmethod - def __new__(cls, x: int, y: str = '') -> 'B3': - super().__new__(cls, 1) - super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A2" - return None - -B1('') # E: Argument 1 to "B1" has incompatible type "str"; expected "int" -B2('') # E: Argument 1 to "B2" has incompatible type "str"; expected "int" -B3('') # E: Argument 1 to "B3" has incompatible type "str"; expected "int" -B1(1) -B2(1) -B3(1) -B1(1, 'x') -B2(1, 'x') -B3(1, 'x') -[builtins fixtures/__new__.pyi] - -reveal_type(C.a) # N: Revealed type is "Any" -[out] - -[case testSuperWithTypeTypeAsSecondArgument_explicit] -class B: - def f(self) -> None: pass - -class C(B): - @staticmethod - def __new__(cls) -> 'C': - super(C, cls).f - return C() - -[builtins fixtures/staticmethod.pyi] - -[case testSuperInInitSubclass_explicit] -class A: - @classmethod - def __init_subclass__(cls) -> None: - super().__init_subclass__() -[builtins fixtures/__init_subclass__.pyi] - -[case testSuperClassGetItem_explicit] -from typing import TypeVar, Type, Any - -T1 = TypeVar("T1", bound="B1") -T2 = TypeVar("T2", bound="B2") -T3 = TypeVar("T3", bound="B3") - -class A1: - def __class_getitem__(cls, item) -> None: pass - -class A2: - @classmethod - def __class_getitem__(cls, item) -> None: pass - -class B1(A1): - @classmethod - def __class_getitem__(cls: Type[T1], item: Any) -> None: - super(B1, cls).__class_getitem__(item) - -class B2(A2): - def __class_getitem__(cls: Type[T2], item: Any) -> None: - super(B2, cls).__class_getitem__(item) - -class B3(A2): - @classmethod - def __class_getitem__(cls: Type[T3], item: Any) -> None: - super(B3, cls).__class_getitem__(item) - -[builtins fixtures/classmethod.pyi] From bb2461cba9142acf9fcd5361463e15c6b5bbcb8a Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Wed, 5 Jul 2023 07:59:59 +0200 Subject: [PATCH 4/6] Remove unnecessary (and probably unsafe) mutation of fdef --- mypy/typeops.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mypy/typeops.py b/mypy/typeops.py index 51b9fbd8b771..519d3de995f5 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -710,8 +710,6 @@ def callable_type( fdef: FuncItem, fallback: Instance, ret_type: Type | None = None ) -> CallableType: # TODO: somewhat unfortunate duplication with prepare_method_signature in semanal - if fdef.name == "__new__": - fdef.is_static = True if fdef.info and (not fdef.is_static or fdef.name == "__new__") and fdef.arg_names: self_type: Type = fill_typevars(fdef.info) if fdef.is_class or fdef.name == "__new__": From bc328d7e97319ae5f446a64b99b7b85d810e7bf7 Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Wed, 5 Jul 2023 08:23:08 +0200 Subject: [PATCH 5/6] Empty commit From 5cb1b777d7a3545c5f9a78a93c73996af1488983 Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Wed, 5 Jul 2023 08:38:56 +0200 Subject: [PATCH 6/6] Remove classmethod and staticmethod from fixtures (complete #bb2461) --- test-data/unit/fixtures/__init_subclass__.pyi | 1 - test-data/unit/fixtures/__new__.pyi | 1 - test-data/unit/fixtures/dict.pyi | 2 -- test-data/unit/fixtures/object_with_init_subclass.pyi | 1 - test-data/unit/fixtures/primitives.pyi | 2 -- test-data/unit/fixtures/tuple.pyi | 1 - 6 files changed, 8 deletions(-) diff --git a/test-data/unit/fixtures/__init_subclass__.pyi b/test-data/unit/fixtures/__init_subclass__.pyi index 1976e401ac80..b4618c28249e 100644 --- a/test-data/unit/fixtures/__init_subclass__.pyi +++ b/test-data/unit/fixtures/__init_subclass__.pyi @@ -12,4 +12,3 @@ class bool: pass class str: pass class function: pass class dict: pass -class classmethod: pass diff --git a/test-data/unit/fixtures/__new__.pyi b/test-data/unit/fixtures/__new__.pyi index b9aee479a97c..401de6fb9cd1 100644 --- a/test-data/unit/fixtures/__new__.pyi +++ b/test-data/unit/fixtures/__new__.pyi @@ -17,4 +17,3 @@ class bool: pass class str: pass class function: pass class dict: pass -class staticmethod: pass diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index b83d1fc95e4e..19d175ff79ab 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -60,8 +60,6 @@ class bool(int): pass class ellipsis: __class__: object -class classmethod: pass -class staticmethod: pass def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass class BaseException: pass diff --git a/test-data/unit/fixtures/object_with_init_subclass.pyi b/test-data/unit/fixtures/object_with_init_subclass.pyi index 204107492076..da062349a204 100644 --- a/test-data/unit/fixtures/object_with_init_subclass.pyi +++ b/test-data/unit/fixtures/object_with_init_subclass.pyi @@ -33,7 +33,6 @@ class bytearray: pass class tuple(Generic[T]): pass class function: pass class ellipsis: pass -class classmethod: pass # copy-pasted from list.pyi class list(Sequence[T]): diff --git a/test-data/unit/fixtures/primitives.pyi b/test-data/unit/fixtures/primitives.pyi index f5c02942b9fc..b74252857d6f 100644 --- a/test-data/unit/fixtures/primitives.pyi +++ b/test-data/unit/fixtures/primitives.pyi @@ -58,8 +58,6 @@ class frozenset(Iterable[T]): def __iter__(self) -> Iterator[T]: pass class function: pass class ellipsis: pass -class classmethod: pass -class staticmethod: pass class range(Sequence[int]): def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass diff --git a/test-data/unit/fixtures/tuple.pyi b/test-data/unit/fixtures/tuple.pyi index 0dd7bf9c5fea..e270f3d79d3e 100644 --- a/test-data/unit/fixtures/tuple.pyi +++ b/test-data/unit/fixtures/tuple.pyi @@ -28,7 +28,6 @@ class function: __name__: str class ellipsis: pass class classmethod: pass -class staticmethod: pass # We need int and slice for indexing tuples. class int: