Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/brain/brain_builtin_inference.py: 23%

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

482 statements  

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"""Astroid hooks for various builtins.""" 

6 

7from __future__ import annotations 

8 

9import itertools 

10from collections.abc import Callable, Iterable, Iterator 

11from functools import partial 

12from typing import TYPE_CHECKING, Any, NoReturn, cast 

13 

14from astroid import arguments, helpers, nodes, objects, util 

15from astroid.builder import AstroidBuilder 

16from astroid.context import InferenceContext 

17from astroid.exceptions import ( 

18 AstroidTypeError, 

19 AttributeInferenceError, 

20 InferenceError, 

21 MroError, 

22 UseInferenceDefault, 

23) 

24from astroid.inference_tip import inference_tip 

25from astroid.manager import AstroidManager 

26from astroid.nodes import scoped_nodes 

27from astroid.typing import ( 

28 ConstFactoryResult, 

29 InferenceResult, 

30 SuccessfulInferenceResult, 

31) 

32 

33if TYPE_CHECKING: 

34 from astroid.bases import Instance 

35 

36ContainerObjects = ( 

37 objects.FrozenSet | objects.DictItems | objects.DictKeys | objects.DictValues 

38) 

39 

40BuiltContainers = type[tuple] | type[list] | type[set] | type[frozenset] 

41 

42CopyResult = nodes.Dict | nodes.List | nodes.Set | objects.FrozenSet 

43 

44OBJECT_DUNDER_NEW = "object.__new__" 

45 

46STR_CLASS = """ 

47class whatever(object): 

48 def join(self, iterable): 

49 return {rvalue} 

50 def replace(self, old, new, count=None): 

51 return {rvalue} 

52 def format(self, *args, **kwargs): 

53 return {rvalue} 

54 def encode(self, encoding='ascii', errors=None): 

55 return b'' 

56 def decode(self, encoding='ascii', errors=None): 

57 return u'' 

58 def capitalize(self): 

59 return {rvalue} 

60 def title(self): 

61 return {rvalue} 

62 def lower(self): 

63 return {rvalue} 

64 def upper(self): 

65 return {rvalue} 

66 def swapcase(self): 

67 return {rvalue} 

68 def index(self, sub, start=None, end=None): 

69 return 0 

70 def find(self, sub, start=None, end=None): 

71 return 0 

72 def count(self, sub, start=None, end=None): 

73 return 0 

74 def strip(self, chars=None): 

75 return {rvalue} 

76 def lstrip(self, chars=None): 

77 return {rvalue} 

78 def rstrip(self, chars=None): 

79 return {rvalue} 

80 def rjust(self, width, fillchar=None): 

81 return {rvalue} 

82 def center(self, width, fillchar=None): 

83 return {rvalue} 

84 def ljust(self, width, fillchar=None): 

85 return {rvalue} 

86""" 

87 

88 

89BYTES_CLASS = """ 

90class whatever(object): 

91 def join(self, iterable): 

92 return {rvalue} 

93 def replace(self, old, new, count=None): 

94 return {rvalue} 

95 def decode(self, encoding='ascii', errors=None): 

96 return u'' 

97 def capitalize(self): 

98 return {rvalue} 

99 def title(self): 

100 return {rvalue} 

101 def lower(self): 

102 return {rvalue} 

103 def upper(self): 

104 return {rvalue} 

105 def swapcase(self): 

106 return {rvalue} 

107 def index(self, sub, start=None, end=None): 

108 return 0 

109 def find(self, sub, start=None, end=None): 

110 return 0 

111 def count(self, sub, start=None, end=None): 

112 return 0 

113 def strip(self, chars=None): 

114 return {rvalue} 

115 def lstrip(self, chars=None): 

116 return {rvalue} 

117 def rstrip(self, chars=None): 

118 return {rvalue} 

119 def rjust(self, width, fillchar=None): 

120 return {rvalue} 

121 def center(self, width, fillchar=None): 

122 return {rvalue} 

123 def ljust(self, width, fillchar=None): 

124 return {rvalue} 

125""" 

126 

127 

128def _use_default() -> NoReturn: # pragma: no cover 

129 raise UseInferenceDefault() 

130 

131 

132def _extend_string_class(class_node, code, rvalue): 

133 """Function to extend builtin str/unicode class.""" 

134 code = code.format(rvalue=rvalue) 

135 fake = AstroidBuilder(AstroidManager()).string_build(code)["whatever"] 

136 for method in fake.mymethods(): 

137 method.parent = class_node 

138 method.lineno = None 

139 method.col_offset = None 

140 if "__class__" in method.locals: 

141 method.locals["__class__"] = [class_node] 

142 class_node.locals[method.name] = [method] 

143 method.parent = class_node 

144 

145 

146def _extend_builtins(class_transforms): 

147 builtin_ast = AstroidManager().builtins_module 

148 for class_name, transform in class_transforms.items(): 

149 transform(builtin_ast[class_name]) 

150 

151 

152def on_bootstrap(): 

153 """Called by astroid_bootstrapping().""" 

