Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/raw_building.py: 70%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
5"""this module contains a set of functions to create astroid trees from scratch
6(build_* functions) or from living object (object_build_* functions)
7"""
9from __future__ import annotations
11import builtins
12import inspect
13import io
14import os
15import sys
16import types
17import warnings
18from collections.abc import Iterable
19from contextlib import redirect_stderr, redirect_stdout
20from typing import TYPE_CHECKING, Any
22from astroid import bases, nodes
23from astroid.const import _EMPTY_OBJECT_MARKER, IS_PYPY
24from astroid.nodes import node_classes
26if TYPE_CHECKING:
27 from astroid.manager import AstroidManager
30_FunctionTypes = (
31 types.FunctionType
32 | types.MethodType
33 | types.BuiltinFunctionType
34 | types.WrapperDescriptorType
35 | types.MethodDescriptorType
36 | types.ClassMethodDescriptorType
37)
39TYPE_NONE = type(None)
40TYPE_NOTIMPLEMENTED = type(NotImplemented)
41TYPE_ELLIPSIS = type(...)
44def _attach_local_node(parent, node, name: str) -> None:
45 node.name = name # needed by add_local_node
46 parent.add_local_node(node)
49def _add_dunder_class(func, parent: nodes.NodeNG, member) -> None:
50 """Add a __class__ member to the given func node, if we can determine it."""
51 python_cls = member.__class__
52 cls_name = getattr(python_cls, "__name__", None)
53 if not cls_name:
54 return
55 cls_bases = [ancestor.__name__ for ancestor in python_cls.__bases__]
56 doc = python_cls.__doc__ if isinstance(python_cls.__doc__, str) else None
57 ast_klass = build_class(cls_name, parent, cls_bases, doc)
58 func.instance_attrs["__class__"] = [ast_klass]
61def build_dummy(runtime_object) -> nodes.EmptyNode:
62 enode = nodes.EmptyNode()
63 enode.object = runtime_object
64 return enode
67def attach_dummy_node(node, name: str, runtime_object=_EMPTY_OBJECT_MARKER) -> None:
68 """create a dummy node and register it in the locals of the given
69 node with the specified name
70 """
71 _attach_local_node(node, build_dummy(runtime_object), name)
74def attach_const_node(node, name: str, value) -> None:
75 """create a Const node and register it in the locals of the given
76 node with the specified name
77 """
78 # Special case: __hash__ = None overrides ObjectModel for unhashable types.
79 # See https://docs.python.org/3/reference/datamodel.html#object.__hash__
80 if name == "__hash__" and value is None:
81 _attach_local_node(node, nodes.const_factory(value), name)
82 elif name not in node.special_attributes:
83 _attach_local_node(node, nodes.const_factory(value), name)
86def attach_import_node(node, modname: str, membername: str) -> None:
87 """create a ImportFrom node and register it in the locals of the given
88 node with the specified name
89 """
90 from_node = nodes.ImportFrom(modname, [(membername, None)])
91 _attach_local_node(node, from_node, membername)
94def build_module(name: str, doc: str | None = None) -> nodes.Module:
95 """create and initialize an astroid Module node"""
96 node = nodes.Module(name, pure_python=False, package=False)
97 node.postinit(
98 body=[],
99 doc_node=nodes.Const(value=doc) if doc else None,
100 )
101 return node
104def build_class(
105 name: str,
106 parent: nodes.NodeNG,
107 basenames: Iterable[str] = (),
108 doc: str | None = None,
109) -> nodes.ClassDef:
110 """Create and initialize an astroid ClassDef node."""
111 node = nodes.ClassDef(
112 name,
113 lineno=0,
114 col_offset=0,
115 end_lineno=0,
116 end_col_offset=0,
117 parent=parent,
118 )
119 node.postinit(
120 bases=[
121 nodes.Name(
122 name=base,
123 lineno=0,
124 col_offset=0,
125 parent=node,
126 end_lineno=None,
127 end_col_offset=None,
128 )
129 for base in basenames
130 ],
131 body=[],
132 decorators=None,
133 doc_node=nodes.Const(value=doc) if doc else None,
134 )
135 return node
138def build_function(
139 name: str,
140 parent: nodes.NodeNG,
141 args: list[str] | None = None,
142 posonlyargs: list[str] | None = None,
143 defaults: list[Any] | None = None,
144 doc: str | None = None,
145 kwonlyargs: list[str] | None = None,
146 kwonlydefaults: list[Any] | None = None,
147) -> nodes.FunctionDef:
148 """create and initialize an astroid FunctionDef node"""
149 # first argument is now a list of decorators
150 func = nodes.FunctionDef(
151 name,
152 lineno=0,
153 col_offset=0,
154 parent=parent,
155 end_col_offset=0,
156 end_lineno=0,
157 )
158 argsnode = nodes.Arguments(parent=func, vararg=None, kwarg=None)
160 # If args is None we don't have any information about the signature
161 # (in contrast to when there are no arguments and args == []). We pass
162 # this to the builder to indicate this.
163 if args is not None:
164 # We set the lineno and col_offset to 0 because we don't have any
165 # information about the location of the function definition.
166 arguments = [
167 nodes.AssignName(
168 name=arg,
169 parent=argsnode,
170 lineno=0,
171 col_offset=0,
172 end_lineno=None,
173 end_col_offset=None,
174 )
175 for arg in args
176 ]
177 else:
178 arguments = None
180 default_nodes: list[nodes.NodeNG] | None
181 if defaults is None:
182 default_nodes = None
183 else:
184 default_nodes = []
185 for default in defaults:
186 default_node = nodes.const_factory(default)
187 default_node.parent = argsnode
188 default_nodes.append(default_node)
190 kwonlydefault_nodes: list[nodes.NodeNG | None] | None
191 if kwonlydefaults is None:
192 kwonlydefault_nodes = None
193 else:
194 kwonlydefault_nodes = []
195 for kwonlydefault in kwonlydefaults:
196 kwonlydefault_node = nodes.const_factory(kwonlydefault)
197 kwonlydefault_node.parent = argsnode
198 kwonlydefault_nodes.append(kwonlydefault_node)
200 # We set the lineno and col_offset to 0 because we don't have any
201 # information about the location of the kwonly and posonlyargs.
202 argsnode.postinit(
203 args=arguments,
204 defaults=default_nodes,
205 kwonlyargs=[
206 nodes.AssignName(
207 name=arg,
208 parent=argsnode,
209 lineno=0,
210 col_offset=0,
211 end_lineno=None,
212 end_col_offset=None,
213 )
214 for arg in kwonlyargs or ()
215 ],
216 kw_defaults=kwonlydefault_nodes,
217 annotations=[],
218 posonlyargs=[
219 nodes.AssignName(
220 name=arg,
221 parent=argsnode,
222 lineno=0,
223 col_offset=0,
224 end_lineno=None,
225 end_col_offset=None,
226 )
227 for arg in posonlyargs or ()
228 ],
229 kwonlyargs_annotations=[],
230 posonlyargs_annotations=[],
231 )
232 func.postinit(
233 args=argsnode,
234 body=[],
235 doc_node=nodes.Const(value=doc) if doc else None,
236 )
237 if args:
238 register_arguments(func)
239 return func
242def build_from_import(fromname: str, names: list[str]) -> nodes.ImportFrom:
243 """create and initialize an astroid ImportFrom import statement"""
244 return nodes.ImportFrom(fromname, [(name, None) for name in names])
247def register_arguments(func: nodes.FunctionDef, args: list | None = None) -> None:
248 """add given arguments to local
250 args is a list that may contains nested lists
251 (i.e. def func(a, (b, c, d)): ...)
252 """
253 # If no args are passed in, get the args from the function.
254 if args is None:
255 if func.args.vararg:
256 func.set_local(func.args.vararg, func.args)
257 if func.args.kwarg:
258 func.set_local(func.args.kwarg, func.args)
259 args = func.args.args
260 # If the function has no args, there is nothing left to do.
261 if args is None:
262 return
263 for arg in args:
264 if isinstance(arg, nodes.AssignName):
265 func.set_local(arg.name, arg)
266 else:
267 register_arguments(func, arg.elts)
270def object_build_class(
271 node: nodes.Module | nodes.ClassDef, member: type
272) -> nodes.ClassDef:
273 """create astroid for a living class object"""
274 basenames = [base.__name__ for base in member.__bases__]
275 return _base_class_object_build(node, member, basenames)
278def _get_args_info_from_callable(
279 member: _FunctionTypes,
280) -> tuple[list[str], list[str], list[Any], list[str], list[Any]]:
281 """Returns args, posonlyargs, defaults, kwonlyargs.
283 :note: currently ignores the return annotation.
284 """
285 signature = inspect.signature(member)
286 args: list[str] = []
287 defaults: list[Any] = []
288 posonlyargs: list[str] = []
289 kwonlyargs: list[str] = []
290 kwonlydefaults: list[Any] = []
292 for param_name, param in signature.parameters.items():
293 if param.kind == inspect.Parameter.POSITIONAL_ONLY:
294 posonlyargs.append(param_name)
295 elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
296 args.append(param_name)
297 elif param.kind == inspect.Parameter.VAR_POSITIONAL:
298 args.append(param_name)
299 elif param.kind == inspect.Parameter.VAR_KEYWORD:
300 args.append(param_name)
301 elif param.kind == inspect.Parameter.KEYWORD_ONLY:
302 kwonlyargs.append(param_name)
303 if param.default is not inspect.Parameter.empty:
304 kwonlydefaults.append(param.default)
305 continue
306 if param.default is not inspect.Parameter.empty:
307 defaults.append(param.default)
309 return args, posonlyargs, defaults, kwonlyargs, kwonlydefaults
312def object_build_function(
313 node: nodes.Module | nodes.ClassDef, member: _FunctionTypes
314) -> nodes.FunctionDef:
315 """create astroid for a living function object"""
316 (
317 args,
318 posonlyargs,
319 defaults,
320 kwonlyargs,
321 kwonly_defaults,
322 ) = _get_args_info_from_callable(member)
324 return build_function(
325 getattr(member, "__name__", "<no-name>"),
326 node,
327 args,
328 posonlyargs,
329 defaults,
330 member.__doc__ if isinstance(member.__doc__, str) else None,
331 kwonlyargs=kwonlyargs,
332 kwonlydefaults=kwonly_defaults,
333 )
336def object_build_datadescriptor(
337 node: nodes.Module | nodes.ClassDef, member: type
338) -> nodes.ClassDef:
339 """create astroid for a living data descriptor object"""
340 return _base_class_object_build(node, member, [])
343def object_build_methoddescriptor(
344 node: nodes.Module | nodes.ClassDef,
345 member: _FunctionTypes,
346) -> nodes.FunctionDef:
347 """create astroid for a living method descriptor object"""
348 # FIXME get arguments ?
349 name = getattr(member, "__name__", "<no-name>")
350 func = build_function(name, node, doc=member.__doc__)
351 _add_dunder_class(func, node, member)
352 return func
355def _base_class_object_build(
356 node: nodes.Module | nodes.ClassDef,
357 member: type,
358 basenames: list[str],
359) -> nodes.ClassDef:
360 """create astroid for a living class object, with a given set of base names
361 (e.g. ancestors)
362 """
363 name = getattr(member, "__name__", "<no-name>")
364 doc = member.__doc__ if isinstance(member.__doc__, str) else None
365 klass = build_class(name, node, basenames, doc)
366 klass._newstyle = isinstance(member, type)
367 try:
368 # limit the instantiation trick since it's too dangerous
369 # (such as infinite test execution...)
370 # this at least resolves common case such as Exception.args,
371 # OSError.errno
372 if issubclass(member, Exception):
373 member_object = member()
374 if hasattr(member_object, "__dict__"):
375 instdict = member_object.__dict__
376 else:
377 raise TypeError
378 else:
379 raise TypeError
380 except TypeError:
381 pass
382 else:
383 for item_name, obj in instdict.items():
384 valnode = nodes.EmptyNode()
385 valnode.object = obj
386 valnode.parent = klass
387 valnode.lineno = 1
388 klass.instance_attrs[item_name] = [valnode]
389 return klass
392def _build_from_function(
393 node: nodes.Module | nodes.ClassDef,
394 member: _FunctionTypes,
395 module: types.ModuleType,
396) -> nodes.FunctionDef | nodes.EmptyNode:
397 # verify this is not an imported function
398 try:
399 code = member.__code__ # type: ignore[union-attr]
400 except AttributeError:
401 # Some implementations don't provide the code object,
402 # such as Jython.
403 code = None
404 filename = getattr(code, "co_filename", None)
405 if filename is None:
406 return object_build_methoddescriptor(node, member)
407 if filename == getattr(module, "__file__", None):
408 return object_build_function(node, member)
409 return build_dummy(member)
412def _safe_has_attribute(obj, member: str) -> bool:
413 """Required because unexpected RunTimeError can be raised.
415 See https://github.com/pylint-dev/astroid/issues/1958
416 """
417 try:
418 return hasattr(obj, member)
419 except Exception: # pylint: disable=broad-except
420 return False
423class InspectBuilder:
424 """class for building nodes from living object
426 this is actually a really minimal representation, including only Module,
427 FunctionDef and ClassDef nodes and some others as guessed.
428 """
430 bootstrapped: bool = False
432 def __init__(self, manager_instance: AstroidManager) -> None:
433 self._manager = manager_instance
434 self._done: dict[types.ModuleType | type, nodes.Module | nodes.ClassDef] = {}
435 self._module: types.ModuleType
437 def inspect_build(
438 self,
439 module: types.ModuleType,
440 modname: str | None = None,
441 path: str | None = None,
442 ) -> nodes.Module:
443 """build astroid from a living module (i.e. using inspect)
444 this is used when there is no python source code available (either
445 because it's a built-in module or because the .py is not available)
446 """
447 self._module = module
448 if modname is None:
449 modname = module.__name__
450 try:
451 node = build_module(modname, module.__doc__)
452 except AttributeError:
453 # in jython, java modules have no __doc__ (see #109562)
454 node = build_module(modname)
455 if path is None:
456 node.path = node.file = path
457 else:
458 node.path = [os.path.abspath(path)]
459 node.file = node.path[0]
460 node.name = modname
461 self._manager.cache_module(node)
462 node.package = hasattr(module, "__path__")
463 self._done = {}
464 self.object_build(node, module)
465 return node
467 def object_build(
468 self, node: nodes.Module | nodes.ClassDef, obj: types.ModuleType | type
469 ) -> None:
470 """recursive method which create a partial ast from real objects
471 (only function, class, and method are handled)
472 """
473 if obj in self._done:
474 return None
475 self._done[obj] = node
476 for alias in dir(obj):
477 # inspect.ismethod() and inspect.isbuiltin() in PyPy return
478 # the opposite of what they do in CPython for __class_getitem__.
479 pypy__class_getitem__ = IS_PYPY and alias == "__class_getitem__"
480 try:
481 with warnings.catch_warnings():
482 warnings.simplefilter("ignore")
483 member = getattr(obj, alias)
484 except (AttributeError, TypeError):
485 # AttributeError: damned ExtensionClass.Base, I know you're
486 # there!
487 # TypeError: PyPy 7.3.22 raises TypeError ("expected str, got
488 # getset_descriptor object") instead of AttributeError for
489 # unset getset descriptors like
490 # ``types.FunctionType.__text_signature__`` when accessed on
491 # the type. Treat that the same as a missing attribute so
492 # ``_astroid_bootstrapping()`` doesn't crash on import.
493 attach_dummy_node(node, alias)
494 continue
495 if inspect.ismethod(member) and not pypy__class_getitem__:
496 member = member.__func__
497 if inspect.isfunction(member):
498 child = _build_from_function(node, member, self._module)
499 elif inspect.isbuiltin(member) or pypy__class_getitem__:
500 if self.imported_member(node, member, alias):
501 continue
502 child = object_build_methoddescriptor(node, member)
503 elif inspect.isclass(member):
504 if self.imported_member(node, member, alias):
505 continue
506 if member in self._done:
507 child = self._done[member]
508 assert isinstance(child, nodes.ClassDef)
509 else:
510 child = object_build_class(node, member)
511 # recursion
512 self.object_build(child, member)
513 elif inspect.ismethoddescriptor(member):
514 child: nodes.NodeNG = object_build_methoddescriptor(node, member)
515 elif inspect.isdatadescriptor(member):
516 child = object_build_datadescriptor(node, member)
517 elif isinstance(member, tuple(node_classes.CONST_CLS)):
518 # Special case: __hash__ = None overrides ObjectModel for unhashable types.
519 # See https://docs.python.org/3/reference/datamodel.html#object.__hash__
520 if alias in node.special_attributes and not (
521 alias == "__hash__" and member is None
522 ):
523 continue
524 child = nodes.const_factory(member)
525 elif inspect.isroutine(member):
526 # This should be called for Jython, where some builtin
527 # methods aren't caught by isbuiltin branch.
528 child = _build_from_function(node, member, self._module)
529 elif _safe_has_attribute(member, "__all__"):
530 child: nodes.NodeNG = build_module(alias)
531 # recursion
532 self.object_build(child, member)
533 else:
534 # create an empty node so that the name is actually defined
535 child: nodes.NodeNG = build_dummy(member)
536 if child not in node.locals.get(alias, ()):
537 node.add_local_node(child, alias)
538 return None
540 def imported_member(self, node, member, name: str) -> bool:
541 """verify this is not an imported class or handle it"""
542 # /!\ some classes like ExtensionClass doesn't have a __module__
543 # attribute ! Also, this may trigger an exception on badly built module
544 # (see http://www.logilab.org/ticket/57299 for instance)
545 try:
546 modname = getattr(member, "__module__", None)
547 except TypeError:
548 modname = None
549 if modname is None:
550 if name in {"__new__", "__subclasshook__"}:
551 # Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14)
552 # >>> print object.__new__.__module__
553 # None
554 modname = builtins.__name__
555 else:
556 attach_dummy_node(node, name, member)
557 return True
559 # On PyPy during bootstrapping we infer _io while _module is
560 # builtins. In CPython _io names itself io, see http://bugs.python.org/issue18602
561 # Therefore, this basically checks whether we are not in PyPy.
562 if modname == "_io" and not self._module.__name__ == "builtins":
563 return False
565 real_name = {"gtk": "gtk_gtk"}.get(modname, modname)
567 if real_name != self._module.__name__:
568 # check if it sounds valid and then add an import node, else use a
569 # dummy node
570 try:
571 with (
572 redirect_stderr(io.StringIO()) as stderr,
573 redirect_stdout(io.StringIO()) as stdout,
574 ):
575 getattr(sys.modules[modname], name)
576 stderr_value = stderr.getvalue()
577 stdout_value = stdout.getvalue()
578 if stderr_value or stdout_value:
579 # pylint: disable=import-outside-toplevel
580 import logging
582 logger = logging.getLogger(__name__)
583 if stderr_value:
584 logger.error(
585 "Captured stderr while getting %s from %s:\n%s",
586 name,
587 sys.modules[modname],
588 stderr_value,
589 )
590 if stdout_value:
591 logger.info(
592 "Captured stdout while getting %s from %s:\n%s",
593 name,
594 sys.modules[modname],
595 stdout_value,
596 )
597 except (KeyError, AttributeError):
598 attach_dummy_node(node, name, member)
599 else:
600 attach_import_node(node, modname, name)
601 return True
602 return False
605# astroid bootstrapping ######################################################
607_CONST_PROXY: dict[type, nodes.ClassDef] = {}
610def _set_proxied(const) -> nodes.ClassDef:
611 # TODO : find a nicer way to handle this situation;
612 return _CONST_PROXY[const.value.__class__]
615def _astroid_bootstrapping() -> None:
616 """astroid bootstrapping the builtins module"""
617 # this boot strapping is necessary since we need the Const nodes to
618 # inspect_build builtins, and then we can proxy Const
619 # pylint: disable-next=import-outside-toplevel
620 from astroid.manager import AstroidManager
622 builder = InspectBuilder(AstroidManager())
623 astroid_builtin = builder.inspect_build(builtins)
625 for cls, node_cls in node_classes.CONST_CLS.items():
626 if cls is TYPE_NONE:
627 proxy = build_class("NoneType", astroid_builtin)
628 elif cls is TYPE_NOTIMPLEMENTED:
629 proxy = build_class("NotImplementedType", astroid_builtin)
630 elif cls is TYPE_ELLIPSIS:
631 proxy = build_class("Ellipsis", astroid_builtin)
632 else:
633 proxy = astroid_builtin.getattr(cls.__name__)[0]
634 assert isinstance(proxy, nodes.ClassDef)
635 if cls in (dict, list, set, tuple):
636 node_cls._proxied = proxy
637 else:
638 _CONST_PROXY[cls] = proxy
640 # Set the builtin module as parent for some builtins.
641 nodes.Const._proxied = property(_set_proxied)
643 _GeneratorType = nodes.ClassDef(
644 types.GeneratorType.__name__,
645 lineno=0,
646 col_offset=0,
647 end_lineno=0,
648 end_col_offset=0,
649 parent=astroid_builtin,
650 )
651 astroid_builtin.set_local(_GeneratorType.name, _GeneratorType)
652 generator_doc_node = (
653 nodes.Const(value=types.GeneratorType.__doc__)
654 if types.GeneratorType.__doc__
655 else None
656 )
657 _GeneratorType.postinit(
658 bases=[],
659 body=[],
660 decorators=None,
661 doc_node=generator_doc_node,
662 )
663 bases.Generator._proxied = _GeneratorType
664 builder.object_build(bases.Generator._proxied, types.GeneratorType)
666 if hasattr(types, "AsyncGeneratorType"):
667 _AsyncGeneratorType = nodes.ClassDef(
668 types.AsyncGeneratorType.__name__,
669 lineno=0,
670 col_offset=0,
671 end_lineno=0,
672 end_col_offset=0,
673 parent=astroid_builtin,
674 )
675 astroid_builtin.set_local(_AsyncGeneratorType.name, _AsyncGeneratorType)
676 async_generator_doc_node = (
677 nodes.Const(value=types.AsyncGeneratorType.__doc__)
678 if types.AsyncGeneratorType.__doc__
679 else None
680 )
681 _AsyncGeneratorType.postinit(
682 bases=[],
683 body=[],
684 decorators=None,
685 doc_node=async_generator_doc_node,
686 )
687 bases.AsyncGenerator._proxied = _AsyncGeneratorType
688 builder.object_build(bases.AsyncGenerator._proxied, types.AsyncGeneratorType)
690 if hasattr(types, "UnionType"):
691 _UnionTypeType = nodes.ClassDef(
692 types.UnionType.__name__,
693 lineno=0,
694 col_offset=0,
695 end_lineno=0,
696 end_col_offset=0,
697 parent=astroid_builtin,
698 )
699 union_type_doc_node = (
700 nodes.Const(value=types.UnionType.__doc__)
701 if types.UnionType.__doc__
702 else None
703 )
704 _UnionTypeType.postinit(
705 bases=[],
706 body=[],
707 decorators=None,
708 doc_node=union_type_doc_node,
709 )
710 bases.UnionType._proxied = _UnionTypeType
711 builder.object_build(bases.UnionType._proxied, types.UnionType)
713 builtin_types = (
714 types.GetSetDescriptorType,
715 types.GeneratorType,
716 types.MemberDescriptorType,
717 TYPE_NONE,
718 TYPE_NOTIMPLEMENTED,
719 types.FunctionType,
720 types.MethodType,
721 types.BuiltinFunctionType,
722 types.ModuleType,
723 types.TracebackType,
724 )
725 for _type in builtin_types:
726 if _type.__name__ not in astroid_builtin:
727 klass = nodes.ClassDef(
728 _type.__name__,
729 lineno=0,
730 col_offset=0,
731 end_lineno=0,
732 end_col_offset=0,
733 parent=astroid_builtin,
734 )
735 doc = _type.__doc__ if isinstance(_type.__doc__, str) else None
736 klass.postinit(
737 bases=[],
738 body=[],
739 decorators=None,
740 doc_node=nodes.Const(doc) if doc else None,
741 )
742 builder.object_build(klass, _type)
743 astroid_builtin[_type.__name__] = klass
745 InspectBuilder.bootstrapped = True
747 # pylint: disable-next=import-outside-toplevel
748 from astroid.brain.brain_builtin_inference import on_bootstrap
750 # Instantiates an AstroidBuilder(), which is where
751 # InspectBuilder.bootstrapped is checked, so place after bootstrapped=True.
752 on_bootstrap()