Beispiel #1
0
def get_features_used(node: Node) -> Set[Feature]:
    """Return a set of (relatively) new Python features used in this file.

    Currently looking for:
    - f-strings;
    - underscores in numeric literals;
    - trailing commas after * or ** in function signatures and calls;
    - positional only arguments in function signatures and lambdas;
    - assignment expression;
    - relaxed decorator syntax;
    """
    features: Set[Feature] = set()
    for n in node.pre_order():
        if n.type == token.STRING:
            value_head = n.value[:2]  # type: ignore
            if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
                features.add(Feature.F_STRINGS)

        elif n.type == token.NUMBER:
            if "_" in n.value:  # type: ignore
                features.add(Feature.NUMERIC_UNDERSCORES)

        elif n.type == token.SLASH:
            if n.parent and n.parent.type in {syms.typedargslist, syms.arglist}:
                features.add(Feature.POS_ONLY_ARGUMENTS)

        elif n.type == token.COLONEQUAL:
            features.add(Feature.ASSIGNMENT_EXPRESSIONS)

        elif n.type == syms.decorator:
            if len(n.children) > 1 and not is_simple_decorator_expression(
                n.children[1]
            ):
                features.add(Feature.RELAXED_DECORATORS)

        elif (
            n.type in {syms.typedargslist, syms.arglist}
            and n.children
            and n.children[-1].type == token.COMMA
        ):
            if n.type == syms.typedargslist:
                feature = Feature.TRAILING_COMMA_IN_DEF
            else:
                feature = Feature.TRAILING_COMMA_IN_CALL

            for ch in n.children:
                if ch.type in STARS:
                    features.add(feature)

                if ch.type == syms.argument:
                    for argch in ch.children:
                        if argch.type in STARS:
                            features.add(feature)

    return features
Beispiel #2
0
def get_features_used(node: Node) -> Set[Feature]:  # noqa: C901
    """Return a set of (relatively) new Python features used in this file.

    Currently looking for:
    - f-strings;
    - underscores in numeric literals;
    - trailing commas after * or ** in function signatures and calls;
    - positional only arguments in function signatures and lambdas;
    - assignment expression;
    - relaxed decorator syntax;
    - print / exec statements;
    """
    features: Set[Feature] = set()
    for n in node.pre_order():
        if n.type == token.STRING:
            value_head = n.value[:2]  # type: ignore
            if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
                features.add(Feature.F_STRINGS)

        elif n.type == token.NUMBER:
            assert isinstance(n, Leaf)
            if "_" in n.value:
                features.add(Feature.NUMERIC_UNDERSCORES)
            elif n.value.endswith(("L", "l")):
                # Python 2: 10L
                features.add(Feature.LONG_INT_LITERAL)
            elif len(n.value
                     ) >= 2 and n.value[0] == "0" and n.value[1].isdigit():
                # Python 2: 0123; 00123; ...
                if not all(char == "0" for char in n.value):
                    # although we don't want to match 0000 or similar
                    features.add(Feature.OCTAL_INT_LITERAL)

        elif n.type == token.SLASH:
            if n.parent and n.parent.type in {
                    syms.typedargslist,
                    syms.arglist,
                    syms.varargslist,
            }:
                features.add(Feature.POS_ONLY_ARGUMENTS)

        elif n.type == token.COLONEQUAL:
            features.add(Feature.ASSIGNMENT_EXPRESSIONS)

        elif n.type == syms.decorator:
            if len(n.children) > 1 and not is_simple_decorator_expression(
                    n.children[1]):
                features.add(Feature.RELAXED_DECORATORS)

        elif (n.type in {syms.typedargslist, syms.arglist} and n.children
              and n.children[-1].type == token.COMMA):
            if n.type == syms.typedargslist:
                feature = Feature.TRAILING_COMMA_IN_DEF
            else:
                feature = Feature.TRAILING_COMMA_IN_CALL

            for ch in n.children:
                if ch.type in STARS:
                    features.add(feature)

                if ch.type == syms.argument:
                    for argch in ch.children:
                        if argch.type in STARS:
                            features.add(feature)

        # Python 2 only features (for its deprecation) except for integers, see above
        elif n.type == syms.print_stmt:
            features.add(Feature.PRINT_STMT)
        elif n.type == syms.exec_stmt:
            features.add(Feature.EXEC_STMT)
        elif n.type == syms.tfpdef:
            # def set_position((x, y), value):
            #     ...
            features.add(Feature.AUTOMATIC_PARAMETER_UNPACKING)
        elif n.type == syms.except_clause:
            # try:
            #     ...
            # except Exception, err:
            #     ...
            if len(n.children) >= 4:
                if n.children[-2].type == token.COMMA:
                    features.add(Feature.COMMA_STYLE_EXCEPT)
        elif n.type == syms.raise_stmt:
            # raise Exception, "msg"
            if len(n.children) >= 4:
                if n.children[-2].type == token.COMMA:
                    features.add(Feature.COMMA_STYLE_RAISE)
        elif n.type == token.BACKQUOTE:
            # `i'm surprised this ever existed`
            features.add(Feature.BACKQUOTE_REPR)

    return features
