mirror of
https://github.com/microsoft/pyright.git
synced 2024-11-03 21:30:08 +03:00
Added additional special-case handling for __init_subclass__
and __class_getitem__
to treat them as implicit class methods even if they are not declared using a def
statement. This addresses #5500.
This commit is contained in:
parent
6236155cb1
commit
844256cfb6
@ -5405,6 +5405,15 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
) {
|
||||
setSymbolAccessed(AnalyzerNodeInfo.getFileInfo(errorNode), memberInfo.symbol, errorNode);
|
||||
}
|
||||
|
||||
// Special-case `__init_subclass` and `__class_getitem__` because
|
||||
// these are always treated as class methods even if they're not
|
||||
// decorated as such.
|
||||
if (memberName === '__init_subclass__' || memberName === '__class_getitem__') {
|
||||
if (isFunction(type) && !FunctionType.isClassMethod(type)) {
|
||||
type = FunctionType.cloneWithNewFlags(type, type.details.flags | FunctionTypeFlags.ClassMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const descriptorResult = applyDescriptorAccessMethod(
|
||||
|
@ -1411,7 +1411,7 @@ export function* getClassIterator(classType: Type, flags = ClassIteratorFlags.De
|
||||
let foundSkipMroClass = skipMroClass === undefined;
|
||||
|
||||
for (const mroClass of classType.details.mro) {
|
||||
// Are we still searching fro teh skipMroClass?
|
||||
// Are we still searching for the skipMroClass?
|
||||
if (!foundSkipMroClass && skipMroClass) {
|
||||
if (!isClass(mroClass)) {
|
||||
foundSkipMroClass = true;
|
||||
|
@ -6,7 +6,7 @@ from datetime import datetime
|
||||
from typing import Any, Optional, Type
|
||||
|
||||
|
||||
class Foo:
|
||||
class ClassA:
|
||||
def __init_subclass__(
|
||||
cls, *, param1: str, param2: float, param3: Optional[Any] = None
|
||||
) -> None:
|
||||
@ -15,32 +15,44 @@ class Foo:
|
||||
|
||||
# This should generate an error because param1 is
|
||||
# the wrong type.
|
||||
class Bar1(Foo, param1=0, param2=4):
|
||||
class ClassB(ClassA, param1=0, param2=4):
|
||||
pass
|
||||
|
||||
|
||||
# This should generate an error because param2 is missing.
|
||||
class Bar2(Foo, param1="0", param3=datetime.now()):
|
||||
class ClassC(ClassA, param1="0", param3=datetime.now()):
|
||||
pass
|
||||
|
||||
|
||||
class Bar3(Foo, param1="0", param2=5.0):
|
||||
class ClassD(ClassA, param1="0", param2=5.0):
|
||||
pass
|
||||
|
||||
|
||||
class Bar4:
|
||||
class ClassE:
|
||||
def __init_subclass__(cls, *, arg: int) -> None:
|
||||
func(cls, arg)
|
||||
func1(cls, arg)
|
||||
|
||||
def __new__(cls) -> "Bar4":
|
||||
func(cls, 9)
|
||||
def __new__(cls) -> "ClassE":
|
||||
func1(cls, 9)
|
||||
return super().__new__(cls)
|
||||
|
||||
|
||||
def func(klass: Type[Bar4], arg: int):
|
||||
def func1(klass: Type[ClassE], arg: int):
|
||||
pass
|
||||
|
||||
|
||||
class Bar5(Foo, param1="hi", param2=3.4):
|
||||
class ClassF(ClassA, param1="hi", param2=3.4):
|
||||
def __init_subclass__(cls, param_alt1: int):
|
||||
super().__init_subclass__(param1="yo", param2=param_alt1)
|
||||
|
||||
|
||||
def func2(cls):
|
||||
pass
|
||||
|
||||
|
||||
class ClassG:
|
||||
__init_subclass__ = func2
|
||||
|
||||
|
||||
class ClassH(ClassG):
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user