Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/astroid/nodes/node_ng.py: 56%

347 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 

5from __future__ import annotations 

6 

7import pprint 

8import sys 

9import warnings 

10from collections.abc import Generator, Iterator 

11from functools import cached_property 

12from functools import singledispatch as _singledispatch 

13from typing import ( 

14 TYPE_CHECKING, 

15 Any, 

16 ClassVar, 

17 Literal, 

18 Tuple, 

19 Type, 

20 TypeVar, 

21 Union, 

22 cast, 

23 overload, 

24) 

25 

26from astroid import util 

27from astroid.context import InferenceContext 

28from astroid.exceptions import ( 

29 AstroidError, 

30 InferenceError, 

31 ParentMissingError, 

32 StatementMissing, 

33 UseInferenceDefault, 

34) 

35from astroid.manager import AstroidManager 

36from astroid.nodes.as_string import AsStringVisitor 

37from astroid.nodes.const import OP_PRECEDENCE 

38from astroid.nodes.utils import Position 

39from astroid.typing import InferenceErrorInfo, InferenceResult, InferFn 

40 

41if sys.version_info >= (3, 11): 

42 from typing import Self 

43else: 

44 from typing_extensions import Self 

45 

46 

47if TYPE_CHECKING: 

48 from astroid import nodes 

49 

50 

51# Types for 'NodeNG.nodes_of_class()' 

52_NodesT = TypeVar("_NodesT", bound="NodeNG") 

53_NodesT2 = TypeVar("_NodesT2", bound="NodeNG") 

54_NodesT3 = TypeVar("_NodesT3", bound="NodeNG") 

55SkipKlassT = Union[None, Type["NodeNG"], Tuple[Type["NodeNG"], ...]] 

56 

57 

58class NodeNG: 

59 """A node of the new Abstract Syntax Tree (AST). 

60 

61 This is the base class for all Astroid node classes. 

62 """ 

63 

64 is_statement: ClassVar[bool] = False 

65 """Whether this node indicates a statement.""" 

66 optional_assign: ClassVar[ 

67 bool 

68 ] = False # True for For (and for Comprehension if py <3.0) 

69 """Whether this node optionally assigns a variable. 

70 

71 This is for loop assignments because loop won't necessarily perform an 

72 assignment if the loop has no iterations. 

73 This is also the case from comprehensions in Python 2. 

74 """ 

75 is_function: ClassVar[bool] = False # True for FunctionDef nodes 

76 """Whether this node indicates a function.""" 

77 is_lambda: ClassVar[bool] = False 

78 

79 # Attributes below are set by the builder module or by raw factories 

80 _astroid_fields: ClassVar[tuple[str, ...]] = () 

81 """Node attributes that contain child nodes. 

82 

83 This is redefined in most concrete classes. 

84 """ 

85 _other_fields: ClassVar[tuple[str, ...]] = () 

86 """Node attributes that do not contain child nodes.""" 

87 _other_other_fields: ClassVar[tuple[str, ...]] = () 

88 """Attributes that contain AST-dependent fields.""" 

89 # instance specific inference function infer(node, context) 

90 _explicit_inference: InferFn[Self] | None = None 

91 

92 def __init__( 

93 self, 

94 lineno: int | None, 

95 col_offset: int | None, 

96 parent: NodeNG | None, 

97 *, 

98 end_lineno: int | None, 

99 end_col_offset: int | None, 

100 ) -> None: 

101 self.lineno = lineno 

102 """The line that this node appears on in the source code.""" 

103 

104 self.col_offset = col_offset 

105 """The column that this node appears on in the source code.""" 

106 

107 self.parent = parent 

108 """The parent node in the syntax tree.""" 

109 

110 self.end_lineno = end_lineno 

111 """The last line this node appears on in the source code.""" 

112 

113 self.end_col_offset = end_col_offset 

114 """The end column this node appears on in the source code. 

115 

116 Note: This is after the last symbol. 

117 """ 