Beispiel #3
0
def get_features_used(  # noqa: C901
        node: Node,
        *,
        future_imports: Optional[Set[str]] = None) -> Set[Feature]:
    """Return a set of (relatively) new Python features used in this file.

    Currently looking for:
    - f-strings;
    - underscores in numeric literals;
    - trailing commas after * or ** in function signatures and calls;
    - positional only arguments in function signatures and lambdas;
    - assignment expression;
    - relaxed decorator syntax;
    - usage of __future__ flags (annotations);
    - print / exec statements;
    """
    features: Set[Feature] = set()
    if future_imports:
        features |= {
            FUTURE_FLAG_TO_FEATURE[future_import]
            for future_import in future_imports
            if future_import in FUTURE_FLAG_TO_FEATURE
        }

    for n in node.pre_order():
        if is_string_token(n):
            value_head = n.value[:2]
            if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
                features.add(Feature.F_STRINGS)

        elif n.type == token.NUMBER:
            assert isinstance(n, Leaf)
            if "_" in n.value:
                features.add(Feature.NUMERIC_UNDERSCORES)

        elif n.type == token.SLASH:
            if n.parent and n.parent.type in {
                    syms.typedargslist,
                    syms.arglist,
                    syms.varargslist,
            }:
                features.add(Feature.POS_ONLY_ARGUMENTS)

        elif n.type == token.COLONEQUAL:
            features.add(Feature.ASSIGNMENT_EXPRESSIONS)

        elif n.type == syms.decorator:
            if len(n.children) > 1 and not is_simple_decorator_expression(
                    n.children[1]):
                features.add(Feature.RELAXED_DECORATORS)

        elif (n.type in {syms.typedargslist, syms.arglist} and n.children
              and n.children[-1].type == token.COMMA):
            if n.type == syms.typedargslist:
                feature = Feature.TRAILING_COMMA_IN_DEF
            else:
                feature = Feature.TRAILING_COMMA_IN_CALL

            for ch in n.children:
                if ch.type in STARS:
                    features.add(feature)

                if ch.type == syms.argument:
                    for argch in ch.children:
                        if argch.type in STARS:
                            features.add(feature)

        elif (n.type in {syms.return_stmt, syms.yield_expr}
              and len(n.children) >= 2
              and n.children[1].type == syms.testlist_star_expr
              and any(child.type == syms.star_expr
                      for child in n.children[1].children)):
            features.add(Feature.UNPACKING_ON_FLOW)

        elif (n.type == syms.annassign and len(n.children) >= 4
              and n.children[3].type == syms.testlist_star_expr):
            features.add(Feature.ANN_ASSIGN_EXTENDED_RHS)

        elif (n.type == syms.except_clause and len(n.children) >= 2
              and n.children[1].type == token.STAR):
            features.add(Feature.EXCEPT_STAR)

    return features