def transform(self, node, results): # First, find a the sys import. We'll just hope it's global scope. if "sys_import" in results: if self.sys_import is None: self.sys_import = results["sys_import"] return func = results["func"].clone() func.prefix = u"" register = pytree.Node(syms.power, Attr(Name(u"atexit"), Name(u"register")) ) call = Call(register, [func], node.prefix) node.replace(call) if self.sys_import is None: # That's interesting. self.warning(node, "Can't find sys import; Please add an atexit " "import at the top of your file.") return # Now add an atexit import after the sys import. names = self.sys_import.children[1] if names.type == syms.dotted_as_names: names.append_child(Comma()) names.append_child(Name(u"atexit", u" ")) else: containing_stmt = self.sys_import.parent position = containing_stmt.children.index(self.sys_import) stmt_container = containing_stmt.parent new_import = pytree.Node(syms.import_name, [Name(u"import"), Name(u"atexit", u" ")] ) new = pytree.Node(syms.simple_stmt, [new_import]) containing_stmt.insert_child(position + 1, Newline()) containing_stmt.insert_child(position + 2, new)
def transform_dot(self, node, results): """Transform for calls to module members in code.""" module_dot = results.get("bare_with_attr") member = results.get("member") new_name = None if isinstance(member, list): member = member[0] for change in MAPPING[module_dot.value]: if member.value in change[1]: new_name = change[0] break if new_name: module_dot.replace(Name(new_name, prefix=module_dot.prefix)) else: self.cannot_convert(node, "This is an invalid module element")
def transform(self, node, results): import_mod = results.get("module_name") if import_mod: mod_name = import_mod.value new_name = unicode(self.mapping[mod_name]) import_mod.replace(Name(new_name, prefix=import_mod.prefix)) if "name_import" in results: # If it's not a "from x import x, y" or "import x as y" import, # marked its usage to be replaced. self.replace[mod_name] = new_name if "multiple_imports" in results: # This is a nasty hack to fix multiple imports on a line (e.g., # "import StringIO, urlparse"). The problem is that I can't # figure out an easy way to make a pattern recognize the keys of # MAPPING randomly sprinkled in an import statement. results = self.match(node) if results: self.transform(node, results) else: # Replace usage of the module. bare_name = results["bare_with_attr"][0] new_name = self.replace.get(bare_name.value) if new_name: bare_name.replace(Name(new_name, prefix=bare_name.prefix))
def assertion(expr, msg, prefix, is_not=False): """Build an assert statement in the AST""" children = [Name("assert")] if is_not: children.append(Leaf(token.NAME, "not", prefix=" ")) # Single space after assert. Maintain the indentation/newline of the expr. if expr.prefix == "": expr.prefix = " " for sub_node in expr.children: if '\n' in sub_node.prefix: sub_node.prefix = " \\" + sub_node.prefix children.append(expr.clone()) children.extend(make_assert_msg(msg)) return Node(syms.assert_stmt, children, prefix=prefix)
def transform_dot(self, node, results): module_dot = results.get('bare_with_attr') member = results.get('member') new_name = None if isinstance(member, list): member = member[0] for change in MAPPING[module_dot.value]: if member.value in change[1]: new_name = change[0] break if new_name: module_dot.replace(Name(new_name, prefix=module_dot.prefix)) else: self.cannot_convert(node, 'This is an invalid module element') return
def transform(self, node, results): prefix = None func = results['func'][0] if ('it' in results and func.value not in (u'ifilterfalse', u'izip_longest')): dot, it = (results['dot'], results['it']) # Remove the 'itertools' prefix = it.prefix it.remove() # Replace the node wich contains ('.', 'function') with the # function (to be consistant with the second part of the pattern) dot.remove() func.parent.replace(func) libmodernize.touch_import(u'six.moves', func.value[1:], node) prefix = prefix or func.prefix func.replace(Name(func.value[1:], prefix=prefix))
def Def(name, args, *body, prefix=""): return Node(syms.funcdef, [ Name("def", prefix=prefix), maybe_name(name), Node(syms.parameters, [ LParen(), args, RParen(), ]), Colon(), Node(syms.suite, [ Newline(), Indent(), *body, Dedent(), ]) ])
def assert_comparison(lhs, comparator, rhs, msg, prefix): """Build an assert statement in the AST""" children = [Name("assert")] # Single space after assert. Maintain the indentation/newline of the rhs, but # have to prepend a backslash for the assert to work. lhs.prefix = " " if "\n" in rhs.prefix: rhs.prefix = " \\" + rhs.prefix children.extend(make_operand(lhs)) children.extend(copy.deepcopy(comparator)) children.extend(make_operand(rhs)) children.extend(make_assert_msg(msg)) return Node(syms.assert_stmt, children, prefix=prefix)
def finish_tree(self, tree, filename): if not self._names: return names = [Leaf(token.LBRACE, "[", prefix=" "), Newline()] for name in self._names: names.append(String('"' + name + '"', prefix=" ")) names.append(Comma()) names.append(Newline()) names.append(Leaf(token.LBRACE, "]", prefix="")) tree.append_child(Assign(Name("__all__"), names)) tree.append_child(Newline()) super(FixAllAttribute, self).finish_tree(tree, filename)
def transform(self, node, results): head = results['head'] method = results['method'][0] tail = results['tail'] syms = self.syms method_name = method.value head = [n.clone() for n in head] tail = [n.clone() for n in tail] if method_name == 'set_radius': #different plural conversion method_name = 'set_radii' elif method_name == 'set_mass': #another different plural form method_name = 'set_masses' else: method_name += 's' #standard plural conversion for all others args = head + [pytree.Node(syms.trailer, [Dot(), Name(method_name, prefix = method.prefix)])] + tail new = pytree.Node(syms.power, args) return new
def wrap_in_fn_call(fn_name, args, prefix=None): """ Example: >>> wrap_in_fn_call("oldstr", (arg,)) oldstr(arg) >>> wrap_in_fn_call("olddiv", (arg1, arg2)) olddiv(arg1, arg2) """ assert len(args) > 0 if len(args) == 1: newargs = args elif len(args) == 2: expr1, expr2 = args newargs = [expr1, Comma(), expr2] else: assert NotImplementedError('write me') return Call(Name(fn_name), newargs, prefix=prefix)
def transform(self, node, results): if 'set_arg' in results: # Case of .set_std_dev() # set_std_dev => std_dev attribute = node.children[-2] # .set_std_dev attribute.children[1].replace(Name('std_dev')) # Call "(arg)": removed node.children[-1].remove() # Replacement by an assignment: node.replace(Assign(node.clone(), results['set_arg'].clone())) else: # '.std_dev' is followed by a call with no argument: the call # is removed: node.children[-1].remove()
def transform(self, node, results): from_import = results.get(u"from_import") from_import_submod = results.get(u"from_import_submod") name_import = results.get(u"name_import") dotted_name = results.get(u"dotted_name") name = results.get(u"name") names = results.get(u"names") attr = results.get(u"attr") imported = results.get(u"imported") if names: for name in names: if name.type == token.NAME: self.fix_simple_name(name) elif name.type == syms.dotted_as_name: self.fix_simple_name(name.children[0]) if name.children[0].type == token.NAME else \ self.fix_dotted_name(name.children[0]) elif name.type == syms.dotted_name: self.fix_dotted_name(name) elif from_import_submod: renamed = results.get(u"renamed") new_name, new_attr = self.get_dotted_import_replacement( name, attr, renamed=renamed) if new_attr is not None: name.replace(new_name) attr.replace(new_attr) else: children = [Name(u"import"), new_name] node.replace( Node(syms.import_name, children, prefix=node.prefix)) elif dotted_name: self.fix_dotted_name(dotted_name) elif name_import or from_import: self.fix_simple_name(name) elif name and not attr: if does_tree_import(None, MAPPING[name.value], node): self.fix_simple_name(name) elif name and attr: # Note that this will fix a dotted name that was never imported. # This will probably not matter. self.fix_dotted_name(node) elif imported and imported.type == syms.import_as_names: self.fix_submod_import(imported=imported.children, node=node, name=name.value)
def transform(self, node: LN, capture: Capture) -> None: imports = [] for n in capture["module_names"]: if n.type == token.COMMA: pass elif n.type == token.NAME: imports.append((n.value, None)) elif n.type == syms.dotted_name: imports.append((traverse_dotted_name(n), None)) elif n.type == syms.dotted_as_name: import_name, import_nick = n.children[0], n.children[2] assert n.children[1].type == token.NAME and n.children[ 1].value == "as" imports.append( (traverse_dotted_name(import_name), import_nick.value)) rename_seen = False nodes = [] indent = find_indentation(node) for name, nick in imports: try: new_name = get_new_name(name) except NameRemovedError as exc: self.warn(node, str(exc)) continue if new_name: rename_seen = True name = new_name new_node = Node( syms.import_name, [Name("import"), ImportAsName(name, nick, prefix=" ")], prefix=f"\n{indent}", ) nodes.append(new_node) if not nodes: return nodes[0].prefix = node.prefix if rename_seen: node.replace(nodes)
def wrap_in_fn_call(fn_name, args, prefix=None): """ Example: >>> wrap_in_fn_call("oldstr", (arg,)) oldstr(arg) >>> wrap_in_fn_call("olddiv", (arg1, arg2)) olddiv(arg1, arg2) >>> wrap_in_fn_call("olddiv", [arg1, comma, arg2, comma, arg3]) olddiv(arg1, arg2, arg3) """ assert len(args) > 0 if len(args) == 2: expr1, expr2 = args newargs = [expr1, Comma(), expr2] else: newargs = args return Call(Name(fn_name), newargs, prefix=prefix)
def new_print(*pos, **opts): """ Constructs a new print_stmt node args is all positional arguments passed to print() kwargs contains zero or more of the following mappings: 'sep': some string 'file': some file-like object that supports the write() method 'end': some string """ children = [Name("print")] sep = None if "sep" not in opts else opts["sep"] file = None if "file" not in opts else opts["file"] end = None if "end" not in opts else opts["end"] add_file_part(file, children) add_sep_part(sep, pos, children) if end is not None and not isNone(end): if not end.value in ('"\\n"', "'\\n'"): children.append(Comma()) return Node(syms.print_stmt, children)
def transform(self, node, results): head = results['head'] method = results['method'][0] tail = results['tail'] syms = self.syms method_name = method.value head = [n.clone() for n in head] tail = [n.clone() for n in tail] replacement_dict = { 'numberOfAtoms': 'n_atoms', 'numberOfResidues': 'n_residues', 'numberOfSegments': 'n_segments' } method_name = replacement_dict[method_name] args = head + [ pytree.Node(syms.trailer, [Dot(), Name(method_name, prefix=method.prefix)]) ] new = pytree.Node(syms.power, args) return new
def transform(self, node, results): u""" a,b,c,d,e,f,*g,h,i = range(100) changes to _3to2list = list(range(100)) a,b,c,d,e,f,g,h,i, = _3to2list[:6] + [_3to2list[6:-2]] + _3to2list[-2:] and for a,b,*c,d,e in iter_of_iters: do_stuff changes to for _3to2iter in iter_of_iters: _3to2list = list(_3to2iter) a,b,c,d,e, = _3to2list[:2] + [_3to2list[2:-2]] + _3to2list[-2:] do_stuff """ self.LISTNAME = self.new_name(u"_3to2list") self.ITERNAME = self.new_name(u"_3to2iter") expl, impl = results.get_products(u"expl"), results.get_products( u"impl") if expl is not None: setup_line, power_line = self.fix_explicit_context(node, results) setup_line.prefix = expl.prefix power_line.prefix = indentation(expl.parent) setup_line.append_child(Newline()) parent = node.parent i = node.remove() parent.insert_child(i, power_line) parent.insert_child(i, setup_line) elif impl is not None: setup_line, power_line = self.fix_implicit_context(node, results) suitify(node) suite = [k for k in node.children if k.type == syms.suite][0] setup_line.prefix = u"" power_line.prefix = suite.children[1].value suite.children[2].prefix = indentation(suite.children[2]) suite.insert_child(2, Newline()) suite.insert_child(2, power_line) suite.insert_child(2, Newline()) suite.insert_child(2, setup_line) results.get_products(u"lst").replace( Name(self.ITERNAME, prefix=u" "))
class FixInt(fixer_base.BaseFix): explicit = True # In most cases, 3.x ints will work just like 2.x ints. PATTERN = "'int' | NUMBER" static_long = Name("long") def base(self, literal): """Returns the base of a valid py3k numeric literal.""" literal = literal.strip() if not literal.startswith("0") or re.match(r"0+$", literal): return 10 elif literal[1] not in "box": return 0 return baseMAPPING[literal[1]] def unmatch(self, node): """Don't match complex numbers, floats, or longs""" val = node.value #For whatever reason, some ints are being matched after we fix them. if val.endswith("L"): return "L" for bad in "jJ+-.": if bad in val: return bad def match(self, node): return super(FixInt, self).match(node) and not self.unmatch(node) def transform(self, node, results): val = node.value if node.type == token.NUMBER and self.base(val) == 10: assert not val[-1] in "lL", "Invalid py3k literal: " + str(val) val += "L" return Number(val, prefix=node.prefix) elif is_probably_builtin(node): assert node.type == token.NAME, "Sanity check failed: " + str(val) new = self.static_long.clone() new.prefix = node.prefix return new
def transform(self, node, results): assert results syms = self.syms anchor = results["anchor"] # There are 2 types of nodes in the AST - Node and Leaf. # Leaf nodes have a prefix and suffix that are meant for whitespaces and comments. # It usually suffices to use the prefix only as the prefix of a node is the suffix # of its previous node. prefix = node.prefix # before is the identifier that precedes the '.' before the 'None'. before = [n.clone() for n in results["before"]] if len(before) == 1: before = before[0] else: before = pytree.Node(syms.power, before) noneKeywd = String(repr("None")) l_args = [before, Comma(), noneKeywd] if l_args: l_args[0].prefix = u"" l_args[2].prefix = u" " new = Call(Name(u"getattr"), l_args) new.prefix = prefix return new
def transform(self, node, results): syms = self.syms prefix = node.prefix args = results.get(u"args") arg = results.get(u"arg") if args: args = [arg.clone() for arg in args] args = Node(syms.atom, [ Leaf(token.LSQB, u"["), Node(syms.listmaker, args), Leaf(token.RSQB, u"]") ]) elif arg: arg = arg.clone() arg = Node(syms.atom, [ Leaf(token.LSQB, u"["), Node(syms.listmaker, [arg]), Leaf(token.RSQB, u"]") ]) return Node( syms.power, [Name(u"set"), LParen(), args or arg, RParen()], prefix=prefix)
def transform(self, node, results): signal = results.get("signal").value signal = re.sub('^["\']([^(]+)(?:\(.*\))?["\']$', '\\1', signal) if 'emitter' in results: emitter = results.get("emitter").clone() emitter.prefix = node.prefix args = results.get("args").clone() args.children = args.children[2:] if args.children: args.children[0].prefix = '' res = Node(syms.power, [emitter, Name('.'), Name(signal), Name('.'), Name('emit')] + [ArgList([args])]) else: sender = results.get("sender").clone() method = results.get("method") if isinstance(method, list): method = method[0] method = method.clone() sender.prefix = node.prefix slot = results.get("slot").clone() slot.prefix = "" res = Node(syms.power, [sender, Name('.'), Name(signal), Name('.'), method] + [ArgList([slot])]) return res
def transform(self, node, results): name = results["name"] name.replace(Name("bar", name.prefix))
def build_attr(prefix, suffix): prefix = prefix if isinstance(prefix, Node) else Name(prefix) suffix = suffix if isinstance(suffix, Node) else Name(suffix) return Node(syms.power, Attr(prefix, suffix))
def transform(self, node, results): name = results[u"name"] name.replace(Name(u"buffer", prefix=name.prefix))
def transform(self, node, results): name = results['name'] name.replace(Name('cheese', name.prefix))
def transform(self, node, results): params_rawlist = results[u"params"] for i, item in enumerate(params_rawlist): if item.type == token.STAR: params_rawlist = params_rawlist[i:] break else: return # params is guaranteed to be a list starting with *. # if fixing is needed, there will be at least 3 items in this list: # [STAR, COMMA, NAME] is the minimum that we need to worry about. new_kwargs = needs_fixing(params_rawlist) # new_kwargs is the name of the kwargs dictionary. if not new_kwargs: return suitify(node) # At this point, params_rawlist is guaranteed to be a list # beginning with a star that includes at least one keyword-only param # e.g., [STAR, NAME, COMMA, NAME, COMMA, DOUBLESTAR, NAME] or # [STAR, COMMA, NAME], or [STAR, COMMA, NAME, COMMA, DOUBLESTAR, NAME] # Anatomy of a funcdef: ['def', 'name', parameters, ':', suite] # Anatomy of that suite: [NEWLINE, INDENT, first_stmt, all_other_stmts] # We need to insert our new stuff before the first_stmt and change the # first_stmt's prefix. suite = node.children[4] first_stmt = suite.children[2] ident = indentation(first_stmt) for name, default_value in gen_params(params_rawlist): if default_value is None: suite.insert_child(2, Newline()) suite.insert_child( 2, String(_assign_template % { u'name': name, u'kwargs': new_kwargs }, prefix=ident)) else: suite.insert_child(2, Newline()) suite.insert_child( 2, String(_else_template % { u'name': name, u'default': default_value }, prefix=ident)) suite.insert_child(2, Newline()) suite.insert_child( 2, String(_if_template % { u'assign': _assign_template % { u'name': name, u'kwargs': new_kwargs }, u'name': name, u'kwargs': new_kwargs }, prefix=ident)) first_stmt.prefix = ident suite.children[2].prefix = u"" # Now, we need to fix up the list of params. must_add_kwargs = remove_params(params_rawlist) if must_add_kwargs: arglist = results[u'arglist'] if len(arglist.children ) > 0 and arglist.children[-1].type != token.COMMA: arglist.append_child(Comma()) arglist.append_child(DoubleStar(prefix=u" ")) arglist.append_child(Name(new_kwargs))
def transform_member(self, node, results): """Transform for imports of specific module elements. Replaces the module to be imported from with the appropriate new module. """ mod_member = results.get('mod_member') pref = mod_member.prefix member = results.get('member') if member: if isinstance(member, list): member = member[0] new_name = None for change in MAPPING[mod_member.value]: if member.value in change[1]: new_name = change[0] break if new_name: mod_member.replace(Name(new_name, prefix=pref)) else: self.cannot_convert(node, 'This is an invalid module element') else: modules = [] mod_dict = {} members = results['members'] for member in members: if member.type == syms.import_as_name: as_name = member.children[2].value member_name = member.children[0].value else: member_name = member.value as_name = None if member_name != u',': for change in MAPPING[mod_member.value]: if member_name in change[1]: if change[0] not in mod_dict: modules.append(change[0]) mod_dict.setdefault(change[0], []).append(member) new_nodes = [] indentation = find_indentation(node) first = True def handle_name(name, prefix): if name.type == syms.import_as_name: kids = [Name(name.children[0].value, prefix=prefix), name.children[1].clone(), name.children[2].clone()] return [Node(syms.import_as_name, kids)] return [Name(name.value, prefix=prefix)] for module in modules: elts = mod_dict[module] names = [] for elt in elts[:-1]: names.extend(handle_name(elt, pref)) names.append(Comma()) names.extend(handle_name(elts[-1], pref)) new = FromImport(module, names) if not first or node.parent.prefix.endswith(indentation): new.prefix = indentation new_nodes.append(new) first = False if new_nodes: nodes = [] for new_node in new_nodes[:-1]: nodes.extend([new_node, Newline()]) nodes.append(new_nodes[-1]) node.replace(nodes) else: self.cannot_convert(node, 'All module elements are invalid') return
def handle_name(name, prefix): if name.type == syms.import_as_name: kids = [Name(name.children[0].value, prefix=prefix), name.children[1].clone(), name.children[2].clone()] return [Node(syms.import_as_name, kids)] return [Name(name.value, prefix=prefix)]
def transform(self, node, results): func = results['func'] touch_import(None, u'collections', node=node) args = [func.clone(), String(u', ')] args.extend(Attr(Name(u'collections'), Name(u'Callable'))) return Call(Name(u'isinstance'), args, prefix=node.prefix)