Skip to content

Commit 8d57ce2

Browse files
Further improve typing of builtins brain (#2225)
Resolves 12 mypy errors Co-authored-by: Daniël van Noord <[email protected]>
1 parent 2f8b636 commit 8d57ce2

File tree

6 files changed

+54
-25
lines changed

6 files changed

+54
-25
lines changed

astroid/arguments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def _unpack_keywords(
9191
keywords: list[tuple[str | None, nodes.NodeNG]],
9292
context: InferenceContext | None = None,
9393
):
94-
values = {}
94+
values: dict[str | None, InferenceResult] = {}
9595
context = context or InferenceContext()
9696
context.extra_context = self.argument_context_map
9797
for name, value in keywords:

astroid/brain/brain_builtin_inference.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from __future__ import annotations
88

99
import itertools
10-
from collections.abc import Callable, Iterator
10+
from collections.abc import Callable, Iterable
1111
from functools import partial
12-
from typing import Any, Type, Union, cast
12+
from typing import TYPE_CHECKING, Any, Iterator, NoReturn, Type, Union, cast
1313

1414
from astroid import arguments, helpers, inference_tip, nodes, objects, util
1515
from astroid.builder import AstroidBuilder
@@ -29,6 +29,9 @@
2929
SuccessfulInferenceResult,
3030
)
3131

32+
if TYPE_CHECKING:
33+
from astroid.bases import Instance
34+
3235
ContainerObjects = Union[
3336
objects.FrozenSet,
3437
objects.DictItems,
@@ -43,6 +46,13 @@
4346
Type[frozenset],
4447
]
4548

49+
CopyResult = Union[
50+
nodes.Dict,
51+
nodes.List,
52+
nodes.Set,
53+
objects.FrozenSet,
54+
]
55+
4656
OBJECT_DUNDER_NEW = "object.__new__"
4757

4858
STR_CLASS = """
@@ -127,6 +137,10 @@ def ljust(self, width, fillchar=None):
127137
"""
128138

129139

140+
def _use_default() -> NoReturn: # pragma: no cover
141+
raise UseInferenceDefault()
142+
143+
130144
def _extend_string_class(class_node, code, rvalue):
131145
"""Function to extend builtin str/unicode class."""
132146
code = code.format(rvalue=rvalue)
@@ -193,7 +207,9 @@ def register_builtin_transform(transform, builtin_name) -> None:
193207
an optional context.
194208
"""
195209

196-
def _transform_wrapper(node, context: InferenceContext | None = None):
210+
def _transform_wrapper(
211+
node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any
212+
) -> Iterator:
197213
result = transform(node, context=context)
198214
if result:
199215
if not result.parent:
@@ -257,10 +273,12 @@ def _container_generic_transform(
257273
iterables: tuple[type[nodes.BaseContainer] | type[ContainerObjects], ...],
258274
build_elts: BuiltContainers,
259275
) -> nodes.BaseContainer | None:
276+
elts: Iterable | str | bytes
277+
260278
if isinstance(arg, klass):
261279
return arg
262280
if isinstance(arg, iterables):
263-
arg = cast(ContainerObjects, arg)
281+
arg = cast(Union[nodes.BaseContainer, ContainerObjects], arg)
264282
if all(isinstance(elt, nodes.Const) for elt in arg.elts):
265283
elts = [cast(nodes.Const, elt).value for elt in arg.elts]
266284
else:
@@ -277,9 +295,10 @@ def _container_generic_transform(
277295
elts.append(evaluated_object)
278296
elif isinstance(arg, nodes.Dict):
279297
# Dicts need to have consts as strings already.
280-
if not all(isinstance(elt[0], nodes.Const) for elt in arg.items):
281-
raise UseInferenceDefault()
282-
elts = [item[0].value for item in arg.items]
298+
elts = [
299+
item[0].value if isinstance(item[0], nodes.Const) else _use_default()
300+
for item in arg.items
301+
]
283302
elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)):
284303
elts = arg.value
285304
else:
@@ -399,6 +418,7 @@ def infer_dict(node: nodes.Call, context: InferenceContext | None = None) -> nod
399418
args = call.positional_arguments
400419
kwargs = list(call.keyword_arguments.items())
401420

421+
items: list[tuple[InferenceResult, InferenceResult]]
402422
if not args and not kwargs:
403423
# dict()
404424
return nodes.Dict(
@@ -695,7 +715,9 @@ def infer_slice(node, context: InferenceContext | None = None):
695715
return slice_node
696716

697717

698-
def _infer_object__new__decorator(node, context: InferenceContext | None = None):
718+
def _infer_object__new__decorator(
719+
node: nodes.ClassDef, context: InferenceContext | None = None, **kwargs: Any
720+
) -> Iterator[Instance]:
699721
# Instantiate class immediately
700722
# since that's what @object.__new__ does
701723
return iter((node.instantiate_class(),))
@@ -944,10 +966,10 @@ def _build_dict_with_elements(elements):
944966
if isinstance(inferred_values, nodes.Const) and isinstance(
945967
inferred_values.value, (str, bytes)
946968
):
947-
elements = [
969+
elements_with_value = [
948970
(nodes.Const(element), default) for element in inferred_values.value
949971
]
950-
return _build_dict_with_elements(elements)
972+
return _build_dict_with_elements(elements_with_value)
951973
if isinstance(inferred_values, nodes.Dict):
952974
keys = inferred_values.itered()
953975
for key in keys:
@@ -964,7 +986,7 @@ def _build_dict_with_elements(elements):
964986

965987
def _infer_copy_method(
966988
node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any
967-
) -> Iterator[InferenceResult]:
989+
) -> Iterator[CopyResult]:
968990
assert isinstance(node.func, nodes.Attribute)
969991
inferred_orig, inferred_copy = itertools.tee(node.func.expr.infer(context=context))
970992
if all(
@@ -973,9 +995,9 @@ def _infer_copy_method(
973995
)
974996
for inferred_node in inferred_orig
975997
):
976-
return inferred_copy
998+
return cast(Iterator[CopyResult], inferred_copy)
977999

978-
raise UseInferenceDefault()
1000+
raise UseInferenceDefault
9791001

9801002

9811003
def _is_str_format_call(node: nodes.Call) -> bool:
@@ -1081,5 +1103,7 @@ def _infer_str_format_call(
10811103
)
10821104

10831105
AstroidManager().register_transform(
1084-
nodes.Call, inference_tip(_infer_str_format_call), _is_str_format_call
1106+
nodes.Call,
1107+
inference_tip(_infer_str_format_call),
1108+
_is_str_format_call,
10851109
)

astroid/nodes/node_classes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,9 +1864,7 @@ def __init__(
18641864
parent=parent,
18651865
)
18661866

1867-
def postinit(
1868-
self, items: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]
1869-
) -> None:
1867+
def postinit(self, items: list[tuple[InferenceResult, InferenceResult]]) -> None:
18701868
"""Do some setup after initialisation.
18711869
18721870
:param items: The key-value pairs contained in the dictionary.
@@ -4058,11 +4056,13 @@ class EvaluatedObject(NodeNG):
40584056
_astroid_fields = ("original",)
40594057
_other_fields = ("value",)
40604058

