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

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

347 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 

5from __future__ import annotations 

6 

7import pprint 

8import sys 

9from collections.abc import Generator, Iterator 

10from functools import cached_property 

11from functools import singledispatch as _singledispatch 

12from typing import ( 

13 TYPE_CHECKING, 

14 Any, 

15 ClassVar, 

16 TypeVar, 

17 cast, 

18 overload, 

19) 

20 

21from astroid import nodes, util 

22from astroid.context import InferenceContext 

23from astroid.exceptions import ( 

24 AstroidError, 

25 InferenceError, 

26 ParentMissingError, 

27 StatementMissing, 

28 UseInferenceDefault, 

29) 

30from astroid.manager import AstroidManager 

31from astroid.nodes.as_string import AsStringVisitor 

32from astroid.nodes.const import OP_PRECEDENCE 

33from astroid.nodes.utils import Position 

34from astroid.typing import InferenceErrorInfo, InferenceResult, InferFn 

35 

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

37 from typing import Self 

38else: 

39 from typing_extensions import Self 

40 

41 

42if TYPE_CHECKING: 

43 from astroid.nodes import _base_nodes 

44 

45 

46# Types for 'NodeNG.nodes_of_class()' 

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

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

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

50SkipKlassT = None | type["NodeNG"] | tuple[type["NodeNG"], ...] 

51 

52 

53class NodeNG: 

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

55 

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

57 """ 

58 

59 is_statement: ClassVar[bool] = False 

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

61 optional_assign: ClassVar[bool] = ( 

62 False # True for For (and for Comprehension if py <3.0) 

63 ) 

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

65 

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

67 assignment if the loop has no iterations. 

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

69 """ 

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

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

72 is_lambda: ClassVar[bool] = False 

73 

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

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

76 """Node attributes that contain child nodes. 

77 

78 This is redefined in most concrete classes. 

79 """ 

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

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

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

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

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

85 _explicit_inference: InferFn[Self] | None = None 

86 

87 def __init__( 

88 self, 

89 lineno: int | None, 

90 col_offset: int | None, 

91 parent: NodeNG | None, 

92 *, 

93 end_lineno: int | None, 

94 end_col_offset: int | None, 

95 ) -> None: 

96 self.lineno = lineno 

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

98 

99 self.col_offset = col_offset 

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

101 

102 self.parent = parent 

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

104 

105 self.end_lineno = end_lineno 

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

107 

108 self.end_col_offset = end_col_offset 

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

110 

111 Note: This is after the last symbol. 

112 """ 

113 

114 self.position: Position | None = None 

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

116 

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

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

119 """ 

120 

121 def infer( 

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

123 ) -> Generator[InferenceResult]: 

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

125 

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

127 

128 .. seealso:: :ref:`inference` 

129 

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

131 called instead of the default interface. 

132 

133 :returns: The inferred values. 

134 :rtype: iterable 

135 """ 

136 if context is None: 

137 context = InferenceContext() 

138 else: 

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

140 if self._explicit_inference is not None: 

141 # explicit_inference is not bound, give it self explicitly 

142 try: 

143 for result in self._explicit_inference( 

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

145 context, 

146 **kwargs, 

147 ): 

148 context.nodes_inferred += 1 

149 yield result 

150 return 

151 except UseInferenceDefault: 

152 pass 

153 

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

155 if key in context.inferred: 

156 yield from context.inferred[key] 

157 return 

158 

159 results = [] 

160 

161 # Limit inference amount to help with performance issues with 

162 # exponentially exploding possible results. 

163 limit = AstroidManager().max_inferable_values 

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

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

166 results.append(util.Uninferable) 

167 yield util.Uninferable 

168 break 

169 results.append(result) 

170 yield result 

171 context.nodes_inferred += 1 

172 

173 # Cache generated results for subsequent inferences of the 

174 # same node using the same context 

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

176 return 

177 

178 def repr_name(self) -> str: 

179 """Get a name for nice representation. 

180 

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