154 _extend_builtins( 

155 { 

156 "bytes": partial(_extend_string_class, code=BYTES_CLASS, rvalue="b''"), 

157 "str": partial(_extend_string_class, code=STR_CLASS, rvalue="''"), 

158 } 

159 ) 

160 

161 

162def _builtin_filter_predicate(node, builtin_name) -> bool: 

163 # pylint: disable = too-many-boolean-expressions 

164 if ( 

165 builtin_name == "type" 

166 and node.root().name == "re" 

167 and isinstance(node.func, nodes.Name) 

168 and node.func.name == "type" 

169 and isinstance(node.parent, nodes.Assign) 

170 and len(node.parent.targets) == 1 

171 and isinstance(node.parent.targets[0], nodes.AssignName) 

172 and node.parent.targets[0].name in {"Pattern", "Match"} 

173 ): 

174 # Handle re.Pattern and re.Match in brain_re 

175 # Match these patterns from stdlib/re.py 

176 # ```py 

177 # Pattern = type(...) 

178 # Match = type(...) 

179 # ``` 

180 return False 

181 if isinstance(node.func, nodes.Name): 

182 return node.func.name == builtin_name 

183 if isinstance(node.func, nodes.Attribute): 

184 return ( 

185 node.func.attrname == "fromkeys" 

186 and isinstance(node.func.expr, nodes.Name) 

187 and node.func.expr.name == "dict" 

188 ) 

189 return False 

190 

191 

192def register_builtin_transform( 

193 manager: AstroidManager, transform, builtin_name 

194) -> None: 

195 """Register a new transform function for the given *builtin_name*. 

196 

197 The transform function must accept two parameters, a node and 

198 an optional context. 

199 """ 

200 

201 def _transform_wrapper( 

202 node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any 

203 ) -> Iterator: 

204 result = transform(node, context=context) 

205 if result: 

206 if not result.parent: 

207 # Let the transformation function determine 

208 # the parent for its result. Otherwise, 

209 # we set it to be the node we transformed from. 

210 result.parent = node 

211 

212 if result.lineno is None: 

213 result.lineno = node.lineno 

214 # Can be a 'Module' see https://github.com/pylint-dev/pylint/issues/4671 

215 # We don't have a regression test on this one: tread carefully 

216 if hasattr(result, "col_offset") and result.col_offset is None: 

217 result.col_offset = node.col_offset 

218 return iter([result]) 

219 

220 manager.register_transform( 

221 nodes.Call, 

222 inference_tip(_transform_wrapper), 

223 partial(_builtin_filter_predicate, builtin_name=builtin_name), 

224 ) 

225 

226 

227def _container_generic_inference( 

228 node: nodes.Call, 

229 context: InferenceContext | None, 

230 node_type: type[nodes.BaseContainer], 

231 transform: Callable[[SuccessfulInferenceResult], nodes.BaseContainer | None], 

232) -> nodes.BaseContainer: 

233 args = node.args 

234 if not args: 

235 return node_type( 

236 lineno=node.lineno, 

237 col_offset=node.col_offset, 

238 parent=node.parent, 

239 end_lineno=node.end_lineno, 

240 end_col_offset=node.end_col_offset, 

241 ) 

242 if len(node.args) > 1: 

243 raise UseInferenceDefault() 

244 

245 (arg,) = args 

246 transformed = transform(arg) 

247 if not transformed: 

248 try: 

249 inferred = next(arg.infer(context=context)) 

250 except (InferenceError, StopIteration) as exc: 

251 raise UseInferenceDefault from exc 

252 if isinstance(inferred, util.UninferableBase): 

253 raise UseInferenceDefault 

254 transformed = transform(inferred) 

255 if not transformed or isinstance(transformed, util.UninferableBase): 

256 raise UseInferenceDefault 

257 return transformed 

258 

259 

260def _container_generic_transform( 

261 arg: SuccessfulInferenceResult, 

262 context: InferenceContext | None, 

263 klass: type[nodes.BaseContainer], 

264 iterables: tuple[type[nodes.BaseContainer] | type[ContainerObjects], ...], 

265 build_elts: BuiltContainers, 

266) -> nodes.BaseContainer | None: 

267 elts: Iterable | str | bytes 

268 

269 if isinstance(arg, klass): 

270 return arg 

271 if isinstance(arg, iterables): 

272 arg = cast((nodes.BaseContainer | ContainerObjects), arg) 

273 if all(isinstance(elt, nodes.Const) for elt in arg.elts): 

274 elts = [cast(nodes.Const, elt).value for elt in arg.elts] 

275 else: 

276 # TODO: Does not handle deduplication for sets. 

277 elts = [] 

278 for element in arg.elts: 

279 if not element: 

280 continue 

281 inferred = util.safe_infer(element, context=context) 

282 if inferred: 

283 evaluated_object = nodes.EvaluatedObject( 

284 original=element, value=inferred 

285 ) 

286 elts.append(evaluated_object) 

287 elif isinstance(arg, nodes.Dict): 

288 # Dicts need to have consts as strings already. 

289 elts = [ 

290 item[0].value if isinstance(item[0], nodes.Const) else _use_default() 

291 for item in arg.items 

292 ] 

293 elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)): 

294 elts = arg.value 

295 else: 

