Skip to content

Commit 955f347

Browse files
temyurchenkocdce8p
authored andcommitted
Make constants have synthetic root as their parent (pylint-dev#2602)
that fixes a bunch of tests in pylint. We also make the synthetic root a singleton, as opposed to a module built in the astroid manager. That allows us to use it as a default value in Const constructors.
1 parent 0954cd4 commit 955f347

File tree

12 files changed

+58
-63
lines changed

12 files changed

+58
-63
lines changed

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Release date: TBA
1010
* Removed internal functions ``infer_numpy_member``, ``name_looks_like_numpy_member``, and
1111
``attribute_looks_like_numpy_member`` from ``astroid.brain.brain_numpy_utils``.
1212

13+
* Constants now have a parent of ``nodes.SYNTHETIC_ROOT``.
14+
1315
* Fix crashes with large positive and negative list multipliers.
1416

1517
Closes #2521

astroid/brain/brain_argparse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def infer_namespace(node, context: InferenceContext | None = None):
2121
"Namespace",
2222
lineno=node.lineno,
2323
col_offset=node.col_offset,
24-
parent=AstroidManager().synthetic_root, # this class is not real
24+
parent=nodes.SYNTHETIC_ROOT, # this class is not real
2525
end_lineno=node.end_lineno,
2626
end_col_offset=node.end_col_offset,
2727
)

