brain_builtin_inference.py 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  2. # For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
  3. # Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
  4. """Astroid hooks for various builtins."""
  5. from __future__ import annotations
  6. import itertools
  7. from collections.abc import Iterator
  8. from functools import partial
  9. from astroid import arguments, helpers, inference_tip, nodes, objects, util
  10. from astroid.builder import AstroidBuilder
  11. from astroid.context import InferenceContext
  12. from astroid.exceptions import (
  13. AstroidTypeError,
  14. AttributeInferenceError,
  15. InferenceError,
  16. MroError,
  17. UseInferenceDefault,
  18. )
  19. from astroid.manager import AstroidManager
  20. from astroid.nodes import scoped_nodes
  21. OBJECT_DUNDER_NEW = "object.__new__"
  22. STR_CLASS = """
  23. class whatever(object):
  24. def join(self, iterable):
  25. return {rvalue}
  26. def replace(self, old, new, count=None):
  27. return {rvalue}
  28. def format(self, *args, **kwargs):
  29. return {rvalue}
  30. def encode(self, encoding='ascii', errors=None):
  31. return b''
  32. def decode(self, encoding='ascii', errors=None):
  33. return u''
  34. def capitalize(self):
  35. return {rvalue}
  36. def title(self):
  37. return {rvalue}
  38. def lower(self):
  39. return {rvalue}
  40. def upper(self):
  41. return {rvalue}
  42. def swapcase(self):
  43. return {rvalue}
  44. def index(self, sub, start=None, end=None):
  45. return 0
  46. def find(self, sub, start=None, end=None):
  47. return 0
  48. def count(self, sub, start=None, end=None):
  49. return 0
  50. def strip(self, chars=None):
  51. return {rvalue}
  52. def lstrip(self, chars=None):
  53. return {rvalue}
  54. def rstrip(self, chars=None):
  55. return {rvalue}
  56. def rjust(self, width, fillchar=None):
  57. return {rvalue}
  58. def center(self, width, fillchar=None):
  59. return {rvalue}
  60. def ljust(self, width, fillchar=None):
  61. return {rvalue}
  62. """
  63. BYTES_CLASS = """
  64. class whatever(object):
  65. def join(self, iterable):
  66. return {rvalue}
  67. def replace(self, old, new, count=None):
  68. return {rvalue}
  69. def decode(self, encoding='ascii', errors=None):
  70. return u''
  71. def capitalize(self):
  72. return {rvalue}
  73. def title(self):
  74. return {rvalue}
  75. def lower(self):
  76. return {rvalue}
  77. def upper(self):
  78. return {rvalue}
  79. def swapcase(self):
  80. return {rvalue}
  81. def index(self, sub, start=None, end=None):
  82. return 0
  83. def find(self, sub, start=None, end=None):
  84. return 0
  85. def count(self, sub, start=None, end=None):
  86. return 0
  87. def strip(self, chars=None):
  88. return {rvalue}
  89. def lstrip(self, chars=None):
  90. return {rvalue}
  91. def rstrip(self, chars=None):
  92. return {rvalue}
  93. def rjust(self, width, fillchar=None):
  94. return {rvalue}
  95. def center(self, width, fillchar=None):
  96. return {rvalue}
  97. def ljust(self, width, fillchar=None):
  98. return {rvalue}
  99. """
  100. def _extend_string_class(class_node, code, rvalue):
  101. """Function to extend builtin str/unicode class."""
  102. code = code.format(rvalue=rvalue)
  103. fake = AstroidBuilder(AstroidManager()).string_build(code)["whatever"]
  104. for method in fake.mymethods():
  105. method.parent = class_node
  106. method.lineno = None
  107. method.col_offset = None
  108. if "__class__" in method.locals:
  109. method.locals["__class__"] = [class_node]
  110. class_node.locals[method.name] = [method]
  111. method.parent = class_node
  112. def _extend_builtins(class_transforms):
  113. builtin_ast = AstroidManager().builtins_module
  114. for class_name, transform in class_transforms.items():
  115. transform(builtin_ast[class_name])
  116. _extend_builtins(
  117. {
  118. "bytes": partial(_extend_string_class, code=BYTES_CLASS, rvalue="b''"),
  119. "str": partial(_extend_string_class, code=STR_CLASS, rvalue="''"),
  120. }
  121. )
  122. def _builtin_filter_predicate(node, builtin_name) -> bool:
  123. if (
  124. builtin_name == "type"
  125. and node.root().name == "re"
  126. and isinstance(node.func, nodes.Name)
  127. and node.func.name == "type"
  128. and isinstance(node.parent, nodes.Assign)
  129. and len(node.parent.targets) == 1
  130. and isinstance(node.parent.targets[0], nodes.AssignName)
  131. and node.parent.targets[0].name in {"Pattern", "Match"}
  132. ):
  133. # Handle re.Pattern and re.Match in brain_re
  134. # Match these patterns from stdlib/re.py
  135. # ```py
  136. # Pattern = type(...)
  137. # Match = type(...)
  138. # ```
  139. return False
  140. if isinstance(node.func, nodes.Name) and node.func.name == builtin_name:
  141. return True
  142. if isinstance(node.func, nodes.Attribute):
  143. return (
  144. node.func.attrname == "fromkeys"
  145. and isinstance(node.func.expr, nodes.Name)
  146. and node.func.expr.name == "dict"
  147. )
  148. return False
  149. def register_builtin_transform(transform, builtin_name) -> None:
  150. """Register a new transform function for the given *builtin_name*.
  151. The transform function must accept two parameters, a node and
  152. an optional context.
  153. """
  154. def _transform_wrapper(node, context: InferenceContext | None = None):
  155. result = transform(node, context=context)
  156. if result:
  157. if not result.parent:
  158. # Let the transformation function determine
  159. # the parent for its result. Otherwise,
  160. # we set it to be the node we transformed from.
  161. result.parent = node
  162. if result.lineno is None:
  163. result.lineno = node.lineno
  164. # Can be a 'Module' see https://github.com/PyCQA/pylint/issues/4671
  165. # We don't have a regression test on this one: tread carefully
  166. if hasattr(result, "col_offset") and result.col_offset is None:
  167. result.col_offset = node.col_offset
  168. return iter([result])
  169. AstroidManager().register_transform(
  170. nodes.Call,
  171. inference_tip(_transform_wrapper),
  172. partial(_builtin_filter_predicate, builtin_name=builtin_name),
  173. )
  174. def _container_generic_inference(node, context, node_type, transform):
  175. args = node.args
  176. if not args:
  177. return node_type()
  178. if len(node.args) > 1:
  179. raise UseInferenceDefault()
  180. (arg,) = args
  181. transformed = transform(arg)
  182. if not transformed:
  183. try:
  184. inferred = next(arg.infer(context=context))
  185. except (InferenceError, StopIteration) as exc:
  186. raise UseInferenceDefault from exc
  187. if isinstance(inferred, util.UninferableBase):
  188. raise UseInferenceDefault
  189. transformed = transform(inferred)
  190. if not transformed or isinstance(transformed, util.UninferableBase):
  191. raise UseInferenceDefault
  192. return transformed
  193. def _container_generic_transform( # pylint: disable=inconsistent-return-statements
  194. arg, context, klass, iterables, build_elts
  195. ):
  196. if isinstance(arg, klass):
  197. return arg
  198. if isinstance(arg, iterables):
  199. if all(isinstance(elt, nodes.Const) for elt in arg.elts):
  200. elts = [elt.value for elt in arg.elts]
  201. else:
  202. # TODO: Does not handle deduplication for sets.
  203. elts = []
  204. for element in arg.elts:
  205. if not element:
  206. continue
  207. inferred = helpers.safe_infer(element, context=context)
  208. if inferred:
  209. evaluated_object = nodes.EvaluatedObject(
  210. original=element, value=inferred
  211. )
  212. elts.append(evaluated_object)
  213. elif isinstance(arg, nodes.Dict):
  214. # Dicts need to have consts as strings already.
  215. if not all(isinstance(elt[0], nodes.Const) for elt in arg.items):
  216. raise UseInferenceDefault()
  217. elts = [item[0].value for item in arg.items]
  218. elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)):
  219. elts = arg.value
  220. else:
  221. return
  222. return klass.from_elements(elts=build_elts(elts))
  223. def _infer_builtin_container(
  224. node, context, klass=None, iterables=None, build_elts=None
  225. ):
  226. transform_func = partial(
  227. _container_generic_transform,
  228. context=context,
  229. klass=klass,
  230. iterables=iterables,
  231. build_elts=build_elts,
  232. )
  233. return _container_generic_inference(node, context, klass, transform_func)
  234. # pylint: disable=invalid-name
  235. infer_tuple = partial(
  236. _infer_builtin_container,
  237. klass=nodes.Tuple,
  238. iterables=(
  239. nodes.List,
  240. nodes.Set,
  241. objects.FrozenSet,
  242. objects.DictItems,
  243. objects.DictKeys,
  244. objects.DictValues,
  245. ),
  246. build_elts=tuple,
  247. )
  248. infer_list = partial(
  249. _infer_builtin_container,
  250. klass=nodes.List,
  251. iterables=(
  252. nodes.Tuple,
  253. nodes.Set,
  254. objects.FrozenSet,
  255. objects.DictItems,
  256. objects.DictKeys,
  257. objects.DictValues,
  258. ),
  259. build_elts=list,
  260. )
  261. infer_set = partial(
  262. _infer_builtin_container,
  263. klass=nodes.Set,
  264. iterables=(nodes.List, nodes.Tuple, objects.FrozenSet, objects.DictKeys),
  265. build_elts=set,
  266. )
  267. infer_frozenset = partial(
  268. _infer_builtin_container,
  269. klass=objects.FrozenSet,
  270. iterables=(nodes.List, nodes.Tuple, nodes.Set, objects.FrozenSet, objects.DictKeys),
  271. build_elts=frozenset,
  272. )
  273. def _get_elts(arg, context):
  274. def is_iterable(n):
  275. return isinstance(n, (nodes.List, nodes.Tuple, nodes.Set))
  276. try:
  277. inferred = next(arg.infer(context))
  278. except (InferenceError, StopIteration) as exc:
  279. raise UseInferenceDefault from exc
  280. if isinstance(inferred, nodes.Dict):
  281. items = inferred.items
  282. elif is_iterable(inferred):
  283. items = []
  284. for elt in inferred.elts:
  285. # If an item is not a pair of two items,
  286. # then fallback to the default inference.
  287. # Also, take in consideration only hashable items,
  288. # tuples and consts. We are choosing Names as well.
  289. if not is_iterable(elt):
  290. raise UseInferenceDefault()
  291. if len(elt.elts) != 2:
  292. raise UseInferenceDefault()
  293. if not isinstance(elt.elts[0], (nodes.Tuple, nodes.Const, nodes.Name)):
  294. raise UseInferenceDefault()
  295. items.append(tuple(elt.elts))
  296. else:
  297. raise UseInferenceDefault()
  298. return items
  299. def infer_dict(node, context: InferenceContext | None = None):
  300. """Try to infer a dict call to a Dict node.
  301. The function treats the following cases:
  302. * dict()
  303. * dict(mapping)
  304. * dict(iterable)
  305. * dict(iterable, **kwargs)
  306. * dict(mapping, **kwargs)
  307. * dict(**kwargs)
  308. If a case can't be inferred, we'll fallback to default inference.
  309. """
  310. call = arguments.CallSite.from_call(node, context=context)
  311. if call.has_invalid_arguments() or call.has_invalid_keywords():
  312. raise UseInferenceDefault
  313. args = call.positional_arguments
  314. kwargs = list(call.keyword_arguments.items())
  315. if not args and not kwargs:
  316. # dict()
  317. return nodes.Dict()
  318. if kwargs and not args:
  319. # dict(a=1, b=2, c=4)
  320. items = [(nodes.Const(key), value) for key, value in kwargs]
  321. elif len(args) == 1 and kwargs:
  322. # dict(some_iterable, b=2, c=4)
  323. elts = _get_elts(args[0], context)
  324. keys = [(nodes.Const(key), value) for key, value in kwargs]
  325. items = elts + keys
  326. elif len(args) == 1:
  327. items = _get_elts(args[0], context)
  328. else:
  329. raise UseInferenceDefault()
  330. value = nodes.Dict(
  331. col_offset=node.col_offset, lineno=node.lineno, parent=node.parent
  332. )
  333. value.postinit(items)
  334. return value
  335. def infer_super(node, context: InferenceContext | None = None):
  336. """Understand super calls.
  337. There are some restrictions for what can be understood:
  338. * unbounded super (one argument form) is not understood.
  339. * if the super call is not inside a function (classmethod or method),
  340. then the default inference will be used.
  341. * if the super arguments can't be inferred, the default inference
  342. will be used.
  343. """
  344. if len(node.args) == 1:
  345. # Ignore unbounded super.
  346. raise UseInferenceDefault
  347. scope = node.scope()
  348. if not isinstance(scope, nodes.FunctionDef):
  349. # Ignore non-method uses of super.
  350. raise UseInferenceDefault
  351. if scope.type not in ("classmethod", "method"):
  352. # Not interested in staticmethods.
  353. raise UseInferenceDefault
  354. cls = scoped_nodes.get_wrapping_class(scope)
  355. if not node.args:
  356. mro_pointer = cls
  357. # In we are in a classmethod, the interpreter will fill
  358. # automatically the class as the second argument, not an instance.
  359. if scope.type == "classmethod":
  360. mro_type = cls
  361. else:
  362. mro_type = cls.instantiate_class()
  363. else:
  364. try:
  365. mro_pointer = next(node.args[0].infer(context=context))
  366. except (InferenceError, StopIteration) as exc:
  367. raise UseInferenceDefault from exc
  368. try:
  369. mro_type = next(node.args[1].infer(context=context))
  370. except (InferenceError, StopIteration) as exc:
  371. raise UseInferenceDefault from exc
  372. if isinstance(mro_pointer, util.UninferableBase) or isinstance(
  373. mro_type, util.UninferableBase
  374. ):
  375. # No way we could understand this.
  376. raise UseInferenceDefault
  377. super_obj = objects.Super(
  378. mro_pointer=mro_pointer, mro_type=mro_type, self_class=cls, scope=scope
  379. )
  380. super_obj.parent = node
  381. return super_obj
  382. def _infer_getattr_args(node, context):
  383. if len(node.args) not in (2, 3):
  384. # Not a valid getattr call.
  385. raise UseInferenceDefault
  386. try:
  387. obj = next(node.args[0].infer(context=context))
  388. attr = next(node.args[1].infer(context=context))
  389. except (InferenceError, StopIteration) as exc:
  390. raise UseInferenceDefault from exc
  391. if isinstance(obj, util.UninferableBase) or isinstance(attr, util.UninferableBase):
  392. # If one of the arguments is something we can't infer,
  393. # then also make the result of the getattr call something
  394. # which is unknown.
  395. return util.Uninferable, util.Uninferable
  396. is_string = isinstance(attr, nodes.Const) and isinstance(attr.value, str)
  397. if not is_string:
  398. raise UseInferenceDefault
  399. return obj, attr.value
  400. def infer_getattr(node, context: InferenceContext | None = None):
  401. """Understand getattr calls.
  402. If one of the arguments is an Uninferable object, then the
  403. result will be an Uninferable object. Otherwise, the normal attribute
  404. lookup will be done.
  405. """
  406. obj, attr = _infer_getattr_args(node, context)
  407. if (
  408. isinstance(obj, util.UninferableBase)
  409. or isinstance(attr, util.UninferableBase)
  410. or not hasattr(obj, "igetattr")
  411. ):
  412. return util.Uninferable
  413. try:
  414. return next(obj.igetattr(attr, context=context))
  415. except (StopIteration, InferenceError, AttributeInferenceError):
  416. if len(node.args) == 3:
  417. # Try to infer the default and return it instead.
  418. try:
  419. return next(node.args[2].infer(context=context))
  420. except (StopIteration, InferenceError) as exc:
  421. raise UseInferenceDefault from exc
  422. raise UseInferenceDefault
  423. def infer_hasattr(node, context: InferenceContext | None = None):
  424. """Understand hasattr calls.
  425. This always guarantees three possible outcomes for calling
  426. hasattr: Const(False) when we are sure that the object
  427. doesn't have the intended attribute, Const(True) when
  428. we know that the object has the attribute and Uninferable
  429. when we are unsure of the outcome of the function call.
  430. """
  431. try:
  432. obj, attr = _infer_getattr_args(node, context)
  433. if (
  434. isinstance(obj, util.UninferableBase)
  435. or isinstance(attr, util.UninferableBase)
  436. or not hasattr(obj, "getattr")
  437. ):
  438. return util.Uninferable
  439. obj.getattr(attr, context=context)
  440. except UseInferenceDefault:
  441. # Can't infer something from this function call.
  442. return util.Uninferable
  443. except AttributeInferenceError:
  444. # Doesn't have it.
  445. return nodes.Const(False)
  446. return nodes.Const(True)
  447. def infer_callable(node, context: InferenceContext | None = None):
  448. """Understand callable calls.
  449. This follows Python's semantics, where an object
  450. is callable if it provides an attribute __call__,
  451. even though that attribute is something which can't be
  452. called.
  453. """
  454. if len(node.args) != 1:
  455. # Invalid callable call.
  456. raise UseInferenceDefault
  457. argument = node.args[0]
  458. try:
  459. inferred = next(argument.infer(context=context))
  460. except (InferenceError, StopIteration):
  461. return util.Uninferable
  462. if isinstance(inferred, util.UninferableBase):
  463. return util.Uninferable
  464. return nodes.Const(inferred.callable())
  465. def infer_property(
  466. node: nodes.Call, context: InferenceContext | None = None
  467. ) -> objects.Property:
  468. """Understand `property` class.
  469. This only infers the output of `property`
  470. call, not the arguments themselves.
  471. """
  472. if len(node.args) < 1:
  473. # Invalid property call.
  474. raise UseInferenceDefault
  475. getter = node.args[0]
  476. try:
  477. inferred = next(getter.infer(context=context))
  478. except (InferenceError, StopIteration) as exc:
  479. raise UseInferenceDefault from exc
  480. if not isinstance(inferred, (nodes.FunctionDef, nodes.Lambda)):
  481. raise UseInferenceDefault
  482. prop_func = objects.Property(
  483. function=inferred,
  484. name=inferred.name,
  485. lineno=node.lineno,
  486. parent=node,
  487. col_offset=node.col_offset,
  488. )
  489. prop_func.postinit(
  490. body=[],
  491. args=inferred.args,
  492. doc_node=getattr(inferred, "doc_node", None),
  493. )
  494. return prop_func
  495. def infer_bool(node, context: InferenceContext | None = None):
  496. """Understand bool calls."""
  497. if len(node.args) > 1:
  498. # Invalid bool call.
  499. raise UseInferenceDefault
  500. if not node.args:
  501. return nodes.Const(False)
  502. argument = node.args[0]
  503. try:
  504. inferred = next(argument.infer(context=context))
  505. except (InferenceError, StopIteration):
  506. return util.Uninferable
  507. if isinstance(inferred, util.UninferableBase):
  508. return util.Uninferable
  509. bool_value = inferred.bool_value(context=context)
  510. if isinstance(bool_value, util.UninferableBase):
  511. return util.Uninferable
  512. return nodes.Const(bool_value)
  513. def infer_type(node, context: InferenceContext | None = None):
  514. """Understand the one-argument form of *type*."""
  515. if len(node.args) != 1:
  516. raise UseInferenceDefault
  517. return helpers.object_type(node.args[0], context)
  518. def infer_slice(node, context: InferenceContext | None = None):
  519. """Understand `slice` calls."""
  520. args = node.args
  521. if not 0 < len(args) <= 3:
  522. raise UseInferenceDefault
  523. infer_func = partial(helpers.safe_infer, context=context)
  524. args = [infer_func(arg) for arg in args]
  525. for arg in args:
  526. if not arg or isinstance(arg, util.UninferableBase):
  527. raise UseInferenceDefault
  528. if not isinstance(arg, nodes.Const):
  529. raise UseInferenceDefault
  530. if not isinstance(arg.value, (type(None), int)):
  531. raise UseInferenceDefault
  532. if len(args) < 3:
  533. # Make sure we have 3 arguments.
  534. args.extend([None] * (3 - len(args)))
  535. slice_node = nodes.Slice(
  536. lineno=node.lineno, col_offset=node.col_offset, parent=node.parent
  537. )
  538. slice_node.postinit(*args)
  539. return slice_node
  540. def _infer_object__new__decorator(node, context: InferenceContext | None = None):
  541. # Instantiate class immediately
  542. # since that's what @object.__new__ does
  543. return iter((node.instantiate_class(),))
  544. def _infer_object__new__decorator_check(node) -> bool:
  545. """Predicate before inference_tip.
  546. Check if the given ClassDef has an @object.__new__ decorator
  547. """
  548. if not node.decorators:
  549. return False
  550. for decorator in node.decorators.nodes:
  551. if isinstance(decorator, nodes.Attribute):
  552. if decorator.as_string() == OBJECT_DUNDER_NEW:
  553. return True
  554. return False
  555. def infer_issubclass(callnode, context: InferenceContext | None = None):
  556. """Infer issubclass() calls.
  557. :param nodes.Call callnode: an `issubclass` call
  558. :param InferenceContext context: the context for the inference
  559. :rtype nodes.Const: Boolean Const value of the `issubclass` call
  560. :raises UseInferenceDefault: If the node cannot be inferred
  561. """
  562. call = arguments.CallSite.from_call(callnode, context=context)
  563. if call.keyword_arguments:
  564. # issubclass doesn't support keyword arguments
  565. raise UseInferenceDefault("TypeError: issubclass() takes no keyword arguments")
  566. if len(call.positional_arguments) != 2:
  567. raise UseInferenceDefault(
  568. f"Expected two arguments, got {len(call.positional_arguments)}"
  569. )
  570. # The left hand argument is the obj to be checked
  571. obj_node, class_or_tuple_node = call.positional_arguments
  572. try:
  573. obj_type = next(obj_node.infer(context=context))
  574. except (InferenceError, StopIteration) as exc:
  575. raise UseInferenceDefault from exc
  576. if not isinstance(obj_type, nodes.ClassDef):
  577. raise UseInferenceDefault("TypeError: arg 1 must be class")
  578. # The right hand argument is the class(es) that the given
  579. # object is to be checked against.
  580. try:
  581. class_container = _class_or_tuple_to_container(
  582. class_or_tuple_node, context=context
  583. )
  584. except InferenceError as exc:
  585. raise UseInferenceDefault from exc
  586. try:
  587. issubclass_bool = helpers.object_issubclass(obj_type, class_container, context)
  588. except AstroidTypeError as exc:
  589. raise UseInferenceDefault("TypeError: " + str(exc)) from exc
  590. except MroError as exc:
  591. raise UseInferenceDefault from exc
  592. return nodes.Const(issubclass_bool)
  593. def infer_isinstance(callnode, context: InferenceContext | None = None):
  594. """Infer isinstance calls.
  595. :param nodes.Call callnode: an isinstance call
  596. :rtype nodes.Const: Boolean Const value of isinstance call
  597. :raises UseInferenceDefault: If the node cannot be inferred
  598. """
  599. call = arguments.CallSite.from_call(callnode, context=context)
  600. if call.keyword_arguments:
  601. # isinstance doesn't support keyword arguments
  602. raise UseInferenceDefault("TypeError: isinstance() takes no keyword arguments")
  603. if len(call.positional_arguments) != 2:
  604. raise UseInferenceDefault(
  605. f"Expected two arguments, got {len(call.positional_arguments)}"
  606. )
  607. # The left hand argument is the obj to be checked
  608. obj_node, class_or_tuple_node = call.positional_arguments
  609. # The right hand argument is the class(es) that the given
  610. # obj is to be check is an instance of
  611. try:
  612. class_container = _class_or_tuple_to_container(
  613. class_or_tuple_node, context=context
  614. )
  615. except InferenceError as exc:
  616. raise UseInferenceDefault from exc
  617. try:
  618. isinstance_bool = helpers.object_isinstance(obj_node, class_container, context)
  619. except AstroidTypeError as exc:
  620. raise UseInferenceDefault("TypeError: " + str(exc)) from exc
  621. except MroError as exc:
  622. raise UseInferenceDefault from exc
  623. if isinstance(isinstance_bool, util.UninferableBase):
  624. raise UseInferenceDefault
  625. return nodes.Const(isinstance_bool)
  626. def _class_or_tuple_to_container(node, context: InferenceContext | None = None):
  627. # Move inferences results into container
  628. # to simplify later logic
  629. # raises InferenceError if any of the inferences fall through
  630. try:
  631. node_infer = next(node.infer(context=context))
  632. except StopIteration as e:
  633. raise InferenceError(node=node, context=context) from e
  634. # arg2 MUST be a type or a TUPLE of types
  635. # for isinstance
  636. if isinstance(node_infer, nodes.Tuple):
  637. try:
  638. class_container = [
  639. next(node.infer(context=context)) for node in node_infer.elts
  640. ]
  641. except StopIteration as e:
  642. raise InferenceError(node=node, context=context) from e
  643. class_container = [
  644. klass_node for klass_node in class_container if klass_node is not None
  645. ]
  646. else:
  647. class_container = [node_infer]
  648. return class_container
  649. def infer_len(node, context: InferenceContext | None = None):
  650. """Infer length calls.
  651. :param nodes.Call node: len call to infer
  652. :param context.InferenceContext: node context
  653. :rtype nodes.Const: a Const node with the inferred length, if possible
  654. """
  655. call = arguments.CallSite.from_call(node, context=context)
  656. if call.keyword_arguments:
  657. raise UseInferenceDefault("TypeError: len() must take no keyword arguments")
  658. if len(call.positional_arguments) != 1:
  659. raise UseInferenceDefault(
  660. "TypeError: len() must take exactly one argument "
  661. "({len}) given".format(len=len(call.positional_arguments))
  662. )
  663. [argument_node] = call.positional_arguments
  664. try:
  665. return nodes.Const(helpers.object_len(argument_node, context=context))
  666. except (AstroidTypeError, InferenceError) as exc:
  667. raise UseInferenceDefault(str(exc)) from exc
  668. def infer_str(node, context: InferenceContext | None = None):
  669. """Infer str() calls.
  670. :param nodes.Call node: str() call to infer
  671. :param context.InferenceContext: node context
  672. :rtype nodes.Const: a Const containing an empty string
  673. """
  674. call = arguments.CallSite.from_call(node, context=context)
  675. if call.keyword_arguments:
  676. raise UseInferenceDefault("TypeError: str() must take no keyword arguments")
  677. try:
  678. return nodes.Const("")
  679. except (AstroidTypeError, InferenceError) as exc:
  680. raise UseInferenceDefault(str(exc)) from exc
  681. def infer_int(node, context: InferenceContext | None = None):
  682. """Infer int() calls.
  683. :param nodes.Call node: int() call to infer
  684. :param context.InferenceContext: node context
  685. :rtype nodes.Const: a Const containing the integer value of the int() call
  686. """
  687. call = arguments.CallSite.from_call(node, context=context)
  688. if call.keyword_arguments:
  689. raise UseInferenceDefault("TypeError: int() must take no keyword arguments")
  690. if call.positional_arguments:
  691. try:
  692. first_value = next(call.positional_arguments[0].infer(context=context))
  693. except (InferenceError, StopIteration) as exc:
  694. raise UseInferenceDefault(str(exc)) from exc
  695. if isinstance(first_value, util.UninferableBase):
  696. raise UseInferenceDefault
  697. if isinstance(first_value, nodes.Const) and isinstance(
  698. first_value.value, (int, str)
  699. ):
  700. try:
  701. actual_value = int(first_value.value)
  702. except ValueError:
  703. return nodes.Const(0)
  704. return nodes.Const(actual_value)
  705. return nodes.Const(0)
  706. def infer_dict_fromkeys(node, context: InferenceContext | None = None):
  707. """Infer dict.fromkeys.
  708. :param nodes.Call node: dict.fromkeys() call to infer
  709. :param context.InferenceContext context: node context
  710. :rtype nodes.Dict:
  711. a Dictionary containing the values that astroid was able to infer.
  712. In case the inference failed for any reason, an empty dictionary
  713. will be inferred instead.
  714. """
  715. def _build_dict_with_elements(elements):
  716. new_node = nodes.Dict(
  717. col_offset=node.col_offset, lineno=node.lineno, parent=node.parent
  718. )
  719. new_node.postinit(elements)
  720. return new_node
  721. call = arguments.CallSite.from_call(node, context=context)
  722. if call.keyword_arguments:
  723. raise UseInferenceDefault("TypeError: int() must take no keyword arguments")
  724. if len(call.positional_arguments) not in {1, 2}:
  725. raise UseInferenceDefault(
  726. "TypeError: Needs between 1 and 2 positional arguments"
  727. )
  728. default = nodes.Const(None)
  729. values = call.positional_arguments[0]
  730. try:
  731. inferred_values = next(values.infer(context=context))
  732. except (InferenceError, StopIteration):
  733. return _build_dict_with_elements([])
  734. if inferred_values is util.Uninferable:
  735. return _build_dict_with_elements([])
  736. # Limit to a couple of potential values, as this can become pretty complicated
  737. accepted_iterable_elements = (nodes.Const,)
  738. if isinstance(inferred_values, (nodes.List, nodes.Set, nodes.Tuple)):
  739. elements = inferred_values.elts
  740. for element in elements:
  741. if not isinstance(element, accepted_iterable_elements):
  742. # Fallback to an empty dict
  743. return _build_dict_with_elements([])
  744. elements_with_value = [(element, default) for element in elements]
  745. return _build_dict_with_elements(elements_with_value)
  746. if isinstance(inferred_values, nodes.Const) and isinstance(
  747. inferred_values.value, (str, bytes)
  748. ):
  749. elements = [
  750. (nodes.Const(element), default) for element in inferred_values.value
  751. ]
  752. return _build_dict_with_elements(elements)
  753. if isinstance(inferred_values, nodes.Dict):
  754. keys = inferred_values.itered()
  755. for key in keys:
  756. if not isinstance(key, accepted_iterable_elements):
  757. # Fallback to an empty dict
  758. return _build_dict_with_elements([])
  759. elements_with_value = [(element, default) for element in keys]
  760. return _build_dict_with_elements(elements_with_value)
  761. # Fallback to an empty dictionary
  762. return _build_dict_with_elements([])
  763. def _infer_copy_method(
  764. node: nodes.Call, context: InferenceContext | None = None
  765. ) -> Iterator[nodes.NodeNG]:
  766. assert isinstance(node.func, nodes.Attribute)
  767. inferred_orig, inferred_copy = itertools.tee(node.func.expr.infer(context=context))
  768. if all(
  769. isinstance(
  770. inferred_node, (nodes.Dict, nodes.List, nodes.Set, objects.FrozenSet)
  771. )
  772. for inferred_node in inferred_orig
  773. ):
  774. return inferred_copy
  775. raise UseInferenceDefault()
  776. def _is_str_format_call(node: nodes.Call) -> bool:
  777. """Catch calls to str.format()."""
  778. if not isinstance(node.func, nodes.Attribute) or not node.func.attrname == "format":
  779. return False
  780. if isinstance(node.func.expr, nodes.Name):
  781. value = helpers.safe_infer(node.func.expr)
  782. else:
  783. value = node.func.expr
  784. return isinstance(value, nodes.Const) and isinstance(value.value, str)
  785. def _infer_str_format_call(
  786. node: nodes.Call, context: InferenceContext | None = None
  787. ) -> Iterator[nodes.Const | util.UninferableBase]:
  788. """Return a Const node based on the template and passed arguments."""
  789. call = arguments.CallSite.from_call(node, context=context)
  790. if isinstance(node.func.expr, nodes.Name):
  791. value: nodes.Const | None = helpers.safe_infer(node.func.expr)
  792. if value is None:
  793. return iter([util.Uninferable])
  794. else:
  795. value = node.func.expr
  796. format_template = value.value
  797. # Get the positional arguments passed
  798. inferred_positional = [
  799. helpers.safe_infer(i, context) for i in call.positional_arguments
  800. ]
  801. if not all(isinstance(i, nodes.Const) for i in inferred_positional):
  802. return iter([util.Uninferable])
  803. pos_values: list[str] = [i.value for i in inferred_positional]
  804. # Get the keyword arguments passed
  805. inferred_keyword = {
  806. k: helpers.safe_infer(v, context) for k, v in call.keyword_arguments.items()
  807. }
  808. if not all(isinstance(i, nodes.Const) for i in inferred_keyword.values()):
  809. return iter([util.Uninferable])
  810. keyword_values: dict[str, str] = {k: v.value for k, v in inferred_keyword.items()}
  811. try:
  812. formatted_string = format_template.format(*pos_values, **keyword_values)
  813. except (AttributeError, IndexError, KeyError, TypeError, ValueError):
  814. # AttributeError: named field in format string was not found in the arguments
  815. # IndexError: there are too few arguments to interpolate
  816. # TypeError: Unsupported format string
  817. # ValueError: Unknown format code
  818. return iter([util.Uninferable])
  819. return iter([nodes.const_factory(formatted_string)])
  820. # Builtins inference
  821. register_builtin_transform(infer_bool, "bool")
  822. register_builtin_transform(infer_super, "super")
  823. register_builtin_transform(infer_callable, "callable")
  824. register_builtin_transform(infer_property, "property")
  825. register_builtin_transform(infer_getattr, "getattr")
  826. register_builtin_transform(infer_hasattr, "hasattr")
  827. register_builtin_transform(infer_tuple, "tuple")
  828. register_builtin_transform(infer_set, "set")
  829. register_builtin_transform(infer_list, "list")
  830. register_builtin_transform(infer_dict, "dict")
  831. register_builtin_transform(infer_frozenset, "frozenset")
  832. register_builtin_transform(infer_type, "type")
  833. register_builtin_transform(infer_slice, "slice")
  834. register_builtin_transform(infer_isinstance, "isinstance")
  835. register_builtin_transform(infer_issubclass, "issubclass")
  836. register_builtin_transform(infer_len, "len")
  837. register_builtin_transform(infer_str, "str")
  838. register_builtin_transform(infer_int, "int")
  839. register_builtin_transform(infer_dict_fromkeys, "dict.fromkeys")
  840. # Infer object.__new__ calls
  841. AstroidManager().register_transform(
  842. nodes.ClassDef,
  843. inference_tip(_infer_object__new__decorator),
  844. _infer_object__new__decorator_check,
  845. )
  846. AstroidManager().register_transform(
  847. nodes.Call,
  848. inference_tip(_infer_copy_method),
  849. lambda node: isinstance(node.func, nodes.Attribute)
  850. and node.func.attrname == "copy",
  851. )
  852. AstroidManager().register_transform(
  853. nodes.Call, inference_tip(_infer_str_format_call), _is_str_format_call
  854. )