def transform(self, node, results): meta_results = has_metaclass(node) if not meta_results: return for meta in meta_results: meta.remove() target = Leaf(token.NAME, u"__metaclass__") equal = Leaf(token.EQUAL, u"=", prefix=u" ") # meta is the last item in what was returned by has_metaclass(): name name = meta name.prefix = u" " stmt_node = Node(syms.atom, [target, equal, name]) suitify(node) for item in node.children: if item.type == syms.suite: for stmt in item.children: if stmt.type == token.INDENT: # Insert, in reverse order, the statement, a newline, # and an indent right after the first indented line loc = item.children.index(stmt) + 1 # Keep consistent indentation form ident = Leaf(token.INDENT, stmt.value) item.insert_child(loc, ident) item.insert_child(loc, Newline()) item.insert_child(loc, stmt_node) break
def has_metaclass(parent): results = None for node in parent.children: kids = node.children if node.type == syms.argument: if kids[0] == Leaf(token.NAME, u"metaclass") and \ kids[1] == Leaf(token.EQUAL, u"=") and \ kids[2]: #Hack to avoid "class X(=):" with this case. results = [node] + kids break elif node.type == syms.arglist: # Argument list... loop through it looking for: # Node(*, [*, Leaf(token.NAME, u"metaclass"), Leaf(token.EQUAL, u"="), Leaf(*, *)] for child in node.children: if results: break if child.type == token.COMMA: #Store the last comma, which precedes the metaclass comma = child elif type(child) == Node: meta = equal = name = None for arg in child.children: if arg == Leaf(token.NAME, u"metaclass"): #We have the (metaclass) part meta = arg elif meta and arg == Leaf(token.EQUAL, u"="): #We have the (metaclass=) part equal = arg elif meta and equal: #Here we go, we have (metaclass=X) name = arg results = (comma, meta, equal, name) break return results
def _generate_import_node(package, name, prefix=""): def DottedName(name, prefix=""): split = name.rsplit('.') if len(split) > 1: # Reconstruct the dotted name as a list of leaves leftmost_name = Leaf(token.NAME, split[0]) children = [leftmost_name] for entry in split[1:]: next_name = [Leaf(token.DOT, '.'), Leaf(token.NAME, entry)] children.extend(next_name) return Node(syms.dotted_name, children, prefix=prefix) return Leaf(token.NAME, name, prefix=prefix) if not package: import_ = Node(syms.import_name, [ Leaf(token.NAME, "import", prefix=prefix), DottedName(name, prefix=" ") ]) else: import_ = Node(syms.import_from, [ Leaf(token.NAME, "from", prefix=prefix), DottedName(package, prefix=" "), Leaf(token.NAME, "import", prefix=" "), Leaf(token.NAME, name, prefix=" "), ]) return import_
def DottedName(name, prefix=""): split = name.rsplit('.') if len(split) > 1: # Reconstruct the dotted name as a list of leaves leftmost_name = Leaf(token.NAME, split[0]) children = [leftmost_name] for entry in split[1:]: next_name = [Leaf(token.DOT, '.'), Leaf(token.NAME, entry)] children.extend(next_name) return Node(syms.dotted_name, children, prefix=prefix) return Leaf(token.NAME, name, prefix=prefix)
def transform(self, node, results): name, val, trc = (results.get_products(u"name"), results.get_products(u"val"), results.get_products(u"trc")) chain = results.get_products(u"chain") if chain is not None: self.warning(node, u"explicit exception chaining is not supported in Python 2") chain.prev_sibling.remove() chain.remove() if trc is not None: val = val[0] if val else Leaf(token.NAME, u"None") val.prefix = trc.prefix = u" " kids = [Leaf(token.NAME, u"raise"), name.clone(), Comma(), val.clone(), Comma(), trc.clone()] raise_stmt = Node(syms.raise_stmt, kids) node.replace(raise_stmt)
def transform(self, node, result): if len(node.children) == 3 and node.children[-1].type == token.NUMBER: userdata_id = int(node.children[-1].value) replacement = self.subfun(userdata_id) if replacement: new = Node(python_symbols.subscriptlist, [Leaf(token.NAME, replacement)]) return new return None
def transform(self, node, results): # Determine the node's column number by finding the first leaf. leaf = node while not isinstance(leaf, Leaf): leaf = leaf.children[0] # Only match functions and the global indentation level. if leaf.column != 0: return indent = None for child in node.children: if isinstance(child, Node) and child.type == python_symbols.suite: indent = find_indentation(child) if isinstance( child, Leaf ) and child.type == token.NAME and child.value == self.funcname: child.value = self.newname elif isinstance(child, Node) and child.type == python_symbols.parameters: pre_params = [] for param in self.pre_params: pre_params.append(Leaf(token.NAME, param)) pre_params.append(Leaf(token.COMMA, ', ')) child.children[1:1] = pre_params post_params = [] for param in self.post_params: post_params.append(Leaf(token.COMMA, ',')) post_params.append(Leaf(token.NAME, param)) child.children[-1:-1] = post_params if child.children[-2].type == token.COMMA: child.children.pop(-2) child.changed() if self.add_statement: node.children.append( Leaf(0, indent + self.add_statement.rstrip() + '\n')) if self.remove: self.results.append(node) node.replace([]) return None else: return node
def _new_type_check_with_import(package, name, root, insert_pos): # type: (Optional[str], str, Node, int) -> None """ Inserts a new TYPE_CHECKING block containing a new import statement for package and name Parameters ----------- package : Optional[str] name : str root : Node insert_pos : int """ # [Grammar] # if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite] type_check_node = Node(syms.if_stmt, [Leaf(token.NAME, 'if'), Leaf(token.NAME, 'TYPE_CHECKING', prefix=" "), Leaf(token.COLON, ':'), # [Grammar] # suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT Node(syms.suite, [Leaf(token.NEWLINE, '\n'), Leaf(token.INDENT, ' '), Node(syms.simple_stmt, [_generate_import_node(package, name), Newline()]), Leaf(token.DEDENT, '')])]) # We can just hardcode the correct insert position since we just created the typing block root.insert_child(insert_pos, type_check_node) # Make sure to import TYPE_CHECKING just before using import_type_checking = [_generate_import_node('typing', 'TYPE_CHECKING'), Newline()] root.insert_child(insert_pos, Node(syms.simple_stmt, import_type_checking))
def assignment_source(num_pre, num_post, LISTNAME, ITERNAME): u""" Accepts num_pre and num_post, which are counts of values before and after the starg (not including the starg) Returns a source fit for Assign() from fixer_util """ children = [] pre = unicode(num_pre) post = unicode(num_post) # This code builds the assignment source from lib2to3 tree primitives. # It's not very readable, but it seems like the most correct way to do it. if num_pre > 0: pre_part = Node(syms.power, [Name(LISTNAME), Node(syms.trailer, [Leaf(token.LSQB, u"["), Node(syms.subscript, [Leaf(token.COLON, u":"), Number(pre)]), Leaf(token.RSQB, u"]")])]) children.append(pre_part) children.append(Leaf(token.PLUS, u"+", prefix=u" ")) main_part = Node(syms.power, [Leaf(token.LSQB, u"[", prefix=u" "), Name(LISTNAME), Node(syms.trailer, [Leaf(token.LSQB, u"["), Node(syms.subscript, [Number(pre) if num_pre > 0 else Leaf(1, u""), Leaf(token.COLON, u":"), Node(syms.factor, [Leaf(token.MINUS, u"-"), Number(post)]) if num_post > 0 else Leaf(1, u"")]), Leaf(token.RSQB, u"]"), Leaf(token.RSQB, u"]")])]) children.append(main_part) if num_post > 0: children.append(Leaf(token.PLUS, u"+", prefix=u" ")) post_part = Node(syms.power, [Name(LISTNAME, prefix=u" "), Node(syms.trailer, [Leaf(token.LSQB, u"["), Node(syms.subscript, [Node(syms.factor, [Leaf(token.MINUS, u"-"), Number(post)]), Leaf(token.COLON, u":")]), Leaf(token.RSQB, u"]")])]) children.append(post_part) source = Node(syms.arith_expr, children) return source
def transform(self, node, results): fixup_parse_tree(node) text_type = node.children[0].type # always Leaf(nnn, 'class') # figure out what kind of classdef we have if len(node.children) == 7: # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) # 0 1 2 3 4 5 6 if node.children[3].type == syms.arglist: arglist = node.children[3] # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) else: parent = node.children[3].clone() arglist = Node(syms.arglist, [parent]) node.set_child(3, arglist) elif len(node.children) == 6: # Node(classdef, ['class', 'name', '(', ')', ':', suite]) # 0 1 2 3 4 5 arglist = Node(syms.arglist, []) node.insert_child(3, arglist) elif len(node.children) == 4: # Node(classdef, ['class', 'name', ':', suite]) # 0 1 2 3 arglist = Node(syms.arglist, []) node.insert_child(2, Leaf(token.RPAR, u')')) node.insert_child(2, arglist) node.insert_child(2, Leaf(token.LPAR, u'(')) else: raise ValueError("Unexpected class definition") for child in arglist.children: if child.value == 'Torsion': child.value = 'Dihedral' if child.value == 'Improper_Torsion': child.value = 'ImproperDihedral'
def transform(self, node, results): u""" This replaces function type annotations with a commented version. """ params = results.get(u"params") body = results.get(u"body") ret = results.get(u"ret") lhs = results.get(u"lhs") ann = results.get(u"ann") rhs = results.get(u"rhs") annnode = results.get(u"annnode") if params is not None and body is not None: ret_type = u"None" types = [] for child in params.children: if child.type == syms.typedargslist: types = handle_typedargslist(child) elif child.type == syms.tname: types = retrieve_type(child) handle_tname_or_name(child) if ret is not None: assert ret.prev_sibling.type == token.RARROW, u"invalid return annotation" ret_type = ret.value ret.prev_sibling.remove() ret.remove() type_sig = "# type: ({}) -> {}".format(", ".join(types), ret_type) type_sig_comment = Leaf(token.COMMENT, type_sig) indents = [l for l in body.leaves() if l.type == token.INDENT] if not len(indents): indent_node = Leaf(token.INDENT, " ") body.insert_child(0, indent_node) body.insert_child(0, Leaf(token.NEWLINE, "\n")) else: indent_node = indents[0] body.insert_child(0, type_sig_comment) body.insert_child(0, indent_node) body.insert_child(0, Leaf(token.NEWLINE, "\n")) elif ann is not None: type_ann_comment = Leaf(token.COMMENT, " # type: {}".format( ''.join(x.value for x in ann.leaves()) )) lhs.parent.append_child(Leaf(token.EQUAL, " =")) if rhs is None: lhs.parent.append_child(Leaf(token.NAME, " None")) else: lhs.parent.append_child(rhs) annnode.remove() lhs.parent.append_child(type_ann_comment)
def Import(name_leafs): for leaf in name_leafs: # Pull the leaves out of their old tree leaf.remove() def add_commas(leafs): yield leafs[0] for a in leafs[1:]: yield Comma() yield a children = [Leaf(token.NAME, u'import'), Node(syms.dotted_as_names, list(add_commas(name_leafs)))] imp = Node(syms.import_name, children) return imp
def transform(self, node, results): if not has_metaclass(node): return # pragma: no cover fixup_parse_tree(node) # find metaclasses, keep the last one last_metaclass = None for suite, i, stmt in find_metas(node): last_metaclass = stmt stmt.remove() text_type = node.children[0].type # always Leaf(nnn, 'class') # figure out what kind of classdef we have if len(node.children) == 7: # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) # 0 1 2 3 4 5 6 if node.children[3].type == syms.arglist: arglist = node.children[3] # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) else: parent = node.children[3].clone() arglist = Node(syms.arglist, [parent]) node.set_child(3, arglist) elif len(node.children) == 6: # Node(classdef, ['class', 'name', '(', ')', ':', suite]) # 0 1 2 3 4 5 arglist = Node(syms.arglist, []) node.insert_child(3, arglist) elif len(node.children) == 4: # Node(classdef, ['class', 'name', ':', suite]) # 0 1 2 3 arglist = Node(syms.arglist, []) node.insert_child(2, Leaf(token.RPAR, u')')) node.insert_child(2, arglist) node.insert_child(2, Leaf(token.LPAR, u'(')) else: raise ValueError("Unexpected class definition") # pragma: no cover touch_import(None, u'six', node) metaclass = last_metaclass.children[0].children[2].clone() metaclass.prefix = u'' arguments = [metaclass] if arglist.children: bases = arglist.clone() bases.prefix = u' ' arguments.extend([Comma(), bases]) arglist.replace( Call(Name(u'six.with_metaclass', prefix=arglist.prefix), arguments)) fixup_indent(suite) # check for empty suite if not suite.children: # one-liner that was just __metaclass__ suite.remove() pass_leaf = Leaf(text_type, u'pass') pass_leaf.prefix = last_metaclass.prefix node.append_child(pass_leaf) node.append_child(Leaf(token.NEWLINE, u'\n')) elif len(suite.children) > 1 and \ (suite.children[-2].type == token.INDENT and suite.children[-1].type == token.DEDENT): # there was only one line in the class body and it was __metaclass__ pass_leaf = Leaf(text_type, u'pass') suite.insert_child(-1, pass_leaf) suite.insert_child(-1, Leaf(token.NEWLINE, u'\n'))
def transform(self, node, results): if not has_metaclass(node): return fixup_parse_tree(node) # find metaclasses, keep the last one last_metaclass = None for suite, i, stmt in find_metas(node): last_metaclass = stmt stmt.remove() text_type = node.children[0].type # always Leaf(nnn, 'class') # figure out what kind of classdef we have if len(node.children) == 7: # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) # 0 1 2 3 4 5 6 if node.children[3].type == syms.arglist: arglist = node.children[3] # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) else: parent = node.children[3].clone() arglist = Node(syms.arglist, [parent]) node.set_child(3, arglist) elif len(node.children) == 6: # Node(classdef, ['class', 'name', '(', ')', ':', suite]) # 0 1 2 3 4 5 arglist = Node(syms.arglist, []) node.insert_child(3, arglist) elif len(node.children) == 4: # Node(classdef, ['class', 'name', ':', suite]) # 0 1 2 3 arglist = Node(syms.arglist, []) node.insert_child(2, Leaf(token.RPAR, u')')) node.insert_child(2, arglist) node.insert_child(2, Leaf(token.LPAR, u'(')) else: raise ValueError("Unexpected class definition") # now stick the metaclass in the arglist meta_txt = last_metaclass.children[0].children[0] meta_txt.value = 'metaclass' orig_meta_prefix = meta_txt.prefix # Was: touch_import(None, u'future.utils', node) touch_import(u'future.utils', u'with_metaclass', node) metaclass = last_metaclass.children[0].children[2].clone() metaclass.prefix = u'' arguments = [metaclass] if arglist.children: if len(arglist.children) == 1: base = arglist.children[0].clone() base.prefix = u' ' else: # Unfortunately six.with_metaclass() only allows one base # class, so we have to dynamically generate a base class if # there is more than one. bases = parenthesize(arglist.clone()) bases.prefix = u' ' base = Call(Name('type'), [ String("'NewBase'"), Comma(), bases, Comma(), Node(syms.atom, [Leaf(token.LBRACE, u'{'), Leaf(token.RBRACE, u'}')], prefix=u' ') ], prefix=u' ') arguments.extend([Comma(), base]) arglist.replace( Call(Name(u'with_metaclass', prefix=arglist.prefix), arguments)) fixup_indent(suite) # check for empty suite if not suite.children: # one-liner that was just __metaclass_ suite.remove() pass_leaf = Leaf(text_type, u'pass') pass_leaf.prefix = orig_meta_prefix node.append_child(pass_leaf) node.append_child(Leaf(token.NEWLINE, u'\n')) elif len(suite.children) > 1 and \ (suite.children[-2].type == token.INDENT and suite.children[-1].type == token.DEDENT): # there was only one line in the class body and it was __metaclass__ pass_leaf = Leaf(text_type, u'pass') suite.insert_child(-1, pass_leaf) suite.insert_child(-1, Leaf(token.NEWLINE, u'\n'))
def transform(self, node, results): if not has_metaclass(node): return fixup_parse_tree(node) # find metaclasses, keep the last one last_metaclass = None for suite, i, stmt in find_metas(node): last_metaclass = stmt stmt.remove() text_type = node.children[0].type # always Leaf(nnn, 'class') # figure out what kind of classdef we have if len(node.children) == 7: # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) # 0 1 2 3 4 5 6 if node.children[3].type == syms.arglist: arglist = node.children[3] # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) else: parent = node.children[3].clone() arglist = Node(syms.arglist, [parent]) node.set_child(3, arglist) elif len(node.children) == 6: # Node(classdef, ['class', 'name', '(', ')', ':', suite]) # 0 1 2 3 4 5 arglist = Node(syms.arglist, []) node.insert_child(3, arglist) elif len(node.children) == 4: # Node(classdef, ['class', 'name', ':', suite]) # 0 1 2 3 arglist = Node(syms.arglist, []) node.insert_child(2, Leaf(token.RPAR, u')')) node.insert_child(2, arglist) node.insert_child(2, Leaf(token.LPAR, u'(')) else: raise ValueError("Unexpected class definition") touch_import(None, u'six', node) metaclass = last_metaclass.children[0].children[2].clone() metaclass.prefix = u'' arguments = [metaclass] if arglist.children: if len(arglist.children) == 1: base = arglist.children[0].clone() base.prefix = u' ' else: # Unfortunately six.with_metaclass() only allows one base # class, so we have to dynamically generate a base class if # there is more than one. bases = parenthesize(arglist.clone()) bases.prefix = u' ' base = Call(Name('type'), [ String("'NewBase'"), Comma(), bases, Comma(), Node( syms.atom, [Leaf(token.LBRACE, u'{'), Leaf(token.RBRACE, u'}')], prefix=u' ' ) ], prefix=u' ') arguments.extend([Comma(), base]) arglist.replace(Call( Name(u'six.with_metaclass', prefix=arglist.prefix), arguments )) fixup_indent(suite) # check for empty suite if not suite.children: # one-liner that was just __metaclass_ suite.remove() pass_leaf = Leaf(text_type, u'pass') pass_leaf.prefix = orig_meta_prefix node.append_child(pass_leaf) node.append_child(Leaf(token.NEWLINE, u'\n')) elif len(suite.children) > 1 and \ (suite.children[-2].type == token.INDENT and suite.children[-1].type == token.DEDENT): # there was only one line in the class body and it was __metaclass__ pass_leaf = Leaf(text_type, u'pass') suite.insert_child(-1, pass_leaf) suite.insert_child(-1, Leaf(token.NEWLINE, u'\n'))
def transform(self, node, results): if not has_metaclass(node): return # pragma: no cover fixup_parse_tree(node) # find metaclasses, keep the last one last_metaclass = None for suite, i, stmt in find_metas(node): last_metaclass = stmt stmt.remove() text_type = node.children[0].type # always Leaf(nnn, 'class') # figure out what kind of classdef we have if len(node.children) == 7: # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) # 0 1 2 3 4 5 6 if node.children[3].type == syms.arglist: arglist = node.children[3] # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) else: parent = node.children[3].clone() arglist = Node(syms.arglist, [parent]) node.set_child(3, arglist) elif len(node.children) == 6: # Node(classdef, ['class', 'name', '(', ')', ':', suite]) # 0 1 2 3 4 5 arglist = Node(syms.arglist, []) node.insert_child(3, arglist) elif len(node.children) == 4: # Node(classdef, ['class', 'name', ':', suite]) # 0 1 2 3 arglist = Node(syms.arglist, []) node.insert_child(2, Leaf(token.RPAR, u")")) node.insert_child(2, arglist) node.insert_child(2, Leaf(token.LPAR, u"(")) else: raise ValueError("Unexpected class definition") # pragma: no cover touch_import(None, u"six", node) metaclass = last_metaclass.children[0].children[2].clone() metaclass.prefix = u"" arguments = [metaclass] if arglist.children: bases = arglist.clone() bases.prefix = u" " arguments.extend([Comma(), bases]) arglist.replace(Call(Name(u"six.with_metaclass", prefix=arglist.prefix), arguments)) fixup_indent(suite) # check for empty suite if not suite.children: # one-liner that was just __metaclass__ suite.remove() pass_leaf = Leaf(text_type, u"pass") pass_leaf.prefix = last_metaclass.prefix node.append_child(pass_leaf) node.append_child(Leaf(token.NEWLINE, u"\n")) elif len(suite.children) > 1 and ( suite.children[-2].type == token.INDENT and suite.children[-1].type == token.DEDENT ): # there was only one line in the class body and it was __metaclass__ pass_leaf = Leaf(text_type, u"pass") suite.insert_child(-1, pass_leaf) suite.insert_child(-1, Leaf(token.NEWLINE, u"\n"))