astroid/brain/brain_builtin_inference.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from astroid.inference_tip import inference_tip
2525
from astroid.manager import AstroidManager
2626
from astroid.nodes import scoped_nodes
27-
from astroid.raw_building import build_module
2827
from astroid.typing import (
2928
ConstFactoryResult,
3029
InferenceResult,
@@ -165,8 +164,6 @@ def _extend_builtins(class_transforms):
165164

166165
def on_bootstrap():
167166
"""Called by astroid_bootstrapping()."""
168-
AstroidManager().cache_module(build_module("__astroid_synthetic"))
169-
170167
_extend_builtins(
171168
{
172169
"bytes": partial(_extend_string_class, code=BYTES_CLASS, rvalue="b''"),
@@ -653,7 +650,7 @@ def infer_property(
653650
# node.frame. It's somewhere in the builtins module, but we are special
654651
# casing it for each "property()" call, so we are making up the
655652
# definition on the spot, ad-hoc.
656-
parent=AstroidManager().synthetic_root,
653+
parent=scoped_nodes.SYNTHETIC_ROOT,
657654
)
658655
prop_func.postinit(
659656
body=[],

astroid/brain/brain_namedtuple_enum.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
)
2525
from astroid.inference_tip import inference_tip
2626
from astroid.manager import AstroidManager
27+
from astroid.nodes.scoped_nodes.scoped_nodes import SYNTHETIC_ROOT
2728

2829
ENUM_QNAME: Final[str] = "enum.Enum"
2930
TYPING_NAMEDTUPLE_QUALIFIED: Final = {
@@ -194,7 +195,7 @@ def infer_named_tuple(
194195
"""Specific inference function for namedtuple Call node."""
195196
tuple_base: nodes.Name = _extract_single_node("tuple")
196197
class_node, name, attributes = infer_func_form(
197-
node, tuple_base, parent=AstroidManager().synthetic_root, context=context
198+
node, tuple_base, parent=SYNTHETIC_ROOT, context=context
198199
)
199200

200201
call_site = arguments.CallSite.from_call(node, context=context)
@@ -360,7 +361,7 @@ def value(self):
360361
class_node = infer_func_form(
361362
node,
362363
enum_meta,
363-
parent=AstroidManager().synthetic_root,
364+
parent=SYNTHETIC_ROOT,
364365
context=context,
365366
enum=True,
366367
)[0]

astroid/manager.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,6 @@ def unregister_transform(self):
115115
def builtins_module(self) -> nodes.Module:
116116
return self.astroid_cache["builtins"]
117117

118-
@property
119-
def synthetic_root(self) -> nodes.Module:
120-
return self.astroid_cache["__astroid_synthetic"]
121-
122118
@property
123119
def prefer_stubs(self) -> bool:
124120
return AstroidManager.brain["prefer_stubs"]

astroid/nodes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
unpack_infer,
9494
)
9595
from astroid.nodes.scoped_nodes import (
96+
SYNTHETIC_ROOT,
9697
AsyncFunctionDef,
9798
ClassDef,
9899
ComprehensionScope,
@@ -276,6 +277,7 @@
276277
"Position",
277278
"Raise",
278279
"Return",
280+
"SYNTHETIC_ROOT",
279281
"Set",
280282
"SetComp",
281283
"Slice",

astroid/nodes/node_classes.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from astroid.nodes import _base_nodes
4747
from astroid.nodes.const import OP_PRECEDENCE
4848
from astroid.nodes.node_ng import NodeNG
49+
from astroid.nodes.scoped_nodes import SYNTHETIC_ROOT
4950
from astroid.typing import (
5051
ConstFactoryResult,
5152
InferenceErrorInfo,
@@ -2038,7 +2039,7 @@ def __init__(
20382039
value: Any,
20392040
lineno: int | None = None,
20402041
col_offset: int | None = None,
2041-
parent: NodeNG | None = None,
2042+
parent: NodeNG = SYNTHETIC_ROOT,
20422043
kind: str | None = None,
20432044
*,
20442045
end_lineno: int | None = None,
@@ -2550,7 +2551,7 @@ def __init__(
25502551
self,
25512552
lineno: None = None,
25522553
col_offset: None = None,
2553-
parent: None = None,
2554+
parent: NodeNG = SYNTHETIC_ROOT,
25542555
*,
25552556
end_lineno: None = None,
25562557
end_col_offset: None = None,
@@ -5535,7 +5536,7 @@ def const_factory(value: Any) -> ConstFactoryResult:
55355536
instance = initializer_cls(
55365537
lineno=None,
55375538
col_offset=None,
5538-
parent=None,
5539+
parent=SYNTHETIC_ROOT,
55395540
end_lineno=None,
55405541
end_col_offset=None,
55415542
)
@@ -5545,7 +5546,7 @@ def const_factory(value: Any) -> ConstFactoryResult:
55455546
instance = initializer_cls(
55465547
lineno=None,
55475548
col_offset=None,
5548-
parent=None,
5549+
parent=SYNTHETIC_ROOT,
55495550
end_lineno=None,
55505551
end_col_offset=None,
55515552
)

astroid/nodes/scoped_nodes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from astroid.nodes.scoped_nodes.mixin import ComprehensionScope, LocalsDictNodeNG
1313
from astroid.nodes.scoped_nodes.scoped_nodes import (
14+
SYNTHETIC_ROOT,
1415
AsyncFunctionDef,
1516
ClassDef,
1617
DictComp,
@@ -37,6 +38,7 @@
3738
"ListComp",
3839
"LocalsDictNodeNG",
3940
"Module",
41+
"SYNTHETIC_ROOT",
4042
"SetComp",
4143
"builtin_lookup",
4244
"function_to_method",

astroid/nodes/scoped_nodes/scoped_nodes.py

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,7 @@
4040
from astroid.interpreter.dunder_lookup import lookup
4141
from astroid.interpreter.objectmodel import ClassModel, FunctionModel, ModuleModel
4242
from astroid.manager import AstroidManager
43-
from astroid.nodes import (
44-
Arguments,
45-
Const,
46-
NodeNG,
47-
_base_nodes,
48-
const_factory,
49-
node_classes,
50-
)
43+
from astroid.nodes import _base_nodes, node_classes
5144
from astroid.nodes.scoped_nodes.mixin import ComprehensionScope, LocalsDictNodeNG
5245
from astroid.nodes.scoped_nodes.utils import builtin_lookup
5346
from astroid.nodes.utils import Position
@@ -60,6 +53,7 @@
6053

6154
if TYPE_CHECKING:
6255
from astroid import nodes, objects
56+
from astroid.nodes import Arguments, Const, NodeNG
6357
from astroid.nodes._base_nodes import LookupMixIn
6458

6559

@@ -177,6 +171,15 @@ def function_to_method(n, klass):
177171
return n
178172

179173

174+
def _infer_last(
175+
arg: SuccessfulInferenceResult, context: InferenceContext
176+
) -> InferenceResult:
177+
res = util.Uninferable
178+
for b in arg.infer(context=context.clone()):
179+
res = b
180+
return res
181+
182+
180183
class Module(LocalsDictNodeNG):
181184
"""Class representing an :class:`ast.Module` node.
182185
@@ -353,7 +356,7 @@ def getattr(
353356
if name in self.special_attributes and not ignore_locals and not name_in_locals:
354357
result = [self.special_attributes.lookup(name)]
355358
if name == "__name__":
356-
main_const = const_factory("__main__")
359+
main_const = node_classes.const_factory("__main__")
357360
main_const.parent = AstroidManager().builtins_module
358361
result.append(main_const)
359362
elif not ignore_locals and name_in_locals:
@@ -607,6 +610,14 @@ def _infer(
607610
yield self
608611

609612

613+
class __SyntheticRoot(Module):
614+
def __init__(self):
615+
super().__init__("__astroid_synthetic", pure_python=False)
616+
617+
618+
SYNTHETIC_ROOT = __SyntheticRoot()
619+
620+
610621
class GeneratorExp(ComprehensionScope):
611622
"""Class representing an :class:`ast.GeneratorExp` node.
612623
@@ -1538,10 +1549,7 @@ def infer_yield_result(self, context: InferenceContext | None = None):
15381549
"""
15391550
for yield_ in self.nodes_of_class(node_classes.Yield):
15401551
if yield_.value is None:
1541-
const = node_classes.Const(None)
1542-
const.parent = yield_
1543-
const.lineno = yield_.lineno
1544-
yield const
1552+
yield node_classes.Const(None, parent=yield_, lineno=yield_.lineno)
15451553
elif yield_.scope() == self:
15461554
yield from yield_.value.infer(context=context)
15471555

@@ -1551,6 +1559,8 @@ def infer_call_result(
15511559
context: InferenceContext | None = None,
15521560
) -> Iterator[InferenceResult]:
15531561
"""Infer what the function returns when called."""
1562+
if context is None:
1563+
context = InferenceContext()
15541564
if self.is_generator():
15551565
if isinstance(self, AsyncFunctionDef):
15561566
generator_cls: type[bases.Generator] = bases.AsyncGenerator
@@ -1572,7 +1582,7 @@ def infer_call_result(
15721582
and len(self.args.args) == 1
15731583
and self.args.vararg is not None
15741584
):
1575-
if isinstance(caller.args, Arguments):
1585+
if isinstance(caller.args, node_classes.Arguments):
15761586
assert caller.args.args is not None
15771587
metaclass = next(caller.args.args[0].infer(context), None)
15781588
elif isinstance(caller.args, list):
@@ -1582,27 +1592,14 @@ def infer_call_result(
15821592
f"caller.args was neither Arguments nor list; got {type(caller.args)}"
15831593
)
15841594
if isinstance(metaclass, ClassDef):
1585-
try:
1586-
class_bases = [
1587-
# Find the first non-None inferred base value
1588-
next(
1589-
b
1590-
for b in arg.infer(
1591-
context=context.clone() if context else context
1592-
)
1593-
if not (isinstance(b, Const) and b.value is None)
1594-
)
1595-
for arg in caller.args[1:]
1596-
]
1597-
except StopIteration as e:
1598-
raise InferenceError(node=caller.args[1:], context=context) from e
1595+
class_bases = [_infer_last(x, context) for x in caller.args[1:]]
15991596
new_class = ClassDef(
16001597
name="temporary_class",
16011598
lineno=0,
16021599
col_offset=0,
16031600
end_lineno=0,
16041601
end_col_offset=0,
1605-
parent=AstroidManager().synthetic_root,
1602+
parent=SYNTHETIC_ROOT,
16061603
)
16071604
new_class.hide = True
16081605
new_class.postinit(
@@ -2827,13 +2824,8 @@ def _inferred_bases(self, context: InferenceContext | None = None):
28272824

28282825
for stmt in self.bases:
28292826
try:
2830-
# Find the first non-None inferred base value
2831-
baseobj = next(
2832-
b
2833-
for b in stmt.infer(context=context.clone())
2834-
if not (isinstance(b, Const) and b.value is None)
2835-
)
2836-
except (InferenceError, StopIteration):
2827+
baseobj = _infer_last(stmt, context)
2828+
except InferenceError:
28372829
continue
28382830
if isinstance(baseobj, bases.Instance):
28392831
baseobj = baseobj._proxied

astroid/objects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def __init__(self, call, name=None, lineno=None, col_offset=None, parent=None):
279279
name,
280280
lineno=lineno,
281281
col_offset=col_offset,
282-
parent=AstroidManager().synthetic_root,
282+
parent=scoped_nodes.SYNTHETIC_ROOT,
283283
end_col_offset=0,
284284
end_lineno=0,
285285
)

0 commit comments

Comments
 (0)