Skip to content

Commit 842548d

Browse files
Improve typing of builtins brain (#2214)
Resolves 14 mypy errors
1 parent 525c3b2 commit 842548d

File tree

2 files changed

+63
-29
lines changed

2 files changed

+63
-29
lines changed

astroid/arguments.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ def has_invalid_keywords(self) -> bool:
8686
"""
8787
return len(self.keyword_arguments) != len(self._unpacked_kwargs)
8888

89-
def _unpack_keywords(self, keywords, context: InferenceContext | None = None):
89+
def _unpack_keywords(
90+
self,
91+
keywords: list[tuple[str | None, nodes.NodeNG]],
92+
context: InferenceContext | None = None,
93+
):
9094
values = {}
9195
context = context or InferenceContext()
9296
context.extra_context = self.argument_context_map

astroid/brain/brain_builtin_inference.py

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from __future__ import annotations
88

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

14-
from astroid import arguments, bases, helpers, inference_tip, nodes, objects, util
14+
from astroid import arguments, helpers, inference_tip, nodes, objects, util
1515
from astroid.builder import AstroidBuilder
1616
from astroid.context import InferenceContext
1717
from astroid.exceptions import (
@@ -23,7 +23,25 @@
2323
)
2424
from astroid.manager import AstroidManager
2525
from astroid.nodes import scoped_nodes
26-
from astroid.typing import InferenceResult, SuccessfulInferenceResult
26+
from astroid.typing import (
27+
ConstFactoryResult,
28+
InferenceResult,
29+
SuccessfulInferenceResult,
30+
)
31+
32+
ContainerObjects = Union[
33+
objects.FrozenSet,
34+
objects.DictItems,
35+
objects.DictKeys,
36+
objects.DictValues,
37+
]
38+
39+
BuiltContainers = Union[
40+
Type[tuple],
41+
Type[list],
42+
Type[set],
43+
Type[frozenset],
44+
]
2745

2846
OBJECT_DUNDER_NEW = "object.__new__"
2947

@@ -232,18 +250,19 @@ def _container_generic_inference(
232250
return transformed
233251

234252

235-
def _container_generic_transform( # pylint: disable=inconsistent-return-statements
253+
def _container_generic_transform(
236254
arg: SuccessfulInferenceResult,
237255
context: InferenceContext | None,
238256
klass: type[nodes.BaseContainer],
239-
iterables: tuple[type[nodes.NodeNG] | type[bases.Proxy], ...],
240-
build_elts: type[Iterable[Any]],
257+
iterables: tuple[type[nodes.BaseContainer] | type[ContainerObjects], ...],
258+
build_elts: BuiltContainers,
241259
) -> nodes.BaseContainer | None:
242260
if isinstance(arg, klass):
243261
return arg
244262
if isinstance(arg, iterables):
263+
arg = cast(ContainerObjects, arg)
245264
if all(isinstance(elt, nodes.Const) for elt in arg.elts):
246-
elts = [elt.value for elt in arg.elts]
265+
elts = [cast(nodes.Const, elt).value for elt in arg.elts]
247266
else:
248267
# TODO: Does not handle deduplication for sets.
249268
elts = []
@@ -264,16 +283,16 @@ def _container_generic_transform( # pylint: disable=inconsistent-return-stateme
264283
elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)):
265284
elts = arg.value
266285
else:
267-
return
286+
return None
268287
return klass.from_elements(elts=build_elts(elts))
269288

270289

271290
def _infer_builtin_container(
272291
node: nodes.Call,
273292
context: InferenceContext | None,
274293
klass: type[nodes.BaseContainer],
275-
iterables: tuple[type[nodes.NodeNG] | type[bases.Proxy], ...],
276-
build_elts: type[Iterable[Any]],
294+
iterables: tuple[type[nodes.NodeNG] | type[ContainerObjects], ...],
295+
build_elts: BuiltContainers,
277296
) -> nodes.BaseContainer:
278297
transform_func = partial(
279298
_container_generic_transform,
@@ -944,8 +963,8 @@ def _build_dict_with_elements(elements):
944963

945964

946965
def _infer_copy_method(
947-
node: nodes.Call, context: InferenceContext | None = None
948-
) -> Iterator[nodes.NodeNG]:
966+
node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any
967+
) -> Iterator[InferenceResult]:
949968
assert isinstance(node.func, nodes.Attribute)
950969
inferred_orig, inferred_copy = itertools.tee(node.func.expr.infer(context=context))
951970
if all(
@@ -973,33 +992,44 @@ def _is_str_format_call(node: nodes.Call) -> bool:
973992

974993

975994
def _infer_str_format_call(
976-
node: nodes.Call, context: InferenceContext | None = None
977-
) -> Iterator[nodes.Const | util.UninferableBase]:
995+
node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any
996+
) -> Iterator[ConstFactoryResult | util.UninferableBase]:
978997
"""Return a Const node based on the template and passed arguments."""
979998
call = arguments.CallSite.from_call(node, context=context)
999+
assert isinstance(node.func, (nodes.Attribute, nodes.AssignAttr, nodes.DelAttr))
1000+
1001+
value: nodes.Const
9801002
if isinstance(node.func.expr, nodes.Name):
981-
value: nodes.Const | None = helpers.safe_infer(node.func.expr)
982-
if value is None:
1003+
if not (inferred := helpers.safe_infer(node.func.expr)) or not isinstance(
1004+
inferred, nodes.Const
1005+
):
9831006
return iter([util.Uninferable])
984-
else:
1007+
value = inferred
1008+
elif isinstance(node.func.expr, nodes.Const):
9851009
value = node.func.expr
1010+
else: # pragma: no cover
1011+
return iter([util.Uninferable])
9861012

9871013
format_template = value.value
9881014

9891015
# Get the positional arguments passed
990-
inferred_positional = [
991-
helpers.safe_infer(i, context) for i in call.positional_arguments
992-
]
993-
if not all(isinstance(i, nodes.Const) for i in inferred_positional):
994-
return iter([util.Uninferable])
1016+
inferred_positional: list[nodes.Const] = []
1017+
for i in call.positional_arguments:
1018+
one_inferred = helpers.safe_infer(i, context)
1019+
if not isinstance(one_inferred, nodes.Const):
1020+
return iter([util.Uninferable])
1021+
inferred_positional.append(one_inferred)
1022+
9951023
pos_values: list[str] = [i.value for i in inferred_positional]
9961024

9971025
# Get the keyword arguments passed
998-
inferred_keyword = {
999-
k: helpers.safe_infer(v, context) for k, v in call.keyword_arguments.items()
1000-
}
1001-
if not all(isinstance(i, nodes.Const) for i in inferred_keyword.values()):
1002-
return iter([util.Uninferable])
1026+
inferred_keyword: dict[str, nodes.Const] = {}
1027+
for k, v in call.keyword_arguments.items():
1028+
one_inferred = helpers.safe_infer(v, context)
1029+
if not isinstance(one_inferred, nodes.Const):
1030+
return iter([util.Uninferable])
1031+
inferred_keyword[k] = one_inferred
1032+
10031033
keyword_values: dict[str, str] = {k: v.value for k, v in inferred_keyword.items()}
10041034

10051035
try:

0 commit comments

Comments
 (0)