Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# 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):
rename = abstract_utils.get_atomic_python_constant(callargs["rename"])
else:
rename = False
return name_var, field_names, rename
# 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):
rename = abstract_utils.get_atomic_python_constant(callargs["rename"])
else:
rename = False
return name_var, field_names, rename
def starargs_as_tuple(self, node, vm):
try:
args = self.starargs and abstract_utils.get_atomic_python_constant(
self.starargs, tuple)
except abstract_utils.ConversionError:
args = None
if not args:
return args
return tuple(var if var.bindings else vm.convert.empty.to_variable(node)
for var in args)
def _get_extra_function_args_3_6(self, state, arg):
"""Get function annotations and defaults from the stack (Python3.6+)."""
free_vars = None
pos_defaults = ()
kw_defaults = {}
annot = {}
if arg & loadmarshal.MAKE_FUNCTION_HAS_FREE_VARS:
state, free_vars = state.pop()
if arg & loadmarshal.MAKE_FUNCTION_HAS_ANNOTATIONS:
state, packed_annot = state.pop()
annot = abstract_utils.get_atomic_python_constant(packed_annot, dict)
for k in annot.keys():
annot[k] = self.annotations_util.convert_function_type_annotation(
k, annot[k])
if arg & loadmarshal.MAKE_FUNCTION_HAS_KW_DEFAULTS:
state, packed_kw_def = state.pop()
kw_defaults = abstract_utils.get_atomic_python_constant(
packed_kw_def, dict)
if arg & loadmarshal.MAKE_FUNCTION_HAS_POS_DEFAULTS:
state, packed_pos_def = state.pop()
pos_defaults = abstract_utils.get_atomic_python_constant(
packed_pos_def, tuple)
annot = self.annotations_util.convert_annotations_list(
state.node, annot.items())
return state, pos_defaults, kw_defaults, annot, free_vars
def make_class(self, node, f_locals):
f_locals = abstract_utils.get_atomic_python_constant(f_locals)
# retrieve __qualname__ to get the name of class
name = f_locals["__qualname__"]
# retrieve __annotations__ to get the dict
# with key-value pair of (variable, type)
anno = f_locals.get("__annotations__", {})
if anno:
anno = abstract_utils.get_atomic_value(anno)
# assemble the arguments that are compatible with NamedTupleFuncBuilder.call
field_list = []
defaults = []
for k, v in anno.items():
if k in f_locals:
defaults.append(f_locals.get(k))
# TODO(ahxun): check if the value matches the declared type
def starstarargs_as_dict(self):
try:
args = self.starstarargs and abstract_utils.get_atomic_python_constant(
self.starstarargs, dict)
except abstract_utils.ConversionError:
args = None
return args
# The way arguments are put on the stack changed in python 3.6:
# https://github.com/python/cpython/blob/3.5/Python/ceval.c#L4712
# https://github.com/python/cpython/blob/3.6/Python/ceval.c#L4806
if self.python_version < (3, 6):
num_kw, num_pos = divmod(num, 256)
# TODO(kramm): Can we omit creating this Dict if num_kw=0?
for _ in range(num_kw):
state, (key, val) = state.popn(2)
namedargs.setitem_slot(state.node, key, val)
state, posargs = state.popn(num_pos)
else:
state, args = state.popn(num)
if starstarargs:
kwnames = abstract_utils.get_atomic_python_constant(starstarargs, tuple)
n = len(args) - len(kwnames)
for key, arg in zip(kwnames, args[n:]):
namedargs.setitem_slot(state.node, key, arg)
posargs = args[0:n]
starstarargs = None
else:
posargs = args
state, func = state.pop()
state, ret = self.call_function_with_state(
state, func, posargs, namedargs, starargs, starstarargs)
return state.push(ret)
def _make_function(self, name, node, code, globs, defaults, kw_defaults,
closure=None, annotations=None):
"""Create a function or closure given the arguments."""
if closure:
closure = tuple(
c for c in abstract_utils.get_atomic_python_constant(closure))
log.info("closure: %r", closure)
if not name:
name = abstract_utils.get_atomic_python_constant(code).co_name
if not name:
name = ""
val = abstract.InterpreterFunction.make(
name, code=abstract_utils.get_atomic_python_constant(code),
f_locals=self.frame.f_locals, f_globals=globs,
defaults=defaults, kw_defaults=kw_defaults,
closure=closure, annotations=annotations, vm=self)
# TODO(ampere): What else needs to be an origin in this case? Probably stuff
# in closure.
var = self.program.NewVariable()
var.AddBinding(val, code.bindings, node)
if val.signature.annotations:
self.functions_type_params_check.append((val, self.frame.current_opcode))
def _getargs(self, node, args):
self.match_args(node, args)
sig, = self.signatures
callargs = {name: var for name, var, _ in sig.signature.iter_args(args)}
# typing.NamedTuple doesn't support rename or verbose
name_var = callargs["typename"]
fields_var = callargs["fields"]
fields = abstract_utils.get_atomic_python_constant(fields_var)
if isinstance(fields, six.string_types):
# Since str matches Sequence, we have to manually check for it.
raise function.WrongArgTypes(
sig.signature, args, self.vm, self._fields_param)
# The fields is a list of tuples, so we need to deeply unwrap them.
fields = [abstract_utils.get_atomic_python_constant(t) for t in fields]
# We need the actual string for the field names and the AtomicAbstractValue
# for the field types.
names = []
types = []
for field in fields:
if isinstance(field, six.string_types):
# Since str matches Sequence, we have to manually check for it.
raise function.WrongArgTypes(
sig.signature, args, self.vm, self._fields_param)
if (len(field) != 2 or
any(not self._is_str_instance(v) for v in field[0].data)):
# Note that we don't need to check field[1] because both 'str'
# (forward reference) and 'type' are valid for it.
raise function.WrongArgTypes(
sig.signature, args, self.vm, self._fields_param)
name, typ = field
def byte_MAKE_FUNCTION(self, state, op):
"""Create a function and push it onto the stack."""
if self.PY2:
name = None
else:
assert self.PY3
state, name_var = state.pop()
name = abstract_utils.get_atomic_python_constant(name_var)
state, code = state.pop()
if self.python_version >= (3, 6):
get_args = self._get_extra_function_args_3_6
else:
get_args = self._get_extra_function_args
state, defaults, kw_defaults, annot, free_vars = get_args(state, op.arg)
# TODO(dbaum): Add support for per-arg type comments.
# TODO(dbaum): Add support for variable type comments.
globs = self.get_globals_dict()
fn = self._make_function(name, state.node, code, globs, defaults,
kw_defaults, annotations=annot, closure=free_vars)
self._process_function_type_comment(state.node, op, fn.data[0])
self.trace_opcode(op, name, fn)
self.trace_functiondef(fn)
return state.push(fn)