Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def _create_module(self, ast):
data = (ast.constants + ast.type_params + ast.classes +
ast.functions + ast.aliases)
members = {val.name.rsplit(".")[-1]: val for val in data}
return abstract.Module(self.vm, ast.name, members, ast)
new_template = range(instance.tuple_length)
if template:
assert len(template) == 1 and template[0] == abstract_utils.T, template
else:
# We have a recursive type. By erasing the instance and value
# information, we'll return Any for all of the tuple elements.
v = instance = None
template = new_template
if instance is None and isinstance(v, abstract.ParameterizedClass):
return [self.value_instance_to_pytd_type(
node, v.get_formal_type_parameter(t), None, seen, view)
for t in template]
elif isinstance(instance, abstract.SimpleAbstractValue):
type_arguments = []
for t in template:
if isinstance(instance, abstract.Tuple):
param_values = self._get_values(node, instance.pyval[t], view)
elif instance.has_instance_type_parameter(t):
param_values = self._get_values(
node, instance.get_instance_type_parameter(t), view)
elif isinstance(v, abstract.CallableClass):
param_values = v.get_formal_type_parameter(t).instantiate(
node or self.vm.root_cfg_node).data
else:
param_values = [self.vm.convert.unsolvable]
if (param_values == [self.vm.convert.unsolvable] and
isinstance(v, abstract.ParameterizedClass) and
not self.vm.annotations_util.get_type_parameters(
v.get_formal_type_parameter(t))):
# When the instance's parameter value is unsolvable, we can get a
# more precise type from the class. Note that we need to be careful
# not to introduce unbound type parameters.
assert left is other_type.base_cls
left = other_type
for type_param in left.template:
class_param = other_type.get_formal_type_parameter(type_param.name)
instance_param = instance.get_instance_type_parameter(
type_param.full_name, node)
instance_type_param = left.get_formal_type_parameter(type_param.name)
if (not instance_param.bindings and isinstance(
instance_type_param, abstract.TypeParameter) and
instance_type_param.name != type_param.name):
# This type parameter was renamed!
instance_param = instance.get_instance_type_parameter(
type_param.full_name, node)
if instance_param.bindings and instance_param not in view:
binding, = instance_param.bindings
assert isinstance(binding.data, abstract.Unsolvable)
view = view.copy()
view[instance_param] = binding
subst = self.match_var_against_type(instance_param, class_param,
subst, node, view)
if subst is None:
return None
return subst
"""Base class for module overlays."""
from pytype import abstract
from pytype import datatypes
class Overlay(abstract.Module):
"""A layer between pytype and a module's pytd definition.
An overlay pretends to be a module, but provides members that generate extra
typing information that cannot be expressed in a pytd file. For example,
collections.namedtuple is a factory method that generates class definitions
at runtime. An overlay is needed for Pytype to generate these classes.
An Overlay will typically import its underlying module in its __init__, e.g.
by calling vm.loader.import_name(). Due to this, Overlays should only be used
when their underlying module is imported by the Python script being analyzed!
A subclass of Overlay should have an __init__ with the signature:
def __init__(self, vm)
Attributes:
real_module: An abstract.Module wrapping the AST for the underlying module.
"""
def _get_value_info(self, inner, ellipses):
if isinstance(inner[0], list):
template = (list(moves.range(len(inner[0]))) +
[t.name for t in self.base_cls.template])
combined_args = self.vm.merge_values(inner[0])
inner = tuple(inner[0]) + (combined_args,) + inner[1:]
self.vm.errorlog.invalid_ellipses(self.vm.frames, ellipses, self.name)
return template, inner, abstract.CallableClass
else:
# An ellipsis may take the place of the ARGS list.
return super(Callable, self)._get_value_info(
inner, ellipses, allowed_ellipses={0})
def _process_base_class(self, node, base):
"""Process a base class for InterpreterClass creation."""
new_base = self.program.NewVariable()
for b in base.bindings:
base_val = b.data
if isinstance(b.data, abstract.AnnotationContainer):
base_val = base_val.base_cls
# A class like `class Foo(List["Foo"])` would lead to infinite recursion
# when instantiated because we attempt to recursively instantiate its
# parameters, so we replace any late annotations with Any.
# TODO(rechen): only replace the current class's name. We should keep
# other late annotations in order to support things like:
# class Foo(List["Bar"]): ...
# class Bar: ...
base_val = self.annotations_util.remove_late_annotations(base_val)
if isinstance(base_val, abstract.Union):
# Union[A,B,...] is a valid base class, but we need to flatten it into a
# single base variable.
for o in base_val.options:
new_base.AddBinding(o, {b}, node)
else:
new_base.AddBinding(base_val, {b}, node)
Called after the instance has been successfully matched against a
formal type to do any remaining matching special to the type.
Args:
left: The instance type, which may be different from instance.cls
depending on where in the mro the match happened.
instance: The instance.
other_type: The formal type that was successfully matched against.
subst: The current type parameter assignment.
node: The current CFG node.
view: The current mapping of Variable to Value.
Returns:
A new type parameter assignment if the matching succeeded, None otherwise.
"""
if (isinstance(left, abstract.TupleClass) or
isinstance(instance, abstract.Tuple) or
isinstance(other_type, abstract.TupleClass)):
return self._match_heterogeneous_tuple_instance(
left, instance, other_type, subst, node, view)
elif (isinstance(left, abstract.CallableClass) or
isinstance(other_type, abstract.CallableClass)):
return self._match_callable_instance(
left, instance, other_type, subst, node, view)
return self._match_maybe_parameterized_instance(
left, instance, other_type, subst, node, view)
def match_from_mro(self, left, other_type, allow_compat_builtins=True):
"""Checks a type's MRO for a match for a formal type.
Args:
left: The type.
other_type: The formal type.
allow_compat_builtins: Whether to allow compatible builtins to match -
e.g., int against float.
Returns:
The match, if any, None otherwise.
"""
for base in left.mro:
if isinstance(base, abstract.ParameterizedClass):
base_cls = base.base_cls
else:
base_cls = base
if isinstance(base_cls, mixin.Class):
if other_type.full_name == base_cls.full_name or (
isinstance(other_type, abstract.ParameterizedClass) and
other_type.base_cls is base_cls) or (allow_compat_builtins and (
(base_cls.full_name,
other_type.full_name) in _COMPATIBLE_BUILTINS)):
return base
elif isinstance(base_cls, abstract.AMBIGUOUS):
# Note that this is a different logic than in pytd/type_match.py, which
# assumes that ambiguous base classes never match, to keep the list of
# types from exploding. Here, however, we want an instance of, say,
# "class Foo(Any)" to match against everything.
return base_cls
allow_noreturn: Whether typing.NoReturn is allowed in the return type.
Returns:
A tuple (CFGNode, Variable). The Variable is the return value.
Raises:
DictKeyMissing: if we retrieved a nonexistent key from a dict and
fallback_to_unsolvable is False.
FailedFunctionCall: if the call fails and fallback_to_unsolvable is False.
"""
assert funcu.bindings
result = self.program.NewVariable()
nodes = []
error = None
has_noreturn = False
for funcv in funcu.bindings:
func = funcv.data
assert isinstance(func, abstract.AtomicAbstractValue), type(func)
one_result = None
try:
new_node, one_result = func.call(node, funcv, args)
except (function.DictKeyMissing, function.FailedFunctionCall) as e:
if e > error:
error = e
else:
if self.convert.no_return in one_result.data:
if allow_noreturn:
# Make sure NoReturn was the only thing returned.
assert len(one_result.data) == 1
has_noreturn = True
else:
for b in one_result.bindings:
if b.data != self.convert.no_return:
result.PasteBinding(b)
# For the latter case, it will be used in byte code `STORE_ANNOTATION`
# to store the `NoReturn` annotation in a dict.
return subst if left == other_type else None
elif isinstance(other_type, mixin.Class):
# Accumulate substitutions in "subst", or break in case of error:
return self._match_type_against_type(left, other_type, subst, node, view)
elif isinstance(other_type, abstract.Union):
matched = False
for t in other_type.options:
new_subst = self._match_value_against_type(value, t, subst, node, view)
if new_subst is not None:
matched = True
subst = new_subst
return subst if matched else None
elif (isinstance(other_type, (abstract.Unknown, abstract.Unsolvable)) or
isinstance(left, (abstract.Unknown, abstract.Unsolvable))):
# We can match anything against unknown types, and unknown types against
# anything.
# TODO(kramm): Do we want to record what we matched them against?
assert not isinstance(other_type, abstract.ParameterizedClass)
return subst
elif isinstance(other_type, abstract.Empty):
return self._match_type_against_type(left, other_type, subst, node, view)
else:
log.error("Invalid type: %s", type(other_type))
return None