118 

119 self.position: Position | None = None 

120 """Position of keyword(s) and name. 

121 

122 Used as fallback for block nodes which might not provide good 

123 enough positional information. E.g. ClassDef, FunctionDef. 

124 """ 

125 

126 def infer( 

127 self, context: InferenceContext | None = None, **kwargs: Any 

128 ) -> Generator[InferenceResult, None, None]: 

129 """Get a generator of the inferred values. 

130 

131 This is the main entry point to the inference system. 

132 

133 .. seealso:: :ref:`inference` 

134 

135 If the instance has some explicit inference function set, it will be 

136 called instead of the default interface. 

137 

138 :returns: The inferred values. 

139 :rtype: iterable 

140 """ 

141 if context is not None: 

142 context = context.extra_context.get(self, context) 

143 if self._explicit_inference is not None: 

144 # explicit_inference is not bound, give it self explicitly 

145 try: 

146 if context is None: 

147 yield from self._explicit_inference( 

148 self, # type: ignore[arg-type] 

149 context, 

150 **kwargs, 

151 ) 

152 return 

153 for result in self._explicit_inference( 

154 self, # type: ignore[arg-type] 

155 context, 

156 **kwargs, 

157 ): 

158 context.nodes_inferred += 1 

159 yield result 

160 return 

161 except UseInferenceDefault: 

162 pass 

163 

164 if not context: 

165 # nodes_inferred? 

166 yield from self._infer(context=context, **kwargs) 

167 return 

168 

169 key = (self, context.lookupname, context.callcontext, context.boundnode) 

170 if key in context.inferred: 

171 yield from context.inferred[key] 

172 return 

173 

174 results = [] 

175 

176 # Limit inference amount to help with performance issues with 

177 # exponentially exploding possible results. 

178 limit = AstroidManager.max_inferable_values 

179 for i, result in enumerate(self._infer(context=context, **kwargs)): 

180 if i >= limit or (context.nodes_inferred > context.max_inferred): 

181 results.append(util.Uninferable) 

182 yield util.Uninferable 

183 break 

184 results.append(result) 

185 yield result 

186 context.nodes_inferred += 1 

187 

188 # Cache generated results for subsequent inferences of the 

189 # same node using the same context 

190 context.inferred[key] = tuple(results) 

191 return 

192 

193 def repr_name(self) -> str: 

194 """Get a name for nice representation. 

195 

196 This is either :attr:`name`, :attr:`attrname`, or the empty string. 

197 """ 

198 if all(name not in self._astroid_fields for name in ("name", "attrname")): 

199 return getattr(self, "name", "") or getattr(self, "attrname", "") 

200 return "" 

201 

202 def __str__(self) -> str: 

203 rname = self.repr_name() 

204 cname = type(self).__name__ 

205 if rname: 

206 string = "%(cname)s.%(rname)s(%(fields)s)" 

207 alignment = len(cname) + len(rname) + 2 

208 else: 

209 string = "%(cname)s(%(fields)s)" 

210 alignment = len(cname) + 1 

211 result = [] 

212 for field in self._other_fields + self._astroid_fields: 

213 value = getattr(self, field) 

214 width = 80 - len(field) - alignment 

215 lines = pprint.pformat(value, indent=2, width=width).splitlines(True) 

216 

217 inner = [lines[0]] 

218 for line in lines[1:]: 

219 inner.append(" " * alignment + line) 

220 result.append(f"{field}={''.join(inner)}") 

221 

222 return string % { 

223 "cname": cname, 

224 "rname": rname, 

225 "fields": (",\n" + " " * alignment).join(result), 

226 } 

227 

228 def __repr__(self) -> str: 

229 rname = self.repr_name() 

230 if rname: 

231 string = "<%(cname)s.%(rname)s l.%(lineno)s at 0x%(id)x>" 

232 else: 

233 string = "<%(cname)s l.%(lineno)s at 0x%(id)x>" 

