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

466 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:53 +0000

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 Any 

13 

14from astroid import arguments, bases, helpers, inference_tip, 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.manager import AstroidManager 

25from astroid.nodes import scoped_nodes 

26from astroid.typing import InferenceResult, SuccessfulInferenceResult 

27 

28OBJECT_DUNDER_NEW = "object.__new__" 

29 

30STR_CLASS = """ 

31class whatever(object): 

32 def join(self, iterable): 

33 return {rvalue} 

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

35 return {rvalue} 

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

37 return {rvalue} 

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

39 return b'' 

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

41 return u'' 

42 def capitalize(self): 

43 return {rvalue} 

44 def title(self): 

45 return {rvalue} 

46 def lower(self): 

47 return {rvalue} 

48 def upper(self): 

49 return {rvalue} 

50 def swapcase(self): 

51 return {rvalue} 

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

53 return 0 

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

55 return 0 

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

57 return 0 

58 def strip(self, chars=None): 

59 return {rvalue} 

60 def lstrip(self, chars=None): 

61 return {rvalue} 

62 def rstrip(self, chars=None): 

63 return {rvalue} 

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

65 return {rvalue} 

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

67 return {rvalue} 

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

69 return {rvalue} 

70""" 

71 

72 

73BYTES_CLASS = """ 

74class whatever(object): 

75 def join(self, iterable): 

76 return {rvalue} 

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

78 return {rvalue} 

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

80 return u'' 

81 def capitalize(self): 

82 return {rvalue} 

83 def title(self): 

84 return {rvalue} 

85 def lower(self): 

86 return {rvalue} 

87 def upper(self): 

88 return {rvalue} 

89 def swapcase(self): 

90 return {rvalue} 

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

92 return 0 

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

94 return 0 

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

96 return 0 

97 def strip(self, chars=None): 

98 return {rvalue} 

99 def lstrip(self, chars=None): 

100 return {rvalue} 

101 def rstrip(self, chars=None): 

102 return {rvalue} 

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

104 return {rvalue} 

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

106 return {rvalue} 

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

108 return {rvalue} 

109""" 

110 

111 

112def _extend_string_class(class_node, code, rvalue): 

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

114 code = code.format(rvalue=rvalue) 

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

116 for method in fake.mymethods(): 

117 method.parent = class_node 

118 method.lineno = None 

119 method.col_offset = None 

120 if "__class__" in method.locals: 

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

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

123 method.parent = class_node 

124 

125 

126def _extend_builtins(class_transforms): 

127 builtin_ast = AstroidManager().builtins_module 

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

129 transform(builtin_ast[class_name]) 

130 

131 

132_extend_builtins( 

133 { 

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

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

136 } 

137) 

138 

139 

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

141 if ( 

142 builtin_name == "type" 

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

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

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

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

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

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

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

150 ): 

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

152 # Match these patterns from stdlib/re.py 

153 # ```py 

154 # Pattern = type(...) 

155 # Match = type(...) 

156 # ``` 

157 return False 

158 if isinstance(node.func, nodes.Name) and node.func.name == builtin_name: 

159 return True 

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

161 return ( 

162 node.func.attrname == "fromkeys" 

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

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

165 ) 

166 return False 

167 

168 

169def register_builtin_transform(transform, builtin_name) -> None: 

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

171 

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

173 an optional context. 

