Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/util.py: 68%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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
6from __future__ import annotations
8import re
9import warnings
10from typing import TYPE_CHECKING, Any, Final, Literal
12from astroid.exceptions import InferenceError
14if TYPE_CHECKING:
15 from astroid import bases, nodes
16 from astroid.context import InferenceContext
17 from astroid.typing import InferenceResult
20class UninferableBase:
21 """Special inference object, which is returned when inference fails.
23 This is meant to be used as a singleton. Use astroid.util.Uninferable to access it.
24 """
26 def __repr__(self) -> Literal["Uninferable"]:
27 return "Uninferable"
29 __str__ = __repr__
31 def __getattribute__(self, name: str) -> Any:
32 if name == "next":
33 raise AttributeError("next method should not be called")
34 if name.startswith("__") and name.endswith("__"):
35 return object.__getattribute__(self, name)
36 if name == "accept":
37 return object.__getattribute__(self, name)
38 return self
40 def __call__(self, *args: Any, **kwargs: Any) -> UninferableBase:
41 return self
43 def __bool__(self) -> Literal[False]:
44 return False
46 def accept(self, visitor):
47 return visitor.visit_uninferable(self)
50Uninferable: Final = UninferableBase()
52# Width/precision in a format spec drive how large a formatted string gets.
53# Match the leading width and the optional ``.precision`` from the start of a
54# format spec (PEP 3101 / format mini-language).
55_FORMAT_SPEC_SIZE = re.compile(
56 r"(?:.?[<>=^])?[-+ ]?z?#?0?(?P<width>\d+)?(?:[,_])?(?:\.(?P<precision>\d+))?"
57)
58# Mirrors the sequence/repetition caps in astroid.protocols.
59MAX_FORMATTED_SIZE = 10**8
62def format_spec_too_large(format_spec: str) -> bool:
63 """Whether a format spec asks for an oversized width or precision.
65 Used to avoid materializing a multi-gigabyte string while inferring a tiny
66 literal such as ``"{:>2000000000}".format("x")`` or ``f"{1.5:.2e9f}"``.
67 """
68 # Every group in _FORMAT_SPEC_SIZE is optional, so match is never None.
69 match = _FORMAT_SPEC_SIZE.match(format_spec)
70 return any(
71 size is not None and int(size) > MAX_FORMATTED_SIZE
72 for size in match.group("width", "precision")
73 )
76class BadOperationMessage:
77 """Object which describes a TypeError occurred somewhere in the inference chain.
79 This is not an exception, but a container object which holds the types and
80 the error which occurred.
81 """
84class BadUnaryOperationMessage(BadOperationMessage):
85 """Object which describes operational failures on UnaryOps."""
87 def __init__(self, operand, op, error):
88 self.operand = operand
89 self.op = op
90 self.error = error
92 @property
93 def _object_type_helper(self):
94 from astroid import helpers # pylint: disable=import-outside-toplevel
96 return helpers.object_type
98 def _object_type(self, obj):
99 objtype = self._object_type_helper(obj)
100 if isinstance(objtype, UninferableBase):
101 return None
103 return objtype
105 def __str__(self) -> str:
106 if hasattr(self.operand, "name"):
107 operand_type = self.operand.name
108 else:
109 object_type = self._object_type(self.operand)
110 if hasattr(object_type, "name"):
111 operand_type = object_type.name
112 else:
113 # Just fallback to as_string
114 operand_type = object_type.as_string()
116 msg = "bad operand type for unary {}: {}"
117 return msg.format(self.op, operand_type)
120class BadBinaryOperationMessage(BadOperationMessage):
121 """Object which describes type errors for BinOps."""
123 def __init__(self, left_type, op, right_type):
124 self.left_type = left_type
125 self.right_type = right_type
126 self.op = op
128 def __str__(self) -> str:
129 return (
130 f"unsupported operand type(s) for {self.op}: {self.left_type.name!r} "
131 f"and {self.right_type.name!r}"
132 )
135def check_warnings_filter() -> bool:
136 """Return True if any other than the default DeprecationWarning filter is enabled.
138 https://docs.python.org/3/library/warnings.html#default-warning-filter
139 """
140 return any(
141 issubclass(DeprecationWarning, filter[2])
142 and filter[0] != "ignore"
143 and filter[3] != "__main__"
144 for filter in warnings.filters
145 )
148def safe_infer(
149 node: nodes.NodeNG | bases.Proxy | UninferableBase,
150 context: InferenceContext | None = None,
151) -> InferenceResult | None:
152 """Return the inferred value for the given node.
154 Return None if inference failed or if there is some ambiguity (more than
155 one node has been inferred).
156 """
157 if isinstance(node, UninferableBase):
158 return node
159 try:
160 inferit = node.infer(context=context)
161 value = next(inferit)
162 except (InferenceError, StopIteration):
163 return None
164 try:
165 next(inferit)
166 return None # None if there is ambiguity on the inferred node
167 except InferenceError:
168 return None # there is some kind of ambiguity
169 except StopIteration:
170 return value