Skip to content

Commit 6f98f5b

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix_long_call
2 parents 99c5ac4 + e5b9d5d commit 6f98f5b

15 files changed

+198
-255
lines changed

libmodernize/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,13 @@ def add_future(node, symbol):
6767
def touch_import(package, name, node):
6868
add_future(node, 'absolute_import')
6969
fixer_util.touch_import(package, name, node)
70+
71+
72+
def is_listcomp(node):
73+
return (isinstance(node, Node) and
74+
node.type == syms.atom and
75+
len(node.children) >= 2 and
76+
isinstance(node.children[0], Leaf) and
77+
node.children[0].value == '[' and
78+
isinstance(node.children[-1], Leaf) and
79+
node.children[-1].value == ']')

libmodernize/fixes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
'libmodernize.fixes.fix_basestring',
3232
'libmodernize.fixes.fix_dict_six',
3333
'libmodernize.fixes.fix_filter',
34+
'libmodernize.fixes.fix_imports_six',
3435
'libmodernize.fixes.fix_input_six',
3536
'libmodernize.fixes.fix_int_long_tuple',
3637
'libmodernize.fixes.fix_map',

libmodernize/fixes/fix_filter.py

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,18 @@
22
# Licensed to PSF under a Contributor Agreement.
33
from __future__ import absolute_import
44

5-
from lib2to3 import fixer_base
6-
from lib2to3.fixer_util import Call, Name, in_special_context
7-
from libmodernize import touch_import
5+
from lib2to3.fixes import fix_filter
6+
import libmodernize
87

98

10-
class FixFilter(fixer_base.ConditionalFix):
9+
class FixFilter(fix_filter.FixFilter):
1110

12-
BM_compatible = True
13-
order = "pre"
1411
skip_on = "six.moves.filter"
1512

16-
PATTERN = """
17-
power< 'filter'
18-
trailer< '('
19-
arglist< (
20-
not(argument<any '=' any>) any ','
21-
not(argument<any '=' any>) any
22-
) >
23-
')' >
24-
>
25-
"""
26-
2713
def transform(self, node, results):
28-
if self.should_skip(node):
29-
# Make the fixer idempotent - if six.moves.filter is already imported,
30-
# skip it. should_skip() caches the state the first time we check,
31-
# so it doesn't skip after *we've* added the six.moves import.
32-
return
33-
34-
touch_import(u'six.moves', u'filter', node)
35-
if in_special_context(node):
36-
# The node is somewhere where it only needs to be an iterator,
37-
# e.g. a for loop - don't wrap in list()
38-
return
39-
40-
new = node.clone()
41-
new.prefix = ""
42-
new = Call(Name("list"), [new])
43-
new.prefix = node.prefix
44-
return new
14+
result = super(FixFilter, self).transform(node, results)
15+
if not libmodernize.is_listcomp(result):
16+
# Keep performance improvement from six.moves.filter in iterator
17+
# contexts on Python 2.7.
18+
libmodernize.touch_import(u'six.moves', u'filter', node)
19+
return result

libmodernize/fixes/fix_imports_six.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from lib2to3.fixes import fix_imports
2+
3+
4+
class FixImportsSix(fix_imports.FixImports):
5+
6+
mapping = {
7+
'__builtin__': 'six.moves.builtins',
8+
'_winreg': 'six.moves.winreg',
9+
'BaseHTTPServer': 'six.moves.BaseHTTPServer',
10+
'CGIHTTPServer': 'six.moves.CGIHTTPServer',
11+
'ConfigParser': 'six.moves.configparser',
12+
'copy_reg': 'six.moves.copyreg',
13+
'Cookie': 'six.moves.http_cookies',
14+
'cookielib': 'six.moves.http_cookiejar',
15+
'cPickle': 'six.moves.cPickle',
16+
'Dialog': 'six.moves.tkinter_dialog',
17+
'dummy_thread': 'six.moves._dummy_thread',
18+
# cStringIO.StringIO()
19+
# email.MIMEBase
20+
# email.MIMEMultipart
21+
# email.MIMENonMultipart
22+
# email.MIMEText
23+
'FileDialog': 'six.moves.tkinter_filedialog',
24+
'gdbm': 'six.moves.dbm_gnu',
25+
'htmlentitydefs': 'six.moves.html_entities',
26+
'HTMLParser': 'six.moves.html_parser',
27+
'httplib': 'six.moves.http_client',
28+
# intern()
29+
# itertools.ifilter()
30+
# itertools.ifilterfalse()
31+
# itertools.imap()
32+
# itertools.izip()
33+
# itertools.zip_longest()
34+
# pipes.quote
35+
'Queue': 'six.moves.queue',
36+
# reduce()
37+
# reload()
38+
'repr': 'six.moves.reprlib',
39+
'robotparser': 'six.moves.urllib_robotparser',
40+
'ScrolledText': 'six.moves.tkinter_scrolledtext',
41+
'SimpleDialog': 'six.moves.tkinter_simpledialog',
42+
'SimpleHTTPServer': 'six.moves.SimpleHTTPServer',
43+
'SimpleXMLRPCServer': 'six.moves.xmlrpc_server',
44+
'SocketServer': 'six.moves.socketserver',
45+
'thread': 'six.moves._thread',
46+
'Tix': 'six.moves.tkinter_tix',
47+
'tkColorChooser': 'six.moves.tkinter_colorchooser',
48+
'tkCommonDialog': 'six.moves.tkinter_commondialog',
49+
'Tkconstants': 'six.moves.tkinter_constants',
50+
'Tkdnd': 'six.moves.tkinter_dnd',
51+
'tkFileDialog': 'six.moves.tkinter_filedialog',
52+
'tkFont': 'six.moves.tkinter_font',
53+
'Tkinter': 'six.moves.tkinter',
54+
'tkMessageBox': 'six.moves.tkinter_messagebox',
55+
'tkSimpleDialog': 'six.moves.tkinter_tksimpledialog',
56+
'ttk': 'six.moves.tkinter_ttk',
57+
# urllib
58+
# UserDict.UserDict
59+
# UserList.UserList
60+
# UserString.UserString
61+
'xmlrpclib': 'six.moves.xmlrpc_client',
62+
}