174 """ 

175 

176 def _transform_wrapper(node, context: InferenceContext | None = None): 

177 result = transform(node, context=context) 

178 if result: 

179 if not result.parent: 

180 # Let the transformation function determine 

181 # the parent for its result. Otherwise, 

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

183 result.parent = node 

184 

185 if result.lineno is None: 

186 result.lineno = node.lineno 

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

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

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

190 result.col_offset = node.col_offset 

191 return iter([result]) 

192 

193 AstroidManager().register_transform( 

194 nodes.Call, 

195 inference_tip(_transform_wrapper), 

196 partial(_builtin_filter_predicate, builtin_name=builtin_name), 

197 ) 

198 

199 

200def _container_generic_inference( 

201 node: nodes.Call, 

202 context: InferenceContext | None, 

203 node_type: type[nodes.BaseContainer], 

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

205) -> nodes.BaseContainer: 

206 args = node.args 

207 if not args: 

208 return node_type( 

209 lineno=node.lineno, 

210 col_offset=node.col_offset, 

211 parent=node.parent, 

212 end_lineno=node.end_lineno, 

213 end_col_offset=node.end_col_offset, 

214 ) 

215 if len(node.args) > 1: 

216 raise UseInferenceDefault() 

217 

218 (arg,) = args 

219 transformed = transform(arg) 

220 if not transformed: 

221 try: 

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

223 except (InferenceError, StopIteration) as exc: 

224 raise UseInferenceDefault from exc 

225 if isinstance(inferred, util.UninferableBase): 

226 raise UseInferenceDefault 

227 transformed = transform(inferred) 

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

229 raise UseInferenceDefault 

230 return transformed 

231 

232 

233def _container_generic_transform( # pylint: disable=inconsistent-return-statements 

234 arg: SuccessfulInferenceResult, 

235 context: InferenceContext | None, 

236 klass: type[nodes.BaseContainer], 

237 iterables: tuple[type[nodes.NodeNG] | type[bases.Proxy], ...], 

238 build_elts: type[Iterable[Any]], 

239) -> nodes.BaseContainer | None: 

240 if isinstance(arg, klass): 

241 return arg 

242 if isinstance(arg, iterables): 

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

244 elts = [elt.value for elt in arg.elts] 

245 else: 

246 # TODO: Does not handle deduplication for sets. 

247 elts = [] 

248 for element in arg.elts: 

249 if not element: 

250 continue 

251 inferred = helpers.safe_infer(element, context=context) 

252 if inferred: 

253 evaluated_object = nodes.EvaluatedObject( 

254 original=element, value=inferred 

255 ) 

256 elts.append(evaluated_object) 

257 elif isinstance(arg, nodes.Dict): 

258 # Dicts need to have consts as strings already. 

259 if not all(isinstance(elt[0], nodes.Const) for elt in arg.items): 

260 raise UseInferenceDefault() 

261 elts = [item[0].value for item in arg.items] 

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

263 elts = arg.value 

264 else: 

265 return 

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

267 

268 

269def _infer_builtin_container( 

270 node: nodes.Call, 

271 context: InferenceContext | None, 

272 klass: type[nodes.BaseContainer], 

273 iterables: tuple[type[nodes.NodeNG] | type[bases.Proxy], ...], 

274 build_elts: type[Iterable[Any]], 

275) -> nodes.BaseContainer: 

276 transform_func = partial( 

277 _container_generic_transform, 

278 context=context, 

279 klass=klass, 

280 iterables=iterables, 

281 build_elts=build_elts, 

282 ) 

283 

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

285 

286 

287# pylint: disable=invalid-name 

288infer_tuple = partial( 

289 _infer_builtin_container, 

290 klass=nodes.Tuple, 

291 iterables=( 

292 nodes.List, 

293 nodes.Set, 

294 objects.FrozenSet, 

295 objects.DictItems, 

296 objects.DictKeys, 

297 objects.DictValues, 

298 ), 

299 build_elts=tuple, 

300) 

301 

302infer_list = partial( 

303 _infer_builtin_container, 

304 klass=nodes.List, 

305 iterables=( 

306 nodes.Tuple, 

307 nodes.Set, 

308 objects.FrozenSet, 

309 objects.DictItems, 

310 objects.DictKeys, 

311 objects.DictValues, 

312 ), 

313 build_elts=list, 

314) 

315 

316infer_set = partial( 

317 _infer_builtin_container, 

318 klass=nodes.Set, 

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

320 build_elts=set, 

321) 

322 

323infer_frozenset = partial( 

324 _infer_builtin_container, 

325 klass=objects.FrozenSet, 

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

327 build_elts=frozenset, 

328) 

329 

330 

331def _get_elts(arg, context): 

332 def is_iterable(n): 

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

334 

335 try: 

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

337 except (InferenceError, StopIteration) as exc: 

338 raise UseInferenceDefault from exc 

339 if isinstance(inferred, nodes.Dict): 

340 items = inferred.items 

341 elif is_iterable(inferred): 

342 items = [] 

343 for elt in inferred.elts: 

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

345 # then fallback to the default inference. 

346 # Also, take in consideration only hashable items, 

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

348 if not is_iterable(elt): 

349 raise UseInferenceDefault() 

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

351 raise UseInferenceDefault() 

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

353 raise UseInferenceDefault() 

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

355 else: 

356 raise UseInferenceDefault() 

357 return items 

358 

359 

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

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

362 

363 The function treats the following cases: 

364 

365 * dict() 

366 * dict(mapping) 

367 * dict(iterable) 

368 * dict(iterable, **kwargs) 

369 * dict(mapping, **kwargs) 

370 * dict(**kwargs) 

371 

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

373 """ 

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

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

