1.1 --- a/common.py Tue Jan 24 19:10:31 2017 +0100
1.2 +++ b/common.py Wed Jan 25 00:00:38 2017 +0100
1.3 @@ -394,9 +394,18 @@
1.4
1.5 name_ref = self.process_structure_node(expr)
1.6
1.7 - # Have the assignment nodes access each item via the sequence API.
1.8 + # Either unpack the items and present them directly to each assignment
1.9 + # node.
1.10 +
1.11 + if isinstance(name_ref, LiteralSequenceRef) and \
1.12 + self.process_literal_sequence_items(n, name_ref):
1.13
1.14 - self.process_assignment_node_items_by_position(n, expr, name_ref)
1.15 + pass
1.16 +
1.17 + # Or have the assignment nodes access each item via the sequence API.
1.18 +
1.19 + else:
1.20 + self.process_assignment_node_items_by_position(n, expr, name_ref)
1.21
1.22 def process_assignment_node_items_by_position(self, n, expr, name_ref):
1.23
1.24 @@ -441,11 +450,31 @@
1.25 """
1.26 Process the given assignment node 'n', obtaining from the given
1.27 'name_ref' the items to be assigned to the assignment targets.
1.28 +
1.29 + Return whether this method was able to process the assignment node as
1.30 + a sequence of direct assignments.
1.31 """
1.32
1.33 if len(n.nodes) == len(name_ref.items):
1.34 - for node, item in zip(n.nodes, name_ref.items):
1.35 - self.process_assignment_node(node, item)
1.36 + assigned_names, count = get_names_from_nodes(n.nodes)
1.37 + accessed_names, _count = get_names_from_nodes(name_ref.items)
1.38 +
1.39 + # Only assign directly between items if all assigned names are
1.40 + # plain names (not attribute assignments), and if the assigned names
1.41 + # do not appear in the accessed names.
1.42 +
1.43 + if len(assigned_names) == count and \
1.44 + not assigned_names.intersection(accessed_names):
1.45 +
1.46 + for node, item in zip(n.nodes, name_ref.items):
1.47 + self.process_assignment_node(node, item)
1.48 +
1.49 + return True
1.50 +
1.51 + # Otherwise, use the position-based mechanism to obtain values.
1.52 +
1.53 + else:
1.54 + return False
1.55 else:
1.56 raise InspectError("In %s, item assignment needing %d items is given %d items." % (
1.57 self.get_namespace_path(), len(n.nodes), len(name_ref.items)))
1.58 @@ -796,6 +825,40 @@
1.59 l.append(arg)
1.60 return l
1.61
1.62 +def get_names_from_nodes(nodes):
1.63 +
1.64 + """
1.65 + Return the names employed in the given 'nodes' along with the number of
1.66 + nodes excluding sequences.
1.67 + """
1.68 +
1.69 + names = set()
1.70 + count = 0
1.71 +
1.72 + for node in nodes:
1.73 +
1.74 + # Add names and count them.
1.75 +
1.76 + if isinstance(node, (compiler.ast.AssName, compiler.ast.Name)):
1.77 + names.add(node.name)
1.78 + count += 1
1.79 +
1.80 + # Add names from sequences and incorporate their counts.
1.81 +
1.82 + elif isinstance(node, (compiler.ast.AssList, compiler.ast.AssTuple,
1.83 + compiler.ast.List, compiler.ast.Set,
1.84 + compiler.ast.Tuple)):
1.85 + _names, _count = get_names_from_nodes(node.nodes)
1.86 + names.update(_names)
1.87 + count += _count
1.88 +
1.89 + # Count non-name, non-sequence nodes.
1.90 +
1.91 + else:
1.92 + count += 1
1.93 +
1.94 + return names, count
1.95 +
1.96 # Result classes.
1.97
1.98 class InstructionSequence:
2.1 --- a/tests/swap.py Tue Jan 24 19:10:31 2017 +0100
2.2 +++ b/tests/swap.py Wed Jan 25 00:00:38 2017 +0100
2.3 @@ -1,10 +1,41 @@
2.4 +# Test attribute accesses with sequence assignments.
2.5 +
2.6 class C:
2.7 a = 1; b = 2; c = 3
2.8
2.9 +# This cannot assign directly...
2.10 +
2.11 print C.a, C.b, C.c # 1 2 3
2.12 C.a, C.b, C.c = C.c, C.b, C.a
2.13 print C.a, C.b, C.c # 3 2 1
2.14
2.15 +# This cannot assign directly...
2.16 +
2.17 D = C
2.18 C.a, C.b, C.c = D.c, D.b, D.a
2.19 print C.a, C.b, C.c # 1 2 3
2.20 +
2.21 +# Test name accesses with sequence assignments.
2.22 +
2.23 +a = 1; b = 2; c = 3
2.24 +
2.25 +# This cannot assign directly...
2.26 +
2.27 +print a, b, c # 1 2 3
2.28 +a, b, c = c, b, a
2.29 +print a, b, c # 3 2 1
2.30 +
2.31 +# This can assign directly...
2.32 +
2.33 +d, e, f = c, b, a
2.34 +print d, e, f # 1 2 3
2.35 +
2.36 +# This can assign directly...
2.37 +
2.38 +a, (b, c) = d, (e, f)
2.39 +print a, b, c # 1 2 3
2.40 +
2.41 +# This cannot assign directly...
2.42 +
2.43 +(c, b), a = (a, b), c
2.44 +print a, b, c # 3 2 1