Beispiel #1
0
def infer_annotation(type_comments):
    # type: (List[str]) -> Tuple[List[Argument], AbstractType]
    """Given some type comments, return a single inferred signature.

    Args:
        type_comments: Strings of form '(arg1, ... argN) -> ret'

    Returns: Tuple of (argument types and kinds, return type).
    """
    assert type_comments
    args = {}  # type: Dict[int, Set[Argument]]
    returns = set()
    for comment in type_comments:
        arg_types, return_type = parse_type_comment(comment)
        for i, arg_type in enumerate(arg_types):
            args.setdefault(i, set()).add(arg_type)
        returns.add(return_type)
    combined_args = []
    for i in sorted(args):
        arg_infos = list(args[i])
        kind = argument_kind(arg_infos)
        if kind is None:
            raise InferError('Ambiguous argument kinds:\n' + '\n'.join(type_comments))
        types = [arg.type for arg in arg_infos]
        combined = combine_types(types)
        if str(combined) == 'None':
            # It's very rare for an argument to actually be typed `None`, more likely than
            # not we simply don't have any data points for this argument.
            combined = UnionType([ClassType('None'), AnyType()])
        if kind != ARG_POS and (len(str(combined)) > 120 or isinstance(combined, UnionType)):
            # Avoid some noise.
            combined = AnyType()
        combined_args.append(Argument(combined, kind))
    combined_return = combine_types(returns)
    return combined_args, combined_return
Beispiel #2
0
 def test_union(self):
     # type: () -> None
     self.assert_type_comment('(Union[int, str]) -> Any', ([
         Argument(UnionType([ClassType('int'),
                             ClassType('str')]), ARG_POS)
     ], AnyType()))
     self.assert_type_comment('(Union[int]) -> Any',
                              ([class_arg('int')], AnyType()))
Beispiel #3
0
 def test_tuple(self):
     # type: () -> None
     self.assert_type_comment('(Tuple[]) -> Any',
                              ([tuple_arg([])], AnyType()))
     self.assert_type_comment('(Tuple[int]) -> Any',
                              ([tuple_arg([ClassType('int')])], AnyType()))
     self.assert_type_comment(
         '(Tuple[int, str]) -> Any',
         ([tuple_arg([ClassType('int'), ClassType('str')])], AnyType()))
Beispiel #4
0
 def test_star_args(self):
     # type: () -> None
     self.assert_type_comment(
         '(*str) -> Any',
         ([Argument(ClassType('str'), ARG_STAR)], AnyType()))
     self.assert_type_comment(
         '(int, *str) -> Any',
         ([class_arg('int'),
           Argument(ClassType('str'), ARG_STAR)], AnyType()))
Beispiel #5
0
 def parse_type(self):
     # type: () -> AbstractType
     t = self.next()
     if not isinstance(t, DottedName):
         self.fail()
     if t.text == 'Any':
         return AnyType()
     elif t.text == 'Tuple':
         self.expect('[')
         args = self.parse_type_list()
         self.expect(']')
         return TupleType(args)
     elif t.text == 'Union':
         self.expect('[')
         items = self.parse_type_list()
         self.expect(']')
         if len(items) == 1:
             return items[0]
         elif len(items) == 0:
             self.fail()
         else:
             return UnionType(items)
     else:
         if self.lookup() == '[':
             self.expect('[')
             args = self.parse_type_list()
             self.expect(']')
             if t.text == 'Optional' and len(args) == 1:
                 return UnionType([args[0], ClassType('None')])
             return ClassType(t.text, args)
         else:
             return ClassType(t.text)
Beispiel #6
0
def filter_ignored_items(items):
    # type: (List[AbstractType]) -> List[AbstractType]
    result = [
        item for item in items
        if not isinstance(item, ClassType) or item.name not in IGNORED_ITEMS
    ]
    return result or [AnyType()]
Beispiel #7
0
def is_redundant_union_item(first, other):
    # type: (AbstractType, AbstractType) -> bool
    """If union has both items, is the first one redundant?

    For example, if first is 'str' and the other is 'Text', return True.

    If items are equal, return False.
    """
    if isinstance(first, ClassType) and isinstance(other, ClassType):
        if first.name == 'str' and other.name == 'Text':
            return True
        elif first.name == 'bool' and other.name == 'int':
            return True
        elif first.name == 'int' and other.name == 'float':
            return True
        elif (first.name in ('List', 'Dict', 'Set')
              and other.name == first.name):
            if not first.args and other.args:
                return True
            elif len(first.args) == len(other.args) and first.args:
                result = all(
                    first_arg == other_arg or other_arg == AnyType()
                    for first_arg, other_arg in zip(first.args, other.args))
                return result

    return False
Beispiel #8
0
 def test_remove_redundant_dict_item_when_simplified(self):
     # type: () -> None
     self.assert_infer([
         '(Dict[str, Any]) -> None',
         '(Dict[str, Union[str, List, Dict, int]]) -> None'
     ], ([(ClassType('Dict', [ClassType('str'), AnyType()]), ARG_POS)
          ], ClassType('None')))