234 return string % { 

235 "cname": type(self).__name__, 

236 "rname": rname, 

237 "lineno": self.fromlineno, 

238 "id": id(self), 

239 } 

240 

241 def accept(self, visitor): 

242 """Visit this node using the given visitor.""" 

243 func = getattr(visitor, "visit_" + self.__class__.__name__.lower()) 

244 return func(self) 

245 

246 def get_children(self) -> Iterator[NodeNG]: 

247 """Get the child nodes below this node.""" 

248 for field in self._astroid_fields: 

249 attr = getattr(self, field) 

250 if attr is None: 

251 continue 

252 if isinstance(attr, (list, tuple)): 

253 yield from attr 

254 else: 

255 yield attr 

256 yield from () 

257 

258 def last_child(self) -> NodeNG | None: 

259 """An optimized version of list(get_children())[-1].""" 

260 for field in self._astroid_fields[::-1]: 

261 attr = getattr(self, field) 

262 if not attr: # None or empty list / tuple 

263 continue 

264 if isinstance(attr, (list, tuple)): 

265 return attr[-1] 

266 return attr 

267 return None 

268 

269 def node_ancestors(self) -> Iterator[NodeNG]: 

270 """Yield parent, grandparent, etc until there are no more.""" 

271 parent = self.parent 

272 while parent is not None: 

273 yield parent 

274 parent = parent.parent 

275 

276 def parent_of(self, node) -> bool: 

277 """Check if this node is the parent of the given node. 

278 

279 :param node: The node to check if it is the child. 

280 :type node: NodeNG 

281 

282 :returns: Whether this node is the parent of the given node. 

283 """ 

284 return any(self is parent for parent in node.node_ancestors()) 

285 

286 @overload 

287 def statement(self, *, future: None = ...) -> nodes.Statement | nodes.Module: 

288 ... 

289 

290 @overload 

291 def statement(self, *, future: Literal[True]) -> nodes.Statement: 

292 ... 

293 

294 def statement( 

295 self, *, future: Literal[None, True] = None 

296 ) -> nodes.Statement | nodes.Module: 

297 """The first parent node, including self, marked as statement node. 

298 

299 TODO: Deprecate the future parameter and only raise StatementMissing and return 

300 nodes.Statement 

301 

302 :raises AttributeError: If self has no parent attribute 

303 :raises StatementMissing: If self has no parent attribute and future is True 

304 """ 

305 if self.is_statement: 

306 return cast("nodes.Statement", self) 

307 if not self.parent: 

308 if future: 

309 raise StatementMissing(target=self) 

310 warnings.warn( 

311 "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement " 

312 "or raise a StatementMissing exception. AttributeError will no longer be raised. " 

313 "This behaviour can already be triggered " 

314 "by passing 'future=True' to a statement() call.", 

315 DeprecationWarning, 

316 stacklevel=2, 

317 ) 

318 raise AttributeError(f"{self} object has no attribute 'parent'") 

319 return self.parent.statement(future=future) 

320 

321 def frame( 

322 self, *, future: Literal[None, True] = None 

323 ) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda: 

324 """The first parent frame node. 

325 

326 A frame node is a :class:`Module`, :class:`FunctionDef`, 

327 :class:`ClassDef` or :class:`Lambda`. 

328 

329 :returns: The first parent frame node. 

330 """ 

331 if self.parent is None: 

332 if future: 

333 raise ParentMissingError(target=self) 

334 warnings.warn( 

335 "In astroid 3.0.0 NodeNG.frame() will return either a Frame node, " 

336 "or raise ParentMissingError. AttributeError will no longer be raised. " 

337 "This behaviour can already be triggered " 

338 "by passing 'future=True' to a frame() call.", 

339 DeprecationWarning, 

340 stacklevel=2, 

341 ) 

342 raise AttributeError(f"{self} object has no attribute 'parent'") 

343 

