Skip to content

Commit 3d99d07

Browse files
committed
Fix for dict.viewitems(), dict.iteritems() etc in chained calls.
Fixes #169
1 parent 5650894 commit 3d99d07

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

libmodernize/fixes/fix_dict_six.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,50 @@
33

44
# Local imports
55
from lib2to3 import fixer_util
6+
from lib2to3 import pytree
67
from lib2to3.fixes import fix_dict
78
import libmodernize
89

910

1011
class FixDictSix(fix_dict.FixDict):
1112

12-
def transform_iter(self, method_name, node, base):
13+
def transform_iter(self, node, results):
1314
"""Call six.(iter|view)items() and friends."""
15+
# Make sure six is imported.
1416
libmodernize.touch_import(None, u'six', node)
15-
new_node = [n.clone() for n in base]
16-
new_node[0].prefix = u''
17+
18+
# Copy of self.transform() from lib2to3.fix_dict with some changes to
19+
# use the six.* methods.
20+
21+
head = results['head']
22+
method = results['method'][0] # Extract node for method name
23+
tail = results['tail']
24+
syms = self.syms
25+
method_name = method.value
1726
name = fixer_util.Name(u'six.' + method_name, prefix=node.prefix)
18-
node.replace(fixer_util.Call(name, new_node))
27+
isiter = method_name.startswith(u'iter')
28+
isview = method_name.startswith(u'view')
29+
assert isiter or isview, repr(method)
30+
assert method_name[4:] in (u'keys', u'items', u'values'), repr(method)
31+
head = [n.clone() for n in head]
32+
tail = [n.clone() for n in tail]
33+
special = not tail and self.in_special_context(node, isiter)
34+
new = pytree.Node(syms.power, head)
35+
if not special:
36+
new.prefix = u''
37+
new = fixer_util.Call(name, [new])
38+
if tail:
39+
new = pytree.Node(syms.power, [new] + tail)
40+
new.prefix = node.prefix
41+
return new
1942

2043
def transform(self, node, results):
2144
method = results['method'][0]
2245
method_name = method.value
2346
if method_name in ('keys', 'items', 'values'):
2447
return super(FixDictSix, self).transform(node, results)
2548
else:
26-
return self.transform_iter(method_name, node, results['head'])
49+
return self.transform_iter(node, results)
2750

2851
def in_special_context(self, node, isiter):
2952
# Redefined from parent class to make "for x in d.items()" count as

tests/test_fix_dict_six.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
pass
3636
""")
3737

38+
CHAINED_CALLS = ("""\
39+
(x + y).foo().iter{type}().bar()
40+
""", """\
41+
from __future__ import absolute_import
42+
import six
43+
six.iter{type}((x + y).foo()).bar()
44+
""")
45+
3846

3947
def check_all_types(input, output):
4048
for type_ in TYPES:
@@ -51,3 +59,6 @@ def test_dict_plain():
5159

5260
def test_dict_in_loop():
5361
check_on_input(*DICT_IN_LOOP)
62+
63+
def test_chained_calls():
64+
check_all_types(*CHAINED_CALLS)

0 commit comments

Comments
 (0)