Skip to content

Commit eb711d2

Browse files
committed
Create UninferableBase
1 parent bcaecce commit eb711d2

21 files changed

+127
-117
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Release date: TBA
1010

1111
Refs PyCQA/pylint#7306
1212

13+
* ``Uninferable`` now has the type ``UninferableBase``. This is to facilitate correctly type annotating
14+
code that uses this singleton.
15+
16+
Closes #1680
17+
1318

1419
What's New in astroid 2.14.2?
1520
=============================

astroid/arguments.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from astroid.bases import Instance
99
from astroid.context import CallContext, InferenceContext
1010
from astroid.exceptions import InferenceError, NoDefault
11-
from astroid.util import Uninferable
11+
from astroid.util import Uninferable, UninferableBase
1212

1313

1414
class CallSite:
@@ -44,12 +44,12 @@ def __init__(
4444
self._unpacked_kwargs = self._unpack_keywords(keywords, context=context)
4545

4646
self.positional_arguments = [
47-
arg for arg in self._unpacked_args if arg is not Uninferable
47+
arg for arg in self._unpacked_args if not isinstance(arg, UninferableBase)
4848
]
4949
self.keyword_arguments = {
5050
key: value
5151
for key, value in self._unpacked_kwargs.items()
52-
if value is not Uninferable
52+
if not isinstance(value, UninferableBase)
5353
}
5454

5555
@classmethod
@@ -142,7 +142,7 @@ def _unpack_args(self, args, context: InferenceContext | None = None):
142142
except StopIteration:
143143
continue
144144

145-
if inferred is Uninferable:
145+
if isinstance(inferred, UninferableBase):
146146
values.append(Uninferable)
147147
continue
148148
if not hasattr(inferred, "elts"):

astroid/bases.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
NameInferenceError,
2929
)
3030
from astroid.typing import InferBinaryOp, InferenceErrorInfo, InferenceResult
31-
from astroid.util import Uninferable, lazy_descriptor, lazy_import
31+
from astroid.util import Uninferable, UninferableBase, lazy_descriptor, lazy_import
3232

