Skip to content

Missing args callable #18990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7ecb077
types = my_types
Apr 16, 2025
b61c9ba
line deleted in suggestions.py
Apr 18, 2025
3ff8f89
removing conflict with types.py
Apr 18, 2025
6b08c08
changed my_types back to types in suggestions
Apr 18, 2025
3930148
build types as standard_types
Apr 18, 2025
4b1d260
all python self tests passed 1647
Apr 18, 2025
615f869
removing std_types 1802
Apr 19, 2025
06f6b73
general code_cleanup 1806
Apr 19, 2025
84e9bba
removing unused type: ignores 1812
Apr 19, 2025
aad7793
no std types self completely passes
Apr 19, 2025
ee5f4b9
fixing build.py 1935
Apr 24, 2025
2b38551
adding test case to suggestions.py
Apr 25, 2025
e8700fa
fix call expr arg checks and formatting
Apr 27, 2025
57d4dd2
edits from diff/prototype included
Apr 27, 2025
cc4fcf3
added unpack test cases
lesliehuh Apr 28, 2025
e93c401
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 28, 2025
17ebfea
Update checkexpr.py
lesliehuh Apr 28, 2025
c4d3d0a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 28, 2025
496db6a
Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks"
lesliehuh Apr 28, 2025
e802b54
Revert "Update checkexpr.py"
lesliehuh Apr 28, 2025
1ae0e62
deleted unrelate file changes
lesliehuh Apr 28, 2025
6761e28
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 28, 2025
f9641dc
deleting erroneous import
lesliehuh Apr 28, 2025
7244902
cleaned code of spacing errors
lesliehuh Apr 28, 2025
97b3730
Delete .github/dependabot.yml
lesliehuh Apr 28, 2025
a39cec1
Delete .devcontainer/devcontainer.json
lesliehuh Apr 28, 2025
23a001e
Update stubgen.test
lesliehuh Apr 28, 2025
4badf10
trying to fix internal error from test suite
lesliehuh Apr 28, 2025
96d250c
Merge branch 'python:master' into missing-args-callable
lesliehuh Apr 28, 2025
91703e5
fixing typeshed internal error
lesliehuh Apr 30, 2025
b261fae
Merge branch 'master' into missing-args-callable
lesliehuh Apr 30, 2025
0c7b3ab
tweaked tests per recommendation
lesliehuh May 2, 2025
d9a86c0
Merge branch 'master' into missing-args-callable
lesliehuh May 2, 2025
a8cb4fc
move typeshed import statement to top
lesliehuh May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 49 additions & 13 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,33 @@ def check_call_expr_with_callee_type(
object_type: Type | None,
member: str | None = None,
) -> Type:

proper_callee = get_proper_type(callee_type)

is_constructor_call = False
if isinstance(e.callee, RefExpr):
node = e.callee.node
if node is not None and hasattr(node, "name"):
is_constructor_call = node.name == "__init__"
elif callable_name is None:
# direct class call without member name
is_constructor_call = True

object_type = get_proper_type(object_type)
if (
isinstance(proper_callee, CallableType)
and isinstance(object_type, Instance)
and is_constructor_call
):
target_name = object_type.type.name
arg_names_set = set(e.arg_names or [])

for name, kind in zip(proper_callee.arg_names, proper_callee.arg_kinds):
if name is not None and kind in (ARG_NAMED, ARG_POS):
if name not in arg_names_set:
if target_name == "misc":
continue # Skip error for miscellaneous/unknown classes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many questions here... First, why is this code block preceding a docstring?

Second, there's no special-cased "misc" typing construct, this simply shouldn't exist. But fortunately this whole block starting from is_constructor_call = ... line is... doing nothing? Is this some kind of merge artifact? I don't see any use of these newly declared variables.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you requested my review, this comment still applies - I don't see any reason for this whole block of code to exist...


