Beispiel #1
0
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))
Beispiel #2
0
    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
Beispiel #3
0
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_
Beispiel #4
0
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)
        ])
Beispiel #5
0
    def transform(self, node: LN, capture: Capture) -> None:
        full_name = []
        trailer: List[LN] = []
        for i, n in enumerate(node.children):
            if n.type == token.NAME:
                full_name.append(n.value)
            elif n.type == syms.trailer:
                if n.children[0].type != token.DOT:
                    trailer = node.children[i:]
                    break
                full_name.append(n.children[1].value)
            else:
                trailer = node.children[i:]

        try:
            new_name = self.renames.get_new_name(".".join(full_name))
        except NameRemovedError as exc:
            self.warn(node, str(exc))
            return

        if new_name:
            new_node = Node(syms.power,
                            AttrChain(new_name),
                            prefix=node.prefix)
            for n in trailer:
                new_node.append_child(n)
            node.replace(new_node)
Beispiel #6
0
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])
Beispiel #7
0
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 fixup_simple_stmt(parent, i, stmt_node):
    """if there is a semi-colon all the parts count as part of the same
    simple_stmt.

    We just want the __metaclass__ part so we move
        everything efter the semi-colon into its own simple_stmt node

    """
    for semi_ind, node in enumerate(stmt_node.children):
        if node.type == token.SEMI:  # *sigh*
            break
    else:
        return

    node.remove()  # kill the semicolon
    new_expr = Node(syms.expr_stmt, [])
    new_stmt = Node(syms.simple_stmt, [new_expr])
    while stmt_node.children[semi_ind:]:
        move_node = stmt_node.children[semi_ind]
        new_expr.append_child(move_node.clone())
        move_node.remove()
    parent.insert_child(i, new_stmt)
    new_leaf1 = new_stmt.children[0].children[0]
    old_leaf1 = stmt_node.children[0].children[0]
    new_leaf1.prefix = old_leaf1.prefix
Beispiel #9
0
 def transform(self, node, results):
     # before
     before = [b.clone() for b in results['before']]
     # tr | translate
     tr = results['tr']
     new_tr = [(tr[0] if isinstance(tr, list) else tr).clone()]
     # message
     message = results['message'].clone()
     for ch in (message.pre_order() if not isinstance(message, Leaf) else [message]):
         if isinstance(ch, Leaf):
             for i in range(N_ARGS):
                 # %1 -> {0}, ...
                 ch.value = ch.value.replace("%{0}".format(i+1), "{%d}" % i)
     new_tr += [ArgList([message])]
     # format
     def format_args():
         for key in sorted(results):
             if key.startswith('arg'):
                 arg = results[key]
                 if isinstance(arg, list):
                     for a in arg:
                         yield a.clone()
                 else:
                     yield arg.clone()
                 yield Comma()
                 yield String(' ')
                                                     # Skip last Comma, String
     new_format = [Dot(), Name('format'), ArgList(list(format_args())[:-2])]
     # rest
     rest = [r.clone() for r in results['rest']]
     # new node
     new = Node(syms.power, before + new_tr + new_format + rest)
     new.prefix = node.prefix
     new.parent = node.parent
     return new
Beispiel #10
0
    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
Beispiel #11
0
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
Beispiel #12
0
    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 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
Beispiel #14
0
def RaisesRegexOp(context, designator, exceptionClass, expected_regex,
                  indent, kws, arglist):
    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)
    with_stmt.insert_child(2, Name('as', prefix=" "))
    with_stmt.insert_child(3, Name(designator, prefix=" "))
    return Node(syms.suite,
                [with_stmt,
                 Newline(),
                 Name('assert re.search(pattern, %s.value)' % designator,
                      prefix=indent)
                 ])
def add_import(import_name, node):
    suite = get_parent_of_type(node, syms.suite)
    test_case = suite
    while test_case.parent.type != syms.file_input:
        test_case = test_case.parent
    file_input = test_case.parent

    if not does_tree_import(None, import_name, node):
        import_stmt = Node(syms.simple_stmt, [
            Node(
                syms.import_name,
                [Name('import'), Name(import_name, prefix=' ')]),
            Newline(),
        ])
        insert_import(import_stmt, test_case, file_input)