344 return self.parent.frame(future=future) 

345 

346 def scope(self) -> nodes.LocalsDictNodeNG: 

347 """The first parent node defining a new scope. 

348 

349 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 

350 

351 :returns: The first parent scope node. 

352 """ 

353 if not self.parent: 

354 raise ParentMissingError(target=self) 

355 return self.parent.scope() 

356 

357 def root(self) -> nodes.Module: 

358 """Return the root node of the syntax tree. 

359 

360 :returns: The root node. 

361 """ 

362 if self.parent: 

363 return self.parent.root() 

364 return self # type: ignore[return-value] # Only 'Module' does not have a parent node. 

365 

366 def child_sequence(self, child): 

367 """Search for the sequence that contains this child. 

368 

369 :param child: The child node to search sequences for. 

370 :type child: NodeNG 

371 

372 :returns: The sequence containing the given child node. 

373 :rtype: iterable(NodeNG) 

374 

375 :raises AstroidError: If no sequence could be found that contains 

376 the given child. 

377 """ 

378 for field in self._astroid_fields: 

379 node_or_sequence = getattr(self, field) 

380 if node_or_sequence is child: 

381 return [node_or_sequence] 

382 # /!\ compiler.ast Nodes have an __iter__ walking over child nodes 

383 if ( 

384 isinstance(node_or_sequence, (tuple, list)) 

385 and child in node_or_sequence 

386 ): 

387 return node_or_sequence 

388 

389 msg = "Could not find %s in %s's children" 

390 raise AstroidError(msg % (repr(child), repr(self))) 

391 

392 def locate_child(self, child): 

393 """Find the field of this node that contains the given child. 

394 

395 :param child: The child node to search fields for. 

396 :type child: NodeNG 

397 

398 :returns: A tuple of the name of the field that contains the child, 

399 and the sequence or node that contains the child node. 

400 :rtype: tuple(str, iterable(NodeNG) or NodeNG) 

401 

402 :raises AstroidError: If no field could be found that contains 

403 the given child. 

404 """ 

405 for field in self._astroid_fields: 

406 node_or_sequence = getattr(self, field) 

407 # /!\ compiler.ast Nodes have an __iter__ walking over child nodes 

408 if child is node_or_sequence: 

409 return field, child 

410 if ( 

411 isinstance(node_or_sequence, (tuple, list)) 

412 and child in node_or_sequence 

413 ): 

414 return field, node_or_sequence 

415 msg = "Could not find %s in %s's children" 

416 raise AstroidError(msg % (repr(child), repr(self))) 

417 

418 # FIXME : should we merge child_sequence and locate_child ? locate_child 

419 # is only used in are_exclusive, child_sequence one time in pylint. 

420 

421 def next_sibling(self): 

422 """The next sibling statement node. 

423 

424 :returns: The next sibling statement node. 

425 :rtype: NodeNG or None 

426 """ 

427 return self.parent.next_sibling() 

428 

429 def previous_sibling(self): 

430 """The previous sibling statement. 

431 

432 :returns: The previous sibling statement node. 

433 :rtype: NodeNG or None 

434 """ 

435 return self.parent.previous_sibling() 

436 

437 # these are lazy because they're relatively expensive to compute for every 

438 # single node, and they rarely get looked at 

439 

440 @cached_property 

441 def fromlineno(self) -> int: 

442 """The first line that this node appears on in the source code. 

443 

444 Can also return 0 if the line can not be determined. 

445 """ 

446 if self.lineno is None: 

447 return self._fixed_source_line() 

448 return self.lineno 

449 

450 @cached_property 

451 def tolineno(self) -> int: 

452 """The last line that this node appears on in the source code. 

453 

454 Can also return 0 if the line can not be determined. 

455 """ 

456 if self.end_lineno is not None: 

457 return self.end_lineno 

458 if not self._astroid_fields: 

459 # can't have children 

460 last_child = None 

461 else: 