376 raise UseInferenceDefault 

377 

378 args = call.positional_arguments 

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

380 

381 if not args and not kwargs: 

382 # dict() 

383 return nodes.Dict( 

384 lineno=node.lineno, 

385 col_offset=node.col_offset, 

386 parent=node.parent, 

387 end_lineno=node.end_lineno, 

388 end_col_offset=node.end_col_offset, 

389 ) 

390 if kwargs and not args: 

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

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

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

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

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

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

397 items = elts + keys 

398 elif len(args) == 1: 

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

400 else: 

401 raise UseInferenceDefault() 

402 value = nodes.Dict( 

403 col_offset=node.col_offset, 

404 lineno=node.lineno, 

405 parent=node.parent, 

406 end_lineno=node.end_lineno, 

407 end_col_offset=node.end_col_offset, 

408 ) 

409 value.postinit(items) 

410 return value 

411 

412 

413def infer_super( 

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

415) -> objects.Super: 

416 """Understand super calls. 

417 

418 There are some restrictions for what can be understood: 

419 

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

421 

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

423 then the default inference will be used. 

424 

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

426 will be used. 

427 """ 

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

429 # Ignore unbounded super. 

430 raise UseInferenceDefault 

431 

432 scope = node.scope() 

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

434 # Ignore non-method uses of super. 

435 raise UseInferenceDefault 

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

437 # Not interested in staticmethods. 

438 raise UseInferenceDefault 

439 

440 cls = scoped_nodes.get_wrapping_class(scope) 

441 assert cls is not None 

442 if not node.args: 

443 mro_pointer = cls 

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

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

446 if scope.type == "classmethod": 

447 mro_type = cls 

448 else: 

449 mro_type = cls.instantiate_class() 

450 else: 

451 try: 

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

453 except (InferenceError, StopIteration) as exc: 

454 raise UseInferenceDefault from exc 

455 try: 

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

457 except (InferenceError, StopIteration) as exc: 

458 raise UseInferenceDefault from exc 

459 

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

461 mro_type, util.UninferableBase 

462 ): 

463 # No way we could understand this. 

464 raise UseInferenceDefault 

465 

466 super_obj = objects.Super( 

467 mro_pointer=mro_pointer, 

468 mro_type=mro_type, 

469 self_class=cls, 

470 scope=scope, 

471 call=node, 

472 ) 

473 super_obj.parent = node 

474 return super_obj 

475 

476 

477def _infer_getattr_args(node, context): 

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

479 # Not a valid getattr call. 

480 raise UseInferenceDefault 

481 

482 try: 

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

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

485 except (InferenceError, StopIteration) as exc: 

486 raise UseInferenceDefault from exc 

487 

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

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

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

491 # which is unknown. 

492 return util.Uninferable, util.Uninferable 

493 

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

495 if not is_string: 

496 raise UseInferenceDefault 

497 

498 return obj, attr.value 

499 

500 

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

502 """Understand getattr calls. 

503 

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

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

506 lookup will be done. 

507 """ 

508 obj, attr = _infer_getattr_args(node, context) 

509 if ( 

510 isinstance(obj, util.UninferableBase) 

511 or isinstance(attr, util.UninferableBase) 

512 or not hasattr(obj, "igetattr") 

513 ): 

514 return util.Uninferable 

515 

516 try: 

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

518 except (StopIteration, InferenceError, AttributeInferenceError): 

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

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

521 try: 

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

523 except (StopIteration, InferenceError) as exc: 

524 raise UseInferenceDefault from exc 

525 

526 raise UseInferenceDefault 

527 

528 

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

530 """Understand hasattr calls. 

531 

532 This always guarantees three possible outcomes for calling 

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

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

535 we know that the object has the attribute and Uninferable 

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

537 """ 

538 try: 

539 obj, attr = _infer_getattr_args(node, context) 

540 if ( 

541 isinstance(obj, util.UninferableBase) 

542 or isinstance(attr, util.UninferableBase) 

543 or not hasattr(obj, "getattr") 

544 ): 

545 return util.Uninferable 

546 obj.getattr(attr, context=context) 

547 except UseInferenceDefault: 

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

549 return util.Uninferable 

550 except AttributeInferenceError: 

551 # Doesn't have it. 

552 return nodes.Const(False) 

553 return nodes.Const(True) 

554 

555 

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

557 """Understand callable calls. 

558 

559 This follows Python's semantics, where an object 

560 is callable if it provides an attribute __call__, 

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

562 called. 

563 """ 

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