"""Type check call expression.

The callee_type should be used as the type of callee expression. In particular,
Expand All @@ -1466,7 +1493,6 @@ def check_call_expr_with_callee_type(
if callable_name is None and member is not None:
assert object_type is not None
callable_name = self.method_fullname(object_type, member)
object_type = get_proper_type(object_type)
if callable_name:
# Try to refine the call signature using plugin hooks before checking the call.
callee_type = self.transform_callee_type(
Expand Down Expand Up @@ -1592,7 +1618,7 @@ def check_call(
callee, args, arg_kinds, arg_names, callable_name, object_type, context
)
elif isinstance(callee, AnyType) or not self.chk.in_checked_function():
return self.check_any_type_call(args, callee)
return self.check_any_type_call(args, callee, arg_kinds, context)
elif isinstance(callee, UnionType):
return self.check_union_call(callee, args, arg_kinds, arg_names, context)
elif isinstance(callee, Instance):
Expand Down Expand Up @@ -2498,15 +2524,7 @@ def check_argument_types(
# Keep track of consumed tuple *arg items.
mapper = ArgTypeExpander(self.argument_infer_context())

for arg_type, arg_kind in zip(arg_types, arg_kinds):
arg_type = get_proper_type(arg_type)
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
self.msg.invalid_var_arg(arg_type, context)
if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type):
is_mapping = is_subtype(
arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
)
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)
self.check_args_unpacking(arg_types, arg_kinds, context)

for i, actuals in enumerate(formal_to_actual):
orig_callee_arg_type = get_proper_type(callee.arg_types[i])
Expand Down Expand Up @@ -3309,8 +3327,13 @@ def apply_generic_arguments(
skip_unsatisfied=skip_unsatisfied,
)

def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Type, Type]:
self.infer_arg_types_in_empty_context(args)
def check_any_type_call(
self, args: list[Expression], callee: Type, arg_kinds: list[ArgKind], context: Context
) -> tuple[Type, Type]:
arg_types = self.infer_arg_types_in_empty_context(args)

self.check_args_unpacking(arg_types, arg_kinds, context)

callee = get_proper_type(callee)
if isinstance(callee, AnyType):
return (
Expand All @@ -3320,6 +3343,19 @@ def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Typ
else:
return AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)

def check_args_unpacking(
self, arg_types: list[Type], arg_kinds: list[ArgKind], context: Context
) -> None:
for arg_type, arg_kind in zip(arg_types, arg_kinds):
arg_type = get_proper_type(arg_type)
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
self.msg.invalid_var_arg(arg_type, context)
if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type):
is_mapping = is_subtype(
arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
)
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)

def check_union_call(
self,
callee: UnionType,
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -7429,7 +7429,7 @@ class A(thing=5):
pass
[out]
main:1: error: Unexpected keyword argument "thing" for "__init_subclass__" of "object"
tmp/builtins.pyi:5: note: "__init_subclass__" of "object" defined here
tmp/builtins.pyi:7: note: "__init_subclass__" of "object" defined here
[builtins fixtures/object_with_init_subclass.pyi]

[case testInitSubclassWithImports]
Expand Down
26 changes: 26 additions & 0 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -3599,3 +3599,29 @@ class Bar(Foo):

def foo(self, value: Union[int, str]) -> Union[int, str]:
return super().foo(value) # E: Call to abstract method "foo" of "Foo" with trivial body via super() is unsafe

[case testInvalidUnpack]
from foo import bar # type: ignore[import-not-found]
from typing import Any, Optional


def g(x: Any):
pass

def baz(x: int):
return bar(*x, **x) # E: Expected iterable as variadic argument # E: Argument after ** must be a mapping, not "int"

def f1(x: int):
return g(**x) # E: Argument after ** must be a mapping, not "int"

def f2(x: list[int]):
return g(*x)

def f3(x: Any):
return g(*x)

def f4(x: Optional[int]):
return g(*x) # E: Expected iterable as variadic argument

def f(x: int):
return g(*x) # E: Expected iterable as variadic argument
2 changes: 2 additions & 0 deletions test-data/unit/fixtures/object_with_init_subclass.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import Sequence, Iterator, TypeVar, Mapping, Iterable, Optional, Union, overload, Tuple, Generic, List
import _typeshed


class object:
def __init__(self) -> None: ...
Expand Down