Beispiel #16
0
 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)]
Beispiel #17
0
def future_import2(feature, node):
    """
    An alternative to future_import() which might not work ...
    """
    root = find_root(node)

    if does_tree_import(u"__future__", feature, node):
        return

    insert_pos = 0
    for idx, node in enumerate(root.children):
        if node.type == syms.simple_stmt and node.children and \
                node.children[0].type == token.STRING:
            insert_pos = idx + 1
            break

    for thing_after in root.children[insert_pos:]:
        if thing_after.type == token.NEWLINE:
            insert_pos += 1
            continue

        prefix = thing_after.prefix
        thing_after.prefix = u""
        break
    else:
        prefix = u""

    import_ = FromImport(u"__future__", [Leaf(token.NAME, feature, prefix=u" ")])

    children = [import_, Newline()]
    root.insert_child(insert_pos, Node(syms.simple_stmt, children, prefix=prefix))
Beispiel #18
0
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
Beispiel #19
0
 def transform(self, node, results):
     FIXME
     name, val, trc = (
         results.get(u"name"),
         results.get(u"val"),
         results.get(u"trc"),
     )
     chain = results.get(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)
Beispiel #20
0
    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 match(self, node):
        u"""
        Since the tree needs to be fixed once and only once if and only if it
        matches, we can start discarding matches after the first.
        """
        if node.type == self.syms.term:
            matched = False
            skip = False
            children = []
            for child in node.children:
                if skip:
                    skip = False
                    continue
                if match_division(child) and not is_floaty(child):
                    matched = True

                    # Strip any leading space for the first number:
                    children[0].prefix = u''

                    children = [
                        wrap_in_fn_call(
                            "old_div",
                            children +
                            [Comma(), child.next_sibling.clone()],
                            prefix=node.prefix)
                    ]
                    skip = True
                else:
                    children.append(child.clone())
            if matched:
                return Node(node.type,
                            children,
                            fixers_applied=node.fixers_applied)

        return False
def RaisesOp(context, exceptionClass, indent, kws, arglist, node):
    exceptionClass.prefix = ""
    args = [exceptionClass]
    # Add match keyword arg to with statement if an expected regex was provided.
    # In py27 the keyword is `expected_regexp`, in py3 is `expected_regex`
    if 'expected_regex' in kws or 'expected_regexp' in kws:
        expected_regex = kws.get('expected_regex',
                                 kws.get('expected_regexp')).clone()
        expected_regex.prefix = ''
        args.append(String(', '))
        args.append(KeywordArg(Name('match'), expected_regex))
    with_item = Call(Name(context), args)
    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:
        # TODO: Newlines within arguments are not handled yet.
        # If argment prefix contains a newline, all whitespace around this
        # ought to be replaced by indent plus 4+1+len(func) spaces.
        suite = Call(func, arglist)

    suite.prefix = indent + (4 * " ")
    return Node(
        syms.with_stmt,
        [Name('with'), with_item,
         Name(':'), Newline(), suite])
Beispiel #23
0
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, 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 CompOp(op, left, right, kws):
    op = Name(op, prefix=" ")
    left = parenthesize_expression(left)
    right = parenthesize_expression(right)

    left.prefix = ""
    if '\n' not in right.prefix:
        right.prefix = " "
    return Node(syms.comparison, (left, op, right), prefix=" ")
Beispiel #26
0
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=" ")
Beispiel #27
0
def FromImport(
    package: str, imports: List[Tuple[str, Optional[str]]], prefix: Optional[str]
) -> Node:
    children = []
    for name, nick in imports:
        children.append(ImportAsName(name, nick, prefix=" "))
        children.append(Comma())
    children.pop()
    import_as_names = Node(syms.import_as_names, children)

    return Node(
        syms.import_from,
        [
            Name("from", prefix=prefix),
            DottedName(package, prefix=" "),
            Name("import", prefix=" "),
            import_as_names,
        ],
    )