296 return None 

297 return klass.from_elements(elts=build_elts(elts)) 

298 

299 

300def _infer_builtin_container( 

301 node: nodes.Call, 

302 context: InferenceContext | None, 

303 klass: type[nodes.BaseContainer], 

304 iterables: tuple[type[nodes.NodeNG] | type[ContainerObjects], ...], 

305 build_elts: BuiltContainers, 

306) -> nodes.BaseContainer: 

307 transform_func = partial( 

308 _container_generic_transform, 

309 context=context, 

310 klass=klass, 

311 iterables=iterables, 

312 build_elts=build_elts, 

313 ) 

314 

315 return _container_generic_inference(node, context, klass, transform_func) 

316 

317 

318# pylint: disable=invalid-name 

319infer_tuple = partial( 

320 _infer_builtin_container, 

321 klass=nodes.Tuple, 

322 iterables=( 

323 nodes.List, 

324 nodes.Set, 

325 objects.FrozenSet, 

326 objects.DictItems, 

327 objects.DictKeys, 

328 objects.DictValues, 

329 ), 

330 build_elts=tuple, 

331) 

332 

333infer_list = partial( 

334 _infer_builtin_container, 

335 klass=nodes.List, 

336 iterables=( 

337 nodes.Tuple, 

338 nodes.Set, 

339 objects.FrozenSet, 

340 objects.DictItems, 

341 objects.DictKeys, 

342 objects.DictValues, 

343 ), 

344 build_elts=list, 

345) 

346 

347infer_set = partial( 

348 _infer_builtin_container, 

349 klass=nodes.Set, 

350 iterables=(nodes.List, nodes.Tuple, objects.FrozenSet, objects.DictKeys), 

351 build_elts=set, 

352) 

353 

354infer_frozenset = partial( 

355 _infer_builtin_container, 

356 klass=objects.FrozenSet, 

357 iterables=(nodes.List, nodes.Tuple, nodes.Set, objects.FrozenSet, objects.DictKeys), 

358 build_elts=frozenset, 

359) 

360 

361 

362def _get_elts(arg, context): 

363 def is_iterable(n) -> bool: 

364 return isinstance(n, (nodes.List, nodes.Tuple, nodes.Set)) 

365 

366 try: 

367 inferred = next(arg.infer(context)) 

368 except (InferenceError, StopIteration) as exc: 

369 raise UseInferenceDefault from exc 

370 if isinstance(inferred, nodes.Dict): 

371 items = inferred.items 

372 elif is_iterable(inferred): 

373 items = [] 

374 for elt in inferred.elts: 

375 # If an item is not a pair of two items, 

376 # then fallback to the default inference. 

377 # Also, take in consideration only hashable items, 

378 # tuples and consts. We are choosing Names as well. 

379 if not is_iterable(elt): 

380 raise UseInferenceDefault() 

381 if len(elt.elts) != 2: 

382 raise UseInferenceDefault() 

383 if not isinstance(elt.elts[0], (nodes.Tuple, nodes.Const, nodes.Name)): 

384 raise UseInferenceDefault() 

385 items.append(tuple(elt.elts)) 

386 else: 

387 raise UseInferenceDefault() 

388 return items 

389 

390 

391def infer_dict(node: nodes.Call, context: InferenceContext | None = None) -> nodes.Dict: 

392 """Try to infer a dict call to a Dict node. 

393 

394 The function treats the following cases: 

395 

396 * dict() 

397 * dict(mapping) 

398 * dict(iterable) 

399 * dict(iterable, **kwargs) 

400 * dict(mapping, **kwargs) 

401 * dict(**kwargs) 

402 

403 If a case can't be inferred, we'll fallback to default inference. 

404 """ 

405 call = arguments.CallSite.from_call(node, context=context) 

406 if call.has_invalid_arguments() or call.has_invalid_keywords(): 

407 raise UseInferenceDefault 

408 

409 args = call.positional_arguments 

410 kwargs = list(call.keyword_arguments.items()) 

411 

412 items: list[tuple[InferenceResult, InferenceResult]] 

413 if not args and not kwargs: 

414 # dict() 

415 return nodes.Dict( 

416 lineno=node.lineno, 

417 col_offset=node.col_offset, 

418 parent=node.parent, 

419 end_lineno=node.end_lineno, 

420 end_col_offset=node.end_col_offset, 

421 ) 

422 if kwargs and not args: 

423 # dict(a=1, b=2, c=4) 

424 items = [(nodes.Const(key), value) for key, value in kwargs] 

425 elif len(args) == 1 and kwargs: 

426 # dict(some_iterable, b=2, c=4) 

427 elts = _get_elts(args[0], context) 

428 keys = [(nodes.Const(key), value) for key, value in kwargs] 

429 items = elts + keys 

430 elif len(args) == 1: 

431 items = _get_elts(args[0], context) 

432 else: 

433 raise UseInferenceDefault() 

434 value = nodes.Dict( 

435 col_offset=node.col_offset, 

436 lineno=node.lineno, 

437 parent=node.parent, 

438 end_lineno=node.end_lineno, 

439 end_col_offset=node.end_col_offset, 

440 ) 