3333
if sys.version_info >= (3, 8):
3434
from typing import Literal
@@ -79,7 +79,9 @@ def _is_property(meth, context: InferenceContext | None = None) -> bool:
7979
if PROPERTIES.intersection(decoratornames):
8080
return True
8181
stripped = {
82-
name.split(".")[-1] for name in decoratornames if name is not Uninferable
82+
name.split(".")[-1]
83+
for name in decoratornames
84+
if not isinstance(name, UninferableBase)
8385
}
8486
if any(name in stripped for name in POSSIBLE_PROPERTIES):
8587
return True
@@ -89,7 +91,7 @@ def _is_property(meth, context: InferenceContext | None = None) -> bool:
8991
return False
9092
for decorator in meth.decorators.nodes or ():
9193
inferred = helpers.safe_infer(decorator, context=context)
92-
if inferred is None or inferred is Uninferable:
94+
if inferred is None or isinstance(inferred, UninferableBase):
9395
continue
9496
if inferred.__class__.__name__ == "ClassDef":
9597
for base_class in inferred.bases:
@@ -144,7 +146,7 @@ def infer( # type: ignore[return]
144146

145147

146148
def _infer_stmts(
147-
stmts: Sequence[nodes.NodeNG | type[Uninferable] | Instance],
149+
stmts: Sequence[nodes.NodeNG | UninferableBase | Instance],
148150
context: InferenceContext | None,
149151
frame: nodes.NodeNG | Instance | None = None,
150152
) -> collections.abc.Generator[InferenceResult, None, None]:
@@ -161,7 +163,7 @@ def _infer_stmts(
161163
context = InferenceContext()
162164

163165
for stmt in stmts:
164-
if stmt is Uninferable:
166+
if isinstance(stmt, UninferableBase):
165167
yield stmt
166168
inferred = True
167169
continue
@@ -172,8 +174,7 @@ def _infer_stmts(
172174
for constraint_stmt, potential_constraints in constraints.items():
173175
if not constraint_stmt.parent_of(stmt):
174176
stmt_constraints.update(potential_constraints)
175-
# Mypy doesn't recognize that 'stmt' can't be Uninferable
176-
for inf in stmt.infer(context=context): # type: ignore[union-attr]
177+
for inf in stmt.infer(context=context):
177178
if all(constraint.satisfied_by(inf) for constraint in stmt_constraints):
178179
yield inf
179180
inferred = True
@@ -206,7 +207,7 @@ def _infer_method_result_truth(instance, method_name, context):
206207
try:
207208
context.callcontext = CallContext(args=[], callee=meth)
208209
for value in meth.infer_call_result(instance, context=context):
209-
if value is Uninferable:
210+
if isinstance(value, UninferableBase):
210211
return value
211212
try:
212213
inferred = next(value.infer(context=context))
@@ -316,7 +317,7 @@ def infer_call_result(
316317

317318
# Otherwise we infer the call to the __call__ dunder normally
318319
for node in self._proxied.igetattr("__call__", context):
319-
if node is Uninferable or not node.callable():
320+
if isinstance(node, UninferableBase) or not node.callable():
320321
continue
321322
for res in node.infer_call_result(caller, context):
322323
inferred = True
@@ -458,7 +459,7 @@ def _infer_builtin_new(
458459
caller: nodes.Call,
459460
context: InferenceContext,
460461
) -> collections.abc.Generator[
461-
nodes.Const | Instance | type[Uninferable], None, None
462+
nodes.Const | Instance | UninferableBase, None, None
462463
]:
463464
if not caller.args:
464465
return
@@ -477,7 +478,7 @@ def _infer_builtin_new(
477478

478479
node_context = context.extra_context.get(caller.args[0])
479480
for inferred in caller.args[0].infer(context=node_context):
480-
if inferred is Uninferable:
481+
if isinstance(inferred, UninferableBase):
481482
yield inferred
482483
if isinstance(inferred, nodes.ClassDef):
483484
yield Instance(inferred)

astroid/brain/brain_builtin_inference.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,10 @@ def _container_generic_inference(node, context, node_type, transform):
209209
inferred = next(arg.infer(context=context))
210210
except (InferenceError, StopIteration) as exc:
211211
raise UseInferenceDefault from exc
212-
if inferred is util.Uninferable:
212+
if isinstance(inferred, util.UninferableBase):
213213
raise UseInferenceDefault
214214
transformed = transform(inferred)
215-
if not transformed or transformed is util.Uninferable:
215+
if not transformed or isinstance(transformed, util.UninferableBase):
216216
raise UseInferenceDefault
217217
return transformed
218218

@@ -423,7 +423,9 @@ def infer_super(node, context: InferenceContext | None = None):
423423
except (InferenceError, StopIteration) as exc:
424424
raise UseInferenceDefault from exc
425425

426-
if mro_pointer is util.Uninferable or mro_type is util.Uninferable:
426+
if isinstance(mro_pointer, util.UninferableBase) or isinstance(
427+
mro_type, util.UninferableBase
428+
):
427429
# No way we could understand this.
428430
raise UseInferenceDefault
429431

@@ -445,7 +447,7 @@ def _infer_getattr_args(node, context):
445447
except (InferenceError, StopIteration) as exc:
446448
raise UseInferenceDefault from exc
447449

448-
if obj is util.Uninferable or attr is util.Uninferable:
450+
if isinstance(obj, util.UninferableBase) or isinstance(attr, util.UninferableBase):
449451
# If one of the arguments is something we can't infer,
450452
# then also make the result of the getattr call something
451453
# which is unknown.
@@ -467,8 +469,8 @@ def infer_getattr(node, context: InferenceContext | None = None):
467469
"""
468470
obj, attr = _infer_getattr_args(node, context)
469471
if (
470-
obj is util.Uninferable
471-
or attr is util.Uninferable
472+
isinstance(obj, util.UninferableBase)
473+
or isinstance(attr, util.UninferableBase)
472474
or not hasattr(obj, "igetattr")
473475
):
474476
return util.Uninferable
@@ -498,8 +500,8 @@ def infer_hasattr(node, context: InferenceContext | None = None):
498500
try:
499501
obj, attr = _infer_getattr_args(node, context)
500502
if (
501-
obj is util.Uninferable
502-
or attr is util.Uninferable
503+
isinstance(obj, util.UninferableBase)
504+
or isinstance(attr, util.UninferableBase)
503505
or not hasattr(obj, "getattr")
504506
):
505507
return util.Uninferable
@@ -530,7 +532,7 @@ def infer_callable(node, context: InferenceContext | None = None):
530532
inferred = next(argument.infer(context=context))
531533
except (InferenceError, StopIteration):
532534
return util.Uninferable
533-
if inferred is util.Uninferable:
535+
if isinstance(inferred, util.UninferableBase):
534536
return util.Uninferable
535537
return nodes.Const(inferred.callable())
536538

@@ -585,11 +587,11 @@ def infer_bool(node, context: InferenceContext | None = None):
585587
inferred = next(argument.infer(context=context))
586588
except (InferenceError, StopIteration):
587589
return util.Uninferable
588-
if inferred is util.Uninferable:
590+
if isinstance(inferred, util.UninferableBase):
589591
return util.Uninferable
590592

591593
bool_value = inferred.bool_value(context=context)
592-
if bool_value is util.Uninferable:
594+
if isinstance(bool_value, util.UninferableBase):
593595
return util.Uninferable
594596
return nodes.Const(bool_value)
595597

@@ -611,7 +613,7 @@ def infer_slice(node, context: InferenceContext | None = None):
611613
infer_func = partial(helpers.safe_infer, context=context)
612614
args = [infer_func(arg) for arg in args]
613615
for arg in args:
614-
if not arg or arg is util.Uninferable:
616+
if not arg or isinstance(arg, util.UninferableBase):
615617
raise UseInferenceDefault
616618
if not isinstance(arg, nodes.Const):
617619
raise UseInferenceDefault
@@ -725,7 +727,7 @@ def infer_isinstance(callnode, context: InferenceContext | None = None):
725727
raise UseInferenceDefault("TypeError: " + str(exc)) from exc
726728
except MroError as exc:
727729
raise UseInferenceDefault from exc
728-
if isinstance_bool is util.Uninferable:
730+
if isinstance(isinstance_bool, util.UninferableBase):
729731
raise UseInferenceDefault
730732
return nodes.Const(isinstance_bool)
731733

@@ -811,7 +813,7 @@ def infer_int(node, context: InferenceContext | None = None):
811813
except (InferenceError, StopIteration) as exc:
812814
raise UseInferenceDefault(str(exc)) from exc
813815

814-
if first_value is util.Uninferable:
816+
if isinstance(first_value, util.UninferableBase):
815817
raise UseInferenceDefault
816818

817819
if isinstance(first_value, nodes.Const) and isinstance(
@@ -924,7 +926,7 @@ def _is_str_format_call(node: nodes.Call) -> bool:
924926

925927
def _infer_str_format_call(
926928
node: nodes.Call, context: InferenceContext | None = None
927-
) -> Iterator[nodes.Const | type[util.Uninferable]]:
929+
) -> Iterator[nodes.Const | util.UninferableBase]:
928930
"""Return a Const node based on the template and passed arguments."""
929931
call = arguments.CallSite.from_call(node, context=context)
930932
if isinstance(node.func.expr, nodes.Name):

astroid/brain/brain_dataclasses.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from astroid.inference_tip import inference_tip
2626
from astroid.manager import AstroidManager
2727
from astroid.typing import InferenceResult
28-
from astroid.util import Uninferable
28+
from astroid.util import Uninferable, UninferableBase
2929

3030
if sys.version_info >= (3, 8):
3131
from typing import Literal
@@ -446,7 +446,7 @@ def _looks_like_dataclass_decorator(
446446
except (InferenceError, StopIteration):
447447
inferred = Uninferable
448448

449-
if inferred is Uninferable:
449+
if isinstance(inferred, UninferableBase):
450450
if isinstance(node, nodes.Name):
451451
return node.name in decorator_names
452452
if isinstance(node, nodes.Attribute):
@@ -594,7 +594,7 @@ def _is_init_var(node: nodes.NodeNG) -> bool:
594594

595595
def _infer_instance_from_annotation(
596596
node: nodes.NodeNG, ctx: context.InferenceContext | None = None
597-
) -> Iterator[type[Uninferable] | bases.Instance]:
597+
) -> Iterator[UninferableBase | bases.Instance]:
598598
"""Infer an instance corresponding to the type annotation represented by node.
599599
600600
Currently has limited support for the typing module.

astroid/brain/brain_functools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from astroid.manager import AstroidManager
1919
from astroid.nodes.node_classes import AssignName, Attribute, Call, Name
2020
from astroid.nodes.scoped_nodes import FunctionDef
21-
from astroid.util import Uninferable
21+
from astroid.util import UninferableBase
2222

2323
LRU_CACHE = "functools.lru_cache"
2424

@@ -84,7 +84,7 @@ def _functools_partial_inference(
8484
inferred_wrapped_function = next(partial_function.infer(context=context))
8585
except (InferenceError, StopIteration) as exc:
8686
raise UseInferenceDefault from exc
87-
if inferred_wrapped_function is Uninferable:
87+
if isinstance(inferred_wrapped_function, UninferableBase):
8888
raise UseInferenceDefault("Cannot infer the wrapped function")
8989
if not isinstance(inferred_wrapped_function, FunctionDef):
9090
raise UseInferenceDefault("The wrapped function is not a function")

astroid/brain/brain_namedtuple_enum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@
5252

5353

5454
def _infer_first(node, context):
55-
if node is util.Uninferable:
55+
if isinstance(node, util.UninferableBase):
5656
raise UseInferenceDefault
5757
try:
5858
value = next(node.infer(context=context))
5959
except StopIteration as exc:
6060
raise InferenceError from exc
61-
if value is util.Uninferable:
61+
if isinstance(value, util.UninferableBase):
6262
raise UseInferenceDefault()
6363
return value
6464

astroid/brain/brain_typing.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
Tuple,
3434
)
3535
from astroid.nodes.scoped_nodes import ClassDef, FunctionDef
36-
from astroid.util import Uninferable
3736

3837
if sys.version_info >= (3, 8):
3938
from typing import Final
@@ -297,7 +296,7 @@ def infer_typing_alias(
297296
col_offset=assign_name.col_offset,
298297
parent=node.parent,
299298
)
300-
if res != Uninferable and isinstance(res, ClassDef):
299+
if isinstance(res, ClassDef):
301300
# Only add `res` as base if it's a `ClassDef`
302301
# This isn't the case for `typing.Pattern` and `typing.Match`
303302
class_def.postinit(bases=[res], body=[], decorators=None)

astroid/builder.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ def delayed_assattr(self, node: nodes.AssignAttr) -> None:
238238
try:
239239
frame = node.frame(future=True)
240240
for inferred in node.expr.infer():
241-
if inferred is util.Uninferable:
241+
if isinstance(inferred, util.UninferableBase):
242242
continue
243243
try:
244244
# pylint: disable=unidiomatic-typecheck # We want a narrow check on the
@@ -255,10 +255,7 @@ def delayed_assattr(self, node: nodes.AssignAttr) -> None:
255255
# Const, Tuple or other containers that inherit from
256256
# `Instance`
257257
continue
258-
elif (
259-
isinstance(inferred, bases.Proxy)
260-
or inferred is util.Uninferable
261-
):
258+
elif isinstance(inferred, (bases.Proxy, util.UninferableBase)):
262259
continue
263260
elif inferred.is_function:
264261
iattrs = inferred.instance_attrs

astroid/constraint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def match(
7474
def satisfied_by(self, inferred: InferenceResult) -> bool:
7575
"""Return True if this constraint is satisfied by the given inferred value."""
7676
# Assume true if uninferable
77-
if inferred is util.Uninferable:
77+
if isinstance(inferred, util.UninferableBase):
7878
return True
7979

8080
# Return the XOR of self.negate and matches(inferred, self.CONST_NONE)

0 commit comments

Comments
 (0)