libmodernize/fixes/fix_map.py

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,17 @@
22
# Licensed to PSF under a Contributor Agreement.
33
from __future__ import absolute_import
44

5-
from lib2to3 import fixer_base
6-
from lib2to3.fixer_util import Call, Name, in_special_context
7-
from libmodernize import touch_import
5+
from lib2to3.fixes import fix_map
6+
import libmodernize
87

8+
class FixMap(fix_map.FixMap):
99

10-
class FixMap(fixer_base.ConditionalFix):
11-
12-
BM_compatible = True
13-
order = "pre"
1410
skip_on = "six.moves.map"
1511

16-
PATTERN = """
17-
power< 'map'
18-
trailer< '('
19-
arglist< (
20-
not(argument<any '=' any>) any ','
21-
(not(argument<any '=' any>) any)+
22-
) >
23-
')' >
24-
>
25-
"""
26-
2712
def transform(self, node, results):
28-
if self.should_skip(node):
29-
# Make the fixer idempotent - if six.moves.map is already imported,
30-
# skip it. should_skip() caches the state the first time we check,
31-
# so it doesn't skip after *we've* added the six.moves import.
32-
return
33-
34-
touch_import(u'six.moves', u'map', node)
35-
if in_special_context(node):
36-
# The node is somewhere where it only needs to be an iterator,
37-
# e.g. a for loop - don't wrap in list()
38-
return
39-
40-
new = node.clone()
41-
new.prefix = ""
42-
new = Call(Name("list"), [new])
43-
new.prefix = node.prefix
44-
return new
13+
result = super(FixMap, self).transform(node, results)
14+
if not libmodernize.is_listcomp(result):
15+
# Always use the import even if no change is required so as to have
16+
# improved performance in iterator contexts even on Python 2.7.
17+
libmodernize.touch_import(u'six.moves', u'map', node)
18+
return result

libmodernize/fixes/fix_open.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
import libmodernize
55

66

7-
class FixOpen(fixer_base.ConditionalFix):
7+
class FixOpen(fixer_base.BaseFix):
88

99
BM_compatible = True
10-
order = "pre"
11-
skip_on = "io.open"
12-
10+
# Fixers don't directly stack, so make sure the 'file' case is covered.
1311
PATTERN = """
14-
power< 'open' trailer< '(' any+ ')' > >
12+
power< ('open' | 'file') trailer< '(' any+ ')' > >
1513
"""
1614

1715
def transform(self, node, results):
18-
if self.should_skip(node):
19-
return
2016
libmodernize.touch_import(u'io', u'open', node)

libmodernize/fixes/fix_print.py

Lines changed: 6 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,13 @@
11
# Copyright 2006 Google, Inc. All Rights Reserved.
22
# Licensed to PSF under a Contributor Agreement.
33