4061-
def __init__(self, original: NodeNG, value: NodeNG | util.UninferableBase) -> None:
4062-
self.original: NodeNG = original
4059+
def __init__(
4060+
self, original: SuccessfulInferenceResult, value: InferenceResult
4061+
) -> None:
4062+
self.original: SuccessfulInferenceResult = original
40634063
"""The original node that has already been evaluated"""
40644064

4065-
self.value: NodeNG | util.UninferableBase = value
4065+
self.value: InferenceResult = value
40664066
"""The inferred value"""
40674067

40684068
super().__init__(

astroid/rebuilder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from astroid.manager import AstroidManager
2323
from astroid.nodes import NodeNG
2424
from astroid.nodes.utils import Position
25-
from astroid.typing import SuccessfulInferenceResult
25+
from astroid.typing import InferenceResult
2626

2727
REDIRECT: Final[dict[str, str]] = {
2828
"arguments": "Arguments",
@@ -1019,7 +1019,7 @@ def visit_dict(self, node: ast.Dict, parent: NodeNG) -> nodes.Dict:
10191019
end_col_offset=node.end_col_offset,
10201020
parent=parent,
10211021
)
1022-
items: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = list(
1022+
items: list[tuple[InferenceResult, InferenceResult]] = list(
10231023
self._visit_dict_items(node, parent, newnode)
10241024
)
10251025
newnode.postinit(items)

astroid/typing.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
)
1818

1919
if TYPE_CHECKING:
20+
from collections.abc import Iterator
21+
2022
from astroid import bases, exceptions, nodes, transforms, util
2123
from astroid.context import InferenceContext
2224
from astroid.interpreter._import import spec
@@ -84,7 +86,7 @@ def __call__(
8486
node: _SuccessfulInferenceResultT_contra,
8587
context: InferenceContext | None = None,
8688
**kwargs: Any,
87-
) -> Generator[InferenceResult, None, None]:
89+
) -> Iterator[InferenceResult]:
8890
... # pragma: no cover
8991

9092

tests/test_nodes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1931,7 +1931,10 @@ def test_str_repr_no_warnings(node):
19311931

19321932
if "int" in param_type.annotation:
19331933
args[name] = random.randint(0, 50)
1934-
elif "NodeNG" in param_type.annotation:
1934+
elif (
1935+
"NodeNG" in param_type.annotation
1936+
or "SuccessfulInferenceResult" in param_type.annotation
1937+
):
19351938
args[name] = nodes.Unknown()
19361939
elif "str" in param_type.annotation:
19371940
args[name] = ""

0 commit comments

Comments
 (0)