182 """ 

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

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

185 return "" 

186 

187 def __str__(self) -> str: 

188 rname = self.repr_name() 

189 cname = type(self).__name__ 

190 if rname: 

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

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

193 else: 

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

195 alignment = len(cname) + 1 

196 result = [] 

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

198 value = getattr(self, field, "Unknown") 

199 width = 80 - len(field) - alignment 

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

201 

202 inner = [lines[0]] 

203 for line in lines[1:]: 

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

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

206 

207 return string % { 

208 "cname": cname, 

209 "rname": rname, 

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

211 } 

212 

213 def __repr__(self) -> str: 

214 rname = self.repr_name() 

215 # The dependencies used to calculate fromlineno (if not cached) may not exist at the time 

216 try: 

217 lineno = self.fromlineno 

218 except AttributeError: 

219 lineno = 0 

220 if rname: 

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

222 else: 

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

224 return string % { 

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

226 "rname": rname, 

227 "lineno": lineno, 

228 "id": id(self), 

229 } 

230 

231 def accept(self, visitor: AsStringVisitor) -> str: 

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

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

234 return func(self) 

235 

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

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

238 for field in self._astroid_fields: 

239 attr = getattr(self, field) 

240 if attr is None: 

241 continue 

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

243 yield from attr 

244 else: 

245 yield attr 

246 yield from () 

247 

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

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

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

251 attr = getattr(self, field) 

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

253 continue 

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

255 return attr[-1] 

256 return attr 

257 return None 

258 

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

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

261 parent = self.parent 

262 while parent is not None: 

263 yield parent 

264 parent = parent.parent 

265 

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

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

268 

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

270 :type node: NodeNG 

271 

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

273 """ 

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

275 

276 def statement(self) -> _base_nodes.Statement: 

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

278 

279 :raises StatementMissing: If self has no parent attribute. 

280 """ 

281 if self.is_statement: 

282 return cast("_base_nodes.Statement", self) 

283 if not self.parent: 

284 raise StatementMissing(target=self) 

285 return self.parent.statement() 

286 

287 def frame(self) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda: 

288 """The first parent frame node. 

289 

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

291 :class:`ClassDef` or :class:`Lambda`. 

292 

293 :returns: The first parent frame node. 

294 :raises ParentMissingError: If self has no parent attribute. 

295 """ 

296 if self.parent is None: 

297 raise ParentMissingError(target=self) 

298 return self.parent.frame() 

299 

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

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

302 

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

304 

305 :returns: The first parent scope node. 

306 """ 

307 if not self.parent: 

308 raise ParentMissingError(target=self) 

309 return self.parent.scope() 

310 

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

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

313 

314 :returns: The root node. 

315 """ 

316 if not (parent := self.parent): 

317 assert isinstance(self, nodes.Module) 

318 return self 

319 

320 while parent.parent: 

321 parent = parent.parent 

322 assert isinstance(parent, nodes.Module) 

323 return parent 

324 

325 def child_sequence(self, child): 

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

327 

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

329 :type child: NodeNG 

330 

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

332 :rtype: iterable(NodeNG) 

333 

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

335 the given child. 

336 """ 

337 for field in self._astroid_fields: 

338 node_or_sequence = getattr(self, field) 

339 if node_or_sequence is child: 

340 return [node_or_sequence] 

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

342 if ( 

343 isinstance(node_or_sequence, (tuple, list)) 

344 and child in node_or_sequence 

345 ): 

346 return node_or_sequence 

347 

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

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

350 

351 def locate_child(self, child): 

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

353 

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

355 :type child: NodeNG 

356 

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

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

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

360 

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

362 the given child. 

363 """ 

364 for field in self._astroid_fields: 

365 node_or_sequence = getattr(self, field) 

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

367 if child is node_or_sequence: 

368 return field, child 

369 if ( 

370 isinstance(node_or_sequence, (tuple, list)) 

371 and child in node_or_sequence 

372 ): 

373 return field, node_or_sequence 

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

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

376 

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

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

379 

380 def next_sibling(self): 

381 """The next sibling statement node. 

382 

383 :returns: The next sibling statement node. 

384 :rtype: NodeNG or None 

385 """ 

386 return self.parent.next_sibling() 

387 

388 def previous_sibling(self): 

389 """The previous sibling statement. 