565 # Invalid callable call. 

566 raise UseInferenceDefault 

567 

568 argument = node.args[0] 

569 try: 

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

571 except (InferenceError, StopIteration): 

572 return util.Uninferable 

573 if isinstance(inferred, util.UninferableBase): 

574 return util.Uninferable 

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

576 

577 

578def infer_property( 

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

580) -> objects.Property: 

581 """Understand `property` class. 

582 

583 This only infers the output of `property` 

584 call, not the arguments themselves. 

585 """ 

586 if len(node.args) < 1: 

587 # Invalid property call. 

588 raise UseInferenceDefault 

589 

590 getter = node.args[0] 

591 try: 

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

593 except (InferenceError, StopIteration) as exc: 

594 raise UseInferenceDefault from exc 

595 

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

597 raise UseInferenceDefault 

598 

599 prop_func = objects.Property( 

600 function=inferred, 

601 name=inferred.name, 

602 lineno=node.lineno, 

603 col_offset=node.col_offset, 

604 ) 

605 # Set parent outside __init__: https://github.com/pylint-dev/astroid/issues/1490 

606 prop_func.parent = node 

607 prop_func.postinit( 

608 body=[], 

609 args=inferred.args, 

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

611 ) 

612 return prop_func 

613 

614 

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

616 """Understand bool calls.""" 

617 if len(node.args) > 1: 

618 # Invalid bool call. 

619 raise UseInferenceDefault 

620 

621 if not node.args: 

622 return nodes.Const(False) 

623 

624 argument = node.args[0] 

625 try: 

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

627 except (InferenceError, StopIteration): 

628 return util.Uninferable 

629 if isinstance(inferred, util.UninferableBase): 

630 return util.Uninferable 

631 

632 bool_value = inferred.bool_value(context=context) 

633 if isinstance(bool_value, util.UninferableBase): 

634 return util.Uninferable 

635 return nodes.Const(bool_value) 

636 

637 

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

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

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

641 raise UseInferenceDefault 

642 

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

644 

645 

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

647 """Understand `slice` calls.""" 

648 args = node.args 

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

650 raise UseInferenceDefault 

651 

652 infer_func = partial(helpers.safe_infer, context=context) 

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

654 for arg in args: 

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

656 raise UseInferenceDefault 

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

658 raise UseInferenceDefault 

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

660 raise UseInferenceDefault 

661 

662 if len(args) < 3: 

663 # Make sure we have 3 arguments. 

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

665 

666 slice_node = nodes.Slice( 

667 lineno=node.lineno, 

668 col_offset=node.col_offset, 

669 parent=node.parent, 

670 end_lineno=node.end_lineno, 

671 end_col_offset=node.end_col_offset, 

672 ) 

673 slice_node.postinit(*args) 

674 return slice_node 

675 

676 

677def _infer_object__new__decorator(node, context: InferenceContext | None = None): 

678 # Instantiate class immediately 

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

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

681 

682 

683def _infer_object__new__decorator_check(node) -> bool: 

684 """Predicate before inference_tip. 

685 

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

687 """ 

688 if not node.decorators: 

689 return False 

690 

691 for decorator in node.decorators.nodes: 

692 if isinstance(decorator, nodes.Attribute): 

693 if decorator.as_string() == OBJECT_DUNDER_NEW: 

694 return True 

695 return False 

696 

697 

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

699 """Infer issubclass() calls. 

700 

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

702 :param InferenceContext context: the context for the inference 

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

704 :raises UseInferenceDefault: If the node cannot be inferred 

705 """ 

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

707 if call.keyword_arguments: 

708 # issubclass doesn't support keyword arguments 

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

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

711 raise UseInferenceDefault( 

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

713 ) 

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

715 obj_node, class_or_tuple_node = call.positional_arguments 

716 

717 try: 

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

719 except (InferenceError, StopIteration) as exc: 

720 raise UseInferenceDefault from exc 

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

722 raise UseInferenceDefault("TypeError: arg 1 must be class") 

723 

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

725 # object is to be checked against. 

726 try: 

727 class_container = _class_or_tuple_to_container( 

728 class_or_tuple_node, context=context 

729 ) 

730 except InferenceError as exc: 

731 raise UseInferenceDefault from exc 

732 try: 

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

734 except AstroidTypeError as exc: 

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

736 except MroError as exc: 

737 raise UseInferenceDefault from exc 

738 return nodes.Const(issubclass_bool) 

739 

740 

741def infer_isinstance( 

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

743) -> nodes.Const: 

