Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def AssertSourceEquals(self, src_or_tree_1, src_or_tree_2):
# Strip leading "\n"s for convenience
ast1 = self.ToAST(src_or_tree_1)
ast2 = self.ToAST(src_or_tree_2)
src1 = pytd_utils.Print(ast1).strip() + "\n"
src2 = pytd_utils.Print(ast2).strip() + "\n"
# Verify printed versions are the same and ASTs are the same.
ast1 = ast1.Visit(visitors.ClassTypeToNamedType())
ast2 = ast2.Visit(visitors.ClassTypeToNamedType())
if src1 != src2 or not pytd_utils.ASTeq(ast1, ast2):
# Due to differing opinions on the form of debug output, allow an
# environment variable to control what output you want. Set
# PY_UNITTEST_DIFF to get diff output.
if os.getenv("PY_UNITTEST_DIFF"):
self.maxDiff = None # for better diff output (assertMultiLineEqual) # pylint: disable=invalid-name
self.assertMultiLineEqual(src1, src2)
else:
sys.stdout.flush()
sys.stderr.flush()
print("Source files or ASTs differ:", file=sys.stderr)
print("-" * 36, " Actual ", "-" * 36, file=sys.stderr)
def Parse(self, src, name=None, version=None, platform=None):
version = version or self.PYTHON_VERSION
tree = parser.parse_string(
textwrap.dedent(src), name=name, python_version=version,
platform=platform)
tree = tree.Visit(visitors.NamedTypeToClassType())
tree = tree.Visit(visitors.AdjustTypeParameters())
# Convert back to named types for easier testing
tree = tree.Visit(visitors.ClassTypeToNamedType())
tree.Visit(visitors.VerifyVisitor())
return tree
def ToAST(self, src_or_tree):
if isinstance(src_or_tree, six.string_types):
# Put into a canonical form (removes comments, standard indents):
return self.Parse(src_or_tree + "\n")
else: # isinstance(src_or_tree, tuple):
src_or_tree.Visit(visitors.VerifyVisitor())
return src_or_tree
def ApplyVisitorToString(self, data, visitor):
tree = self.Parse(data)
new_tree = tree.Visit(visitor)
return pytd_utils.Print(new_tree)
if len(signatures) == 1:
val = self.signature_to_callable(signatures[0], self.vm)
if (not isinstance(v, abstract.PYTD_FUNCTION_TYPES) or
not self.vm.annotations_util.get_type_parameters(val)):
# This is a workaround to make sure we don't put unexpected type
# parameters in call traces.
return self.value_instance_to_pytd_type(node, val, None, seen, view)
return pytd.NamedType("typing.Callable")
elif isinstance(v, (abstract.ClassMethod, abstract.StaticMethod)):
return self.value_to_pytd_type(node, v.method, seen, view)
elif isinstance(v, (special_builtins.IsInstance,
special_builtins.ClassMethodCallable)):
return pytd.NamedType("typing.Callable")
elif isinstance(v, mixin.Class):
param = self.value_instance_to_pytd_type(node, v, None, seen, view)
return pytd.GenericType(base_type=pytd.NamedType("__builtin__.type"),
parameters=(param,))
elif isinstance(v, abstract.Module):
return pytd.NamedType("__builtin__.module")
elif isinstance(v, abstract.SimpleAbstractValue):
if v.cls:
ret = self.value_instance_to_pytd_type(
node, v.cls, v, seen=seen, view=view)
ret.Visit(visitors.FillInLocalPointers(
{"__builtin__": self.vm.loader.builtins}))
return ret
else:
# We don't know this type's __class__, so return AnythingType to
# indicate that we don't know anything about what this is.
# This happens e.g. for locals / globals, which are returned from the
# code in class declarations.
log.info("Using ? for %s", v.name)
def p_funcdef(self, p):
"""funcdef : decorators DEF NAME LPAREN params RPAREN return raises signature maybe_body"""
_, decorators, _, name, _, params, _, return_type, raises, _, body = p
# TODO(kramm): Output a warning if we already encountered a signature
# with these types (but potentially different argument names)
if name == "__init__" and isinstance(return_type, pytd.AnythingType):
ret = pytd.NamedType("NoneType")
else:
ret = return_type
signature = pytd.Signature(params=tuple(params.required), return_type=ret,
starargs=params.starargs,
starstarargs=params.starstarargs,
exceptions=tuple(raises), template=())
for mutator in body:
try:
signature = signature.Visit(mutator)
except NotImplementedError as e:
make_syntax_error(self, e.message, p)
if not mutator.successful:
make_syntax_error(self, "No parameter named %s" % mutator.name, p)
# TODO(acaceres): if not inside a class, any decorator should be an error
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)
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)
# abstract.PyTDFunction.match_args checks the args for this call.
self.match_args(node, args)
# namedtuple only has one signature
sig, = self.signatures
callargs = {name: var for name, var, _ in sig.signature.iter_args(args)}
# The name of the namedtuple class is the first arg (a Variable)
# We need the actual Variable later, so we'll just return name_var and
# extract the name itself later.
name_var = callargs["typename"]
# The fields are also a Variable, which stores the field names as Variables.
# Extract the list itself, we don't need the wrapper.
fields_var = callargs["field_names"]
fields = abstract_utils.get_atomic_python_constant(fields_var)
# namedtuple fields can be given as a single string, e.g. "a, b, c" or as a
# list [Variable('a'), Variable('b'), Variable('c')].
# We just want a list of strings.
if isinstance(fields, (bytes, six.text_type)):
fields = compat.native_str(fields)
field_names = fields.replace(",", " ").split()
else:
field_names = [abstract_utils.get_atomic_python_constant(f)
for f in fields]
field_names = [compat.native_str(f) for f in field_names]
# namedtuple also takes a "verbose" argument, but we don't care about that.
# rename will take any problematic field names and give them a new name.
# Like the other args, it's stored as a Variable, but we want just a bool.
if callargs.get("rename", None):