diff --git a/astroid/builder.py b/astroid/builder.py index 24caa0c6e..f53c4297c 100644 --- a/astroid/builder.py +++ b/astroid/builder.py @@ -134,9 +134,9 @@ def file_build(self, path, modname=None): module, builder = self._data_build(data, modname, path) return self._post_build(module, builder, encoding) - def string_build(self, data, modname="", path=None): + def string_build(self, data, modname="", path=None, *, tree_rev: int | None = None): """Build astroid from source code string.""" - module, builder = self._data_build(data, modname, path) + module, builder = self._data_build(data, modname, path, tree_rev) module.file_bytes = data.encode("utf-8") return self._post_build(module, builder, "utf-8") @@ -162,7 +162,7 @@ def _post_build( return module def _data_build( - self, data: str, modname, path + self, data: str, modname, path, tree_rev: int | None = None ) -> tuple[nodes.Module, rebuilder.TreeRebuilder]: """Build tree node from data and add some informations""" try: @@ -188,7 +188,12 @@ def _data_build( path is not None and os.path.splitext(os.path.basename(path))[0] == "__init__" ) - builder = rebuilder.TreeRebuilder(self._manager, parser_module, data) + builder = rebuilder.TreeRebuilder( + self._manager, + parser_module, + data, + tree_rev=tree_rev or AstroidManager.tree_rev, + ) module = builder.visit_module(node, modname, node_file, package) return module, builder @@ -265,7 +270,14 @@ def build_namespace_package_module(name: str, path: list[str]) -> nodes.Module: return nodes.Module(name, path=path, package=True) -def parse(code, module_name="", path=None, apply_transforms=True): +def parse( + code, + module_name="", + path=None, + apply_transforms=True, + *, + tree_rev: int | None = None, +): """Parses a source string in order to obtain an astroid AST from it :param str code: The code for the module. @@ -279,7 +291,7 @@ def parse(code, module_name="", path=None, apply_transforms=True): builder = AstroidBuilder( manager=AstroidManager(), apply_transforms=apply_transforms ) - return builder.string_build(code, modname=module_name, path=path) + return builder.string_build(code, modname=module_name, path=path, tree_rev=tree_rev) def _extract_expressions(node): diff --git a/astroid/const.py b/astroid/const.py index 87682c942..4059c0836 100644 --- a/astroid/const.py +++ b/astroid/const.py @@ -6,6 +6,11 @@ import sys from pathlib import Path +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + PY38 = sys.version_info[:2] == (3, 8) PY38_PLUS = sys.version_info >= (3, 8) PY39_PLUS = sys.version_info >= (3, 9) @@ -33,3 +38,6 @@ class Context(enum.Enum): ASTROID_INSTALL_DIRECTORY = Path(__file__).parent BRAIN_MODULES_DIRECTORY = ASTROID_INSTALL_DIRECTORY / "brain" + +TREE_REV: Final = 1 +"""Default AST tree revision. Any update here is a breaking change!""" diff --git a/astroid/manager.py b/astroid/manager.py index 23330d5b9..5f82782b0 100644 --- a/astroid/manager.py +++ b/astroid/manager.py @@ -15,7 +15,7 @@ from importlib.util import find_spec, module_from_spec from typing import TYPE_CHECKING, ClassVar -from astroid.const import BRAIN_MODULES_DIRECTORY +from astroid.const import BRAIN_MODULES_DIRECTORY, TREE_REV from astroid.exceptions import AstroidBuildingError, AstroidImportError from astroid.interpreter._import import spec from astroid.modutils import ( @@ -62,6 +62,7 @@ class AstroidManager: "_transform": TransformVisitor(), } max_inferable_values: ClassVar[int] = 100 + tree_rev: ClassVar[int] = TREE_REV def __init__(self): # NOTE: cache entries are added by the [re]builder diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py index e4f9ee5a1..84f2bff2c 100644 --- a/astroid/rebuilder.py +++ b/astroid/rebuilder.py @@ -18,7 +18,7 @@ from astroid import nodes from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment -from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS, Context +from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS, TREE_REV, Context from astroid.manager import AstroidManager from astroid.nodes import NodeNG from astroid.nodes.utils import Position @@ -61,9 +61,12 @@ def __init__( manager: AstroidManager, parser_module: ParserModule | None = None, data: str | None = None, + *, + tree_rev: int = TREE_REV, ) -> None: self._manager = manager self._data = data.split("\n") if data else None + self._tree_rev = tree_rev self._global_names: list[dict[str, list[nodes.Global]]] = [] self._import_from_nodes: list[nodes.ImportFrom] = [] self._delayed_assattr: list[nodes.AssignAttr] = []