744 """Infer isinstance calls. 

745 

746 :param nodes.Call callnode: an isinstance call 

747 :raises UseInferenceDefault: If the node cannot be inferred 

748 """ 

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

750 if call.keyword_arguments: 

751 # isinstance doesn't support keyword arguments 

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

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

754 raise UseInferenceDefault( 

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

756 ) 

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

758 obj_node, class_or_tuple_node = call.positional_arguments 

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

760 # obj is to be check is an instance of 

761 try: 

762 class_container = _class_or_tuple_to_container( 

763 class_or_tuple_node, context=context 

764 ) 

765 except InferenceError as exc: 

766 raise UseInferenceDefault from exc 

767 try: 

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

769 except AstroidTypeError as exc: 

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

771 except MroError as exc: 

772 raise UseInferenceDefault from exc 

773 if isinstance(isinstance_bool, util.UninferableBase): 

774 raise UseInferenceDefault 

775 return nodes.Const(isinstance_bool) 

776 

777 

778def _class_or_tuple_to_container( 

779 node: InferenceResult, context: InferenceContext | None = None 

780) -> list[InferenceResult]: 

781 # Move inferences results into container 

782 # to simplify later logic 

783 # raises InferenceError if any of the inferences fall through 

784 try: 

785 node_infer = next(node.infer(context=context)) 

786 except StopIteration as e: 

787 raise InferenceError(node=node, context=context) from e 

788 # arg2 MUST be a type or a TUPLE of types 

789 # for isinstance 

790 if isinstance(node_infer, nodes.Tuple): 

791 try: 

792 class_container = [ 

793 next(node.infer(context=context)) for node in node_infer.elts 

794 ] 

795 except StopIteration as e: 

796 raise InferenceError(node=node, context=context) from e 

797 else: 

798 class_container = [node_infer] 

799 return class_container 

800 

801 

802def infer_len(node, context: InferenceContext | None = None): 

803 """Infer length calls. 

804 

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

806 :param context.InferenceContext: node context 

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

808 """ 

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

810 if call.keyword_arguments: 

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

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

813 raise UseInferenceDefault( 

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

815 "({len}) given".format(len=len(call.positional_arguments)) 

816 ) 

817 [argument_node] = call.positional_arguments 

818 

819 try: 

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

821 except (AstroidTypeError, InferenceError) as exc: 

822 raise UseInferenceDefault(str(exc)) from exc 

823 

824 

825def infer_str(node, context: InferenceContext | None = None): 

826 """Infer str() calls. 

827 

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

829 :param context.InferenceContext: node context 

830 :rtype nodes.Const: a Const containing an empty string 

831 """ 

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

833 if call.keyword_arguments: 

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

835 try: 

836 return nodes.Const("") 

837 except (AstroidTypeError, InferenceError) as exc: 

838 raise UseInferenceDefault(str(exc)) from exc 

839 

840 

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

842 """Infer int() calls. 

843 

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

845 :param context.InferenceContext: node context 

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

847 """ 

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

849 if call.keyword_arguments: 

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

851 

852 if call.positional_arguments: 

853 try: 

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

855 except (InferenceError, StopIteration) as exc: 

856 raise UseInferenceDefault(str(exc)) from exc 

857 

858 if isinstance(first_value, util.UninferableBase): 

859 raise UseInferenceDefault 

860 

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

862 first_value.value, (int, str) 

863 ): 

864 try: 

865 actual_value = int(first_value.value) 

866 except ValueError: 

867 return nodes.Const(0) 

868 return nodes.Const(actual_value) 

869 

870 return nodes.Const(0) 

871 

872 

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

874 """Infer dict.fromkeys. 

875 

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

877 :param context.InferenceContext context: node context 

878 :rtype nodes.Dict: 

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

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

881 will be inferred instead. 

882 """ 

883 

884 def _build_dict_with_elements(elements): 

885 new_node = nodes.Dict( 

886 col_offset=node.col_offset, 

887 lineno=node.lineno, 

888 parent=node.parent, 

889 end_lineno=node.end_lineno, 

890 end_col_offset=node.end_col_offset, 

891 ) 

892 new_node.postinit(elements) 

893 return new_node 

894 

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

896 if call.keyword_arguments: 

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

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

899 raise UseInferenceDefault( 

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

901 ) 

902 

903 default = nodes.Const(None) 

904 values = call.positional_arguments[0] 

905 try: 

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

907 except (InferenceError, StopIteration): 

908 return _build_dict_with_elements([]) 