def RaisesRegexOp(context, designator, exceptionClass, expected_regex, indent,
                  kws, arglist, node):
    arglist = [a.clone() for a in arglist.children]
    pattern = arglist[2]
    del arglist[2:4]  # remove pattern and comma
    arglist = Node(syms.arglist, arglist)
    with_stmt = RaisesOp(context, exceptionClass, indent, kws, arglist, node)

    # 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)
        return with_stmt
    else:
        return Node(syms.suite, [with_stmt])
Beispiel #29
0
def DottedName(full_name: str, prefix: Optional[str]) -> Node:
    names = [name.strip() for name in full_name.split(".")]

    dotted_name = []
    for name in names:
        dotted_name.append(Name(name))
        dotted_name.append(Dot())
    dotted_name.pop()

    return Node(syms.dotted_name, dotted_name, prefix=prefix)
Beispiel #30
0
 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 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 match(self, node):
        u"""
        Since the tree needs to be fixed once and only once if and only if it
        matches, we can start discarding matches after the first.
        """
        if node.type == self.syms.term:
            matched = False
            skip = False
            children = []
            for child in node.children:
                if skip:
                    skip = False
                    continue
                if match_division(child) and not is_floaty(child):
                    matched = True

                    # Strip any leading space for the first number:
                    children[0].prefix = u''

                    children = [
                        wrap_in_fn_call(
                            "old_div",
                            children +
                            [Comma(), child.next_sibling.clone()],
                            prefix=node.prefix)
                    ]
                    skip = True
                else:
                    children.append(child.clone())
            if matched:
                # In Python 2.6, `Node` does not have the fixers_applied attribute
                # https://github.com/python/cpython/blob/8493c0cd66cfc181ac1517268a74f077e9998701/Lib/lib2to3/pytree.py#L235
                if hasattr(Node, "fixers_applied"):
                    return Node(node.type,
                                children,
                                fixers_applied=node.fixers_applied)
                else:
                    return Node(node.type, children)

        return False
Beispiel #33
0
def fixup_simple_stmt(parent, i, stmt_node):
    """ if there is a semi-colon all the parts count as part of the same
        simple_stmt.  We just want the __metaclass__ part so we move
        everything efter the semi-colon into its own simple_stmt node
    """
    for semi_ind, node in enumerate(stmt_node.children):
        if node.type == token.SEMI:  # *sigh*
            break
    else:
        return

    node.remove()  # kill the semicolon
    new_expr = Node(syms.expr_stmt, [])
    new_stmt = Node(syms.simple_stmt, [new_expr])
    while stmt_node.children[semi_ind:]:
        move_node = stmt_node.children[semi_ind]
        new_expr.append_child(move_node.clone())
        move_node.remove()
    parent.insert_child(i, new_stmt)
    new_leaf1 = new_stmt.children[0].children[0]
    old_leaf1 = stmt_node.children[0].children[0]
    new_leaf1.prefix = old_leaf1.prefix
Beispiel #34
0
def fixup_parse_tree(cls_node):
    """one-line classes don't get a suite in the parse tree so we add one to
    normalize the tree."""
    for node in cls_node.children:
        if node.type == syms.suite:
            # already in the preferred format, do nothing
            return

    # !%@#! oneliners have no suite node, we have to fake one up
    for i, node in enumerate(cls_node.children):
        if node.type == token.COLON:
            break
    else:
        raise ValueError("No class suite and no ':'!")

    # move everything into a suite node
    suite = Node(syms.suite, [])
    while cls_node.children[i + 1:]:
        move_node = cls_node.children[i + 1]
        suite.append_child(move_node.clone())
        move_node.remove()
    cls_node.append_child(suite)
    node = suite
    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"))
