Skip to content

Commit

Permalink
stubgen: Don't annotate unknown argument and return types (#10626)
Browse files Browse the repository at this point in the history
### 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.
  • Loading branch information
srittau authored and JukkaL committed Jun 18, 2021
1 parent 2ce3677 commit ae3dcc7
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 98 deletions.
48 changes: 27 additions & 21 deletions mypy/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
from mypy.options import Options as MypyOptions
from mypy.types import (
Type, TypeStrVisitor, CallableType, UnboundType, NoneType, TupleType, TypeList, Instance,
AnyType
AnyType, get_proper_type
)
from mypy.visitor import NodeVisitor
from mypy.find_sources import create_source_list, InvalidSourceList
Expand Down Expand Up @@ -624,26 +624,24 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False,
# name their 0th argument other than self/cls
is_self_arg = i == 0 and name == 'self'
is_cls_arg = i == 0 and name == 'cls'
if (annotated_type is None
and not arg_.initializer
and not is_self_arg
and not is_cls_arg):
self.add_typing_import("Any")
annotation = ": {}".format(self.typing_name("Any"))
elif annotated_type and not is_self_arg and not is_cls_arg:
annotation = ": {}".format(self.print_annotation(annotated_type))
else:
annotation = ""
annotation = ""
if annotated_type and not is_self_arg and not is_cls_arg:
# Luckily, an argument explicitly annotated with "Any" has
# type "UnboundType" and will not match.
if not isinstance(get_proper_type(annotated_type), AnyType):
annotation = ": {}".format(self.print_annotation(annotated_type))
if arg_.initializer:
initializer = '...'
if kind in (ARG_NAMED, ARG_NAMED_OPT) and not any(arg.startswith('*')
for arg in args):
args.append('*')
if not annotation:
typename = self.get_str_type_of_node(arg_.initializer, True)
annotation = ': {} = ...'.format(typename)
typename = self.get_str_type_of_node(arg_.initializer, True, False)
if typename == '':
annotation = '=...'
else:
annotation = ': {} = ...'.format(typename)
else:
annotation += '={}'.format(initializer)
annotation += ' = ...'
arg = name + annotation
elif kind == ARG_STAR:
arg = '*%s%s' % (name, annotation)
Expand All @@ -654,12 +652,16 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False,
args.append(arg)
retname = None
if o.name != '__init__' and isinstance(o.unanalyzed_type, CallableType):
retname = self.print_annotation(o.unanalyzed_type.ret_type)
if isinstance(get_proper_type(o.unanalyzed_type.ret_type), AnyType):
# Luckily, a return type explicitly annotated with "Any" has
# type "UnboundType" and will enter the else branch.
retname = None # implicit Any
else:
retname = self.print_annotation(o.unanalyzed_type.ret_type)
elif isinstance(o, FuncDef) and (o.is_abstract or o.name in METHODS_WITH_RETURN_VALUE):
# Always assume abstract methods return Any unless explicitly annotated. Also
# some dunder methods should not have a None return type.
retname = self.typing_name('Any')
self.add_typing_import("Any")
retname = None # implicit Any
elif not has_return_statement(o) and not is_abstract:
retname = 'None'
retfield = ''
Expand Down Expand Up @@ -1148,7 +1150,8 @@ def is_private_member(self, fullname: str) -> bool:
return False

def get_str_type_of_node(self, rvalue: Expression,
can_infer_optional: bool = False) -> str:
can_infer_optional: bool = False,
can_be_any: bool = True) -> str:
if isinstance(rvalue, IntExpr):
return 'int'
if isinstance(rvalue, StrExpr):
Expand All @@ -1165,8 +1168,11 @@ def get_str_type_of_node(self, rvalue: Expression,
isinstance(rvalue, NameExpr) and rvalue.name == 'None':
self.add_typing_import('Any')
return '{} | None'.format(self.typing_name('Any'))
self.add_typing_import('Any')
return self.typing_name('Any')
if can_be_any:
self.add_typing_import('Any')
return self.typing_name('Any')
else:
return ''

def print_annotation(self, t: Type) -> str:
printer = AnnotationPrinter(self)
Expand Down

0 comments on commit ae3dcc7

Please sign in to comment.