diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 31487f9d0dcf1..c0984df7e9c69 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -424,7 +424,7 @@ def strip_or_import( stripped_subtyp = strip_or_import(subtyp.strip(), module, known_modules, imports) if stripped_subtyp != subtyp: stripped_type = re.sub( - r"(^|[\[, ]+)" + re.escape(subtyp) + r"($|[\], ]+)", + r"(^|[\[, ]+)" + re.escape(subtyp) + r"($|[\[\], ]+)", r"\1" + stripped_subtyp + r"\2", stripped_type, ) diff --git a/mypy/test/teststubgen.py b/mypy/test/teststubgen.py index 7e30515ac8926..102986f7123d2 100644 --- a/mypy/test/teststubgen.py +++ b/mypy/test/teststubgen.py @@ -1146,6 +1146,36 @@ def test(arg0: str) -> None: assert_equal(output, ["def test(arg0: argparse.Action) -> argparse.Action: ..."]) assert_equal(set(imports), {"import argparse"}) + def test_generate_c_function_same_module_custom_nested(self) -> None: + """Test that if annotation references a complicated nested type from same module but using full path, + no module will be imported, and type specification will be striped to local reference. + """ + + # Provide different type in python spec than in docstring to make sure, that docstring + # information is used. + def test(arg0: str) -> None: + """ + test(arg0: argparse.Action[int, argparse.OtherType[str]]) -> argparse.Action[argparse.OtherType[str,str], int] + """ + + output: list[str] = [] + imports: list[str] = [] + mod = ModuleType("argparse", "") + generate_c_function_stub( + mod, + "test", + test, + output=output, + imports=imports, + known_modules=[mod.__name__], + sig_generators=get_sig_generators(parse_options([])), + ) + assert_equal( + output, + ["def test(arg0: Action[int,OtherType[str]]) -> Action[OtherType[str,str],int]: ..."], + ) + assert_equal(imports, []) + def test_generate_c_function_same_module_nested(self) -> None: """Test that if annotation references type from same module but using full path, no module will be imported, and type specification will be stripped to local reference.