Skip to content

Commit 55bd489

Browse files
authored
stubgen: Don't annotate unknown argument and return types (#10626)
### Description Don't annotate unknown argument and return types with explicit `Any`. Also, fix formatting of functions that have an explicit type and default argument. ## Test Plan I adapted the existing tests. I also added tests to ensure that explicit `Any`s remain in the stub. I also added a test for the formatting fix.
1 parent e2010cc commit 55bd489

File tree

2 files changed

+100
-98
lines changed

2 files changed

+100
-98
lines changed

mypy/stubgen.py

+27-21
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
from mypy.options import Options as MypyOptions
8686
from mypy.types import (
8787
Type, TypeStrVisitor, CallableType, UnboundType, NoneType, TupleType, TypeList, Instance,
88-
AnyType
88+
AnyType, get_proper_type
8989
)
9090
from mypy.visitor import NodeVisitor
9191
from mypy.find_sources import create_source_list, InvalidSourceList
@@ -624,26 +624,24 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False,
624624
# name their 0th argument other than self/cls
625625
is_self_arg = i == 0 and name == 'self'
626626
is_cls_arg = i == 0 and name == 'cls'
627-
if (annotated_type is None
628-
and not arg_.initializer
629-
and not is_self_arg
630-
and not is_cls_arg):
631-
self.add_typing_import("Any")
632-
annotation = ": {}".format(self.typing_name("Any"))
633-
elif annotated_type and not is_self_arg and not is_cls_arg:
634-
annotation = ": {}".format(self.print_annotation(annotated_type))
635-
else:
636-
annotation = ""
627+
annotation = ""
628+
if annotated_type and not is_self_arg and not is_cls_arg:
629+
# Luckily, an argument explicitly annotated with "Any" has
630+
# type "UnboundType" and will not match.
631+
if not isinstance(get_proper_type(annotated_type), AnyType):
632+
annotation = ": {}".format(self.print_annotation(annotated_type))
637633
if arg_.initializer:
638-
initializer = '...'
639634
if kind in (ARG_NAMED, ARG_NAMED_OPT) and not any(arg.startswith('*')
640635
for arg in args):
641636
args.append('*')
642637
if not annotation:
643-
typename = self.get_str_type_of_node(arg_.initializer, True)
644-
annotation = ': {} = ...'.format(typename)
638+
typename = self.get_str_type_of_node(arg_.initializer, True, False)
639+
if typename == '':
640+
annotation = '=...'
641+
else:
642+
annotation = ': {} = ...'.format(typename)
645643
else:
646-
annotation += '={}'.format(initializer)
644+
annotation += ' = ...'
647645
arg = name + annotation
648646
elif kind == ARG_STAR:
649647
arg = '*%s%s' % (name, annotation)
@@ -654,12 +652,16 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False,
654652
args.append(arg)
655653
retname = None
656654
if o.name != '__init__' and isinstance(o.unanalyzed_type, CallableType):
657-
retname = self.print_annotation(o.unanalyzed_type.ret_type)
655+
if isinstance(get_proper_type(o.unanalyzed_type.ret_type), AnyType):
656+
# Luckily, a return type explicitly annotated with "Any" has
657+
# type "UnboundType" and will enter the else branch.
658+
retname = None # implicit Any
659+
else:
660+
retname = self.print_annotation(o.unanalyzed_type.ret_type)
658661
elif isinstance(o, FuncDef) and (o.is_abstract or o.name in METHODS_WITH_RETURN_VALUE):
659662
# Always assume abstract methods return Any unless explicitly annotated. Also
660663
# some dunder methods should not have a None return type.
661-
retname = self.typing_name('Any')
662-
self.add_typing_import("Any")
664+
retname = None # implicit Any
663665
elif not has_return_statement(o) and not is_abstract:
664666
retname = 'None'
665667
retfield = ''
@@ -1148,7 +1150,8 @@ def is_private_member(self, fullname: str) -> bool:
11481150
return False
11491151

11501152
def get_str_type_of_node(self, rvalue: Expression,
1151-
can_infer_optional: bool = False) -> str:
1153+
can_infer_optional: bool = False,
1154+
can_be_any: bool = True) -> str:
11521155
if isinstance(rvalue, IntExpr):
11531156
return 'int'
11541157
if isinstance(rvalue, StrExpr):
@@ -1165,8 +1168,11 @@ def get_str_type_of_node(self, rvalue: Expression,
11651168
isinstance(rvalue, NameExpr) and rvalue.name == 'None':
11661169
self.add_typing_import('Any')
11671170
return '{} | None'.format(self.typing_name('Any'))
1168-
self.add_typing_import('Any')
1169-
return self.typing_name('Any')
1171+
if can_be_any:
1172+
self.add_typing_import('Any')
1173+
return self.typing_name('Any')
1174+
else:
1175+
return ''
11701176

11711177
def print_annotation(self, t: Type) -> str:
11721178
printer = AnnotationPrinter(self)

0 commit comments

Comments
 (0)