def is_special_target(right: ProperType) -> bool: """Whitelist some special cases for use in isinstance() with improper types.""" if isinstance(right, CallableType) and right.is_type_obj(): if right.type_object().fullname() == 'builtins.tuple': # Used with Union[Type, Tuple[Type, ...]]. return True if right.type_object().fullname() in ('mypy.types.Type', 'mypy.types.ProperType', 'mypy.types.TypeAliasType'): # Special case: things like assert isinstance(typ, ProperType) are always OK. return True if right.type_object().fullname() in ('mypy.types.UnboundType', 'mypy.types.TypeVarType', 'mypy.types.RawExpressionType', 'mypy.types.EllipsisType', 'mypy.types.StarType', 'mypy.types.TypeList', 'mypy.types.CallableArgument', 'mypy.types.PartialType', 'mypy.types.ErasedType'): # Special case: these are not valid targets for a type alias and thus safe. # TODO: introduce a SyntheticType base to simplify this? return True elif isinstance(right, TupleType): return all(is_special_target(t) for t in get_proper_types(right.items)) return False
def is_dangerous_target(typ: ProperType) -> bool: """Is this a dangerous target (right argument) for an isinstance() check?""" if isinstance(typ, TupleType): return any(is_dangerous_target(get_proper_type(t)) for t in typ.items) if isinstance(typ, CallableType) and typ.is_type_obj(): return typ.type_object().has_base('mypy.types.Type') return False
def _type_object_overlap(left: ProperType, right: ProperType) -> bool: """Special cases for type object types overlaps.""" # TODO: these checks are a bit in gray area, adjust if they cause problems. # 1. Type[C] vs Callable[..., C], where the latter is class object. if isinstance(left, TypeType) and isinstance(right, CallableType) and right.is_type_obj(): return _is_overlapping_types(left.item, right.ret_type) # 2. Type[C] vs Meta, where Meta is a metaclass for C. if (isinstance(left, TypeType) and isinstance(left.item, Instance) and isinstance(right, Instance)): left_meta = left.item.type.metaclass_type if left_meta is not None: return _is_overlapping_types(left_meta, right) # builtins.type (default metaclass) overlaps with all metaclasses return right.type.has_base('builtins.type') # 3. Callable[..., C] vs Meta is considered below, when we switch to fallbacks. return False
def add_operator_method_dependency_for_type(self, typ: ProperType, method: str) -> None: # Note that operator methods can't be (non-metaclass) methods of type objects # (that is, TypeType objects or Callables representing a type). if isinstance(typ, TypeVarType): typ = get_proper_type(typ.upper_bound) if isinstance(typ, TupleType): typ = typ.partial_fallback if isinstance(typ, Instance): trigger = make_trigger(typ.type.fullname + '.' + method) self.add_dependency(trigger) elif isinstance(typ, UnionType): for item in typ.items: self.add_operator_method_dependency_for_type(get_proper_type(item), method) elif isinstance(typ, FunctionLike) and typ.is_type_obj(): self.add_operator_method_dependency_for_type(typ.fallback, method) elif isinstance(typ, TypeType): if isinstance(typ.item, Instance) and typ.item.type.metaclass_type is not None: self.add_operator_method_dependency_for_type(typ.item.type.metaclass_type, method)