Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3a2fb14

Browse files
committed
Merged revisions 66453 via svnmerge from
svn+ssh://[email protected]/python/trunk ................ r66453 | benjamin.peterson | 2008-09-13 12:43:19 -0500 (Sat, 13 Sep 2008) | 24 lines Merged revisions 66191,66418,66438,66445 via svnmerge from svn+ssh://[email protected]/sandbox/trunk/2to3/lib2to3 ........ r66191 | benjamin.peterson | 2008-09-03 17:00:52 -0500 (Wed, 03 Sep 2008) | 1 line update the Grammar file after recent syntax changes ........ r66418 | benjamin.peterson | 2008-09-12 18:49:48 -0500 (Fri, 12 Sep 2008) | 1 line a trival fix to get a few more print corner cases #2899 ........ r66438 | benjamin.peterson | 2008-09-12 21:32:30 -0500 (Fri, 12 Sep 2008) | 5 lines add Jack Diederich's fixer for metaclass syntax #2366 my contribution to this was adding a few tests and fixing a few bugs I also reviewed it (Jack is a committer) ........ r66445 | benjamin.peterson | 2008-09-13 10:50:00 -0500 (Sat, 13 Sep 2008) | 1 line add a few more tests concerning int literals and weird spacing ........ ................
1 parent c575c90 commit 3a2fb14

6 files changed

Lines changed: 519 additions & 78 deletions

File tree

Lib/lib2to3/Grammar.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ dictsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
138138

139139
classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
140140

141-
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
141+
arglist: (argument ',')* (argument [',']
142+
|'*' test (',' argument)* [',' '**' test]
143+
|'**' test)
142144
argument: test [comp_for] | test '=' test # Really [keyword '='] test
143145

144146
comp_iter: comp_for | comp_if