4-
"""Fixer for print.
4+
from lib2to3.fixes import fix_print
5+
import libmodernize
56

6-
Change:
7-
"print" into "print()"
8-
"print ..." into "print(...)"
9-
"print(...)" not changed
10-
"print ... ," into "print(..., end=' ')"
11-
"print >>x, ..." into "print(..., file=x)"
127

13-
No changes are applied if print_function is imported from __future__
14-
15-
"""
16-
from __future__ import absolute_import
17-
18-
# Local imports
19-
from lib2to3 import patcomp, pytree, fixer_base
20-
from lib2to3.pgen2 import token
21-
from lib2to3.fixer_util import Name, Call, Comma, String
22-
from libmodernize import add_future
23-
24-
parend_expr = patcomp.compile_pattern(
25-
"""atom< '(' [arith_expr|atom|power|term|STRING|NAME] ')' >"""
26-
)
27-
28-
29-
class FixPrint(fixer_base.BaseFix):
30-
31-
BM_compatible = True
32-
33-
PATTERN = """
34-
simple_stmt< any* bare='print' any* > | print_stmt
35-
"""
8+
class FixPrint(fix_print.FixPrint):
369

3710
def transform(self, node, results):
38-
assert results
39-
40-
bare_print = results.get("bare")
41-
42-
if bare_print:
43-
# Special-case print all by itself.
44-
bare_print.replace(Call(Name(u"print"), [],
45-
prefix=bare_print.prefix))
46-
add_future(node, u'print_function')
47-
return
48-
assert node.children[0] == Name(u"print")
49-
args = node.children[1:]
50-
if len(args) == 1 and parend_expr.match(args[0]):
51-
# We don't want to keep sticking parens around an
52-
# already-parenthesised expression.
53-
return
54-
55-
end = file = None
56-
if args and args[-1] == Comma():
57-
args = args[:-1]
58-
end = " "
59-
if args and args[0] == pytree.Leaf(token.RIGHTSHIFT, u">>"):
60-
assert len(args) >= 2
61-
file = args[1].clone()
62-
args = args[3:] # Strip a possible comma after the file expression
63-
# Now synthesize a print(args, end=..., file=...) node
64-
# (sep is not used).
65-
l_args = [arg.clone() for arg in args]
66-
if l_args:
67-
l_args[0].prefix = u""
68-
if end is not None or file is not None:
69-
if end is not None:
70-
self.add_kwarg(l_args, u"end", String(repr(end)))
71-
if file is not None:
72-
self.add_kwarg(l_args, u"file", file)
73-
n_stmt = Call(Name(u"print"), l_args)
74-
n_stmt.prefix = node.prefix
75-
76-
# Note that there are corner cases where adding this future-import is
77-
# incorrect, for example when the file also has a 'print ()' statement
78-
# that was intended to print "()".
79-
add_future(node, u'print_function')
80-
return n_stmt
81-
82-
def add_kwarg(self, l_nodes, s_kwd, n_expr):
83-
# XXX All this prefix-setting may lose comments (though rarely)
84-
n_expr.prefix = u""
85-
n_argument = pytree.Node(self.syms.argument,
86-
(Name(s_kwd),
87-
pytree.Leaf(token.EQUAL, u"="),
88-
n_expr))
89-
if l_nodes:
90-
l_nodes.append(Comma())
91-
n_argument.prefix = u" "
92-
l_nodes.append(n_argument)
11+
result = super(FixPrint, self).transform(node, results)
12+
libmodernize.add_future(node, u'print_function')
13+
return result

libmodernize/fixes/fix_zip.py

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,16 @@
22
# Licensed to PSF under a Contributor Agreement.
33
from __future__ import absolute_import
44

5-
from lib2to3 import fixer_base
6-
from lib2to3.fixer_util import Name, Call, in_special_context
7-
from libmodernize import touch_import
5+
from lib2to3.fixes import fix_zip
6+
import libmodernize
87

8+
class FixZip(fix_zip.FixZip):
99

10-
class FixZip(fixer_base.ConditionalFix):
11-
12-
BM_compatible = True
13-
order = "pre"
1410
skip_on = "six.moves.zip"
1511

16-
PATTERN = """
17-
power< 'zip'
18-
trailer< '('
19-
( not(arglist | argument<any '=' any>) any* |
20-
arglist < not(argument<any '=' any>) any* > )
21-
')' >
22-
>
23-
"""
24-
2512
def transform(self, node, results):
26-
if self.should_skip(node):
27-
# Make the fixer idempotent - if six.moves.zip is already imported,
28-
# skip it. should_skip() caches the state the first time we check,
29-
# so it doesn't skip after *we've* added the six.moves import.
30-
return
31-
32-
touch_import(u'six.moves', u'zip', node)
33-
if in_special_context(node):
34-
# The node is somewhere where it only needs to be an iterator,
35-
# e.g. a for loop - don't wrap in list()
36-
return
37-
38-
new = node.clone()
39-
new.prefix = ""
40-
new = Call(Name("list"), [new])
41-
new.prefix = node.prefix
42-
return new
13+
result = super(FixZip, self).transform(node, results)
14+
# Always use six.moves.zip so that even Python 2.7 gets performance
15+
# boost from using itertools in iterator contexts.
16+
libmodernize.touch_import(u'six.moves', u'zip', node)
17+
return result

0 commit comments

Comments
 (0)