909 if inferred_values is util.Uninferable: 

910 return _build_dict_with_elements([]) 

911 

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

913 accepted_iterable_elements = (nodes.Const,) 

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

915 elements = inferred_values.elts 

916 for element in elements: 

917 if not isinstance(element, accepted_iterable_elements): 

918 # Fallback to an empty dict 

919 return _build_dict_with_elements([]) 

920 

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

922 return _build_dict_with_elements(elements_with_value) 

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

924 inferred_values.value, (str, bytes) 

925 ): 

926 elements = [ 

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

928 ] 

929 return _build_dict_with_elements(elements) 

930 if isinstance(inferred_values, nodes.Dict): 

931 keys = inferred_values.itered() 

932 for key in keys: 

933 if not isinstance(key, accepted_iterable_elements): 

934 # Fallback to an empty dict 

935 return _build_dict_with_elements([]) 

936 

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

938 return _build_dict_with_elements(elements_with_value) 

939 

940 # Fallback to an empty dictionary 

941 return _build_dict_with_elements([]) 

942 

943 

944def _infer_copy_method( 

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

946) -> Iterator[nodes.NodeNG]: 

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

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

949 if all( 

950 isinstance( 

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

952 ) 

953 for inferred_node in inferred_orig 

954 ): 

955 return inferred_copy 

956 

957 raise UseInferenceDefault() 

958 

959 

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

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

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

963 return False 

964 

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

966 value = helpers.safe_infer(node.func.expr) 

967 else: 

968 value = node.func.expr 

969 

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

971 

972 

973def _infer_str_format_call( 

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

975) -> Iterator[nodes.Const | util.UninferableBase]: 

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

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

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

979 value: nodes.Const | None = helpers.safe_infer(node.func.expr) 

980 if value is None: 

981 return iter([util.Uninferable]) 

982 else: 

983 value = node.func.expr 

984 

985 format_template = value.value 

986 

987 # Get the positional arguments passed 

988 inferred_positional = [ 

989 helpers.safe_infer(i, context) for i in call.positional_arguments 

990 ] 

991 if not all(isinstance(i, nodes.Const) for i in inferred_positional): 

992 return iter([util.Uninferable]) 

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

994 

995 # Get the keyword arguments passed 

996 inferred_keyword = { 

997 k: helpers.safe_infer(v, context) for k, v in call.keyword_arguments.items() 

998 } 

999 if not all(isinstance(i, nodes.Const) for i in inferred_keyword.values()): 

1000 return iter([util.Uninferable]) 

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

1002 

1003 try: 

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

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

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

1007 # IndexError: there are too few arguments to interpolate 

1008 # TypeError: Unsupported format string 

1009 # ValueError: Unknown format code 

1010 return iter([util.Uninferable]) 

1011 

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

1013 

1014 

1015# Builtins inference 

1016register_builtin_transform(infer_bool, "bool") 

1017register_builtin_transform(infer_super, "super") 

1018register_builtin_transform(infer_callable, "callable") 

1019register_builtin_transform(infer_property, "property") 

1020register_builtin_transform(infer_getattr, "getattr") 

1021register_builtin_transform(infer_hasattr, "hasattr") 

1022register_builtin_transform(infer_tuple, "tuple") 

1023register_builtin_transform(infer_set, "set") 

1024register_builtin_transform(infer_list, "list") 

1025register_builtin_transform(infer_dict, "dict") 

1026register_builtin_transform(infer_frozenset, "frozenset") 

1027register_builtin_transform(infer_type, "type") 

1028register_builtin_transform(infer_slice, "slice") 

1029register_builtin_transform(infer_isinstance, "isinstance") 

1030register_builtin_transform(infer_issubclass, "issubclass") 

1031register_builtin_transform(infer_len, "len") 

1032register_builtin_transform(infer_str, "str") 

1033register_builtin_transform(infer_int, "int") 

1034register_builtin_transform(infer_dict_fromkeys, "dict.fromkeys") 

1035 

1036 

1037# Infer object.__new__ calls 

1038AstroidManager().register_transform( 

1039 nodes.ClassDef, 

1040 inference_tip(_infer_object__new__decorator), 

1041 _infer_object__new__decorator_check, 

1042) 

1043 

1044AstroidManager().register_transform( 

1045 nodes.Call, 

1046 inference_tip(_infer_copy_method), 

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

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

1049) 

1050 

1051AstroidManager().register_transform( 

1052 nodes.Call, inference_tip(_infer_str_format_call), _is_str_format_call 

1053)