441 value.postinit(items) 

442 return value 

443 

444 

445def infer_super( 

446 node: nodes.Call, context: InferenceContext | None = None 

447) -> objects.Super: 

448 """Understand super calls. 

449 

450 There are some restrictions for what can be understood: 

451 

452 * unbounded super (one argument form) is not understood. 

453 

454 * if the super call is not inside a function (classmethod or method), 

455 then the default inference will be used. 

456 

457 * if the super arguments can't be inferred, the default inference 

458 will be used. 

459 """ 

460 if len(node.args) == 1: 

461 # Ignore unbounded super. 

462 raise UseInferenceDefault 

463 

464 scope = node.scope() 

465 if not isinstance(scope, nodes.FunctionDef): 

466 # Ignore non-method uses of super. 

467 raise UseInferenceDefault 

468 if scope.type not in ("classmethod", "method"): 

469 # Not interested in staticmethods. 

470 raise UseInferenceDefault 

471 

472 cls = scoped_nodes.get_wrapping_class(scope) 

473 assert cls is not None 

474 if not node.args: 

475 mro_pointer = cls 

476 # In we are in a classmethod, the interpreter will fill 

477 # automatically the class as the second argument, not an instance. 

478 if scope.type == "classmethod": 

479 mro_type = cls 

480 else: 

481 mro_type = cls.instantiate_class() 

482 else: 

483 try: 

484 mro_pointer = next(node.args[0].infer(context=context)) 

485 except (InferenceError, StopIteration) as exc: 

486 raise UseInferenceDefault from exc 

487 try: 

488 mro_type = next(node.args[1].infer(context=context)) 

489 except (InferenceError, StopIteration) as exc: 

490 raise UseInferenceDefault from exc 

491 

492 if isinstance(mro_pointer, util.UninferableBase) or isinstance( 

493 mro_type, util.UninferableBase 

494 ): 

495 # No way we could understand this. 

496 raise UseInferenceDefault 

497 

498 super_obj = objects.Super( 

499 mro_pointer=mro_pointer, 

500 mro_type=mro_type, 

501 self_class=cls, 

502 scope=scope, 

503 call=node, 

504 ) 

505 super_obj.parent = node 

506 return super_obj 

507 

508 

509def _infer_getattr_args(node, context): 

510 if len(node.args) not in (2, 3): 

511 # Not a valid getattr call. 

512 raise UseInferenceDefault 

513 

514 try: 

515 obj = next(node.args[0].infer(context=context)) 

516 attr = next(node.args[1].infer(context=context)) 

517 except (InferenceError, StopIteration) as exc: 

518 raise UseInferenceDefault from exc 

519 

520 if isinstance(obj, util.UninferableBase) or isinstance(attr, util.UninferableBase): 

521 # If one of the arguments is something we can't infer, 

522 # then also make the result of the getattr call something 

523 # which is unknown. 

524 return util.Uninferable, util.Uninferable 

525 

526 is_string = isinstance(attr, nodes.Const) and isinstance(attr.value, str) 

527 if not is_string: 

528 raise UseInferenceDefault 

529 

530 return obj, attr.value 

531 

532 

533def infer_getattr(node, context: InferenceContext | None = None): 

534 """Understand getattr calls. 

535 

536 If one of the arguments is an Uninferable object, then the 

537 result will be an Uninferable object. Otherwise, the normal attribute 

538 lookup will be done. 

539 """ 

540 obj, attr = _infer_getattr_args(node, context) 

541 if ( 

542 isinstance(obj, util.UninferableBase) 

543 or isinstance(attr, util.UninferableBase) 

544 or not hasattr(obj, "igetattr") 

545 ): 

546 return util.Uninferable 

547 

548 try: 

549 return next(obj.igetattr(attr, context=context)) 

550 except (StopIteration, InferenceError, AttributeInferenceError): 

551 if len(node.args) == 3: 

552 # Try to infer the default and return it instead. 

553 try: 

554 return next(node.args[2].infer(context=context)) 

555 except (StopIteration, InferenceError) as exc: 

556 raise UseInferenceDefault from exc 

557 

558 raise UseInferenceDefault 

559 

560 

561def infer_hasattr(node, context: InferenceContext | None = None): 

562 """Understand hasattr calls. 

563 

564 This always guarantees three possible outcomes for calling 

565 hasattr: Const(False) when we are sure that the object 

566 doesn't have the intended attribute, Const(True) when 

567 we know that the object has the attribute and Uninferable 

568 when we are unsure of the outcome of the function call. 

569 """ 

570 try: 

571 obj, attr = _infer_getattr_args(node, context) 

572 if ( 

573 isinstance(obj, util.UninferableBase) 

574 or isinstance(attr, util.UninferableBase) 

575 or not hasattr(obj, "getattr") 

576 ): 

577 return util.Uninferable 

578 obj.getattr(attr, context=context) 

579 except UseInferenceDefault: 

580 # Can't infer something from this function call. 

581 return util.Uninferable 

582 except AttributeInferenceError: 

583 # Doesn't have it. 

584 return nodes.Const(False) 

585 return nodes.Const(True) 

586 

587 