462 last_child = self.last_child() 

463 if last_child is None: 

464 return self.fromlineno 

465 return last_child.tolineno 

466 

467 def _fixed_source_line(self) -> int: 

468 """Attempt to find the line that this node appears on. 

469 

470 We need this method since not all nodes have :attr:`lineno` set. 

471 Will return 0 if the line number can not be determined. 

472 """ 

473 line = self.lineno 

474 _node = self 

475 try: 

476 while line is None: 

477 _node = next(_node.get_children()) 

478 line = _node.lineno 

479 except StopIteration: 

480 parent = self.parent 

481 while parent and line is None: 

482 line = parent.lineno 

483 parent = parent.parent 

484 return line or 0 

485 

486 def block_range(self, lineno: int) -> tuple[int, int]: 

487 """Get a range from the given line number to where this node ends. 

488 

489 :param lineno: The line number to start the range at. 

490 

491 :returns: The range of line numbers that this node belongs to, 

492 starting at the given line number. 

493 """ 

494 return lineno, self.tolineno 

495 

496 def set_local(self, name: str, stmt: NodeNG) -> None: 

497 """Define that the given name is declared in the given statement node. 

498 

499 This definition is stored on the parent scope node. 

500 

501 .. seealso:: :meth:`scope` 

502 

503 :param name: The name that is being defined. 

504 

505 :param stmt: The statement that defines the given name. 

506 """ 

507 assert self.parent 

508 self.parent.set_local(name, stmt) 

509 

510 @overload 

511 def nodes_of_class( 

512 self, 

513 klass: type[_NodesT], 

514 skip_klass: SkipKlassT = ..., 

515 ) -> Iterator[_NodesT]: 

516 ... 

517 

518 @overload 

519 def nodes_of_class( 

520 self, 

521 klass: tuple[type[_NodesT], type[_NodesT2]], 

522 skip_klass: SkipKlassT = ..., 

523 ) -> Iterator[_NodesT] | Iterator[_NodesT2]: 

524 ... 

525 

526 @overload 

527 def nodes_of_class( 

528 self, 

529 klass: tuple[type[_NodesT], type[_NodesT2], type[_NodesT3]], 

530 skip_klass: SkipKlassT = ..., 

531 ) -> Iterator[_NodesT] | Iterator[_NodesT2] | Iterator[_NodesT3]: 

532 ... 

533 

534 @overload 

535 def nodes_of_class( 

536 self, 

537 klass: tuple[type[_NodesT], ...], 

538 skip_klass: SkipKlassT = ..., 

539 ) -> Iterator[_NodesT]: 

540 ... 

541 

542 def nodes_of_class( # type: ignore[misc] # mypy doesn't correctly recognize the overloads 

543 self, 

544 klass: ( 

545 type[_NodesT] 

546 | tuple[type[_NodesT], type[_NodesT2]] 

547 | tuple[type[_NodesT], type[_NodesT2], type[_NodesT3]] 

548 | tuple[type[_NodesT], ...] 

549 ), 

550 skip_klass: SkipKlassT = None, 

551 ) -> Iterator[_NodesT] | Iterator[_NodesT2] | Iterator[_NodesT3]: 

552 """Get the nodes (including this one or below) of the given types. 

553 

554 :param klass: The types of node to search for. 

555 

556 :param skip_klass: The types of node to ignore. This is useful to ignore 

557 subclasses of :attr:`klass`. 

558 

559 :returns: The node of the given types. 

560 """ 

561 if isinstance(self, klass): 

562 yield self 

563 

564 if skip_klass is None: 

565 for child_node in self.get_children(): 

566 yield from child_node.nodes_of_class(klass, skip_klass) 

567 

568 return 

569 

570 for child_node in self.get_children(): 

571 if isinstance(child_node, skip_klass): 

572 continue 

573 yield from child_node.nodes_of_class(klass, skip_klass) 

574 

575 @cached_property 

