Skip to content

Allow star args in ctypes.Array constructor #6213

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

Merged
merged 4 commits into from
Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
25 changes: 17 additions & 8 deletions mypy/plugins/ctypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Fully qualified instead of "from mypy.plugin import ..." to avoid circular import problems.
import mypy.plugin
from mypy import nodes
from mypy.maptype import map_instance_to_supertype
from mypy.subtypes import is_subtype
from mypy.types import (
Expand Down Expand Up @@ -116,19 +117,27 @@ def array_constructor_callback(ctx: 'mypy.plugin.FunctionContext') -> Type:
allowed = _autoconvertible_to_cdata(et, ctx.api)
assert len(ctx.arg_types) == 1, \
"The stub of the ctypes.Array constructor should have a single vararg parameter"
for arg_num, arg_type in enumerate(ctx.arg_types[0], 1):
# TODO This causes false errors if the argument list contains *args.
# In a function hook, the type of an *args parameter is the type of the iterable being
# unpacked. However, FunctionContext currently doesn't provide a way to differentiate
# between normal arguments and *args, so the iterable type is considered invalid.
# Once FunctionContext has an API for this, *args should be allowed here if the
# iterable's element type is compatible with the array element type.
if not is_subtype(arg_type, allowed):
for arg_num, (arg_kind, arg_type) in enumerate(zip(ctx.arg_kinds[0], ctx.arg_types[0]), 1):
if arg_kind not in {nodes.ARG_POS, nodes.ARG_STAR}:
ctx.api.msg.fail(
"Array constructor does not allow keyword arguments",
Copy link
Member

Choose a reason for hiding this comment

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

Please add a test that triggers this error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like this actually isn't ever called -- it looks like the constructor in typeshed def __init__(self, *args: Any) -> None) definition takes care of this case.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, wait, so if it is never going to be called, maybe we can remove this code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

ctx.context
)
elif arg_kind == nodes.ARG_POS and not is_subtype(arg_type, allowed):
ctx.api.msg.fail(
'Array constructor argument {} of type "{}"'
' is not convertible to the array element type "{}"'
.format(arg_num, arg_type, et),
ctx.context)
elif arg_kind == nodes.ARG_STAR:
ty = ctx.api.named_generic_type("typing.Iterable", [allowed])
if not is_subtype(arg_type, ty):
ctx.api.msg.fail(
'Array constructor argument {} of type "{}"'
' is not convertible to the array element type "Iterable[{}]"'
Copy link
Member

Choose a reason for hiding this comment

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

Please also add a test for this error message.

.format(arg_num, arg_type, et),
ctx.context)

return ctx.default_return_type


Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-ctypes.test
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ oa.value # E: ctypes.Array attribute "value" is only available with element typ
oa.raw # E: ctypes.Array attribute "raw" is only available with element type c_char, not "ctypes.c_int"
[builtins fixtures/floatdict.pyi]

[case testCtypesArrayConstructorStarargs-skip]
[case testCtypesArrayConstructorStarargs]
import ctypes

intarr4 = ctypes.c_int * 4
Expand Down