588def infer_callable(node, context: InferenceContext | None = None): 

589 """Understand callable calls. 

590 

591 This follows Python's semantics, where an object 

592 is callable if it provides an attribute __call__, 

593 even though that attribute is something which can't be 

594 called. 

595 """ 

596 if len(node.args) != 1: 

597 # Invalid callable call. 

598 raise UseInferenceDefault 

599 

600 argument = node.args[0] 

601 try: 

602 inferred = next(argument.infer(context=context)) 

603 except (InferenceError, StopIteration): 

604 return util.Uninferable 

605 if isinstance(inferred, util.UninferableBase): 

606 return util.Uninferable 

607 return nodes.Const(inferred.callable()) 

608 

609 

610def infer_property( 

611 node: nodes.Call, context: InferenceContext | None = None 

612) -> objects.Property: 

613 """Understand `property` class. 

614 

615 This only infers the output of `property` 

616 call, not the arguments themselves. 

617 """ 

618 if len(node.args) < 1: 

619 # Invalid property call. 

620 raise UseInferenceDefault 

621 

622 getter = node.args[0] 

623 try: 

624 inferred = next(getter.infer(context=context)) 

625 except (InferenceError, StopIteration) as exc: 

626 raise UseInferenceDefault from exc 

627 

628 if not isinstance(inferred, (nodes.FunctionDef, nodes.Lambda)): 

629 raise UseInferenceDefault 

630 

631 prop_func = objects.Property( 

632 function=inferred, 

633 name="<property>", 

634 lineno=node.lineno, 

635 col_offset=node.col_offset, 

636 # ↓ semantically, the definition of the class of property isn't within 

637 # node.frame. It's somewhere in the builtins module, but we are special 

638 # casing it for each "property()" call, so we are making up the 

639 # definition on the spot, ad-hoc. 

640 parent=scoped_nodes.SYNTHETIC_ROOT, 

641 ) 

642 prop_func.postinit( 

643 body=[], 

644 args=inferred.args, 

645 doc_node=getattr(inferred, "doc_node", None), 

646 ) 

647 return prop_func 

648 

649 

650def infer_bool(node, context: InferenceContext | None = None): 

651 """Understand bool calls.""" 

652 if len(node.args) > 1: 

653 # Invalid bool call. 

654 raise UseInferenceDefault 

655 

656 if not node.args: 

657 return nodes.Const(False) 

658 

659 argument = node.args[0] 

660 try: 

661 inferred = next(argument.infer(context=context)) 

662 except (InferenceError, StopIteration): 

663 return util.Uninferable 

664 if isinstance(inferred, util.UninferableBase): 

665 return util.Uninferable 

666 

667 bool_value = inferred.bool_value(context=context) 

668 if isinstance(bool_value, util.UninferableBase): 

669 return util.Uninferable 

670 return nodes.Const(bool_value) 

671 

672 

673def infer_type(node, context: InferenceContext | None = None): 

674 """Understand the one-argument form of *type*.""" 

675 if len(node.args) != 1: 

676 raise UseInferenceDefault 

677 

678 return helpers.object_type(node.args[0], context) 

679 

680 

681def infer_slice(node, context: InferenceContext | None = None): 

682 """Understand `slice` calls.""" 

683 args = node.args 

684 if not 0 < len(args) <= 3: 

685 raise UseInferenceDefault 

686 

687 infer_func = partial(util.safe_infer, context=context) 

688 args = [infer_func(arg) for arg in args] 

689 for arg in args: 

690 if not arg or isinstance(arg, util.UninferableBase): 

691 raise UseInferenceDefault 

692 if not isinstance(arg, nodes.Const): 

693 raise UseInferenceDefault 

694 if not isinstance(arg.value, (type(None), int)): 

695 raise UseInferenceDefault 

696 

697 if len(args) < 3: 

698 # Make sure we have 3 arguments. 

699 args.extend([None] * (3 - len(args))) 

700 

701 slice_node = nodes.Slice( 

702 lineno=node.lineno, 

703 col_offset=node.col_offset, 

704 parent=node.parent, 

705 end_lineno=node.end_lineno, 

706 end_col_offset=node.end_col_offset, 

707 ) 

708 slice_node.postinit(*args) 

709 return slice_node 

710 

711 

712def _infer_object__new__decorator( 

713 node: nodes.ClassDef, context: InferenceContext | None = None, **kwargs: Any 

714) -> Iterator[Instance]: 

715 # Instantiate class immediately 

716 # since that's what @object.__new__ does 

717 return iter((node.instantiate_class(),)) 

718 

719 

720def _infer_object__new__decorator_check(node) -> bool: 

721 """Predicate before inference_tip. 

722 

723 Check if the given ClassDef has an @object.__new__ decorator 

724 """ 

725 if not node.decorators: 

726 return False 

727 

728 for decorator in node.decorators.nodes: 

729 if isinstance(decorator, nodes.Attribute): 

730 if decorator.as_string() == OBJECT_DUNDER_NEW: 

731 return True 

732 return False 

733 

734 

735def infer_issubclass(callnode, context: InferenceContext | None = None): 