390 

391 :returns: The previous sibling statement node. 

392 :rtype: NodeNG or None 

393 """ 

394 return self.parent.previous_sibling() 

395 

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

397 # single node, and they rarely get looked at 

398 

399 @cached_property 

400 def fromlineno(self) -> int: 

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

402 

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

404 """ 

405 if self.lineno is None: 

406 return self._fixed_source_line() 

407 return self.lineno 

408 

409 @cached_property 

410 def tolineno(self) -> int: 

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

412 

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

414 """ 

415 if self.end_lineno is not None: 

416 return self.end_lineno 

417 if not self._astroid_fields: 

418 # can't have children 

419 last_child = None 

420 else: 

421 last_child = self.last_child() 

422 if last_child is None: 

423 return self.fromlineno 

424 return last_child.tolineno 

425 

426 def _fixed_source_line(self) -> int: 

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

428 

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

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

431 """ 

432 line = self.lineno 

433 _node = self 

434 try: 

435 while line is None: 

436 _node = next(_node.get_children()) 

437 line = _node.lineno 

438 except StopIteration: 

439 parent = self.parent 

440 while parent and line is None: 

441 line = parent.lineno 

442 parent = parent.parent 

443 return line or 0 

444 

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

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

447 

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

449 

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

451 starting at the given line number. 

452 """ 

453 return lineno, self.tolineno 

454 

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

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

457 

458 This definition is stored on the parent scope node. 

459 

460 .. seealso:: :meth:`scope` 

461 

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

463 

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

465 """ 

466 assert self.parent 

467 self.parent.set_local(name, stmt) 

468 

469 @overload 

470 def nodes_of_class( 

471 self, 

472 klass: type[_NodesT], 

473 skip_klass: SkipKlassT = ..., 

474 ) -> Iterator[_NodesT]: ... 

475 

476 @overload 

477 def nodes_of_class( 

478 self, 

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

480 skip_klass: SkipKlassT = ..., 

481 ) -> Iterator[_NodesT] | Iterator[_NodesT2]: ... 

482 

483 @overload 

484 def nodes_of_class( 

485 self, 

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

487 skip_klass: SkipKlassT = ..., 

488 ) -> Iterator[_NodesT] | Iterator[_NodesT2] | Iterator[_NodesT3]: ... 

489 

490 @overload 

491 def nodes_of_class( 

492 self, 

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

494 skip_klass: SkipKlassT = ..., 

495 ) -> Iterator[_NodesT]: ... 

496 

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

498 self, 

499 klass: ( 

500 type[_NodesT] 

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

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

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

504 ), 

505 skip_klass: SkipKlassT = None, 

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

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

508 

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

510 

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

512 subclasses of :attr:`klass`. 

513 

514 :returns: The node of the given types. 

515 """ 

516 if isinstance(self, klass): 

517 yield self 

518 

519 if skip_klass is None: 

520 for child_node in self.get_children(): 

521 yield from child_node.nodes_of_class(klass, skip_klass) 

522 

523 return 

524 

525 for child_node in self.get_children(): 

526 if isinstance(child_node, skip_klass): 

527 continue 

528 yield from child_node.nodes_of_class(klass, skip_klass) 

529 

530 @cached_property 

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

532 return [] 

533 

534 def _get_name_nodes(self): 

535 for child_node in self.get_children(): 

536 yield from child_node._get_name_nodes() 

537 

538 def _get_return_nodes_skip_functions(self): 

539 yield from () 

540 

541 def _get_yield_nodes_skip_functions(self): 

542 yield from () 

543 

544 def _get_yield_nodes_skip_lambdas(self): 

545 yield from () 

546 

547 def _infer_name(self, frame, name): 

548 # overridden for ImportFrom, Import, Global, Try, TryStar and Arguments 

549 pass 

550 

551 def _infer( 

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

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

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

555 # this method is overridden by most concrete classes 

556 raise InferenceError( 

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

558 ) 

559 

560 def inferred(self): 

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

562 

563 .. seealso:: :ref:`inference` 

564 

565 :returns: The inferred values. 

566 :rtype: list 

567 """ 

