Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/libfuturize/fixes/fix_metaclass.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 # coding: utf-8 | |
2 """Fixer for __metaclass__ = X -> (future.utils.with_metaclass(X)) methods. | |
3 | |
4 The various forms of classef (inherits nothing, inherits once, inherints | |
5 many) don't parse the same in the CST so we look at ALL classes for | |
6 a __metaclass__ and if we find one normalize the inherits to all be | |
7 an arglist. | |
8 | |
9 For one-liner classes ('class X: pass') there is no indent/dedent so | |
10 we normalize those into having a suite. | |
11 | |
12 Moving the __metaclass__ into the classdef can also cause the class | |
13 body to be empty so there is some special casing for that as well. | |
14 | |
15 This fixer also tries very hard to keep original indenting and spacing | |
16 in all those corner cases. | |
17 """ | |
18 # This is a derived work of Lib/lib2to3/fixes/fix_metaclass.py under the | |
19 # copyright of the Python Software Foundation, licensed under the Python | |
20 # Software Foundation License 2. | |
21 # | |
22 # Copyright notice: | |
23 # | |
24 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, | |
25 # 2011, 2012, 2013 Python Software Foundation. All rights reserved. | |
26 # | |
27 # Full license text: http://docs.python.org/3.4/license.html | |
28 | |
29 # Author: Jack Diederich, Daniel Neuhäuser | |
30 | |
31 # Local imports | |
32 from lib2to3 import fixer_base | |
33 from lib2to3.pygram import token | |
34 from lib2to3.fixer_util import Name, syms, Node, Leaf, touch_import, Call, \ | |
35 String, Comma, parenthesize | |
36 | |
37 | |
38 def has_metaclass(parent): | |
39 """ we have to check the cls_node without changing it. | |
40 There are two possiblities: | |
41 1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta') | |
42 2) clsdef => simple_stmt => expr_stmt => Leaf('__meta') | |
43 """ | |
44 for node in parent.children: | |
45 if node.type == syms.suite: | |
46 return has_metaclass(node) | |
47 elif node.type == syms.simple_stmt and node.children: | |
48 expr_node = node.children[0] | |
49 if expr_node.type == syms.expr_stmt and expr_node.children: | |
50 left_side = expr_node.children[0] | |
51 if isinstance(left_side, Leaf) and \ | |
52 left_side.value == '__metaclass__': | |
53 return True | |
54 return False | |
55 | |
56 | |
57 def fixup_parse_tree(cls_node): | |
58 """ one-line classes don't get a suite in the parse tree so we add | |
59 one to normalize the tree | |
60 """ | |
61 for node in cls_node.children: | |
62 if node.type == syms.suite: | |
63 # already in the preferred format, do nothing | |
64 return | |
65 | |
66 # !%@#! oneliners have no suite node, we have to fake one up | |
67 for i, node in enumerate(cls_node.children): | |
68 if node.type == token.COLON: | |
69 break | |
70 else: | |
71 raise ValueError("No class suite and no ':'!") | |
72 | |
73 # move everything into a suite node | |
74 suite = Node(syms.suite, []) | |
75 while cls_node.children[i+1:]: | |
76 move_node = cls_node.children[i+1] | |
77 suite.append_child(move_node.clone()) | |
78 move_node.remove() | |
79 cls_node.append_child(suite) | |
80 node = suite | |
81 | |
82 | |
83 def fixup_simple_stmt(parent, i, stmt_node): | |
84 """ if there is a semi-colon all the parts count as part of the same | |
85 simple_stmt. We just want the __metaclass__ part so we move | |
86 everything efter the semi-colon into its own simple_stmt node | |
87 """ | |
88 for semi_ind, node in enumerate(stmt_node.children): | |
89 if node.type == token.SEMI: # *sigh* | |
90 break | |
91 else: | |
92 return | |
93 | |
94 node.remove() # kill the semicolon | |
95 new_expr = Node(syms.expr_stmt, []) | |
96 new_stmt = Node(syms.simple_stmt, [new_expr]) | |
97 while stmt_node.children[semi_ind:]: | |
98 move_node = stmt_node.children[semi_ind] | |
99 new_expr.append_child(move_node.clone()) | |
100 move_node.remove() | |
101 parent.insert_child(i, new_stmt) | |
102 new_leaf1 = new_stmt.children[0].children[0] | |
103 old_leaf1 = stmt_node.children[0].children[0] | |
104 new_leaf1.prefix = old_leaf1.prefix | |
105 | |
106 | |
107 def remove_trailing_newline(node): | |
108 if node.children and node.children[-1].type == token.NEWLINE: | |
109 node.children[-1].remove() | |
110 | |
111 | |
112 def find_metas(cls_node): | |
113 # find the suite node (Mmm, sweet nodes) | |
114 for node in cls_node.children: | |
115 if node.type == syms.suite: | |
116 break | |
117 else: | |
118 raise ValueError("No class suite!") | |
119 | |
120 # look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ] | |
121 for i, simple_node in list(enumerate(node.children)): | |
122 if simple_node.type == syms.simple_stmt and simple_node.children: | |
123 expr_node = simple_node.children[0] | |
124 if expr_node.type == syms.expr_stmt and expr_node.children: | |
125 # Check if the expr_node is a simple assignment. | |
126 left_node = expr_node.children[0] | |
127 if isinstance(left_node, Leaf) and \ | |
128 left_node.value == u'__metaclass__': | |
129 # We found a assignment to __metaclass__. | |
130 fixup_simple_stmt(node, i, simple_node) | |
131 remove_trailing_newline(simple_node) | |
132 yield (node, i, simple_node) | |
133 | |
134 | |
135 def fixup_indent(suite): | |
136 """ If an INDENT is followed by a thing with a prefix then nuke the prefix | |
137 Otherwise we get in trouble when removing __metaclass__ at suite start | |
138 """ | |
139 kids = suite.children[::-1] | |
140 # find the first indent | |
141 while kids: | |
142 node = kids.pop() | |
143 if node.type == token.INDENT: | |
144 break | |
145 | |
146 # find the first Leaf | |
147 while kids: | |
148 node = kids.pop() | |
149 if isinstance(node, Leaf) and node.type != token.DEDENT: | |
150 if node.prefix: | |
151 node.prefix = u'' | |
152 return | |
153 else: | |
154 kids.extend(node.children[::-1]) | |
155 | |
156 | |
157 class FixMetaclass(fixer_base.BaseFix): | |
158 BM_compatible = True | |
159 | |
160 PATTERN = """ | |
161 classdef<any*> | |
162 """ | |
163 | |
164 def transform(self, node, results): | |
165 if not has_metaclass(node): | |
166 return | |
167 | |
168 fixup_parse_tree(node) | |
169 | |
170 # find metaclasses, keep the last one | |
171 last_metaclass = None | |
172 for suite, i, stmt in find_metas(node): | |
173 last_metaclass = stmt | |
174 stmt.remove() | |
175 | |
176 text_type = node.children[0].type # always Leaf(nnn, 'class') | |
177 | |
178 # figure out what kind of classdef we have | |
179 if len(node.children) == 7: | |
180 # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) | |
181 # 0 1 2 3 4 5 6 | |
182 if node.children[3].type == syms.arglist: | |
183 arglist = node.children[3] | |
184 # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) | |
185 else: | |
186 parent = node.children[3].clone() | |
187 arglist = Node(syms.arglist, [parent]) | |
188 node.set_child(3, arglist) | |
189 elif len(node.children) == 6: | |
190 # Node(classdef, ['class', 'name', '(', ')', ':', suite]) | |
191 # 0 1 2 3 4 5 | |
192 arglist = Node(syms.arglist, []) | |
193 node.insert_child(3, arglist) | |
194 elif len(node.children) == 4: | |
195 # Node(classdef, ['class', 'name', ':', suite]) | |
196 # 0 1 2 3 | |
197 arglist = Node(syms.arglist, []) | |
198 node.insert_child(2, Leaf(token.RPAR, u')')) | |
199 node.insert_child(2, arglist) | |
200 node.insert_child(2, Leaf(token.LPAR, u'(')) | |
201 else: | |
202 raise ValueError("Unexpected class definition") | |
203 | |
204 # now stick the metaclass in the arglist | |
205 meta_txt = last_metaclass.children[0].children[0] | |
206 meta_txt.value = 'metaclass' | |
207 orig_meta_prefix = meta_txt.prefix | |
208 | |
209 # Was: touch_import(None, u'future.utils', node) | |
210 touch_import(u'future.utils', u'with_metaclass', node) | |
211 | |
212 metaclass = last_metaclass.children[0].children[2].clone() | |
213 metaclass.prefix = u'' | |
214 | |
215 arguments = [metaclass] | |
216 | |
217 if arglist.children: | |
218 if len(arglist.children) == 1: | |
219 base = arglist.children[0].clone() | |
220 base.prefix = u' ' | |
221 else: | |
222 # Unfortunately six.with_metaclass() only allows one base | |
223 # class, so we have to dynamically generate a base class if | |
224 # there is more than one. | |
225 bases = parenthesize(arglist.clone()) | |
226 bases.prefix = u' ' | |
227 base = Call(Name('type'), [ | |
228 String("'NewBase'"), | |
229 Comma(), | |
230 bases, | |
231 Comma(), | |
232 Node( | |
233 syms.atom, | |
234 [Leaf(token.LBRACE, u'{'), Leaf(token.RBRACE, u'}')], | |
235 prefix=u' ' | |
236 ) | |
237 ], prefix=u' ') | |
238 arguments.extend([Comma(), base]) | |
239 | |
240 arglist.replace(Call( | |
241 Name(u'with_metaclass', prefix=arglist.prefix), | |
242 arguments | |
243 )) | |
244 | |
245 fixup_indent(suite) | |
246 | |
247 # check for empty suite | |
248 if not suite.children: | |
249 # one-liner that was just __metaclass_ | |
250 suite.remove() | |
251 pass_leaf = Leaf(text_type, u'pass') | |
252 pass_leaf.prefix = orig_meta_prefix | |
253 node.append_child(pass_leaf) | |
254 node.append_child(Leaf(token.NEWLINE, u'\n')) | |
255 | |
256 elif len(suite.children) > 1 and \ | |
257 (suite.children[-2].type == token.INDENT and | |
258 suite.children[-1].type == token.DEDENT): | |
259 # there was only one line in the class body and it was __metaclass__ | |
260 pass_leaf = Leaf(text_type, u'pass') | |
261 suite.insert_child(-1, pass_leaf) | |
262 suite.insert_child(-1, Leaf(token.NEWLINE, u'\n')) |