1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
4
5"""This module contains exceptions used in the astroid library."""
6
7from __future__ import annotations
8
9from collections.abc import Iterable, Iterator
10from typing import TYPE_CHECKING, Any
11
12from astroid.typing import InferenceResult, SuccessfulInferenceResult
13
14if TYPE_CHECKING:
15 from astroid import arguments, bases, nodes, objects
16 from astroid.context import InferenceContext
17
18__all__ = (
19 "AstroidBuildingError",
20 "AstroidError",
21 "AstroidImportError",
22 "AstroidIndexError",
23 "AstroidSyntaxError",
24 "AstroidTypeError",
25 "AstroidValueError",
26 "AttributeInferenceError",
27 "DuplicateBasesError",
28 "InconsistentMroError",
29 "InferenceError",
30 "InferenceOverwriteError",
31 "MroError",
32 "NameInferenceError",
33 "NoDefault",
34 "NotFoundError",
35 "ParentMissingError",
36 "ResolveError",
37 "StatementMissing",
38 "SuperArgumentTypeError",
39 "SuperError",
40 "TooManyLevelsError",
41 "UnresolvableName",
42 "UseInferenceDefault",
43)
44
45
46class AstroidError(Exception):
47 """Base exception class for all astroid related exceptions.
48
49 AstroidError and its subclasses are structured, intended to hold
50 objects representing state when the exception is thrown. Field
51 values are passed to the constructor as keyword-only arguments.
52 Each subclass has its own set of standard fields, but use your
53 best judgment to decide whether a specific exception instance
54 needs more or fewer fields for debugging. Field values may be
55 used to lazily generate the error message: self.message.format()
56 will be called with the field names and values supplied as keyword
57 arguments.
58 """
59
60 def __init__(self, message: str = "", **kws: Any) -> None:
61 super().__init__(message)
62 self.message = message
63 for key, value in kws.items():
64 setattr(self, key, value)
65
66 def __str__(self) -> str:
67 return self.message.format(**vars(self))
68
69
70class AstroidBuildingError(AstroidError):
71 """Exception class when we are unable to build an astroid representation.
72
73 Standard attributes:
74 modname: Name of the module that AST construction failed for.
75 error: Exception raised during construction.
76 """
77
78 def __init__(
79 self,
80 message: str = "Failed to import module {modname}.",
81 modname: str | None = None,
82 error: Exception | None = None,
83 source: str | None = None,
84 path: str | None = None,
85 cls: type | None = None,
86 class_repr: str | None = None,
87 **kws: Any,
88 ) -> None:
89 self.modname = modname
90 self.error = error
91 self.source = source
92 self.path = path
93 self.cls = cls
94 self.class_repr = class_repr
95 super().__init__(message, **kws)
96
97
98class AstroidImportError(AstroidBuildingError):
99 """Exception class used when a module can't be imported by astroid."""
100
101
102class TooManyLevelsError(AstroidImportError):
103 """Exception class which is raised when a relative import was beyond the top-level.
104
105 Standard attributes:
106 level: The level which was attempted.
107 name: the name of the module on which the relative import was attempted.
108 """
109
110 def __init__(
111 self,
112 message: str = "Relative import with too many levels "
113 "({level}) for module {name!r}",
114 level: int | None = None,
115 name: str | None = None,
116 **kws: Any,
117 ) -> None:
118 self.level = level
119 self.name = name
120 super().__init__(message, **kws)
121
122
123class AstroidSyntaxError(AstroidBuildingError):
124 """Exception class used when a module can't be parsed."""
125
126 def __init__(
127 self,
128 message: str,
129 modname: str | None,
130 error: Exception,
131 path: str | None,
132 source: str | None = None,
133 ) -> None:
134 super().__init__(message, modname, error, source, path)
135
136
137class NoDefault(AstroidError):
138 """Raised by function's `default_value` method when an argument has
139 no default value.
140
141 Standard attributes:
142 func: Function node.
143 name: Name of argument without a default.
144 """
145
146 def __init__(
147 self,
148 message: str = "{func!r} has no default for {name!r}.",
149 func: nodes.FunctionDef | None = None,
150 name: str | None = None,
151 **kws: Any,
152 ) -> None:
153 self.func = func
154 self.name = name
155 super().__init__(message, **kws)
156
157
158class ResolveError(AstroidError):
159 """Base class of astroid resolution/inference error.
160
161 ResolveError is not intended to be raised.
162
163 Standard attributes:
164 context: InferenceContext object.
165 """
166
167 def __init__(
168 self, message: str = "", context: InferenceContext | None = None, **kws: Any
169 ) -> None:
170 self.context = context
171 super().__init__(message, **kws)
172
173
174class MroError(ResolveError):
175 """Error raised when there is a problem with method resolution of a class.
176
177 Standard attributes:
178 mros: A sequence of sequences containing ClassDef nodes.
179 cls: ClassDef node whose MRO resolution failed.
180 context: InferenceContext object.
181 """
182
183 def __init__(
184 self,
185 message: str,
186 mros: Iterable[Iterable[nodes.ClassDef]],
187 cls: nodes.ClassDef,
188 context: InferenceContext | None = None,
189 **kws: Any,
190 ) -> None:
191 self.mros = mros
192 self.cls = cls
193 self.context = context
194 super().__init__(message, **kws)
195
196 def __str__(self) -> str:
197 mro_names = ", ".join(f"({', '.join(b.name for b in m)})" for m in self.mros)
198 return self.message.format(mros=mro_names, cls=self.cls)
199
200
201class DuplicateBasesError(MroError):
202 """Error raised when there are duplicate bases in the same class bases."""
203
204
205class InconsistentMroError(MroError):
206 """Error raised when a class's MRO is inconsistent."""
207
208
209class SuperError(ResolveError):
210 """Error raised when there is a problem with a *super* call.
211
212 Standard attributes:
213 *super_*: The Super instance that raised the exception.
214 context: InferenceContext object.
215 """
216
217 def __init__(self, message: str, super_: objects.Super, **kws: Any) -> None:
218 self.super_ = super_
219 super().__init__(message, **kws)
220
221 def __str__(self) -> str:
222 return self.message.format(**vars(self.super_))
223
224
225class InferenceError(ResolveError): # pylint: disable=too-many-instance-attributes
226 """Raised when we are unable to infer a node.
227
228 Standard attributes:
229 node: The node inference was called on.
230 context: InferenceContext object.
231 """
232
233 def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments
234 self,
235 message: str = "Inference failed for {node!r}.",
236 node: InferenceResult | None = None,
237 context: InferenceContext | None = None,
238 target: InferenceResult | None = None,
239 targets: InferenceResult | None = None,
240 attribute: str | None = None,
241 unknown: InferenceResult | None = None,
242 assign_path: list[int] | None = None,
243 caller: SuccessfulInferenceResult | None = None,
244 stmts: Iterator[InferenceResult] | None = None,
245 frame: InferenceResult | None = None,
246 call_site: arguments.CallSite | None = None,
247 func: InferenceResult | None = None,
248 arg: str | None = None,
249 positional_arguments: list | None = None,
250 unpacked_args: list | None = None,
251 keyword_arguments: dict | None = None,
252 unpacked_kwargs: dict | None = None,
253 **kws: Any,
254 ) -> None:
255 self.node = node
256 self.context = context
257 self.target = target
258 self.targets = targets
259 self.attribute = attribute
260 self.unknown = unknown
261 self.assign_path = assign_path
262 self.caller = caller
263 self.stmts = stmts
264 self.frame = frame
265 self.call_site = call_site
266 self.func = func
267 self.arg = arg
268 self.positional_arguments = positional_arguments
269 self.unpacked_args = unpacked_args
270 self.keyword_arguments = keyword_arguments
271 self.unpacked_kwargs = unpacked_kwargs
272 super().__init__(message, **kws)
273
274
275# Why does this inherit from InferenceError rather than ResolveError?
276# Changing it causes some inference tests to fail.
277class NameInferenceError(InferenceError):
278 """Raised when a name lookup fails, corresponds to NameError.
279
280 Standard attributes:
281 name: The name for which lookup failed, as a string.
282 scope: The node representing the scope in which the lookup occurred.
283 context: InferenceContext object.
284 """
285
286 def __init__(
287 self,
288 message: str = "{name!r} not found in {scope!r}.",
289 name: str | None = None,
290 scope: nodes.LocalsDictNodeNG | None = None,
291 context: InferenceContext | None = None,
292 **kws: Any,
293 ) -> None:
294 self.name = name
295 self.scope = scope
296 self.context = context
297 super().__init__(message, **kws)
298
299
300class AttributeInferenceError(ResolveError):
301 """Raised when an attribute lookup fails, corresponds to AttributeError.
302
303 Standard attributes:
304 target: The node for which lookup failed.
305 attribute: The attribute for which lookup failed, as a string.
306 context: InferenceContext object.
307 """
308
309 def __init__(
310 self,
311 message: str = "{attribute!r} not found on {target!r}.",
312 attribute: str = "",
313 target: nodes.NodeNG | bases.BaseInstance | None = None,
314 context: InferenceContext | None = None,
315 mros: list[nodes.ClassDef] | None = None,
316 super_: nodes.ClassDef | None = None,
317 cls: nodes.ClassDef | None = None,
318 **kws: Any,
319 ) -> None:
320 self.attribute = attribute
321 self.target = target
322 self.context = context
323 self.mros = mros
324 self.super_ = super_
325 self.cls = cls
326 super().__init__(message, **kws)
327
328
329class UseInferenceDefault(Exception):
330 """Exception to be raised in custom inference function to indicate that it
331 should go back to the default behaviour.
332 """
333
334
335class _NonDeducibleTypeHierarchy(Exception):
336 """Raised when is_subtype / is_supertype can't deduce the relation between two
337 types.
338 """
339
340
341class AstroidIndexError(AstroidError):
342 """Raised when an Indexable / Mapping does not have an index / key."""
343
344 def __init__(
345 self,
346 message: str = "",
347 node: nodes.NodeNG | bases.Instance | None = None,
348 index: nodes.Subscript | None = None,
349 context: InferenceContext | None = None,
350 **kws: Any,
351 ) -> None:
352 self.node = node
353 self.index = index
354 self.context = context
355 super().__init__(message, **kws)
356
357
358class AstroidTypeError(AstroidError):
359 """Raised when a TypeError would be expected in Python code."""
360
361 def __init__(
362 self,
363 message: str = "",
364 node: nodes.NodeNG | bases.Instance | None = None,
365 index: nodes.Subscript | None = None,
366 context: InferenceContext | None = None,
367 **kws: Any,
368 ) -> None:
369 self.node = node
370 self.index = index
371 self.context = context
372 super().__init__(message, **kws)
373
374
375class AstroidValueError(AstroidError):
376 """Raised when a ValueError would be expected in Python code."""
377
378
379class InferenceOverwriteError(AstroidError):
380 """Raised when an inference tip is overwritten.
381
382 Currently only used for debugging.
383 """
384
385
386class ParentMissingError(AstroidError):
387 """Raised when a node which is expected to have a parent attribute is missing one.
388
389 Standard attributes:
390 target: The node for which the parent lookup failed.
391 """
392
393 def __init__(self, target: nodes.NodeNG) -> None:
394 self.target = target
395 super().__init__(message=f"Parent not found on {target!r}.")
396
397
398class StatementMissing(ParentMissingError):
399 """Raised when a call to node.statement() does not return a node.
400
401 This is because a node in the chain does not have a parent attribute
402 and therefore does not return a node for statement().
403
404 Standard attributes:
405 target: The node for which the parent lookup failed.
406 """
407
408 def __init__(self, target: nodes.NodeNG) -> None:
409 super(ParentMissingError, self).__init__(
410 message=f"Statement not found on {target!r}"
411 )
412
413
414SuperArgumentTypeError = SuperError
415UnresolvableName = NameInferenceError
416NotFoundError = AttributeInferenceError