Skip to content

Commit

Permalink
don't generate stubs from invalid signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
mattangus committed Aug 9, 2024
1 parent 9d56820 commit eb2e4ab
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
25 changes: 24 additions & 1 deletion mypy/stubdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ def __init__(self, function_name: str) -> None:

def add_token(self, token: tokenize.TokenInfo) -> None:
"""Process next token from the token stream."""

if (
self.state[-1] == STATE_ARGUMENT_TYPE
and token.type != tokenize.NAME
and len(self.accumulator) == 0
):
# the next token after : must be a name
self.reset()
return

if (
token.type == tokenize.NAME
and token.string == self.function_name
Expand Down Expand Up @@ -282,8 +292,13 @@ def add_token(self, token: tokenize.TokenInfo) -> None:
self.accumulator = ""

elif token.type == tokenize.OP and token.string == "->" and self.state[-1] == STATE_INIT:
if len(self.accumulator) == 0:
self.state.append(STATE_RETURN_VALUE)
else:
# ) is not directly followed by ->
self.reset()
return
self.accumulator = ""
self.state.append(STATE_RETURN_VALUE)

# ENDMAKER is necessary for python 3.4 and 3.5.
elif token.type in (tokenize.NEWLINE, tokenize.ENDMARKER) and self.state[-1] in (
Expand All @@ -306,6 +321,14 @@ def add_token(self, token: tokenize.TokenInfo) -> None:
self.args = []
self.ret_type = "Any"
# Leave state as INIT.
elif (
token.type == tokenize.NAME
and self.state[-1] == STATE_ARGUMENT_LIST
and len(self.accumulator) != 0
):
# not the first name in a row
self.reset()
return
else:
self.accumulator += token.string

Expand Down
79 changes: 79 additions & 0 deletions mypy/test/teststubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,85 @@ def test_infer_sig_from_docstring_bad_indentation(self) -> None:
None,
)

def test_infer_sig_from_docstring_invalid_signature(self) -> None:

assert_equal(infer_sig_from_docstring("\nfunc() --> None", "func"), [])

assert_equal(
infer_sig_from_docstring("\nfunc(name1 name2) -> None", "func"), []
)

assert_equal(
infer_sig_from_docstring("\nfunc(name1, name2 name3) -> None", "func"), []
)

assert_equal(
infer_sig_from_docstring("\nfunc(name2, name3) -> None, None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(invalid::name) -> None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(invalid: [type]) -> None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(invalid: (type)) -> None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(invalid: -type) -> None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(invalid<name) -> None", "func"),
[],
)

assert_equal(
infer_sig_from_docstring("\nfunc(cpp::type name) -> None", "func"),
[],
)
assert_equal(
infer_sig_from_docstring("\nfunc(name) -> cpp::type", "func"),
[],
)
assert_equal(
infer_sig_from_docstring("\nvoid func(int name) {", "func"),
[],
)
assert_equal(
infer_sig_from_docstring("\nvoid func(std::vector<int> name)", "func"),
[],
)

def test_infer_sig_from_docstring_deeply_nested_types(self) -> None:
assert_equal(
infer_sig_from_docstring(
"\nfunc(name: dict[str, dict[str, list[tuple[int, float]]]]) -> None",
"func",
),
[
FunctionSig(
name="func",
args=[
ArgSig(
name="name",
type="dict[str,dict[str,list[tuple[int,float]]]]",
)
],
ret_type="None",
)
],
)

def test_infer_arg_sig_from_anon_docstring(self) -> None:
assert_equal(
infer_arg_sig_from_anon_docstring("(*args, **kwargs)"),
Expand Down

0 comments on commit eb2e4ab

Please sign in to comment.