Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
"""This visitor method tracks situations like this:
x: A # When analyzing this type we will get an Instance from SemanticAnalyzerPass1.
# Now we need to update this to actual analyzed TupleType.
class A(NamedTuple):
attr: str
If from_fallback is True, then we always return an Instance type. This is needed
since TupleType and TypedDictType fallbacks are always instances.
"""
info = t.type
# Special case, analyzed bases transformed the type into TupleType.
if info.tuple_type and not from_fallback:
items = [it.accept(self) for it in info.tuple_type.items]
info.tuple_type.items = items
return TupleType(items, Instance(info, []))
# Update forward Instances to corresponding analyzed NamedTuples.
if info.replaced and info.replaced.tuple_type:
tp = info.replaced.tuple_type
if self.check_recursion(tp):
# The key idea is that when we recursively return to a type already traversed,
# then we break the cycle and put AnyType as a leaf.
return AnyType(TypeOfAny.from_error)
return tp.copy_modified(fallback=Instance(info.replaced, [],
line=t.line)).accept(self)
# Same as above but for TypedDicts.
if info.replaced and info.replaced.typeddict_type:
td = info.replaced.typeddict_type
if self.check_recursion(td):
# We also break the cycles for TypedDicts as explained above for NamedTuples.
return AnyType(TypeOfAny.from_error)
return td.copy_modified(fallback=Instance(info.replaced, [],
def anal_type(self, t: Type, allow_tuple_literal: bool = False) -> Type:
if t:
if allow_tuple_literal:
# Types such as (t1, t2, ...) only allowed in assignment statements. They'll
# generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
if isinstance(t, TupleType):
# Unlike TypeAnalyser, also allow implicit tuple types (without Tuple[...]).
star_count = sum(1 for item in t.items if isinstance(item, StarType))
if star_count > 1:
self.fail('At most one star type allowed in a tuple', t)
return TupleType([AnyType() for _ in t.items],
self.builtin_type('builtins.tuple'), t.line)
items = [self.anal_type(item, True)
for item in t.items]
return TupleType(items, self.builtin_type('builtins.tuple'), t.line)
a = TypeAnalyser(self.lookup_qualified,
self.lookup_fully_qualified,
self.fail)
return t.accept(a)
else:
return None
self.num_precise += 1
self.record_line(self.line, TYPE_PRECISE)
if isinstance(t, Instance):
if t.args:
if any(is_complex(arg) for arg in t.args):
self.num_complex += 1
else:
self.num_generic += 1
else:
self.num_simple += 1
elif isinstance(t, Void):
self.num_simple += 1
elif isinstance(t, FunctionLike):
self.num_function += 1
elif isinstance(t, TupleType):
if any(is_complex(item) for item in t.items):
self.num_complex += 1
else:
self.num_tuple += 1
elif isinstance(t, TypeVarType):
self.num_typevar += 1
def expr_to_analyzed_type(self, expr: Node) -> Type:
if isinstance(expr, CallExpr):
expr.accept(self)
info = self.check_namedtuple(expr)
if info is None:
# Some form of namedtuple is the only valid type that looks like a call
# expression. This isn't a valid type.
raise TypeTranslationError()
fallback = Instance(info, [])
return TupleType(info.tuple_type.items, fallback=fallback)
typ = expr_to_unanalyzed_type(expr)
return self.anal_type(typ)
def make_oneoff_named_tuple(api: TypeChecker, name: str, fields: 'OrderedDict[str, MypyType]') -> TupleType:
current_module = api.scope.stack[0]
namedtuple_info = add_new_class_for_module(current_module, name,
bases=[api.named_generic_type('typing.NamedTuple', [])],
fields=fields)
return TupleType(list(fields.values()), fallback=Instance(namedtuple_info, []))
def make_tuple(api: 'TypeChecker', fields: List[MypyType]) -> TupleType:
implicit_any = AnyType(TypeOfAny.special_form)
fallback = api.named_generic_type('builtins.tuple', [implicit_any])
return TupleType(fields, fallback=fallback)
def are_tuples_overlapping(left: Type, right: Type, *,
ignore_promotions: bool = False,
prohibit_none_typevar_overlap: bool = False) -> bool:
"""Returns true if left and right are overlapping tuples."""
left, right = get_proper_types((left, right))
left = adjust_tuple(left, right) or left
right = adjust_tuple(right, left) or right
assert isinstance(left, TupleType), 'Type {} is not a tuple'.format(left)
assert isinstance(right, TupleType), 'Type {} is not a tuple'.format(right)
if len(left.items) != len(right.items):
return False
return all(is_overlapping_types(l, r,
ignore_promotions=ignore_promotions,
prohibit_none_typevar_overlap=prohibit_none_typevar_overlap)
for l, r in zip(left.items, right.items))
sub_info: TypeInfo,
super_info: TypeInfo) -> Type:
"""Map type variables in a type defined in a supertype context to be valid
in the subtype context. Assume that the result is unique; if more than
one type is possible, return one of the alternatives.
For example, assume
class D(Generic[S]): ...
class C(D[E[T]], Generic[T]): ...
Now S in the context of D would be mapped to E[T] in the context of C.
"""
# Create the type of self in subtype, of form t[a1, ...].
inst_type = fill_typevars(sub_info)
if isinstance(inst_type, TupleType):
inst_type = tuple_fallback(inst_type)
# Map the type of self to supertype. This gets us a description of the
# supertype type variables in terms of subtype variables, i.e. t[t1, ...]
# so that any type variables in tN are to be interpreted in subtype
# context.
inst_type = map_instance_to_supertype(inst_type, super_info)
# Finally expand the type variables in type with those in the previously
# constructed type. Note that both type and inst_type may have type
# variables, but in type they are interpreted in supertype context while
# in inst_type they are interpreted in subtype context. This works even if
# the names of type variables in supertype and subtype overlap.
return expand_type_by_instance(typ, inst_type)
items.extend(tt.items)
j += len(tt.items)
else:
# A star expression that's not a Tuple.
# Treat the whole thing as a variable-length tuple.
return self.check_lst_expr(e.items, 'builtins.tuple', '', e)
else:
if not type_context_items or j >= len(type_context_items):
tt = self.accept(item)
else:
tt = self.accept(item, type_context_items[j])
j += 1
self.check_usable_type(tt, e)
items.append(tt)
fallback_item = join.join_type_list(items)
return TupleType(items, self.chk.named_generic_type('builtins.tuple', [fallback_item]))
def analyze_type_callable_member_access(name: str,
typ: FunctionLike,
mx: MemberContext) -> Type:
# Class attribute.
# TODO super?
ret_type = typ.items()[0].ret_type
assert isinstance(ret_type, ProperType)
if isinstance(ret_type, TupleType):
ret_type = tuple_fallback(ret_type)
if isinstance(ret_type, Instance):
if not mx.is_operator:
# When Python sees an operator (eg `3 == 4`), it automatically translates that
# into something like `int.__eq__(3, 4)` instead of `(3).__eq__(4)` as an
# optimization.
#
# While it normally it doesn't matter which of the two versions are used, it
# does cause inconsistencies when working with classes. For example, translating
# `int == int` to `int.__eq__(int)` would not work since `int.__eq__` is meant to
# compare two int _instances_. What we really want is `type(int).__eq__`, which
# is meant to compare two types or classes.
#
# This check makes sure that when we encounter an operator, we skip looking up
# the corresponding method in the current instance to avoid this edge case.
# See https://github.com/python/mypy/pull/1787 for more info.