Skip to content

Commit 734e4ad

Browse files
authored
stubtest: fix signature construction for overload + implicit classmethod (#9921)
__class_getitem__ and __init_subclass__ are always classmethods, even if they aren't decorated. We previously only handled this correctly if these methods weren't overloaded. This came up in python/typeshed#4937 Co-authored-by: hauntsaninja <>
1 parent 92923b2 commit 734e4ad

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

mypy/stubtest.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ def _verify_arg_default_value(
377377
)
378378

379379

380+
def maybe_strip_cls(name: str, args: List[nodes.Argument]) -> List[nodes.Argument]:
381+
if name in ("__init_subclass__", "__class_getitem__"):
382+
# These are implicitly classmethods. If the stub chooses not to have @classmethod, we
383+
# should remove the cls argument
384+
if args[0].variable.name == "cls":
385+
return args[1:]
386+
return args
387+
388+
380389
class Signature(Generic[T]):
381390
def __init__(self) -> None:
382391
self.pos = [] # type: List[T]
@@ -428,7 +437,8 @@ def get_desc(arg: Any) -> str:
428437
@staticmethod
429438
def from_funcitem(stub: nodes.FuncItem) -> "Signature[nodes.Argument]":
430439
stub_sig = Signature() # type: Signature[nodes.Argument]
431-
for stub_arg in stub.arguments:
440+
stub_args = maybe_strip_cls(stub.name, stub.arguments)
441+
for stub_arg in stub_args:
432442
if stub_arg.kind in (nodes.ARG_POS, nodes.ARG_OPT):
433443
stub_sig.pos.append(stub_arg)
434444
elif stub_arg.kind in (nodes.ARG_NAMED, nodes.ARG_NAMED_OPT):
@@ -476,7 +486,8 @@ def from_overloadedfuncdef(stub: nodes.OverloadedFuncDef) -> "Signature[nodes.Ar
476486
all_args = {} # type: Dict[str, List[Tuple[nodes.Argument, int]]]
477487
for func in map(_resolve_funcitem_from_decorator, stub.items):
478488
assert func is not None
479-
for index, arg in enumerate(func.arguments):
489+
args = maybe_strip_cls(stub.name, func.arguments)
490+
for index, arg in enumerate(args):
480491
# For positional-only args, we allow overloads to have different names for the same
481492
# argument. To accomplish this, we just make up a fake index-based name.
482493
name = (
@@ -658,13 +669,6 @@ def verify_funcitem(
658669
# catch RuntimeError because of https://bugs.python.org/issue39504
659670
return
660671

661-
if stub.name in ("__init_subclass__", "__class_getitem__"):
662-
# These are implicitly classmethods. If the stub chooses not to have @classmethod, we
663-
# should remove the cls argument
664-
if stub.arguments[0].variable.name == "cls":
665-
stub = copy.copy(stub)
666-
stub.arguments = stub.arguments[1:]
667-
668672
stub_sig = Signature.from_funcitem(stub)
669673
runtime_sig = Signature.from_inspect_signature(signature)
670674

0 commit comments

Comments
 (0)