736 """Infer issubclass() calls. 

737 

738 :param nodes.Call callnode: an `issubclass` call 

739 :param InferenceContext context: the context for the inference 

740 :rtype nodes.Const: Boolean Const value of the `issubclass` call 

741 :raises UseInferenceDefault: If the node cannot be inferred 

742 """ 

743 call = arguments.CallSite.from_call(callnode, context=context) 

744 if call.keyword_arguments: 

745 # issubclass doesn't support keyword arguments 

746 raise UseInferenceDefault("TypeError: issubclass() takes no keyword arguments") 

747 if len(call.positional_arguments) != 2: 

748 raise UseInferenceDefault( 

749 f"Expected two arguments, got {len(call.positional_arguments)}" 

750 ) 

751 # The left hand argument is the obj to be checked 

752 obj_node, class_or_tuple_node = call.positional_arguments 

753 

754 try: 

755 obj_type = next(obj_node.infer(context=context)) 

756 except (InferenceError, StopIteration) as exc: 

757 raise UseInferenceDefault from exc 

758 if not isinstance(obj_type, nodes.ClassDef): 

759 raise UseInferenceDefault( 

760 f"TypeError: arg 1 must be class, not {type(obj_type)!r}" 

761 ) 

762 

763 # The right hand argument is the class(es) that the given 

764 # object is to be checked against. 

765 try: 

766 class_container = helpers.class_or_tuple_to_container( 

767 class_or_tuple_node, context=context 

768 ) 

769 except InferenceError as exc: 

770 raise UseInferenceDefault from exc 

771 try: 

772 issubclass_bool = helpers.object_issubclass(obj_type, class_container, context) 

773 except AstroidTypeError as exc: 

774 raise UseInferenceDefault("TypeError: " + str(exc)) from exc 

775 except MroError as exc: 

776 raise UseInferenceDefault from exc 

777 return nodes.Const(issubclass_bool) 

778 

779 

780def infer_isinstance( 

781 callnode: nodes.Call, context: InferenceContext | None = None 

782) -> nodes.Const: 

783 """Infer isinstance calls. 

784 

785 :param nodes.Call callnode: an isinstance call 

786 :raises UseInferenceDefault: If the node cannot be inferred 

787 """ 

788 call = arguments.CallSite.from_call(callnode, context=context) 

789 if call.keyword_arguments: 

790 # isinstance doesn't support keyword arguments 

791 raise UseInferenceDefault("TypeError: isinstance() takes no keyword arguments") 

792 if len(call.positional_arguments) != 2: 

793 raise UseInferenceDefault( 

794 f"Expected two arguments, got {len(call.positional_arguments)}" 

795 ) 

796 # The left hand argument is the obj to be checked 

797 obj_node, class_or_tuple_node = call.positional_arguments 

798 # The right hand argument is the class(es) that the given 

799 # obj is to be check is an instance of 

800 try: 

801 class_container = helpers.class_or_tuple_to_container( 

802 class_or_tuple_node, context=context 

803 ) 

804 except InferenceError as exc: 

805 raise UseInferenceDefault from exc 

806 try: 

807 isinstance_bool = helpers.object_isinstance(obj_node, class_container, context) 

808 except AstroidTypeError as exc: 

809 raise UseInferenceDefault("TypeError: " + str(exc)) from exc 

810 except MroError as exc: 

811 raise UseInferenceDefault from exc 

812 if isinstance(isinstance_bool, util.UninferableBase): 

813 raise UseInferenceDefault 

814 return nodes.Const(isinstance_bool) 

815 

816 

817def infer_len(node, context: InferenceContext | None = None) -> nodes.Const: 

818 """Infer length calls. 

819 

820 :param nodes.Call node: len call to infer 

821 :param context.InferenceContext: node context 

822 :rtype nodes.Const: a Const node with the inferred length, if possible 

823 """ 

824 call = arguments.CallSite.from_call(node, context=context) 

825 if call.keyword_arguments: 

826 raise UseInferenceDefault("TypeError: len() must take no keyword arguments") 

827 if len(call.positional_arguments) != 1: 

828 raise UseInferenceDefault( 

829 "TypeError: len() must take exactly one argument " 

830 f"({len(call.positional_arguments)}) given" 

831 ) 

832 [argument_node] = call.positional_arguments 

833 

834 try: 

835 return nodes.Const(helpers.object_len(argument_node, context=context)) 

836 except (AstroidTypeError, InferenceError) as exc: 

837 raise UseInferenceDefault(str(exc)) from exc 

838 

839 

840def infer_str(node, context: InferenceContext | None = None) -> nodes.Const: 

841 """Infer str() calls. 

842 

843 :param nodes.Call node: str() call to infer 

844 :param context.InferenceContext: node context 

845 :rtype nodes.Const: 

846 a Const containing a stringified value of str() call if possible, else an empty string 

847 """ 

848 call = arguments.CallSite.from_call(node, context=context) 

849 if call.keyword_arguments: 

850 raise UseInferenceDefault("TypeError: str() must take no keyword arguments") 

851 

852 fallback = nodes.Const("") 

853 

854 if not call.positional_arguments: 

855 return fallback 

856 

857 # Accept only if all inferred values resolve to the same string 