Beispiel #9
0
def simplify_types(types):
    # type: (Iterable[AbstractType]) -> List[AbstractType]
    """Given some types, give simplified types representing the union of types."""
    flattened = flatten_types(types)
    items = remove_redundant_items(flattened)
    items = [simplify_recursive(item) for item in items]
    items = merge_items(items)
    items = dedupe_types(items)
    if len(items) > 3:
        return [AnyType()]
    else:
        return items
Beispiel #10
0
def simplify_types(types):
    # type: (Iterable[AbstractType]) -> List[AbstractType]
    """Given some types, give simplified types representing the union of types."""
    flattened = flatten_types(types)
    items = filter_ignored_items(flattened)
    items = [simplify_recursive(item) for item in items]
    items = merge_items(items)
    items = dedupe_types(items)
    # We have to remove reundant items after everything has been simplified and
    # merged as this simplification may be what makes items redundant.
    items = remove_redundant_items(items)
    if len(items) > 3:
        return [AnyType()]
    else:
        return items
Beispiel #11
0
def simplify_recursive(typ):
    # type: (AbstractType) -> AbstractType
    """Simplify all components of a type."""
    if isinstance(typ, UnionType):
        return combine_types(typ.items)
    elif isinstance(typ, ClassType):
        simplified = ClassType(typ.name, [simplify_recursive(arg) for arg in typ.args])
        args = simplified.args
        if (simplified.name == 'Dict' and len(args) == 2
                and isinstance(args[0], ClassType) and args[0].name in ('str', 'Text')
                and isinstance(args[1], UnionType) and not is_optional(args[1])):
            # Looks like a potential case for TypedDict, which we don't properly support yet.
            return ClassType('Dict', [args[0], AnyType()])
        return simplified
    elif isinstance(typ, TupleType):
        return TupleType([simplify_recursive(item) for item in typ.items])
    return typ
Beispiel #12
0
 def test_simplify_potential_typed_dict(self):
     # type: () -> None
     # Fall back to Dict[x, Any] in case of a complex Dict type.
     self.assert_infer(['(Dict[str, Union[int, str]]) -> Any'],
                       ([(ClassType('Dict', [ClassType('str'), AnyType()]), ARG_POS)],
                        AnyType()))
     self.assert_infer(['(Dict[Text, Union[int, str]]) -> Any'],
                       ([(ClassType('Dict', [ClassType('Text'), AnyType()]), ARG_POS)],
                        AnyType()))
     # Not a potential TypedDict so ordinary simplification applies.
     self.assert_infer(['(Dict[str, Union[str, Text]]) -> Any'],
                       ([(ClassType('Dict', [ClassType('str'), ClassType('Text')]), ARG_POS)],
                        AnyType()))
     self.assert_infer(['(Dict[str, Union[int, None]]) -> Any'],
                       ([(ClassType('Dict', [ClassType('str'),
                                             UnionType([ClassType('int'),
                                                        ClassType('None')])]), ARG_POS)],
                        AnyType()))
Beispiel #13
0
 def test_unicode(self):
     # type: () -> None
     self.assert_type_comment('(unicode) -> Any',
                              ([class_arg('Text')], AnyType()))
Beispiel #14
0
 def test_any_type_str(self):
     # type: () -> None
     assert str(AnyType()) == 'Any'
Beispiel #15
0
 def test_remove_redundant_dict_item(self):
     # type: () -> None
     self.assert_infer(['(Dict[str, Any]) -> None',
                        '(Dict[str, str]) -> None'],
                        ([(ClassType('Dict', [ClassType('str'), AnyType()]), ARG_POS)],
                         ClassType('None')))
Beispiel #16
0
 def test_infer_ignore_mock_fallback_to_any(self):
     # type: () -> None
     self.assert_infer(['(mock.mock.Mock) -> str',
                        '(mock.mock.Mock) -> int'],
                        ([(AnyType(), ARG_POS)],
                         UnionType([ClassType('str'), ClassType('int')])))
Beispiel #17
0
 def test_any_and_unknown(self):
     # type: () -> None
     self.assert_type_comment(
         '(Any) -> pyannotate_runtime.collect_types.UnknownType',
         ([any_arg()], AnyType()))
Beispiel #18
0
 def test_optional(self):
     # type: () -> None
     self.assert_type_comment('(Optional[int]) -> Any', ([
         Argument(UnionType([ClassType('int'),
                             ClassType('None')]), ARG_POS)
     ], AnyType()))
Beispiel #19
0
def any_arg():
    # type: () -> Argument
    return Argument(AnyType(), ARG_POS)
Beispiel #20
0
 def test_infer_none_argument(self):
     # type: () -> None
     self.assert_infer(['(None) -> None'],
                        ([(UnionType([ClassType('None'), AnyType()]), ARG_POS)],
                         ClassType('None')))
Beispiel #21
0
 def test_function(self):
     # type: () -> None
     self.assert_type_comment('(function) -> Any',
                              ([class_arg('Callable')], AnyType()))