def test_simple_args(self): # type: () -> None self.assert_type_comment('(int) -> None', ([class_arg('int')], ClassType('None'))) self.assert_type_comment( '(int, str) -> bool', ([class_arg('int'), class_arg('str')], ClassType('bool')))
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')))
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 == 'mypy_extensions.NoReturn': return NoReturnType() 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)
def test_simplify_multiple_empty_collections(self): # type: () -> None self.assert_infer( ['() -> Tuple[List, List[x]]', '() -> Tuple[List, List]'], ([], TupleType( [ClassType('List'), ClassType('List', [ClassType('x')])])))
def test_merge_unions(self): # type: () -> None self.assert_infer( ['(Union[int, str]) -> None', '(Union[str, None]) -> None'], ([(UnionType( [ClassType('int'), ClassType('str'), ClassType('None')]), ARG_POS)], ClassType('None')))
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()))
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()))
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()))
def merged_type(t, s): # type: (AbstractType, AbstractType) -> Optional[AbstractType] """Return merged type if two items can be merged in to a different, more general type. Return None if merging is not possible. """ if isinstance(t, TupleType) and isinstance(s, TupleType): if len(t.items) == len(s.items): return TupleType( [combine_types([ti, si]) for ti, si in zip(t.items, s.items)]) all_items = t.items + s.items if all_items and all(item == all_items[0] for item in all_items[1:]): # Merge multiple compatible fixed-length tuples into a variable-length tuple type. return ClassType('Tuple', [all_items[0]]) elif (isinstance(t, TupleType) and isinstance(s, ClassType) and s.name == 'Tuple' and len(s.args) == 1): if all(item == s.args[0] for item in t.items): # Merge fixed-length tuple and variable-length tuple. return s elif isinstance(s, TupleType) and isinstance( t, ClassType) and t.name == 'Tuple': return merged_type(s, t) elif isinstance(s, NoReturnType): return t elif isinstance(t, NoReturnType): return s elif isinstance(s, AnyType): # This seems to be usually desirable, since Anys tend to come from unknown types. return t elif isinstance(t, AnyType): # Similar to above. return s return None
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
def test_optional(Self): # type: () -> None assert str(UnionType([ClassType('str'), ClassType('None')])) == 'Optional[str]' assert str(UnionType([ClassType('None'), ClassType('str')])) == 'Optional[str]' assert str( UnionType([ClassType('None'), ClassType('str'), ClassType('int')])) == 'Union[None, str, int]'
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
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')))
def test_optional(self): # type: () -> None self.assert_type_comment('(Optional[int]) -> Any', ([ Argument(UnionType([ClassType('int'), ClassType('None')]), ARG_POS) ], AnyType()))
def test_remove_redundant_union_item(self): # type: () -> None self.assert_infer(['(str) -> None', '(unicode) -> None'], ([(ClassType('Text'), ARG_POS)], ClassType('None')))
def test_infer_union_return(self): # type: () -> None self.assert_infer(['() -> int', '() -> str'], ([], UnionType([ClassType('int'), ClassType('str')])))
def test_star_arg(self): # type: () -> None self.assert_infer(['(int) -> None', '(int, *bool) -> None'], ([(ClassType('int'), ARG_POS), (ClassType('bool'), ARG_STAR)], ClassType('None')))
def test_infer_none_argument(self): # type: () -> None self.assert_infer(['(None) -> None'], ([(UnionType( [ClassType('None'), AnyType()]), ARG_POS)], ClassType('None')))
def test_infer_union_arg(self): # type: () -> None self.assert_infer(['(int) -> None', '(str) -> None'], ([ (UnionType([ClassType('int'), ClassType('str')]), ARG_POS) ], ClassType('None')))
def class_arg(name, args=None): # type: (str, Optional[List[AbstractType]]) -> Argument return Argument(ClassType(name, args), ARG_POS)
def test_simple(self): # type: () -> None self.assert_infer(['(int) -> str'], ([(ClassType('int'), ARG_POS)], ClassType('str')))
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()))
def test_empty(self): # type: () -> None self.assert_type_comment('() -> None', ([], ClassType('None')))
def test_uniform_tuple_str(self): # type: () -> None assert str(ClassType('Tuple', [ClassType('int')])) == 'Tuple[int, ...]'
def test_tuple_type_str(self): # type: () -> None assert str(TupleType([ClassType('int')])) == 'Tuple[int]' assert str(TupleType([ClassType('int'), ClassType('str')])) == 'Tuple[int, str]' assert str(TupleType([])) == 'Tuple[()]'
def test_union_type_str(Self): # type: () -> None assert str(UnionType([ClassType('int'), ClassType('str')])) == 'Union[int, str]'
def test_simplify_list_item_types(self): # type: () -> None self.assert_infer(['(List[Union[bool, int]]) -> None'], ([(ClassType( 'List', [ClassType('int')]), ARG_POS)], ClassType('None')))
def test_infer_ignore_mock(self): # type: () -> None self.assert_infer(['(mock.mock.Mock) -> None', '(str) -> None'], ([(ClassType('str'), ARG_POS)], ClassType('None')))
def test_instance_str(self): # type: () -> None assert str(ClassType('int')) == 'int' assert str(ClassType('List', [ClassType('int')])) == 'List[int]' assert str(ClassType( 'Dict', [ClassType('int'), ClassType('str')])) == 'Dict[int, str]'
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')])))