576 def _assign_nodes_in_scope(self) -> list[nodes.Assign]: 

577 return [] 

578 

579 def _get_name_nodes(self): 

580 for child_node in self.get_children(): 

581 yield from child_node._get_name_nodes() 

582 

583 def _get_return_nodes_skip_functions(self): 

584 yield from () 

585 

586 def _get_yield_nodes_skip_lambdas(self): 

587 yield from () 

588 

589 def _infer_name(self, frame, name): 

590 # overridden for ImportFrom, Import, Global, TryExcept, TryStar and Arguments 

591 pass 

592 

593 def _infer( 

594 self, context: InferenceContext | None = None, **kwargs: Any 

595 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

596 """We don't know how to resolve a statement by default.""" 

597 # this method is overridden by most concrete classes 

598 raise InferenceError( 

599 "No inference function for {node!r}.", node=self, context=context 

600 ) 

601 

602 def inferred(self): 

603 """Get a list of the inferred values. 

604 

605 .. seealso:: :ref:`inference` 

606 

607 :returns: The inferred values. 

608 :rtype: list 

609 """ 

610 return list(self.infer()) 

611 

612 def instantiate_class(self): 

613 """Instantiate an instance of the defined class. 

614 

615 .. note:: 

616 

617 On anything other than a :class:`ClassDef` this will return self. 

618 

619 :returns: An instance of the defined class. 

620 :rtype: object 

621 """ 

622 return self 

623 

624 def has_base(self, node) -> bool: 

625 """Check if this node inherits from the given type. 

626 

627 :param node: The node defining the base to look for. 

628 Usually this is a :class:`Name` node. 

629 :type node: NodeNG 

630 """ 

631 return False 

632 

633 def callable(self) -> bool: 

634 """Whether this node defines something that is callable. 

635 

636 :returns: Whether this defines something that is callable. 

637 """ 

638 return False 

639 

640 def eq(self, value) -> bool: 

641 return False 

642 

643 def as_string(self) -> str: 

644 """Get the source code that this node represents.""" 

645 return AsStringVisitor()(self) 

646 

647 def repr_tree( 

648 self, 

649 ids=False, 

650 include_linenos=False, 

651 ast_state=False, 

652 indent=" ", 

653 max_depth=0, 

654 max_width=80, 

655 ) -> str: 

656 """Get a string representation of the AST from this node. 

657 

658 :param ids: If true, includes the ids with the node type names. 

659 :type ids: bool 

660 

661 :param include_linenos: If true, includes the line numbers and 

662 column offsets. 

663 :type include_linenos: bool 

664 

665 :param ast_state: If true, includes information derived from 

666 the whole AST like local and global variables. 

667 :type ast_state: bool 

668 

669 :param indent: A string to use to indent the output string. 

670 :type indent: str 

671 

672 :param max_depth: If set to a positive integer, won't return 

673 nodes deeper than max_depth in the string. 

674 :type max_depth: int 

675 

676 :param max_width: Attempt to format the output string to stay 

677 within this number of characters, but can exceed it under some 

678 circumstances. Only positive integer values are valid, the default is 80. 

679 :type max_width: int 

680 

681 :returns: The string representation of the AST. 

682 :rtype: str 

683 """ 

684 

685 @_singledispatch 

686 def _repr_tree(node, result, done, cur_indent="", depth=1): 

687 """Outputs a representation of a non-tuple/list, non-node that's 

688 contained within an AST, including strings. 

689 """ 

690 lines = pprint.pformat( 

691 node, width=max(max_width - len(cur_indent), 1) 

692 ).splitlines(True) 

693 result.append(lines[0]) 

694 result.extend([cur_indent + line for line in lines[1:]]) 

695 return len(lines) != 1 

696 

697 # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch 

698 @_repr_tree.register(tuple) 

699 @_repr_tree.register(list) 

700 def _repr_seq(node, result, done, cur_indent="", depth=1): 

701 """Outputs a representation of a sequence that's contained within an 

702 AST. 

703 """ 

704 cur_indent += indent 

705 result.append("[") 

706 if not node: 

707 broken = False 

708 elif len(node) == 1: 

709 broken = _repr_tree(node[0], result, done, cur_indent, depth) 

710 elif len(node) == 2: 

711 broken = _repr_tree(node[0], result, done, cur_indent, depth) 

712 if not broken: 

713 result.append(", ") 

714 else: 

715 result.append(",\n") 

716 result.append(cur_indent) 

717 broken = _repr_tree(node[1], result, done, cur_indent, depth) or broken 

718 else: 

719 result.append("\n") 

720 result.append(cur_indent) 

721 for child in node[:-1]: 

722 _repr_tree(child, result, done, cur_indent, depth) 

723 result.append(",\n") 

724 result.append(cur_indent) 

725 _repr_tree(node[-1], result, done, cur_indent, depth) 

726 broken = True 

727 result.append("]") 

728 return broken 

729 

730 # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch 

731 @_repr_tree.register(NodeNG) 

732 def _repr_node(node, result, done, cur_indent="", depth=1): 

733 """Outputs a strings representation of an astroid node.""" 

734 if node in done: 

735 result.append( 

736 indent + f"<Recursion on {type(node).__name__} with id={id(node)}" 

737 ) 

738 return False 

739 done.add(node) 

740 

741 if max_depth and depth > max_depth: 

742 result.append("...") 

743 return False 

744 depth += 1 

745 cur_indent += indent 

746 if ids: 

747 result.append(f"{type(node).__name__}<0x{id(node):x}>(\n") 

748 else: 

749 result.append(f"{type(node).__name__}(") 

750 fields = [] 

751 if include_linenos: 

752 fields.extend(("lineno", "col_offset")) 

753 fields.extend(node._other_fields) 

754 fields.extend(node._astroid_fields) 

755 if ast_state: 

756 fields.extend(node._other_other_fields) 

757 if not fields: 

758 broken = False 

759 elif len(fields) == 1: 

760 result.append(f"{fields[0]}=") 

761 broken = _repr_tree( 

762 getattr(node, fields[0]), result, done, cur_indent, depth 

763 ) 

764 else: 

765 result.append("\n") 

766 result.append(cur_indent) 

767 for field in fields[:-1]: 

768 # TODO: Remove this after removal of the 'doc' attribute 

769 if field == "doc": 

770 continue 

771 result.append(f"{field}=") 

772 _repr_tree(getattr(node, field), result, done, cur_indent, depth) 

773 result.append(",\n") 

774 result.append(cur_indent) 

775 result.append(f"{fields[-1]}=") 

776 _repr_tree(getattr(node, fields[-1]), result, done, cur_indent, depth) 

777 broken = True 

778 result.append(")") 

779 return broken 

780 

781 result: list[str] = [] 

782 _repr_tree(self, result, set()) 

783 return "".join(result) 

784 

785 def bool_value(self, context: InferenceContext | None = None): 

786 """Determine the boolean value of this node. 

787 

788 The boolean value of a node can have three 

789 possible values: 

790 

791 * False: For instance, empty data structures, 

792 False, empty strings, instances which return 

793 explicitly False from the __nonzero__ / __bool__ 

794 method. 

795 * True: Most of constructs are True by default: 

796 classes, functions, modules etc 

797 * Uninferable: The inference engine is uncertain of the 

798 node's value. 

799 

800 :returns: The boolean value of this node. 

801 :rtype: bool or Uninferable 

802 """ 

803 return util.Uninferable 

804 

805 def op_precedence(self): 

806 # Look up by class name or default to highest precedence 

807 return OP_PRECEDENCE.get(self.__class__.__name__, len(OP_PRECEDENCE)) 

808 

809 def op_left_associative(self) -> bool: 

810 # Everything is left associative except `**` and IfExp 

811 return True