Skip to content

Make manager required in AstroidBuilder/InspectBuilder #2313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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