858 candidates: set[str] = set() 

859 try: 

860 for inferred in call.positional_arguments[0].infer(context=context): 

861 if not isinstance(inferred, nodes.Const): 

862 return fallback 

863 

864 try: 

865 candidates.add(str(inferred.value)) 

866 except ValueError: 

867 return fallback 

868 except InferenceError: 

869 return fallback 

870 

871 if len(candidates) == 1: 

872 return nodes.Const(next(iter(candidates))) 

873 return fallback 

874 

875 

876def infer_int(node, context: InferenceContext | None = None): 

877 """Infer int() calls. 

878 

879 :param nodes.Call node: int() call to infer 

880 :param context.InferenceContext: node context 

881 :rtype nodes.Const: a Const containing the integer value of the int() call 

882 """ 

883 call = arguments.CallSite.from_call(node, context=context) 

884 if call.keyword_arguments: 

885 raise UseInferenceDefault("TypeError: int() must take no keyword arguments") 

886 

887 if call.positional_arguments: 

888 try: 

889 first_value = next(call.positional_arguments[0].infer(context=context)) 

890 except (InferenceError, StopIteration) as exc: 

891 raise UseInferenceDefault(str(exc)) from exc 

892 

893 if isinstance(first_value, util.UninferableBase): 

894 raise UseInferenceDefault 

895 

896 if isinstance(first_value, nodes.Const) and isinstance( 

897 first_value.value, (int, str) 

898 ): 

899 try: 

900 actual_value = int(first_value.value) 

901 except ValueError: 

902 return nodes.Const(0) 

903 return nodes.Const(actual_value) 

904 

905 return nodes.Const(0) 

906 

907 

908def infer_dict_fromkeys(node, context: InferenceContext | None = None): 

909 """Infer dict.fromkeys. 

910 

911 :param nodes.Call node: dict.fromkeys() call to infer 

912 :param context.InferenceContext context: node context 

913 :rtype nodes.Dict: 

914 a Dictionary containing the values that astroid was able to infer. 

915 In case the inference failed for any reason, an empty dictionary 

916 will be inferred instead. 

917 """ 

918 

919 def _build_dict_with_elements(elements: list) -> nodes.Dict: 

920 new_node = nodes.Dict( 

921 col_offset=node.col_offset, 

922 lineno=node.lineno, 

923 parent=node.parent, 

924 end_lineno=node.end_lineno, 

925 end_col_offset=node.end_col_offset, 

926 ) 

927 new_node.postinit(elements) 

928 return new_node 

929 

930 call = arguments.CallSite.from_call(node, context=context) 

931 if call.keyword_arguments: 

932 raise UseInferenceDefault("TypeError: int() must take no keyword arguments") 

933 if len(call.positional_arguments) not in {1, 2}: 

934 raise UseInferenceDefault( 

935 "TypeError: Needs between 1 and 2 positional arguments" 

936 ) 

937 

938 default = nodes.Const(None) 

939 values = call.positional_arguments[0] 

940 try: 

941 inferred_values = next(values.infer(context=context)) 

942 except (InferenceError, StopIteration): 

943 return _build_dict_with_elements([]) 

944 if inferred_values is util.Uninferable: 

945 return _build_dict_with_elements([]) 

946 

947 # Limit to a couple of potential values, as this can become pretty complicated 

948 accepted_iterable_elements = (nodes.Const,) 

949 if isinstance(inferred_values, (nodes.List, nodes.Set, nodes.Tuple)): 

950 elements = inferred_values.elts 

951 for element in elements: 

952 if not isinstance(element, accepted_iterable_elements): 

953 # Fallback to an empty dict 

954 return _build_dict_with_elements([]) 

955 

956 elements_with_value = [(element, default) for element in elements] 

957 return _build_dict_with_elements(elements_with_value) 

958 if isinstance(inferred_values, nodes.Const) and isinstance( 

959 inferred_values.value, (str, bytes) 

960 ): 

961 elements_with_value = [ 

962 (nodes.Const(element), default) for element in inferred_values.value 

963 ] 

964 return _build_dict_with_elements(elements_with_value) 

965 if isinstance(inferred_values, nodes.Dict): 

966 keys = inferred_values.itered() 

967 for key in keys: 

968 if not isinstance(key, accepted_iterable_elements): 

969 # Fallback to an empty dict 

970 return _build_dict_with_elements([]) 

971 

972 elements_with_value = [(element, default) for element in keys] 

973 return _build_dict_with_elements(elements_with_value) 

974 

975 # Fallback to an empty dictionary 

976 return _build_dict_with_elements([]) 

977 

978 

979def _infer_copy_method( 

980 node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any 

981) -> Iterator[CopyResult]: 

982 assert isinstance(node.func, nodes.Attribute) 

983 inferred_orig, inferred_copy = itertools.tee(node.func.expr.infer(context=context)) 

984 if all( 

985 isinstance( 

986 inferred_node, (nodes.Dict, nodes.List, nodes.Set, objects.FrozenSet) 

987 ) 

988 for inferred_node in inferred_orig 

989 ): 

990 return cast(Iterator[CopyResult], inferred_copy) 

991 

