Skip to content

Commit

Permalink
Make manager required in AstroidBuilder/InspectBuilder (#2313)
Browse files Browse the repository at this point in the history
Co-authored-by: Pierre Sassoulas <[email protected]>
  • Loading branch information
jacobtylerwalls and Pierre-Sassoulas authored Feb 3, 2025
1 parent d2fa037 commit 3c6516e
Show file tree
Hide file tree
Showing 16 changed files with 331 additions and 253 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Release date: TBA
* Removed internal functions ``infer_numpy_member``, ``name_looks_like_numpy_member``, and
``attribute_looks_like_numpy_member`` from ``astroid.brain.brain_numpy_utils``.

* To alleviate circular imports, the ``manager`` argument to ``AstroidBuilder()`` is now required.

* Constants now have a parent of ``nodes.SYNTHETIC_ROOT``.

* Fix crashes with large positive and negative list multipliers.
Expand Down
4 changes: 2 additions & 2 deletions astroid/brain/brain_nose.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def _pep8(name, caps=CAPITALS):

def _nose_tools_functions():
"""Get an iterator of names and bound methods."""
module = AstroidBuilder().string_build(
module = AstroidBuilder(AstroidManager()).string_build(
textwrap.dedent(
"""
import unittest
Expand Down Expand Up @@ -54,7 +54,7 @@ def _nose_tools_transform(node):

def _nose_tools_trivial_transform():
"""Custom transform for the nose.tools module."""
stub = AstroidBuilder().string_build("""__all__ = []""")
stub = AstroidBuilder(AstroidManager()).string_build("""__all__ = []""")
all_entries = ["ok_", "eq_"]

for pep8_name, method in _nose_tools_functions():
Expand Down
21 changes: 11 additions & 10 deletions astroid/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
from collections.abc import Iterator, Sequence
from io import TextIOWrapper
from tokenize import detect_encoding
from typing import TYPE_CHECKING

from astroid import bases, modutils, nodes, raw_building, rebuilder, util
from astroid._ast import ParserModule, get_parser_module
from astroid.const import PY312_PLUS
from astroid.exceptions import AstroidBuildingError, AstroidSyntaxError, InferenceError
from astroid.manager import AstroidManager

if TYPE_CHECKING:
from astroid.manager import AstroidManager

# The name of the transient function that is used to
# wrap expressions to be extracted when calling
Expand Down Expand Up @@ -62,20 +65,17 @@ def _can_assign_attr(node: nodes.ClassDef, attrname: str | None) -> bool:
class AstroidBuilder(raw_building.InspectBuilder):
"""Class for building an astroid tree from source code or from a live module.
The param *manager* specifies the manager class which should be used.
If no manager is given, then the default one will be used. The
The param *manager* specifies the manager class which should be used. The
param *apply_transforms* determines if the transforms should be
applied after the tree was built from source or from a live object,
by default being True.
"""

def __init__(
self, manager: AstroidManager | None = None, apply_transforms: bool = True
) -> None:
def __init__(self, manager: AstroidManager, apply_transforms: bool = True) -> None:
super().__init__(manager)
self._apply_transforms = apply_transforms
if not raw_building.InspectBuilder.bootstrapped:
raw_building._astroid_bootstrapping()
manager.bootstrap()

def module_build(
self, module: types.ModuleType, modname: str | None = None
Expand Down Expand Up @@ -292,10 +292,11 @@ def parse(
Apply the transforms for the give code. Use it if you
don't want the default transforms to be applied.
"""
# pylint: disable-next=import-outside-toplevel
from astroid.manager import AstroidManager

code = textwrap.dedent(code)
builder = AstroidBuilder(
manager=AstroidManager(), apply_transforms=apply_transforms
)
builder = AstroidBuilder(AstroidManager(), apply_transforms=apply_transforms)
return builder.string_build(code, modname=module_name, path=path)


Expand Down
6 changes: 5 additions & 1 deletion astroid/interpreter/_import/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from typing import Literal, NamedTuple, Protocol

from astroid.const import PY310_PLUS
from astroid.modutils import EXT_LIB_DIRS, cached_os_path_isfile

from . import util

Expand Down Expand Up @@ -134,6 +133,9 @@ def find_module(
processed: tuple[str, ...],
submodule_path: tuple[str, ...] | None,
) -> ModuleSpec | None:
# pylint: disable-next=import-outside-toplevel
from astroid.modutils import cached_os_path_isfile

# Although we should be able to use `find_spec` this doesn't work on PyPy for builtins.
# Therefore, we use the `builtin_module_nams` heuristic for these.
if submodule_path is None and modname in sys.builtin_module_names:
Expand Down Expand Up @@ -225,6 +227,8 @@ def contribute_to_path(
if spec.location is None:
# Builtin.
return None
# pylint: disable-next=import-outside-toplevel
from astroid.modutils import EXT_LIB_DIRS

if _is_setuptools_namespace(Path(spec.location)):
# extend_path is called, search sys.path for module/packages
Expand Down
19 changes: 1 addition & 18 deletions astroid/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from typing import Any, ClassVar

from astroid import nodes
from astroid.builder import AstroidBuilder, build_namespace_package_module
from astroid.context import InferenceContext, _invalidate_cache
from astroid.exceptions import AstroidBuildingError, AstroidImportError
from astroid.interpreter._import import spec, util
Expand Down Expand Up @@ -161,9 +162,6 @@ def ast_from_file(
):
return self.astroid_cache[modname]
if source:
# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import AstroidBuilder

return AstroidBuilder(self).file_build(filepath, modname)
if fallback and modname:
return self.ast_from_module_name(modname)
Expand All @@ -175,23 +173,14 @@ def ast_from_string(
"""Given some source code as a string, return its corresponding astroid
object.
"""
# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import AstroidBuilder

return AstroidBuilder(self).string_build(data, modname, filepath)

def _build_stub_module(self, modname: str) -> nodes.Module:
# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import AstroidBuilder

return AstroidBuilder(self).string_build("", modname)

def _build_namespace_module(
self, modname: str, path: Sequence[str]
) -> nodes.Module:
# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import build_namespace_package_module

return build_namespace_package_module(modname, path)

def _can_load_extension(self, modname: str) -> bool:
Expand Down Expand Up @@ -290,9 +279,6 @@ def zip_import_data(self, filepath: str) -> nodes.Module | None:
if zipimport is None:
return None

# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import AstroidBuilder

builder = AstroidBuilder(self)
for ext in ZIP_IMPORT_EXTS:
try:
Expand Down Expand Up @@ -351,9 +337,6 @@ def ast_from_module(
except AttributeError:
pass

# pylint: disable=import-outside-toplevel; circular import
from astroid.builder import AstroidBuilder

return AstroidBuilder(self).module_build(module, modname)

def ast_from_class(self, klass: type, modname: str | None = None) -> nodes.ClassDef:
Expand Down
19 changes: 11 additions & 8 deletions astroid/raw_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import warnings
from collections.abc import Iterable
from contextlib import redirect_stderr, redirect_stdout
from typing import Any, Union
from typing import TYPE_CHECKING, Any, Union

from astroid import bases, nodes
from astroid.const import _EMPTY_OBJECT_MARKER, IS_PYPY
from astroid.manager import AstroidManager
from astroid.nodes import node_classes

if TYPE_CHECKING:
from astroid.manager import AstroidManager

logger = logging.getLogger(__name__)


Expand All @@ -37,8 +39,6 @@
types.ClassMethodDescriptorType,
]

# the keys of CONST_CLS eg python builtin types
_CONSTANTS = tuple(node_classes.CONST_CLS)
TYPE_NONE = type(None)
TYPE_NOTIMPLEMENTED = type(NotImplemented)
TYPE_ELLIPSIS = type(...)
Expand Down Expand Up @@ -424,8 +424,8 @@ class InspectBuilder:

bootstrapped: bool = False

def __init__(self, manager_instance: AstroidManager | None = None) -> None:
self._manager = manager_instance or AstroidManager()
def __init__(self, manager_instance: AstroidManager) -> None:
self._manager = manager_instance
self._done: dict[types.ModuleType | type, nodes.Module | nodes.ClassDef] = {}
self._module: types.ModuleType

Expand Down Expand Up @@ -502,7 +502,7 @@ def object_build(
child: nodes.NodeNG = object_build_methoddescriptor(node, member)
elif inspect.isdatadescriptor(member):
child = object_build_datadescriptor(node, member)
elif isinstance(member, _CONSTANTS):
elif isinstance(member, tuple(node_classes.CONST_CLS)):
if alias in node.special_attributes:
continue
child = nodes.const_factory(member)
Expand Down Expand Up @@ -595,7 +595,10 @@ def _astroid_bootstrapping() -> None:
"""astroid bootstrapping the builtins module"""
# this boot strapping is necessary since we need the Const nodes to
# inspect_build builtins, and then we can proxy Const
builder = InspectBuilder()
# pylint: disable-next=import-outside-toplevel
from astroid.manager import AstroidManager

builder = InspectBuilder(AstroidManager())
astroid_builtin = builder.inspect_build(builtins)

for cls, node_cls in node_classes.CONST_CLS.items():
Expand Down
Loading

0 comments on commit 3c6516e

Please sign in to comment.