568 return list(self.infer()) 

569 

570 def instantiate_class(self): 

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

572 

573 .. note:: 

574 

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

576 

577 :returns: An instance of the defined class. 

578 :rtype: object 

579 """ 

580 return self 

581 

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

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

584 

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

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

587 :type node: NodeNG 

588 """ 

589 return False 

590 

591 def callable(self) -> bool: 

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

593 

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

595 """ 

596 return False 

597 

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

599 return False 

600 

601 def as_string(self) -> str: 

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

603 return AsStringVisitor()(self) 

604 

605 def repr_tree( 

606 self, 

607 ids=False, 

608 include_linenos=False, 

609 ast_state=False, 

610 indent=" ", 

611 max_depth=0, 

612 max_width=80, 

613 ) -> str: 

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

615 

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

617 :type ids: bool 

618 

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

620 column offsets. 

621 :type include_linenos: bool 

622 

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

624 the whole AST like local and global variables. 

625 :type ast_state: bool 

626 

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

628 :type indent: str 

629 

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

631 nodes deeper than max_depth in the string. 

632 :type max_depth: int 

633 

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

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

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

637 :type max_width: int 

638 

639 :returns: The string representation of the AST. 

640 :rtype: str 

641 """ 

642 

643 # pylint: disable = too-many-statements 

644 

645 @_singledispatch 

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

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

648 contained within an AST, including strings. 

649 """ 

650 lines = pprint.pformat( 

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

652 ).splitlines(True) 

653 result.append(lines[0]) 

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

655 return len(lines) != 1 

656 

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

658 @_repr_tree.register(tuple) 

659 @_repr_tree.register(list) 

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

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

662 AST. 

663 """ 

664 cur_indent += indent 

665 result.append("[") 

666 if not node: 

667 broken = False 

668 elif len(node) == 1: 

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

670 elif len(node) == 2: 

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

672 if not broken: 

673 result.append(", ") 

674 else: 

675 result.append(",\n") 

676 result.append(cur_indent) 

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

678 else: 

679 result.append("\n") 

680 result.append(cur_indent) 

681 for child in node[:-1]: 

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

683 result.append(",\n") 

684 result.append(cur_indent) 

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

686 broken = True 

687 result.append("]") 

688 return broken 

689 

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

691 @_repr_tree.register(NodeNG) 

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

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

694 if node in done: 

695 result.append( 

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

697 ) 

698 return False 

699 done.add(node) 

700 

701 if max_depth and depth > max_depth: 

702 result.append("...") 

703 return False 

704 depth += 1 

705 cur_indent += indent 

706 if ids: 

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

708 else: 

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

710 fields = [] 

711 if include_linenos: 

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

713 fields.extend(node._other_fields) 

714 fields.extend(node._astroid_fields) 

715 if ast_state: 

716 fields.extend(node._other_other_fields) 

717 if not fields: 

718 broken = False 

719 elif len(fields) == 1: 

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

721 broken = _repr_tree( 

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

723 ) 

724 else: 

725 result.append("\n") 

726 result.append(cur_indent) 

727 for field in fields[:-1]: 

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

729 if field == "doc": 

730 continue 

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

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

733 result.append(",\n") 

734 result.append(cur_indent) 

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

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

737 broken = True 

738 result.append(")") 

739 return broken 

740 

741 result: list[str] = [] 

742 _repr_tree(self, result, set()) 

743 return "".join(result) 

744 

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

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

747 

748 The boolean value of a node can have three 

749 possible values: 

750 

751 * False: For instance, empty data structures, 

752 False, empty strings, instances which return 

753 explicitly False from the __nonzero__ / __bool__ 

754 method. 

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

756 classes, functions, modules etc 

757 * Uninferable: The inference engine is uncertain of the 

758 node's value. 

759 

760 :returns: The boolean value of this node. 

761 :rtype: bool or Uninferable 

762 """ 

763 return util.Uninferable 

764 

765 def op_precedence(self) -> int: 

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

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

768 

769 def op_left_associative(self) -> bool: 

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

771 return True