992 raise UseInferenceDefault 

993 

994 

995def _is_str_format_call(node: nodes.Call) -> bool: 

996 """Catch calls to str.format().""" 

997 if not (isinstance(node.func, nodes.Attribute) and node.func.attrname == "format"): 

998 return False 

999 

1000 if isinstance(node.func.expr, nodes.Name): 

1001 value = util.safe_infer(node.func.expr) 

1002 else: 

1003 value = node.func.expr 

1004 

1005 return isinstance(value, nodes.Const) and isinstance(value.value, str) 

1006 

1007 

1008def _infer_str_format_call( 

1009 node: nodes.Call, context: InferenceContext | None = None, **kwargs: Any 

1010) -> Iterator[ConstFactoryResult | util.UninferableBase]: 

1011 """Return a Const node based on the template and passed arguments.""" 

1012 call = arguments.CallSite.from_call(node, context=context) 

1013 assert isinstance(node.func, (nodes.Attribute, nodes.AssignAttr, nodes.DelAttr)) 

1014 

1015 value: nodes.Const 

1016 if isinstance(node.func.expr, nodes.Name): 

1017 if not ( 

1018 (inferred := util.safe_infer(node.func.expr)) 

1019 and isinstance(inferred, nodes.Const) 

1020 ): 

1021 return iter([util.Uninferable]) 

1022 value = inferred 

1023 elif isinstance(node.func.expr, nodes.Const): 

1024 value = node.func.expr 

1025 else: # pragma: no cover 

1026 return iter([util.Uninferable]) 

1027 

1028 format_template = value.value 

1029 

1030 # Get the positional arguments passed 

1031 inferred_positional: list[nodes.Const] = [] 

1032 for i in call.positional_arguments: 

1033 one_inferred = util.safe_infer(i, context) 

1034 if not isinstance(one_inferred, nodes.Const): 

1035 return iter([util.Uninferable]) 

1036 inferred_positional.append(one_inferred) 

1037 

1038 pos_values: list[str] = [i.value for i in inferred_positional] 

1039 

1040 # Get the keyword arguments passed 

1041 inferred_keyword: dict[str, nodes.Const] = {} 

1042 for k, v in call.keyword_arguments.items(): 

1043 one_inferred = util.safe_infer(v, context) 

1044 if not isinstance(one_inferred, nodes.Const): 

1045 return iter([util.Uninferable]) 

1046 inferred_keyword[k] = one_inferred 

1047 

1048 keyword_values: dict[str, str] = {k: v.value for k, v in inferred_keyword.items()} 

1049 

1050 try: 

1051 formatted_string = format_template.format(*pos_values, **keyword_values) 

1052 except (AttributeError, IndexError, KeyError, TypeError, ValueError): 

1053 # AttributeError: named field in format string was not found in the arguments 

1054 # IndexError: there are too few arguments to interpolate 

1055 # TypeError: Unsupported format string 

1056 # ValueError: Unknown format code 

1057 return iter([util.Uninferable]) 

1058 

1059 return iter([nodes.const_factory(formatted_string)]) 

1060 

1061 

1062def register(manager: AstroidManager) -> None: 

1063 # Builtins inference 

1064 register_builtin_transform(manager, infer_bool, "bool") 

1065 register_builtin_transform(manager, infer_super, "super") 

1066 register_builtin_transform(manager, infer_callable, "callable") 

1067 register_builtin_transform(manager, infer_property, "property") 

1068 register_builtin_transform(manager, infer_getattr, "getattr") 

1069 register_builtin_transform(manager, infer_hasattr, "hasattr") 

1070 register_builtin_transform(manager, infer_tuple, "tuple") 

1071 register_builtin_transform(manager, infer_set, "set") 

1072 register_builtin_transform(manager, infer_list, "list") 

1073 register_builtin_transform(manager, infer_dict, "dict") 

1074 register_builtin_transform(manager, infer_frozenset, "frozenset") 

1075 register_builtin_transform(manager, infer_type, "type") 

1076 register_builtin_transform(manager, infer_slice, "slice") 

1077 register_builtin_transform(manager, infer_isinstance, "isinstance") 

1078 register_builtin_transform(manager, infer_issubclass, "issubclass") 

1079 register_builtin_transform(manager, infer_len, "len") 

1080 register_builtin_transform(manager, infer_str, "str") 

1081 register_builtin_transform(manager, infer_int, "int") 

1082 register_builtin_transform(manager, infer_dict_fromkeys, "dict.fromkeys") 

1083 

1084 # Infer object.__new__ calls 

1085 manager.register_transform( 

1086 nodes.ClassDef, 

1087 inference_tip(_infer_object__new__decorator), 

1088 _infer_object__new__decorator_check, 

1089 ) 

1090 

1091 manager.register_transform( 

1092 nodes.Call, 

1093 inference_tip(_infer_copy_method), 

1094 lambda node: isinstance(node.func, nodes.Attribute) 

1095 and node.func.attrname == "copy", 

1096 ) 

1097 

1098 manager.register_transform( 

1099 nodes.Call, 

1100 inference_tip(_infer_str_format_call), 

1101 _is_str_format_call, 

1102 )