Skip to content

Commit 64ebff3

Browse files
committed
Fixed stubgen parsing generics from C extensions
1 parent a04bdbf commit 64ebff3

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

mypy/stubgenc.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,16 @@ def strip_or_import(typ: str, module: ModuleType, imports: List[str]) -> str:
201201
imports: list of import statements (may be modified during the call)
202202
"""
203203
stripped_type = typ
204-
if module and typ.startswith(module.__name__ + '.'):
204+
if any(c in typ for c in '[,'):
205+
for subtyp in re.split(r'[\[,\]]', typ):
206+
strip_or_import(subtyp.strip(), module, imports)
207+
if module:
208+
stripped_type = re.sub(
209+
r'(^|[\[, ]+)' + re.escape(module.__name__ + '.'),
210+
r'\1',
211+
typ,
212+
)
213+
elif module and typ.startswith(module.__name__ + '.'):
205214
stripped_type = typ[len(module.__name__) + 1:]
206215
elif '.' in typ:
207216
arg_module = typ[:typ.rindex('.')]

mypy/test/teststubgen.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
mypy_options, is_blacklisted_path, is_non_library_module
2020
)
2121
from mypy.stubutil import walk_packages, remove_misplaced_type_comments, common_dir_prefix
22-
from mypy.stubgenc import generate_c_type_stub, infer_method_sig, generate_c_function_stub
22+
from mypy.stubgenc import (
23+
add_typing_import, generate_c_type_stub, infer_method_sig, generate_c_function_stub,
24+
)
2325
from mypy.stubdoc import (
2426
parse_signature, parse_all_signatures, build_signature, find_unique_signatures,
2527
infer_sig_from_docstring, infer_prop_type_from_docstring, FunctionSig, ArgSig,
@@ -778,6 +780,81 @@ def test(arg0: str) -> None:
778780
assert_equal(output, ['def test(arg0: str) -> Action: ...'])
779781
assert_equal(imports, [])
780782

783+
def test_generate_c_type_with_single_arg_generic(self) -> None:
784+
class TestClass:
785+
def test(self, arg0: str) -> None:
786+
"""
787+
test(self: TestClass, arg0: List[int])
788+
"""
789+
pass
790+
output = [] # type: List[str]
791+
imports = [] # type: List[str]
792+
mod = ModuleType(TestClass.__module__, '')
793+
generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
794+
self_var='self', class_name='TestClass')
795+
assert_equal(output, ['def test(self, arg0: List[int]) -> Any: ...'])
796+
assert_equal(imports, [])
797+
798+
def test_generate_c_type_with_double_arg_generic(self) -> None:
799+
class TestClass:
800+
def test(self, arg0: str) -> None:
801+
"""
802+
test(self: TestClass, arg0: Dict[str, int])
803+
"""
804+
pass
805+
output = [] # type: List[str]
806+
imports = [] # type: List[str]
807+
mod = ModuleType(TestClass.__module__, '')
808+
generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
809+
self_var='self', class_name='TestClass')
810+
assert_equal(output, ['def test(self, arg0: Dict[str,int]) -> Any: ...'])
811+
assert_equal(imports, [])
812+
813+
def test_generate_c_type_with_nested_generic(self) -> None:
814+
class TestClass:
815+
def test(self, arg0: str) -> None:
816+
"""
817+
test(self: TestClass, arg0: Dict[str, List[int]])
818+
"""
819+
pass
820+
output = [] # type: List[str]
821+
imports = [] # type: List[str]
822+
mod = ModuleType(TestClass.__module__, '')
823+
generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
824+
self_var='self', class_name='TestClass')
825+
assert_equal(output, ['def test(self, arg0: Dict[str,List[int]]) -> Any: ...'])
826+
assert_equal(imports, [])
827+
828+
def test_generate_c_type_with_generic_using_other_module_first(self) -> None:
829+
class TestClass:
830+
def test(self, arg0: str) -> None:
831+
"""
832+
test(self: TestClass, arg0: Dict[argparse.Action, int])
833+
"""
834+
pass
835+
output = [] # type: List[str]
836+
imports = [] # type: List[str]
837+
mod = ModuleType(TestClass.__module__, '')
838+
generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
839+
self_var='self', class_name='TestClass')
840+
assert_equal(output, ['def test(self, arg0: Dict[argparse.Action,int]) -> Any: ...'])
841+
assert_equal(imports, ['import argparse'])
842+
843+
def test_generate_c_type_with_generic_using_other_module_last(self) -> None:
844+
class TestClass:
845+
def test(self, arg0: str) -> None:
846+
"""
847+
test(self: TestClass, arg0: Dict[str, argparse.Action])
848+
"""
849+
pass
850+
output = [] # type: List[str]
851+
imports = [] # type: List[str]
852+
mod = ModuleType(TestClass.__module__, '')
853+
generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
854+
self_var='self', class_name='TestClass')
855+
assert_equal(output, ['def test(self, arg0: Dict[str,argparse.Action]) -> Any: ...'])
856+
assert_equal(imports, ['import argparse'])
857+
781858
def test_generate_c_type_with_overload_pybind11(self) -> None:
782859
class TestClass:
783860
def __init__(self, arg0: str) -> None:

0 commit comments

Comments
 (0)