Beispiel #36
0
    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):

        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()
                kwargs[name.value] = value
                if '\n' in arg.prefix:
                    value.prefix = arg.prefix
                else:
                    value.prefix = arg.prefix.strip() + " "
            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'],
                                         node=node)
        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']))

        def fix_line_wrapping(x):
            for c in x.children:
                # no need to worry about wrapping of "[", "{" and "("
                if c.type in [token.LSQB, token.LBRACE, token.LPAR]:
                    break
                if c.prefix.startswith('\n'):
                    c.prefix = c.prefix.replace('\n', ' \\\n')
                fix_line_wrapping(c)
        fix_line_wrapping(n_stmt)
        # the prefix should be set only after fixing line wrapping because it can contain a '\n'
        n_stmt.prefix = node.prefix

        # add necessary imports
        if 'Raises' in method or 'Warns' in method:
            add_import('pytest', node)
        if 'Regex' in method:
            add_import('re', node)

        return n_stmt
Beispiel #38
0
    def transform(self, node, results):
        if 'name' in results:
            # This matched an import statement. Fix that up:
            name = results["name"]
            name.replace(Name(self.DECORATOR_NAME, prefix=name.prefix))
        if 'rename' in results:
            # The import statement use import as
            self._add_pattern("'%s'" % results['rename'].value)
        if 'interface_rename' in results:
            self._add_pattern("'%s' trailer< '.' '%s' > " % (
                results['interface_rename'].value, self.FUNCTION_NAME))
        if 'statement' in results:
            # This matched a class that has an <FUNCTION_NAME>(IFoo) statement.
            # We must convert that statement to a class decorator
            # and put it before the class definition.

            statement = results['statement']
            if not isinstance(statement, list):
                statement = [statement]
            # Make a copy for insertion before the class:
            statement = [x.clone() for x in statement]
            # Get rid of leading whitespace:
            statement[0].prefix = ''
            # Rename function to decorator:
            if statement[-1].children:
                func = statement[-1].children[-1]
            else:
                func = statement[-1]
            if func.value == self.FUNCTION_NAME:
                func.value = self.DECORATOR_NAME

            interface = results['interface']
            if not isinstance(interface, list):
                interface = [interface]
            interface = [x.clone() for x in interface]

            # Create the decorator:
            decorator = Node(syms.decorator, [Leaf(50, '@'),] + statement +
                             [Leaf(7, '(')] + interface + [Leaf(8, ')')])

            # Take the current class constructor prefix, and stick it into
            # the decorator, to set the decorators indentation.
            nodeprefix = node.prefix
            decorator.prefix = nodeprefix
            # Preserve only the indent:
            if '\n' in nodeprefix:
                nodeprefix = nodeprefix[nodeprefix.rfind('\n')+1:]

            # Then find the last line of the previous node and use that as
            # indentation, and add that to the class constructors prefix.

            previous = node.prev_sibling
            if previous is None:
                prefix = ''
            else:
                prefix = str(previous)
            if '\n' in prefix:
                prefix = prefix[prefix.rfind('\n')+1:]
            prefix = prefix + nodeprefix

            if not prefix or prefix[0] != '\n':
                prefix = '\n' + prefix
            node.prefix = prefix
            new_node = Node(syms.decorated, [decorator, node.clone()])
            # Look for the actual function calls in the new node and remove it.
            for node in new_node.post_order():
                for pattern in self.function_patterns:
                    if pattern.match(node, results):
                        parent = node.parent
                        previous = node.prev_sibling
                        # Remove the node
                        node.remove()
                        if not str(parent).strip():
                            # This is an empty class. Stick in a pass
                            if (len(parent.children) < 3 or
                                ' ' in parent.children[2].value):
                                # This class had no body whitespace.
                                parent.insert_child(2, Leaf(0, '    pass'))
                            else:
                                # This class had body whitespace already.
                                parent.insert_child(2, Leaf(0, 'pass'))
                            parent.insert_child(3, Leaf(0, '\n'))
                        elif (prefix and isinstance(previous, Leaf) and
                            '\n' not in previous.value and
                            previous.value.strip() == ''):
                            # This is just whitespace, remove it:
                            previous.remove()

            return new_node