def _get_offsets(func_ast):
for arg in func_ast.args:
start_line, start_col = arg.lineno - 2, arg.col_offset - 1
# horrible hack for http://bugs.python.org/issue31241
if isinstance(arg, (ast.ListComp, ast.GeneratorExp)):
start_col -= 1
yield start_line, start_col
for kw in func_ast.keywords:
yield kw.value.lineno - 2, kw.value.col_offset - len(kw.arg) - 2
python类ListComp()的实例源码
def visit_Call(self, node):
if (
isinstance(node.func, ast.Name) and
node.func.id == 'dict' and
len(node.args) == 1 and
not _has_kwargs(node) and
isinstance(node.args[0], (ast.ListComp, ast.GeneratorExp)) and
isinstance(node.args[0].elt, (ast.Tuple, ast.List)) and
len(node.args[0].elt.elts) == 2
):
arg, = node.args
key = Offset(node.func.lineno, node.func.col_offset)
self.dicts[key] = arg
self.generic_visit(node)
def visit_ListComp(self, node):
# type: (ast.ListComp) -> None
# 'listcomp' is the string literal used by python
# to creating the SymbolTable for the corresponding
# list comp function.
self._handle_comprehension(node, 'listcomp')
def test_listcomp(self):
self._simple_comp(ast.ListComp)
def visit_Call(self, node):
if node.func.id not in GRP_FUNCS:
return node
else:
self.generic_visit(node)
return ast.Call(
func=node.func,
args=[
ast.ListComp(
elt=node.args[0],
generators=[
ast.comprehension(
target=ast.Name(id="datarow", ctx=ast.Store(), lineno=0, col_offset=0),
iter=ast.Name(id="data", ctx=ast.Load(), lineno=0, col_offset=0),
ifs=[],
lineno=0,
col_offset=0
)
],
lineno=0,
col_offset=0,
)
],
keywords=[],
ctx=ast.Load(),
lineno=0,
col_offset=0,
)
def test_listcomp(self):
self._simple_comp(ast.ListComp)
def resolve_attr_id(node):
if isinstance(node, (ast.Attribute, ast.Subscript)):
value_id = None
if isinstance(node.value, (ast.Name, ast.Attribute, ast.Subscript)):
value_id = resolve_attr_id(node.value)
elif isinstance(node.value, ast.Call):
value_id = resolve_attr_id(node.value)
elif isinstance(node.value, ast.Str):
value_id = 'str'
elif isinstance(node.value, ast.Bytes):
value_id = 'bytes'
elif isinstance(node.value, (ast.List, ast.ListComp)):
value_id = 'list'
elif isinstance(node.value, ast.Tuple):
value_id = 'tuple'
elif isinstance(node.value, (ast.Set, ast.SetComp)):
value_id = 'set'
elif isinstance(node.value, (ast.Dict, ast.DictComp)):
value_id = 'dict'
else:
raise SyntaxError(
'unsupport type: {}'.format(ast.dump(node.value))
)
if isinstance(node, ast.Attribute):
return '{}.{}'.format(value_id, node.attr)
elif isinstance(node, ast.Subscript):
slice = None
if isinstance(node.slice.value, ast.Str):
slice = node.slice.value.s
elif isinstance(node.slice.value, ast.Num):
slice = node.slice.value.n
elif isinstance(node.slice.value, ast.Name):
slice = resolve_attr_id(node.slice.value)
return '{}[{}]'.format(value_id, slice)
elif isinstance(node, ast.Call):
return '{}()'.format(resolve_attr_id(node.func))
return node.id
def test_listcomp(self):
self._simple_comp(ast.ListComp)
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
tf_upgrade.py 文件源码
项目:Stacked_LSTMS_Highway_Residual_On_TimeSeries_Datasets
作者: praveendareddy21
项目源码
文件源码
阅读 27
收藏 0
点赞 0
评论 0
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def iter_expr_values(parent, node, child=None):
"""
Yield each value for *node* which can be tracked. Literals are returned as
their evaluated value where as nodes which fail to evaluate to literals are
returned as is.
:param node parent: The parent node used to mark the start of the search path.
:param node node: The target ast.Name node to find literal values for.
:param node child: An optional child node to mark the end of the search path.
"""
child = child or node
success, value = eval_ast.literal_expr(node)
if success:
yield value
return
if not isinstance(node, ast.Name):
return
test_nodes = collections.deque()
def_nodes = get_definition_nodes(parent, node.id, child)
for def_node_idx, def_node in enumerate(def_nodes):
each = False
next_node = (def_nodes[def_node_idx + 1] if len(def_nodes) > def_node_idx + 1 else child)
src_node = None
test_nodes.clear()
if isinstance(def_node, ast.Assign):
test_node = get_expr_value_src_dst(def_node.value, def_node.targets[0], node)
if test_node:
test_nodes.append(test_node)
elif isinstance(def_node, ast.For):
src_node = get_expr_value_src_dst(def_node.iter, def_node.target, node)
each = node_is_child_of_parent(def_node.body, next_node)
elif isinstance(def_node, ast.ListComp):
for generator in def_node.generators:
src_node = get_expr_value_src_dst(generator.iter, generator.target, node)
if src_node:
break
if isinstance(src_node, (ast.List, ast.Tuple, ast.Set)):
test_nodes.extend(src_node.elts if each else src_node.elts[-1:])
for test_node in test_nodes:
success, value = eval_ast.literal_expr(test_node)
if success:
yield value
continue
for value in iter_expr_values(parent, test_node):
success = True
yield value
if success:
continue
for def_node in get_definition_nodes(parent, test_node):
for value in iter_expr_values(parent, def_node):
success = True
yield value
yield test_node
def node_defines_name(node, name):
"""
Check if the specified statement node defines symbol *name*.
:param node: The node to check.
:param name: The symbol name to check.
:return: Whether or not the node defines the symbole specified.
:rtype: bool
"""
if isinstance(name, ast.Name):
name = name.id
if isinstance(node, ast.Assign):
if node_targets_name(node, name):
return True
if isinstance(node.value, (ast.DictComp, ast.ListComp, ast.SetComp)):
return node_defines_name(node.value, name)
elif isinstance(node, ast.ClassDef):
return node.name == name
# these ones all assume the iterable will be executed at least once
elif isinstance(node, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)):
for generator in node.generators:
target = generator.target
if isinstance(target, ast.Name):
if target.id == name:
return True
continue
for child_node in iter_child_expr_nodes(target):
if isinstance(child_node, ast.Name) and child_node.id == name:
return True
return False
elif isinstance(node, ast.ExceptHandler):
if isinstance(node.name, ast.Name):
return node.name.id == name
elif isinstance(node.name, str):
return node.name == name
elif isinstance(node, ast.Expr):
if isinstance(node.value, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)):
return node_defines_name(node.value, name)
elif isinstance(node, ast.For):
return isinstance(node.target, ast.Name) and node.target.id == name
elif isinstance(node, ast.FunctionDef):
return node.name == name
elif isinstance(node, (ast.Import, ast.ImportFrom)):
return next((alias for alias in node.names if (alias.asname or alias.name) == name), None) is not None
return False
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def infer(node, context, solver, from_call=False):
"""Infer the type of a given AST node"""
if isinstance(node, ast.Num):
return infer_numeric(node, solver)
elif isinstance(node, ast.Str):
return solver.z3_types.string
elif (sys.version_info[0] >= 3 and sys.version_info[1] >= 6 and
(isinstance(node, ast.FormattedValue) or isinstance(node, ast.JoinedStr))):
# Formatted strings were introduced in Python 3.6
return solver.z3_types.string
elif isinstance(node, ast.Bytes):
return solver.z3_types.bytes
elif isinstance(node, ast.List):
return infer_list(node, context, solver)
elif isinstance(node, ast.Dict):
return infer_dict(node, context, solver)
elif isinstance(node, ast.Tuple):
return infer_tuple(node, context, solver)
elif isinstance(node, ast.NameConstant):
return infer_name_constant(node, solver)
elif isinstance(node, ast.Set):
return infer_set(node, context, solver)
elif isinstance(node, ast.BinOp):
return infer_binary_operation(node, context, solver)
elif isinstance(node, ast.BoolOp):
return infer_boolean_operation(node, context, solver)
elif isinstance(node, ast.UnaryOp):
return infer_unary_operation(node, context, solver)
elif isinstance(node, ast.IfExp):
return infer_if_expression(node, context, solver)
elif isinstance(node, ast.Subscript):
return infer_subscript(node, context, solver)
elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.Await):
# Await and Async were introduced in Python 3.5
return infer(node.value, context, solver)
elif isinstance(node, ast.Yield):
return infer(node.value, context, solver)
elif isinstance(node, ast.Compare):
return infer_compare(node, context, solver)
elif isinstance(node, ast.Name):
return infer_name(node, context)
elif isinstance(node, ast.ListComp):
return infer_sequence_comprehension(node, solver.z3_types.list, context, solver)
elif isinstance(node, ast.SetComp):
return infer_sequence_comprehension(node, solver.z3_types.set, context, solver)
elif isinstance(node, ast.DictComp):
return infer_dict_comprehension(node, context, solver)
elif isinstance(node, ast.Call):
return infer_func_call(node, context, solver)
elif isinstance(node, ast.Attribute):
return infer_attribute(node, context, from_call, solver)
elif isinstance(node, ast.Lambda):
return _infer_lambda(node, context, solver)
raise NotImplementedError("Inference for expression {} is not implemented yet.".format(type(node).__name__))
def _find_true_position(self, node):
"""Return correct line number and column offset for a given node.
This is necessary mainly because ListComp's location reporting reports
the next token after the list comprehension list opening.
Args:
node: Node for which we wish to know the lineno and col_offset
"""
import re
find_open = re.compile("^\s*(\\[).*$")
find_string_chars = re.compile("['\"]")
if isinstance(node, ast.ListComp):
# Strangely, ast.ListComp returns the col_offset of the first token
# after the '[' token which appears to be a bug. Workaround by
# explicitly finding the real start of the list comprehension.
line = node.lineno
col = node.col_offset
# loop over lines
while 1:
# Reverse the text to and regular expression search for whitespace
text = self._lines[line-1]
reversed_preceding_text = text[:col][::-1]
# First find if a [ can be found with only whitespace between it and
# col.
m = find_open.match(reversed_preceding_text)
if m:
new_col_offset = col - m.start(1) - 1
return line, new_col_offset
else:
if (reversed_preceding_text=="" or
reversed_preceding_text.isspace()):
line = line - 1
prev_line = self._lines[line - 1]
# TODO(aselle):
# this is poor comment detection, but it is good enough for
# cases where the comment does not contain string literal starting/
# ending characters. If ast gave us start and end locations of the
# ast nodes rather than just start, we could use string literal
# node ranges to filter out spurious #'s that appear in string
# literals.
comment_start = prev_line.find("#")
if comment_start == -1:
col = len(prev_line) -1
elif find_string_chars.search(prev_line[comment_start:]) is None:
col = comment_start
else:
return None, None
else:
return None, None
# Most other nodes return proper locations (with notably does not), but
# it is not possible to use that in an argument.
return node.lineno, node.col_offset
def peval_comprehension(state, node, ctx):
accum_cls = {
ast.ListComp: ListAccumulator,
ast.GeneratorExp: GeneratorExpAccumulator,
ast.SetComp: SetAccumulator,
ast.DictComp: DictAccumulator,
}
# variables from generators temporary mask bindings
target_names = set()
for generator in node.generators:
if type(generator.target) == ast.Name:
target_names.add(generator.target.id)
else:
target_names.update([elt.id for elt in generator.target.elts])
# pre-evaluate the expression
elt_bindings = dict(ctx.bindings)
for name in target_names:
if name in elt_bindings:
del elt_bindings[name]
elt_ctx = ctx.update(bindings=elt_bindings)
if type(node) == ast.DictComp:
elt = ast.Tuple(elts=[node.key, node.value])
else:
elt = node.elt
state, new_elt = _peval_expression(state, elt, elt_ctx)
try:
state, container = _peval_comprehension(
state, accum_cls[type(node)], new_elt, node.generators, ctx)
evaluated = True
except CannotEvaluateComprehension:
evaluated = False
if evaluated:
return state, KnownValue(value=container)
else:
state, new_elt = map_reify(state, new_elt)
state, new_generators = _peval_comprehension_generators(state, node.generators, ctx)
if type(node) == ast.DictComp:
key, value = new_elt.elts
return state, replace_fields(node, key=key, value=value, generators=new_generators)
else:
return state, replace_fields(node, elt=new_elt, generators=new_generators)