Skip to content

Commit 3f55e5c

Browse files
committed
make constants have synthetic root as their parent
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. Note the changes to the test. Before, we in fact tested that constants don't have a parent. Is that reasonable? In fact, it seems like there are a variety of interpretations and we shouldn't commit to one by explicitly testing for a certain parent or lack thereof.
1 parent 275f508 commit 3f55e5c

10 files changed

+48
-49
lines changed

Diff for: astroid/brain/brain_argparse.py

+1-1
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
)

Diff for: astroid/brain/brain_builtin_inference.py

+1-4
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=[],

Diff for: astroid/brain/brain_namedtuple_enum.py

+3-2
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]

Diff for: astroid/manager.py

-4
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"]

Diff for: astroid/nodes/__init__.py

+2
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",

Diff for: astroid/nodes/node_classes.py

+5-4
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
)

Diff for: astroid/nodes/scoped_nodes/__init__.py

+2
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",

Diff for: astroid/nodes/scoped_nodes/scoped_nodes.py

+21-23
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 NodeNG, Const, Arguments
6357
from astroid.nodes._base_nodes import LookupMixIn
6458

6559

@@ -353,7 +347,7 @@ def getattr(
353347
if name in self.special_attributes and not ignore_locals and not name_in_locals:
354348
result = [self.special_attributes.lookup(name)]
355349
if name == "__name__":
356-
main_const = const_factory("__main__")
350+
main_const = node_classes.const_factory("__main__")
357351
main_const.parent = AstroidManager().builtins_module
358352
result.append(main_const)
359353
elif not ignore_locals and name_in_locals:
@@ -607,6 +601,14 @@ def _infer(
607601
yield self
608602

609603

604+
class __SyntheticRoot(Module):
605+
def __init__(self):
606+
super().__init__("__astroid_synthetic", pure_python=False)
607+
608+
609+
SYNTHETIC_ROOT = __SyntheticRoot()
610+
611+
610612
class GeneratorExp(ComprehensionScope):
611613
"""Class representing an :class:`ast.GeneratorExp` node.
612614
@@ -1572,7 +1574,7 @@ def infer_call_result(
15721574
and len(self.args.args) == 1
15731575
and self.args.vararg is not None
15741576
):
1575-
if isinstance(caller.args, Arguments):
1577+
if isinstance(caller.args, node_classes.Arguments):
15761578
assert caller.args.args is not None
15771579
metaclass = next(caller.args.args[0].infer(context), None)
15781580
elif isinstance(caller.args, list):
@@ -1583,17 +1585,13 @@ def infer_call_result(
15831585
)
15841586
if isinstance(metaclass, ClassDef):
15851587
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-
]
1588+
# Find the first non-None inferred base value
1589+
get_base = lambda arg: next(
1590+
b
1591+
for b in arg.infer(context=context.clone() if context else None)
1592+
if not (isinstance(b, node_classes.Const) and b.value is None)
1593+
)
1594+
class_bases = [get_base(arg) for arg in caller.args[1:]]
15971595
except StopIteration as e:
15981596
raise InferenceError(node=caller.args[1:], context=context) from e
15991597
new_class = ClassDef(
@@ -1602,7 +1600,7 @@ def infer_call_result(
16021600
col_offset=0,
16031601
end_lineno=0,
16041602
end_col_offset=0,
1605-
parent=AstroidManager().synthetic_root,
1603+
parent=SYNTHETIC_ROOT,
16061604
)
16071605
new_class.hide = True
16081606
new_class.postinit(
@@ -2831,7 +2829,7 @@ def _inferred_bases(self, context: InferenceContext | None = None):
28312829
baseobj = next(
28322830
b
28332831
for b in stmt.infer(context=context.clone())
2834-
if not (isinstance(b, Const) and b.value is None)
2832+
if not (isinstance(b, node_classes.Const) and b.value is None)
28352833
)
28362834
except (InferenceError, StopIteration):
28372835
continue

Diff for: astroid/objects.py

+1-1
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
)

Diff for: tests/test_nodes.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@
3434
AstroidBuildingError,
3535
AstroidSyntaxError,
3636
AttributeInferenceError,
37-
ParentMissingError,
3837
StatementMissing,
3938
)
40-
from astroid.manager import AstroidManager
4139
from astroid.nodes.node_classes import (
4240
AssignAttr,
4341
AssignName,
@@ -46,7 +44,13 @@
4644
ImportFrom,
4745
Tuple,
4846
)
49-
from astroid.nodes.scoped_nodes import ClassDef, FunctionDef, GeneratorExp, Module
47+
from astroid.nodes.scoped_nodes import (
48+
SYNTHETIC_ROOT,
49+
ClassDef,
50+
FunctionDef,
51+
GeneratorExp,
52+
Module,
53+
)
5054
from tests.testdata.python3.recursion_error import LONG_CHAINED_METHOD_CALL
5155

5256
from . import resources
@@ -623,12 +627,10 @@ def _test(self, value: Any) -> None:
623627
with self.assertRaises(StatementMissing):
624628
node.statement()
625629

626-
with self.assertRaises(ParentMissingError):
627-
with pytest.warns(DeprecationWarning) as records:
628-
node.frame(future=True)
629-
assert len(records) == 1
630-
with self.assertRaises(ParentMissingError):
631-
node.frame()
630+
with pytest.warns(DeprecationWarning) as records:
631+
assert node.frame(future=True) is SYNTHETIC_ROOT
632+
assert len(records) == 1
633+
assert node.frame() is SYNTHETIC_ROOT
632634

633635
def test_none(self) -> None:
634636
self._test(None)
@@ -1962,7 +1964,7 @@ def test_str_repr_no_warnings(node):
19621964
continue
19631965

19641966
if name == "parent" and "NodeNG" in param_type.annotation:
1965-
args[name] = AstroidManager().synthetic_root
1967+
args[name] = SYNTHETIC_ROOT
19661968
elif "int" in param_type.annotation:
19671969
args[name] = random.randint(0, 50)
19681970
elif (

0 commit comments

Comments
 (0)