Ejemplo n.º 1
0
def convert_file_input(config: ParserConfig, children: Sequence[Any]) -> Any:
    *body, footer = children
    if len(body) == 0:
        # If there's no body, the header and footer are ambiguous. The header is more
        # important, and should own the EmptyLine nodes instead of the footer.
        header = footer
        footer = ()
        if (len(config.lines) == 2 and NEWLINE_RE.fullmatch(config.lines[0])
                and config.lines[1] == ""):
            # This is an empty file (not even a comment), so special-case this to an
            # empty list instead of a single dummy EmptyLine (which is what we'd
            # normally parse).
            header = ()
    else:
        # Steal the leading lines from the first statement, and move them into the
        # header.
        first_stmt = body[0]
        header = first_stmt.leading_lines
        body[0] = first_stmt.with_changes(leading_lines=())
    return Module(
        header=header,
        body=body,
        footer=footer,
        encoding=config.encoding,
        default_indent=config.default_indent,
        default_newline=config.default_newline,
        has_trailing_newline=config.has_trailing_newline,
    )
Ejemplo n.º 2
0
def _detect_trailing_newline(source_str: str) -> bool:
    if len(source_str) == 0 or not NEWLINE_RE.fullmatch(source_str[-1]):
        return False
    # Make sure that the last newline wasn't following a continuation
    return not (
        _CONTINUATION_RE.fullmatch(source_str[-2:])
        or _CONTINUATION_RE.fullmatch(source_str[-3:])
    )
Ejemplo n.º 3
0
    def __post_init__(self) -> None:
        raw_python_version = self.python_version

        if isinstance(raw_python_version, AutoConfig):
            # If unspecified, we'll try to pick the same as the running
            # interpreter.  There will always be at least one entry.
            parsed_python_version = _pick_compatible_python_version()
        else:
            # If the caller specified a version, we require that to be a known
            # version (because we don't want to encourage doing duplicate work
            # when there weren't syntax changes).

            # `parse_version_string` will raise a ValueError if the version is
            # invalid.
            parsed_python_version = parse_version_string(raw_python_version)

        if not any(
            parsed_python_version == parse_version_string(v)
            for v in KNOWN_PYTHON_VERSION_STRINGS
        ):
            comma_versions = ", ".join(KNOWN_PYTHON_VERSION_STRINGS)
            raise ValueError(
                "LibCST can only parse code using one of the following versions of "
                + f"Python's grammar: {comma_versions}. More versions may be "
                + "supported by future releases."
            )

        # We use object.__setattr__ because the dataclass is frozen. See:
        # https://docs.python.org/3/library/dataclasses.html#frozen-instances
        # This should be safe behavior inside of `__post_init__`.
        object.__setattr__(self, "parsed_python_version", parsed_python_version)

        encoding = self.encoding
        if not isinstance(encoding, AutoConfig):
            try:
                codecs.lookup(encoding)
            except LookupError:
                raise ValueError(f"{repr(encoding)} is not a supported encoding")

        newline = self.default_newline
        if (
            not isinstance(newline, AutoConfig)
            and NEWLINE_RE.fullmatch(newline) is None
        ):
            raise ValueError(
                f"Got an invalid value for default_newline: {repr(newline)}"
            )

        indent = self.default_indent
        if not isinstance(indent, AutoConfig) and _INDENT_RE.fullmatch(indent) is None:
            raise ValueError(f"Got an invalid value for default_indent: {repr(indent)}")
Ejemplo n.º 4
0
    def __post_init__(self) -> None:
        raw_python_version = self.python_version
        # `parse_version_string` will raise a ValueError if the version is invalid.
        #
        # We use object.__setattr__ because the dataclass is frozen. See:
        # https://docs.python.org/3/library/dataclasses.html#frozen-instances
        # This should be safe behavior inside of `__post_init__`.
        parsed_python_version = parse_version_string(None if isinstance(
            raw_python_version, AutoConfig) else raw_python_version)

        # Once we add support for more versions of Python, we can change this to detect
        # the supported version range.
        if parsed_python_version not in (
                PythonVersionInfo(3, 5),
                PythonVersionInfo(3, 6),
                PythonVersionInfo(3, 7),
                PythonVersionInfo(3, 8),
        ):
            raise ValueError(
                "LibCST can only parse code using one of the following versions of "
                +
                "Python's grammar: 3.5, 3.6, 3.7, 3.8. More versions may be " +
                "supported by future releases.")

        object.__setattr__(self, "parsed_python_version",
                           parsed_python_version)

        encoding = self.encoding
        if not isinstance(encoding, AutoConfig):
            try:
                codecs.lookup(encoding)
            except LookupError:
                raise ValueError(
                    f"{repr(encoding)} is not a supported encoding")

        newline = self.default_newline
        if (not isinstance(newline, AutoConfig)
                and NEWLINE_RE.fullmatch(newline) is None):
            raise ValueError(
                f"Got an invalid value for default_newline: {repr(newline)}")

        indent = self.default_indent
        if not isinstance(indent,
                          AutoConfig) and _INDENT_RE.fullmatch(indent) is None:
            raise ValueError(
                f"Got an invalid value for default_indent: {repr(indent)}")