def _pick_compatible_python_version(version: Optional[str] = None) -> PythonVersionInfo: max_version = parse_version_string(version) for v in KNOWN_PYTHON_VERSION_STRINGS[::-1]: tmp = parse_version_string(v) if tmp <= max_version: return tmp raise ValueError( f"No version found older than {version} ({max_version}) while " + f"running on {sys.version_info}" )
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)}")
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 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." ) 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)}")
def _get_version_comparison(version: str) -> Tuple[str, PythonVersionInfo]: if version[:2] in (">=", "<=", "==", "!="): return (version[:2], parse_version_string(version[2:].strip())) if version[:1] in (">", "<"): return (version[:1], parse_version_string(version[1:].strip())) raise Exception(f"Invalid version comparison specifier '{version}'")
def __init__(self, bnf_grammar: str) -> None: self._bnf_grammar: str = bnf_grammar self.generator = tokenize(bnf_grammar, version_info=parse_version_string("3.6")) self._gettoken() # Initialize lookahead
def _get_token_list(string, version=None): # Load the current version. version_info = parse_version_string(version) return list(tokenize(string, version_info))
def test_tokenize_start_pos(self, code, positions): tokens = list(tokenize(code, version_info=parse_version_string("3.6"))) assert positions == [p.start_pos for p in tokens]