def transform(self, node, results): if 'sys_import' in results: if self.sys_import is None: self.sys_import = results['sys_import'] return else: 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: self.warning(node, "Can't find sys import; Please add an atexit import at the top of your file.") return 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) return
def transform(self, node, results): signame = results['signame'] if 'emitter' in results: emitter = results.get("emitter") emitter = Name(''.join(map(str, emitter))) if 'sigarg' in results: args = results.get("args").clone() args.children = args.children[2:] if args.children: args.children[0].prefix = '' res = Node(syms.power, [emitter, Name('.'), Name(signame), Name('.'), Name('emit')] + [ArgList([args])]) else: res = Node(syms.power, [emitter, Name('.'), Name(signame), Name('.'), Name('emit()')]) 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(signame), Name('.'), method] + [ArgList([slot])]) return res
def RaisesOp(context, exceptionClass, indent, kws, arglist, node): with_item = Call(Name(context), [exceptionClass]) with_item.prefix = " " args = [] arglist = [a.clone() for a in arglist.children[4:]] if arglist: arglist[0].prefix = "" func = None # :fixme: this uses hardcoded parameter names, which may change if 'callableObj' in kws: func = kws['callableObj'] elif 'callable_obj' in kws: func = kws['callable_obj'] elif kws['args']: # any arguments assigned to `*args` func = kws['args'][0] else: func = None if func is None: # Context manager return Node(syms.with_stmt, [with_item]) if func.type == syms.lambdef: suite = func.children[-1].clone() else: suite = Call(func, arglist) suite.prefix = indent + (4 * " ") return Node( syms.with_stmt, [Name('with'), with_item, Name(':'), Newline(), suite])
def RaisesRegexOp(context, designator, exceptionClass, expected_regex, indent, kws, arglist, node): expected_regex.prefix = "" arglist = [a.clone() for a in arglist.children] del arglist[2:4] # remove pattern and comma arglist = Node(syms.arglist, arglist) with_stmt = RaisesOp(context, exceptionClass, indent, kws, arglist, node) with_stmt.insert_child(2, Name('as', prefix=" ")) with_stmt.insert_child(3, Name(designator, prefix=" ")) # if this is already part of a with statement we need to insert re.search # after the last leaf with content if node.parent.type == syms.with_stmt: parent_with = node.parent for leaf in reversed(list(parent_with.leaves())): if leaf.value.strip(): break i = leaf.parent.children.index(leaf) leaf.parent.insert_child(i + 1, Newline()) leaf.parent.insert_child( i + 2, Name('assert %s.match(%s)' % (designator, expected_regex), prefix=indent)) return with_stmt else: return Node(syms.suite, [ with_stmt, Newline(), Name('assert %s.match(%s)' % (designator, expected_regex), prefix=indent) ])
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): cls = node.parent.parent.parent.parent assert cls.type == syms.classdef, ( "Internal error in the fields annotator" ) ast_node_name = cls.children[1].value ast_node = self.astnodes()[ast_node_name] ":type: langkit.compiled_types.ASTNodeType" field_name = node.parent.children[0].value field = ast_node.get_abstract_node_data_dict()[field_name] field_type_name = field.type.dsl_name # This assumes that a typerepo instance of name T is available in # the environment in which nodes are defined. type_expr = build_attr("T", field_type_name) if field.type.is_list_type: type_expr = build_attr( build_attr("T", field.type.element_type.dsl_name), "list" ) return Call(Name(" Field"), [KeywordArg(Name("type"), type_expr)])
def transform(self, node, results): u""" Call __builtins__.long() with the value and the base of the value. This works because 0b10 is int("10", 2), 0o10 is int("10", 8), etc. """ val = node.value base_ = base(val) if base_ == 8: assert val.strip().startswith(u"0o") or \ val.strip().startswith( u"0O"), u"Invalid format for octal literal" node.changed() node.value = u"".join((u"0", val[2:])) elif base_ == 2: assert val.startswith(u"0") and val[1] in u"bB", \ u"Invalid format for binary literal" # __builtins__.long func_name = Node(syms.power, Attr(Name(u"__builtins__"), Name(u"long"))) # ("...", 2) func_args = [ String(u"".join((u"\"", val.strip()[2:], u"\""))), Comma(), Number(2, prefix=u" ") ] new_node = Call(func_name, func_args, node.prefix) return new_node
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. import pdb pdb.set_trace() 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 transform(self, node, results): # Mostly copied from fix_imports.py import_mod = results.get("module_name") if import_mod: try: mod_name = import_mod.value except AttributeError: # XXX: A hack to remove whitespace prefixes and suffixes mod_name = str(import_mod).strip() new_name = 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_text = ''.join(map(str, results['bare_with_attr'])).strip() new_name = self.replace.get(bare_name_text) bare_name = results["bare_with_attr"][0] if new_name: node.replace(Name(new_name, prefix=bare_name.prefix))
def transform(self, node: LN, capture: Capture) -> None: if node.type == syms.simple_stmt: trust_trace_headers_value = None header_trust_handler_seen = False for prev_argument, argument in pairwise(capture["arguments"]): if argument.type == syms.argument: if argument.children[0].value == "trust_trace_headers": assert argument.children[1].value == "=" trust_trace_headers_value = argument.children[2].clone() argument.remove() if prev_argument.type == token.COMMA: prev_argument.remove() elif argument.children[0].value == "header_trust_handler": header_trust_handler_seen = True if trust_trace_headers_value and not header_trust_handler_seen: capture["arglist"].append_child(Comma()) handler_kwarg = KeywordArg( Name("trust_headers"), trust_trace_headers_value ) handler = Call(Name("StaticTrustHandler"), args=[handler_kwarg]) kwarg = KeywordArg(Name("header_trust_handler"), handler) kwarg.prefix = " " capture["arglist"].append_child(kwarg) self.added_static_trust_handler = True
def RaisesOp(context, exceptionClass, indent, kws, arglist): with_item = Call(Name(context), [exceptionClass]) with_item.prefix = " " args = [] arglist = [a.clone() for a in arglist.children[4:]] if arglist: arglist[0].prefix="" func = None # :fixme: this uses hardcoded parameter names, which may change if 'callableObj' in kws: func = kws['callableObj'] elif 'callable_obj' in kws: func = kws['callable_obj'] elif kws['args']: # any arguments assigned to `*args` func = kws['args'][0] else: raise NotImplementedError('with %s is not implemented' % context) if func is unittest.case._sentinel: # with self.assertRaises(SomeException): return Node(syms.with_stmt, [with_item]) suite = Call(func, arglist) suite.prefix = indent + (4 * " ") return Node(syms.with_stmt, [Name('with'), with_item, Name(':'), Newline(), suite])
def fix_dotted_name(self, node, mapping=MAPPING): u""" Accepts either a DottedName node or a power node with a trailer. If mapping is given, use it; otherwise use our MAPPING Returns a node that can be in-place replaced by the node given """ if node.type == syms.dotted_name: _name = node.children[0] _attr = node.children[2] elif node.type == syms.power: _name = node.children[0] _attr = node.children[1].children[1] name = _name.value attr = _attr.value full_name = name + u'.' + attr if not full_name in mapping: return to_repl = mapping[full_name] if u'.' in to_repl: repl_name, repl_attr = to_repl.split(u'.') _name.replace(Name(repl_name, prefix=_name.prefix)) _attr.replace(Name(repl_attr, prefix=_attr.prefix)) elif node.type == syms.dotted_name: node.replace(Name(to_repl, prefix=node.prefix)) elif node.type == syms.power: _name.replace(Name(to_repl, prefix=_name.prefix)) parent = _attr.parent _attr.remove() parent.remove()
def transform(self, node, results): head = results["head"] method = results["method"][0] # Extract node for method name tail = results["tail"] syms = self.syms method_name = method.value isiter = method_name.startswith(u"iter") isview = method_name.startswith(u"view") head = [n.clone() for n in head] tail = [n.clone() for n in tail] # no changes neccessary if the call is in a special context special = not tail and self.in_special_context(node, isiter) new = pytree.Node(syms.power, head) new.prefix = u"" if isiter or isview: # replace the method with the six function # e.g. d.iteritems() -> from six import iteritems\n iteritems(d) new = Call(Name(method_name), [new]) touch_import_top('six', method_name, node) elif special: # it is not neccessary to change this case return node elif method_name in ("items", "values"): # ensure to return a list in python 3 new = Call(Name(u"list" + method_name), [new]) touch_import_top('future.utils', 'list' + method_name, node) else: # method_name is "keys"; removed it and cast the dict to list new = Call(Name(u"list"), [new]) if tail: new = pytree.Node(syms.power, [new] + tail) new.prefix = node.prefix return new
def ImportAsName(name: str, nick: Optional[str], prefix: Optional[str] = None) -> Node: if not nick: return Name(name, prefix=prefix) return Node( syms.import_as_name, [Name(name), Name("as", prefix=" "), Name(nick, prefix=" ")], prefix=prefix, )
def transform(self, node, results): tb = results['tb'].clone() tb.prefix = '' with_tb = Attr(results['val'].clone(), Name('with_traceback')) + \ [ArgList([tb])] new = pytree.Node(self.syms.simple_stmt, [Name("raise")] + with_tb) new.prefix = node.prefix return new
def ImportAsName(name, as_name, prefix=None): new_name = Name(name) new_as = Name(u"as", prefix=u" ") new_as_name = Name(as_name, prefix=u" ") new_node = Node(syms.import_as_name, [new_name, new_as, new_as_name]) if prefix is not None: new_node.prefix = prefix return new_node
def name_import_replacement(name, attr): children = [Name("import")] for c in all_candidates(name.value, attr.value): children.append(Name(c, prefix=" ")) children.append(Comma()) children.pop() replacement = Node(syms.import_name, children) return replacement
def transform(self, node, results): func = results['func'] touch_import(None, 'collections', node=node) args = [func.clone(), String(', ')] args.extend(Attr(Name('collections'), Name('Callable'))) return Call(Name('isinstance'), args, prefix=node.prefix)
def _CreateCode(indent, package, symbols, comment): """ Create code: from <package> import <symbols> # <comment> """ # children: the children nodes for the final from-import statement children = [ Name('from', prefix=' ' * indent), Name(package, prefix=' '), Name('import', prefix=' '), ] # name_leaf: list of leaf nodes with the symbols to import name_leafs = [] symbols = sorted(symbols) for i, i_symbol in enumerate(symbols): prefix = ' ' if i == 0 else ', ' name_leafs.append(i_symbol.CreateNameNode(prefix)) # nodes_wrap: if true, we need to wrap the import statement nodes_wrap = False line_len = 0 line_len += six.moves.reduce(lambda x, y: x + y, map(len, map(str, children)), 0) line_len += six.moves.reduce(lambda x, y: x + y, map(len, map(str, name_leafs)), 0) if line_len > page_width: # Add parenthesis around the "from" names name_leafs[0].prefix = '' name_leafs.insert(0, Name('(', prefix=' ')) name_leafs.append(Name(')')) nodes_wrap = True # Adds the name_leafs to the children list children += [ Node(pygram.python_symbols.import_as_names, name_leafs) ] # from_import: the final node for the import statement from_import = Node(pygram.python_symbols.import_from, children) # result: a simple-statement node with the import statement and # EOL. new_line = Newline() new_line.prefix = comment result = Node( pygram.python_symbols.simple_stmt, children=[ from_import, new_line, ], ) # Wrap nodes if necessary (see nodes_wrap above) if nodes_wrap: ImportBlock.TextWrapForNode(result, page_width, indent) return result
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_import(self, node, results): import_mod = results.get('module') pref = import_mod.prefix names = [] for name in MAPPING[import_mod.value][:-1]: names.extend([Name(name[0], prefix=pref), Comma()]) names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref)) import_mod.replace(names)
def UnaryOp(prefix, postfix, value, kws): kids = [] if prefix: kids.append(Name(prefix, prefix=" ")) value.prefix = " " kids.append(value) if postfix: kids.append(Name(postfix, prefix=" ")) return Node(syms.test, kids, prefix=" ")
def _handle_buildin(self, node, method_name): if method_name == "open": arglist = node.children[1].children[1] first_arg, remaining_args = self._split_arguments(arglist) x = Call(Name("Path"), first_arg, prefix=node.prefix) x.append_child(Call(Name("open"), remaining_args, prefix=".")) return x else: raise ValueError("Method not found")
def _handle_no_args(self, node, method_name): if method_name == "getcwd": method_name = "cwd" if method_name == "listdir": return Call(Name('list'), [Call(Name('Path(".").glob'), args=[String('"*"')])], prefix=node.prefix) return Call(Name('Path.{}'.format(method_name)), prefix=node.prefix)
def new_future_import(self, old): new = FromImport("__future__", [ Name("absolute_import", prefix=" "), Comma(), Name("division", prefix=" "), Comma(), Name("print_function", prefix=" ") ]) if old is not None: new.prefix = old.prefix return new
def transform(self, node, results): if 'name' in results: touch_import(None, u'six', node) name = results['name'] name.replace(Name(u'six.text_type', prefix=name.prefix)) elif node.type == token.STRING and _literal_re.match(node.value): touch_import(None, u'six', node) new = node.clone() new.value = new.value[1:] new.prefix = '' node.replace(Call(Name(u'six.u', prefix=node.prefix), [new]))
def transform(self, node, results): def process_arg(arg): if isinstance(arg, Leaf) and arg.type == token.COMMA: return elif isinstance(arg, Node) and arg.type == syms.argument: # keyword argument name, equal, value = arg.children assert name.type == token.NAME # what is the symbol for 1? assert equal.type == token.EQUAL # what is the symbol for 1? value = value.clone() value.prefix = " " kwargs[name.value] = value else: assert not kwargs, 'all positional args are assumed to come first' posargs.append(arg.clone()) method = results['method'][0].value # map (deprecated) aliases to original to avoid analysing # the decorator function method = _method_aliases.get(method, method) posargs = [] kwargs = {} # This is either a "arglist" or a single argument if results['arglist'].type == syms.arglist: for arg in results['arglist'].children: process_arg(arg) else: process_arg(results['arglist']) try: test_func = getattr(unittest.TestCase, method) except AttributeError: raise RuntimeError("Your unittest package does not support '%s'. " "consider updating the package" % method) required_args, argsdict = utils.resolve_func_args(test_func, posargs, kwargs) if method.startswith(('assertRaises', 'assertWarns')): n_stmt = _method_map[method](*required_args, indent=find_indentation(node), kws=argsdict, arglist=results['arglist']) else: n_stmt = Node(syms.assert_stmt, [Name('assert'), _method_map[method](*required_args, kws=argsdict)]) if argsdict.get('msg', None) is not None: n_stmt.children.extend((Name(','), argsdict['msg'])) n_stmt.prefix = node.prefix return n_stmt
def NameImport(package, as_name=None, prefix=None): """ Accepts a package (Name node), name to import it as (string), and optional prefix and returns a node: import <package> [as <as_name>] """ if prefix is None: prefix = u"" children = [Name(u"import", prefix=prefix), package] if as_name is not None: children.extend([Name(u"as", prefix=u" "), Name(as_name, prefix=u" ")]) return Node(syms.import_name, children)
def transform_import(self, node, results): """Transform for the basic import case. Replaces the old import name with a comma separated list of its replacements. """ import_mod = results.get('module') pref = import_mod.prefix names = [] for name in MAPPING[import_mod.value][:-1]: names.extend([Name(name[0], prefix=pref), Comma()]) names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref)) import_mod.replace(names)
def UnaryOp(prefix, postfix, value, kws): if prefix or postfix: value = parenthesize_expression(value) kids = [] if prefix: kids.append(Name(prefix, prefix=" ")) value.prefix = " " kids.append(value) if postfix: kids.append(Name(postfix, prefix=" ")) return Node(syms.test, kids, prefix=" ")
def transform(self, node, results): def process_arg(arg): if isinstance(arg, Leaf) and arg.type == token.COMMA: return elif isinstance(arg, Node) and arg.type == syms.argument: # keyword argument name, equal, value = arg.children assert name.type == token.NAME # what is the symbol for 1? assert equal.type == token.EQUAL # what is the symbol for 1? value = value.clone() value.prefix = " " kwargs[name.value] = value else: assert not kwargs, 'all positional args are assumed to come first' posargs.append(arg.clone()) func = results['func'].value custom_helper = False if node.parent.type == syms.return_stmt: # custom helper with `return eq_(...)` # We're not rendering the `assert` in that case # to allow the code to continue functioning custom_helper = True posargs = [] kwargs = [] if results['arglist'].type == syms.arglist: for arg in results['arglist'].children: process_arg(arg) else: process_arg(results['arglist']) if len(posargs) == 2: left, right = posargs elif len(posargs) == 3: left, right, _ = posargs left.prefix = " " right.prefix = " " strip_newlines(left) strip_newlines(right) # Ignore customized assert messages for now if isinstance(right, Leaf) and right.value in ('None', 'True', 'False'): op = Name('is', prefix=' ') body = [Node(syms.comparison, (left, op, right))] else: op = Name('==', prefix=' ') body = [Node(syms.comparison, (left, op, right))] indent = find_indentation(node) ret = Name('assert') if node.parent.prefix.endswith(indent): ret.prefix = indent if custom_helper: return body return [ret] + body