Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def _to_pytd(datum, loader, ast):
if not datum:
return pytd.AnythingType()
t = pytd_utils.JoinTypes(v.to_type() for v in datum).Visit(
visitors.RemoveUnknownClasses())
return loader.resolve_type(t, ast)
if (len(options) > 1 and
not all(isinstance(o, abstract.FUNCTION_TYPES) for o in options)):
# It's ambiguous whether this is a type, a function or something
# else, so encode it as a constant.
combined_types = pytd_utils.JoinTypes(t.to_type(self.exitpoint)
for t in options)
data.append(pytd.Constant(name, combined_types))
elif options:
for option in options:
try:
d = option.to_pytd_def(self.exitpoint, name) # Deep definition
except NotImplementedError:
d = option.to_type(self.exitpoint) # Type only
if isinstance(d, pytd.NothingType):
if isinstance(option, abstract.Empty):
d = pytd.AnythingType()
else:
assert isinstance(option, typing_overlay.NoReturn)
if isinstance(d, pytd.Type) and not isinstance(d, pytd.TypeParameter):
data.append(pytd.Constant(name, d))
else:
data.append(d)
else:
log.error("No visible options for %s", name)
data.append(pytd.Constant(name, pytd.AnythingType()))
return pytd_utils.WrapTypeDeclUnit("inferred", data)
seen = set()
new_types = []
while queue:
t = queue.popleft()
if isinstance(t, pytd.UnionType):
queue.extendleft(reversed(t.type_list))
elif isinstance(t, pytd.NothingType):
pass
elif t not in seen:
new_types.append(t)
seen.add(t)
if len(new_types) == 1:
return new_types.pop()
elif any(isinstance(t, pytd.AnythingType) for t in new_types):
return pytd.AnythingType()
elif new_types:
return pytd.UnionType(tuple(new_types)) # tuple() to make unions hashable
else:
return pytd.NothingType()
is_abstract = name_to_is_abstract[name]
is_coroutine = name_to_is_coroutine[name]
if name == "__new__" or decorator == "staticmethod":
kind = pytd.STATICMETHOD
elif decorator == "classmethod":
kind = pytd.CLASSMETHOD
elif _is_property(name, decorator, sigs[0]):
kind = pytd.PROPERTY
# If we have only setters and/or deleters, replace them with a single
# method foo(...) -> Any, so that we infer a constant `foo: Any` even if
# the original method signatures are all `foo(...) -> None`. (If we have a
# getter we use its return type, but in the absence of a getter we want to
# fall back on Any since we cannot say anything about what the setter sets
# the type of foo to.)
if decorator.endswith(".setter") or decorator.endswith(".deleter"):
sigs = [sigs[0].Replace(return_type=pytd.AnythingType())]
else:
kind = pytd.METHOD
flags = 0
if is_abstract:
flags |= pytd.Function.IS_ABSTRACT
if is_coroutine:
flags |= pytd.Function.IS_COROUTINE
methods.append(pytd.Function(name, tuple(sigs), kind, flags))
return methods
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.
arg = self.value_instance_to_pytd_type(
node, v.get_formal_type_parameter(t), None, seen, view)
else:
arg = pytd_utils.JoinTypes(self.value_to_pytd_type(
node, p, seen, view) for p in param_values)
type_arguments.append(arg)
return type_arguments
else:
return [pytd.AnythingType() for _ in template]
for p in parameters:
if self._is_none(p):
literal_parameters.append(p)
elif isinstance(p, pytd.NamedType) and p.name not in ("True", "False"):
# TODO(b/123775699): support enums.
literal_parameters.append(pytd.AnythingType())
else:
literal_parameters.append(pytd.Literal(p))
return pytd_utils.JoinTypes(literal_parameters)
elif any(isinstance(p, (int, str)) for p in parameters):
parameters = ", ".join(
str(p) if isinstance(p, (int, str)) else "_" for p in parameters)
raise ParseError(
"%s[%s] not supported" % (pytd_utils.Print(base_type), parameters))
elif self._is_any(base_type):
return pytd.AnythingType()
elif len(parameters) == 2 and parameters[-1] is self.ELLIPSIS and (
not self._is_callable_base_type(base_type)):
element_type = parameters[0]
if element_type is self.ELLIPSIS:
raise ParseError("[..., ...] not supported")
return pytd.GenericType(base_type=base_type, parameters=(element_type,))
else:
parameters = tuple(pytd.AnythingType() if p is self.ELLIPSIS else p
for p in parameters)
if self._is_tuple_base_type(base_type):
return self._heterogeneous_tuple(base_type, parameters)
elif (self._is_callable_base_type(base_type) and
self._is_heterogeneous_tuple(parameters[0])):
if len(parameters) > 2:
raise ParseError(
"Expected 2 parameters to Callable, got %d" % len(parameters))
return item
elif isinstance(item, Class):
return ClassType(item.name, item)
elif isinstance(item, Function):
return FunctionType(item.name, item)
elif isinstance(item, Constant):
if allow_constants:
# TODO(kramm): This is wrong. It would be better if we resolve Alias
# in the same way we resolve NamedType.
return item
else:
# TODO(kramm): We should be more picky here. In particular, we shouldn't
# allow pyi like this:
# object = ... # type: int
# def f(x: object) -> Any
return AnythingType()
elif isinstance(item, Alias):
return item.type
else:
raise NotImplementedError("Can't convert %s: %s" % (type(item), item))
def _normal_param(name, param_type, default, kwonly):
"""Return a pytd.Parameter object for a normal argument."""
if default is not None:
default_type = _type_for_default(default)
if default_type == pytd.NamedType("NoneType"):
if param_type is not None:
param_type = pytd.UnionType((param_type, default_type))
elif param_type is None:
param_type = default_type
if param_type is None:
param_type = pytd.AnythingType()
optional = default is not None
return pytd.Parameter(name, param_type, kwonly, optional, None)
def VisitUnionType(self, _):
return pytd.AnythingType()
for name, member in v.members.items():
if name in CLASS_LEVEL_IGNORE:
continue
for value, is_annotation in self.get_annotated_values(
node, name, member, annots):
if is_annotation:
constants[name].add_type(value)
continue
if isinstance(value, special_builtins.PropertyInstance):
# For simplicity, output properties as constants, since our parser
# turns them into constants anyway.
if value.fget:
for typ in self._function_to_return_types(node, value.fget):
constants[name].add_type(typ)
else:
constants[name].add_type(pytd.AnythingType())
elif isinstance(value, special_builtins.StaticMethodInstance):
try:
methods[name] = self._static_method_to_def(
node, value, name, pytd.STATICMETHOD)
except abstract_utils.ConversionError:
constants[name].add_type(pytd.AnythingType())
elif isinstance(value, special_builtins.ClassMethodInstance):
try:
methods[name] = self._class_method_to_def(
node, value, name, pytd.CLASSMETHOD)
except abstract_utils.ConversionError:
constants[name].add_type(pytd.AnythingType())
elif isinstance(value, abstract.Function):
# TODO(rechen): Removing mutations altogether won't work for generic
# classes. To support those, we'll need to change the mutated type's
# base to the current class, rename aliased type parameters, and