Skip to content

Commit

Permalink
added support for inline functions
Browse files Browse the repository at this point in the history
  • Loading branch information
InvincibleRMC committed Jul 22, 2024
1 parent 1ed6c91 commit 1a197f7
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
5 changes: 3 additions & 2 deletions mypy/stubdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def format_sig(
is_async: bool = False,
any_val: str | None = None,
docstring: str | None = None,
generic: str = ""
) -> str:
args: list[str] = []
for arg in self.args:
Expand Down Expand Up @@ -141,8 +142,8 @@ def format_sig(
retfield = " -> " + ret_type

prefix = "async " if is_async else ""
sig = "{indent}{prefix}def {name}({args}){ret}:".format(
indent=indent, prefix=prefix, name=self.name, args=", ".join(args), ret=retfield
sig = "{indent}{prefix}def {name}{generic}({args}){ret}:".format(
indent=indent, prefix=prefix, name=self.name, args=", ".join(args), ret=retfield, generic=generic
)
if docstring:
suffix = f"\n{indent} {mypy.util.quote_docstring(docstring)}"
Expand Down
8 changes: 7 additions & 1 deletion mypy/stubgenc.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,13 @@ def generate_function_stub(

if docstring:
docstring = self._indent_docstring(docstring)
output.extend(self.format_func_def(inferred, decorators=decorators, docstring=docstring))

if hasattr(obj, "__type_params__"):
generic = generate_inline_generic(obj.__type_params__)
else:
generic = ""

output.extend(self.format_func_def(inferred, decorators=decorators, docstring=docstring, generic=generic))
self._fix_iter(ctx, inferred, output)

def _indent_docstring(self, docstring: str) -> str:
Expand Down
5 changes: 5 additions & 0 deletions mypy/stubutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ def format_func_def(
is_coroutine: bool = False,
decorators: list[str] | None = None,
docstring: str | None = None,
generic: str = "",
) -> list[str]:
lines: list[str] = []
if decorators is None:
Expand All @@ -781,6 +782,7 @@ def format_func_def(
indent=self._indent,
is_async=is_coroutine,
docstring=docstring if self._include_docstrings else None,
generic=generic
)
)
return lines
Expand Down Expand Up @@ -847,6 +849,9 @@ def should_reexport(self, name: str, full_module: str, name_is_alias: bool) -> b
def generate_inline_generic(type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...]) -> str:
"""Generate stub for inline generic from __type_params__"""

if len(type_params) == 0:
return ""

generic_arg_list: list[str] = []

for type_param in type_params:
Expand Down
67 changes: 45 additions & 22 deletions mypy/test/teststubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,29 @@ def test_common_dir_prefix_win(self) -> None:
assert common_dir_prefix([r"foo\bar/x.pyi"]) == r"foo\bar"
assert common_dir_prefix([r"foo/bar/x.pyi"]) == r"foo\bar"

def test_generate_inline_generic(self) -> None:
assert generate_inline_generic(()) == ""
T = TypeVar("T")
assert generate_inline_generic((T,)) == "[T]"
TBound = TypeVar("TBound", bound=int)
assert generate_inline_generic((TBound,)) == "[TBound: int]"
TBoundTuple = TypeVar("TBoundTuple", int, str)
assert generate_inline_generic((TBoundTuple,)) == "[TBoundTuple: (int, str)]"
P = ParamSpec("P")
p_tuple = cast(tuple[ParamSpec], (P,))
assert generate_inline_generic(p_tuple) == "[**P]"
U = TypeVarTuple("U")
u_tuple = cast(tuple[TypeVarTuple], (U,))
assert generate_inline_generic(u_tuple) == "[*U]"
all_tuple = cast(
tuple[TypeVar, TypeVar, TypeVar, ParamSpec, TypeVarTuple],
(T, TBound, TBoundTuple, P, U),
)
assert (
generate_inline_generic(all_tuple)
== "[T, TBound: int, TBoundTuple: (int, str), **P, *U]"
)


class StubgenHelpersSuite(unittest.TestCase):
def test_is_blacklisted_path(self) -> None:
Expand Down Expand Up @@ -826,28 +849,6 @@ def test_infer_cast_sig(self) -> None:
for op in ("float", "bool", "bytes", "int"):
assert_equal(infer_method_ret_type(f"__{op}__"), op)

def test_generate_inline_generic(self) -> None:
T = TypeVar("T")
assert generate_inline_generic((T,)) == "[T]"
TBound = TypeVar("TBound", bound=int)
assert generate_inline_generic((TBound,)) == "[TBound: int]"
TBoundTuple = TypeVar("TBoundTuple", int, str)
assert generate_inline_generic((TBoundTuple,)) == "[TBoundTuple: (int, str)]"
P = ParamSpec("P")
p_tuple = cast(tuple[ParamSpec], (P,))
assert generate_inline_generic(p_tuple) == "[**P]"
U = TypeVarTuple("U")
u_tuple = cast(tuple[TypeVarTuple], (U,))
assert generate_inline_generic(u_tuple) == "[*U]"
all_tuple = cast(
tuple[TypeVar, TypeVar, TypeVar, ParamSpec, TypeVarTuple],
(T, TBound, TBoundTuple, P, U),
)
assert (
generate_inline_generic(all_tuple)
== "[T, TBound: int, TBoundTuple: (int, str), **P, *U]"
)

def test_generate_class_stub_no_crash_for_object(self) -> None:
output: list[str] = []
mod = ModuleType("module", "") # any module is fine
Expand Down Expand Up @@ -942,6 +943,28 @@ class TestClass:
gen.generate_class_stub("C", TestClass, output)
assert_equal(output, ["class C[T]: ..."])

def test_inline_generic_function(self) -> None:
T = TypeVar("T", bound=int)
class TestClass:
def test(self, arg0: T) -> T:
"""
test(self, arg0: T) -> T
"""
return arg0

test.__type_params__ = (T, )

output: list[str] = []
mod = ModuleType(TestClass.__module__, "")
gen = InspectionStubGenerator(mod.__name__, known_modules=[mod.__name__], module=mod)
gen.generate_function_stub(
"test",
TestClass.test,
output=output,
class_info=ClassInfo(self_var="self", cls=TestClass, name="TestClass"),
)
assert_equal(output, ["def test[T: int](self, arg0: T) -> T: ..."])

def test_generate_c_type_inheritance_builtin_type(self) -> None:
class TestClass(type):
pass
Expand Down

0 comments on commit 1a197f7

Please sign in to comment.