Lib/lib2to3/fixes/fix_metaclass.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
"""Fixer for __metaclass__ = X -> (metaclass=X) methods.
2+
3+
The various forms of classef (inherits nothing, inherits once, inherints
4+
many) don't parse the same in the CST so we look at ALL classes for
5+
a __metaclass__ and if we find one normalize the inherits to all be
6+
an arglist.
7+
8+
For one-liner classes ('class X: pass') there is no indent/dedent so
9+
we normalize those into having a suite.
10+
11+
Moving the __metaclass__ into the classdef can also cause the class
12+
body to be empty so there is some special casing for that as well.
13+
14+
This fixer also tries very hard to keep original indenting and spacing
15+
in all those corner cases.
16+
17+
"""
18+
# Author: Jack Diederich
19+
20+
import os
21+
22+
# Local imports
23+
from .. import fixer_base
24+
from ..pygram import token
25+
from ..fixer_util import Name, syms, Node, Leaf
26+
27+
28+
def has_metaclass(parent):
29+
""" we have to check the cls_node without changing it.
30+
There are two possiblities:
31+
1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta')
32+
2) clsdef => simple_stmt => expr_stmt => Leaf('__meta')
33+
"""
34+
for node in parent.children:
35+
if node.type == syms.suite:
36+
return has_metaclass(node)
37+
elif node.type == syms.simple_stmt and node.children:
38+
expr_node = node.children[0]
39+
if expr_node.type == syms.expr_stmt and expr_node.children:
40+
leaf_node = expr_node.children[0]
41+
if leaf_node.value == '__metaclass__':
42+
return True
43+
return False
44+
45+
46+
def fixup_parse_tree(cls_node):
47+
""" one-line classes don't get a suite in the parse tree so we add
48+
one to normalize the tree
49+
"""
50+
for node in cls_node.children:
51+
if node.type == syms.suite:
52+
# already in the prefered format, do nothing
53+
return
54+
55+
# !%@#! oneliners have no suite node, we have to fake one up
56+
for i, node in enumerate(cls_node.children):
57+
if node.type == token.COLON:
58+
break
59+
else:
60+
raise ValueError("No class suite and no ':'!")
61+
62+
# move everything into a suite node
63+
suite = Node(syms.suite, [])
64+
while cls_node.children[i+1:]:
65+
move_node = cls_node.children[i+1]
66+
suite.append_child(move_node.clone())
67+
move_node.remove()
68+
cls_node.append_child(suite)
69+
node = suite
70+
71+
72+
def fixup_simple_stmt(parent, i, stmt_node):
73+
""" if there is a semi-colon all the parts count as part of the same
74+
simple_stmt. We just want the __metaclass__ part so we move
75+
everything efter the semi-colon into its own simple_stmt node
76+
"""
77+
for semi_ind, node in enumerate(stmt_node.children):
78+
if node.type == token.SEMI: # *sigh*
79+
break
80+
else:
81+
return
82+
83+
node.remove() # kill the semicolon
84+
new_expr = Node(syms.expr_stmt, [])
85+
new_stmt = Node(syms.simple_stmt, [new_expr])
86+
while stmt_node.children[semi_ind:]:
87+
move_node = stmt_node.children[semi_ind]
88+
new_expr.append_child(move_node.clone())
89+
move_node.remove()
90+
parent.insert_child(i, new_stmt)
91+
new_leaf1 = new_stmt.children[0].children[0]
92+
old_leaf1 = stmt_node.children[0].children[0]
93+
new_leaf1.set_prefix(old_leaf1.get_prefix())
94+
95+
96+
def remove_trailing_newline(node):
97+
if node.children and node.children[-1].type == token.NEWLINE:
98+
node.children[-1].remove()
99+
100+
101+
def find_metas(cls_node):
102+
# find the suite node (Mmm, sweet nodes)
103+
for node in cls_node.children:
104+
if node.type == syms.suite:
105+
break
106+
else:
107+
raise ValueError("No class suite!")
108+
109+
# look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ]
110+
for i, simple_node in list(enumerate(node.children)):
111+
if simple_node.type == syms.simple_stmt and simple_node.children:
112+
expr_node = simple_node.children[0]
113+
if expr_node.type == syms.expr_stmt and expr_node.children:
114+
leaf_node = expr_node.children[0]
115+
if leaf_node.value == '__metaclass__':
116+
fixup_simple_stmt(node, i, simple_node)
117+
remove_trailing_newline(simple_node)
118+
yield (node, i, simple_node)
119+
120+
121+
def fixup_indent(suite):
122+
""" If an INDENT is followed by a thing with a prefix then nuke the prefix
123+
Otherwise we get in trouble when removing __metaclass__ at suite start
124+
"""
125+
kids = suite.children[::-1]
126+
# find the first indent
127+
while kids:
128+
node = kids.pop()
129+
if node.type == token.INDENT:
130+
break
131+
132+
# find the first Leaf
133+
while kids:
134+
node = kids.pop()
135+
if isinstance(node, Leaf) and node.type != token.DEDENT:
136+
if node.prefix:
137+
node.set_prefix('')
138+
return
139+
else:
140+
kids.extend(node.children[::-1])
141+
142+
143+
class FixMetaclass(fixer_base.BaseFix):
144+
145+
PATTERN = """
146+
classdef<any*>
147+
"""
148+
149+
def transform(self, node, results):
150+
if not has_metaclass(node):
151+
return node
152+
153+
fixup_parse_tree(node)
154+
155+
# find metaclasses, keep the last one
156+
last_metaclass = None
157+
for suite, i, stmt in find_metas(node):
158+
last_metaclass = stmt
159+
stmt.remove()
160+
161+
text_type = node.children[0].type # always Leaf(nnn, 'class')
162+
163+
# figure out what kind of classdef we have
164+
if len(node.children) == 7:
165+
# Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite])
166+
# 0 1 2 3 4 5 6
167+
if node.children[3].type == syms.arglist:
168+
arglist = node.children[3]
169+
# Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite])
170+
elif isinstance(node.children[3], Leaf):
171+
parent = node.children[3].clone()
172+
arglist = Node(syms.arglist, [parent])
173+
node.set_child(3, arglist)
174+
else:
175+
raise ValueError("Unexpected class inheritance arglist")
176+
elif len(node.children) == 6:
177+
# Node(classdef, ['class', 'name', '(', ')', ':', suite])
178+
# 0 1 2 3 4 5
179+
arglist = Node(syms.arglist, [])
180+
node.insert_child(3, arglist)
181+
elif len(node.children) == 4:
182+
# Node(classdef, ['class', 'name', ':', suite])
183+
# 0 1 2 3
184+
arglist = Node(syms.arglist, [])
185+
node.insert_child(2, Leaf(token.RPAR, ')'))
186+
node.insert_child(2, arglist)
187+
node.insert_child(2, Leaf(token.LPAR, '('))
188+
else:
189+
raise ValueError("Unexpected class definition")
190+
191+
# now stick the metaclass in the arglist
192+
meta_txt = last_metaclass.children[0].children[0]
193+
meta_txt.value = 'metaclass'
194+
orig_meta_prefix = meta_txt.get_prefix()
195+
196+
if arglist.children:
197+
arglist.append_child(Leaf(token.COMMA, ','))
198+
meta_txt.set_prefix(' ')
199+
else:
200+
meta_txt.set_prefix('')
201+
202+
# compact the expression "metaclass = Meta" -> "metaclass=Meta"
203+
expr_stmt = last_metaclass.children[0]
204+
assert expr_stmt.type == syms.expr_stmt
205+
expr_stmt.children[1].set_prefix('')
206+
expr_stmt.children[2].set_prefix('')
207+
208+
arglist.append_child(last_metaclass)
209+
210+
fixup_indent(suite)
211+
212+
# check for empty suite
213+
if not suite.children:
214+
# one-liner that was just __metaclass_
215+
suite.remove()
216+
pass_leaf = Leaf(text_type, 'pass')
217+
pass_leaf.set_prefix(orig_meta_prefix)
218+
node.append_child(pass_leaf)
219+
node.append_child(Leaf(token.NEWLINE, os.linesep))
220+
221+
elif len(suite.children) > 1 and \
222+
(suite.children[-2].type == token.INDENT and
223+
suite.children[-1].type == token.DEDENT):
224+
# there was only one line in the class body and it was __metaclass__
225+
pass_leaf = Leaf(text_type, 'pass')
226+
suite.insert_child(-1, pass_leaf)
227+
suite.insert_child(-1, Leaf(token.NEWLINE, os.linesep))

Lib/lib2to3/fixes/fix_print.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
class FixPrint(fixer_base.ConditionalFix):
3030

3131
PATTERN = """
32-
simple_stmt< bare='print' any > | print_stmt
32+
simple_stmt< any* bare='print' any* > | print_stmt
3333
"""
3434

3535
skip_on = '__future__.print_function'

0 commit comments

Comments
 (0)