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

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

352 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 sys 

8from collections.abc import Generator, Iterator 

9from functools import cached_property 

10from functools import singledispatch as _singledispatch 

11from typing import ( 

12 TYPE_CHECKING, 

13 ClassVar, 

14 TypeVar, 

15 cast, 

16 overload, 

17) 

18 

19from astroid import nodes, util 

20from astroid.context import InferenceContext 

21from astroid.exceptions import ( 

22 AstroidError, 

23 InferenceError, 

24 ParentMissingError, 

25 StatementMissing, 

26 UseInferenceDefault, 

27) 

28from astroid.manager import AstroidManager 

29from astroid.nodes.as_string import AsStringVisitor 

30from astroid.nodes.const import OP_PRECEDENCE 

31from astroid.nodes.utils import Position 

32from astroid.typing import InferenceErrorInfo, InferenceResult, InferFn 

33 

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

35 from typing import Self 

36else: 

37 from typing_extensions import Self 

38 

39 

40if TYPE_CHECKING: 

41 from astroid.nodes import _base_nodes 

42 

43 FrameType = nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda 

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] = False # True for For 

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

63 

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

65 assignment if the loop has no iterations. 

66 """ 

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

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

69 is_lambda: ClassVar[bool] = False 

70 

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

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

73 """Node attributes that contain child nodes. 

74 

75 This is redefined in most concrete classes. 

76 """ 

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

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

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

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

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

82 _explicit_inference: InferFn[Self] | None = None 

83 

84 def __init__( 

85 self, 

86 lineno: int | None, 

87 col_offset: int | None, 

88 parent: NodeNG | None, 

89 *, 

90 end_lineno: int | None, 

91 end_col_offset: int | None, 

92 ) -> None: 

93 self.lineno = lineno 

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

95 

96 self.col_offset = col_offset 

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

98 

99 self.parent = parent 

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

101 

102 self.end_lineno = end_lineno 

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

104 

105 self.end_col_offset = end_col_offset 

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

107 

108 Note: This is after the last symbol. 

109 """ 

110 

111 self.position: Position | None = None 

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

113 

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

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

116 """ 

117 

118 def infer( 

119 self, context: InferenceContext | None = None 

120 ) -> Generator[InferenceResult]: 

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

122 

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

124 

125 .. seealso:: :ref:`inference` 

126 

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

128 called instead of the default interface. 

129 

130 :returns: The inferred values. 

131 :rtype: Iterator 

132 """ 

133 if context is None: 

134 context = InferenceContext() 

135 else: 

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

137 if self._explicit_inference is not None: 

138 # explicit_inference is not bound, give it self explicitly 

139 try: 

140 for result in self._explicit_inference( 

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

142 context, 

143 ): 

144 context.nodes_inferred += 1 

145 yield result 

146 return 

147 except UseInferenceDefault: 

148 pass 

149 

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

151 if key in context.inferred: 

152 yield from context.inferred[key] 

153 return 

154 

155 results = [] 

156 

157 # Limit inference amount to help with performance issues with 

158 # exponentially exploding possible results. 

159 limit = AstroidManager().max_inferable_values 

160 for i, result in enumerate(self._infer(context=context)): 

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

162 results.append(util.Uninferable) 

163 yield util.Uninferable 

164 break 

165 results.append(result) 

166 yield result 

167 context.nodes_inferred += 1 

168 

169 # Cache generated results for subsequent inferences of the 

170 # same node using the same context 

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

172 return 

173 

174 def repr_name(self) -> str: 

175 """Get a name for nice representation. 

176 

177 This is either ``name``, ``attrname``, or the empty string. 

178 """ 

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

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

181 return "" 

182 

183 def __str__(self) -> str: 

184 import pprint # pylint: disable=import-outside-toplevel 

185 

186 rname = self.repr_name() 

187 cname = type(self).__name__ 

188 if rname: 

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

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

191 else: 

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

193 alignment = len(cname) + 1 

194 result = [] 

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

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

197 width = max(80 - len(field) - alignment, 1) 

198 try: 

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

200 except ValueError: 

201 lines = [f"<{type(value).__name__}>"] 

202 

203 inner = [lines[0]] 

204 for line in lines[1:]: 

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

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

207 

208 return string % { 

209 "cname": cname, 

210 "rname": rname, 

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

212 } 

213 

214 def __repr__(self) -> str: 

215 rname = self.repr_name() 

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

217 try: 

218 lineno = self.fromlineno 

219 except AttributeError: 

220 lineno = 0 

221 if rname: 

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

223 else: 

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

225 return string % { 

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

227 "rname": rname, 

228 "lineno": lineno, 

229 "id": id(self), 

230 } 

231 

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

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

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

235 return func(self) 

236 

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

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

239 for field in self._astroid_fields: 

240 attr = getattr(self, field) 

241 if attr is None: 

242 continue 

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

244 yield from attr 

245 else: 

246 yield attr 

247 yield from () 

248 

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

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

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

252 attr = getattr(self, field) 

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

254 continue 

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

256 return attr[-1] 

257 return attr 

258 return None 

259 

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

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

262 parent = self.parent 

263 while parent is not None: 

264 yield parent 

265 parent = parent.parent 

266 

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

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

269 

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

271 :type node: NodeNG 

272 

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

274 """ 

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

276 

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

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

279 

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

281 """ 

282 if self.is_statement: 

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

284 if not self.parent: 

285 raise StatementMissing(target=self) 

286 return self.parent.statement() 

287 

288 def frame(self) -> FrameType: 

289 """The first parent frame node. 

290 

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

292 :class:`ClassDef` or :class:`Lambda`. 

293 

294 :returns: The first parent frame node. 

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

296 """ 

297 if self.parent is None: 

298 raise ParentMissingError(target=self) 

299 return self.parent.frame() 

300 

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

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

303 

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

305 

306 :returns: The first parent scope node. 

307 """ 

308 if not self.parent: 

309 raise ParentMissingError(target=self) 

310 return self.parent.scope() 

311 

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

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

314 

315 :returns: The root node. 

316 """ 

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

318 assert isinstance(self, nodes.Module) 

319 return self 

320 

321 while parent.parent: 

322 parent = parent.parent 

323 assert isinstance(parent, nodes.Module) 

324 return parent 

325 

326 def child_sequence(self, child): 

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

328 

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

330 :type child: NodeNG 

331 

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

333 :rtype: Iterator[NodeNG] 

334 

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

336 the given child. 

337 """ 

338 for field in self._astroid_fields: 

339 node_or_sequence = getattr(self, field) 

340 if node_or_sequence is child: 

341 return [node_or_sequence] 

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

343 if ( 

344 isinstance(node_or_sequence, (tuple, list)) 

345 and child in node_or_sequence 

346 ): 

347 return node_or_sequence 

348 

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

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

351 

352 def locate_child(self, child): 

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

354 

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

356 :type child: NodeNG 

357 

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

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

360 :rtype: tuple[str, Iterator[NodeNG] or NodeNG] 

361 

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

363 the given child. 

364 """ 

365 for field in self._astroid_fields: 

366 node_or_sequence = getattr(self, field) 

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

368 if child is node_or_sequence: 

369 return field, child 

370 if ( 

371 isinstance(node_or_sequence, (tuple, list)) 

372 and child in node_or_sequence 

373 ): 

374 return field, node_or_sequence 

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

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

377 

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

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

380 

381 def next_sibling(self): 

382 """The next sibling statement node. 

383 

384 :returns: The next sibling statement node. 

385 :rtype: NodeNG or None 

386 """ 

387 return self.parent.next_sibling() 

388 

389 def previous_sibling(self): 

390 """The previous sibling statement. 

391 

392 :returns: The previous sibling statement node. 

393 :rtype: NodeNG or None 

394 """ 

395 return self.parent.previous_sibling() 

396 

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

398 # single node, and they rarely get looked at 

399 

400 @cached_property 

401 def fromlineno(self) -> int: 

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

403 

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

405 """ 

406 if self.lineno is None: 

407 return self._fixed_source_line() 

408 return self.lineno 

409 

410 @cached_property 

411 def tolineno(self) -> int: 

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

413 

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

415 """ 

416 if self.end_lineno is not None: 

417 return self.end_lineno 

418 if not self._astroid_fields: 

419 # can't have children 

420 last_child = None 

421 else: 

422 last_child = self.last_child() 

423 if last_child is None: 

424 return self.fromlineno 

425 return last_child.tolineno 

426 

427 def _fixed_source_line(self) -> int: 

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

429 

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

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

432 """ 

433 line = self.lineno 

434 _node = self 

435 try: 

436 while line is None: 

437 _node = next(_node.get_children()) 

438 line = _node.lineno 

439 except StopIteration: 

440 parent = self.parent 

441 while parent and line is None: 

442 line = parent.lineno 

443 parent = parent.parent 

444 return line or 0 

445 

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

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

448 

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

450 

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

452 starting at the given line number. 

453 """ 

454 return lineno, self.tolineno 

455 

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

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

458 

459 This definition is stored on the parent scope node. 

460 

461 .. seealso:: :meth:`scope` 

462 

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

464 

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

466 """ 

467 assert self.parent 

468 self.parent.set_local(name, stmt) 

469 

470 @overload 

471 def nodes_of_class( 

472 self, 

473 klass: type[_NodesT], 

474 skip_klass: SkipKlassT = ..., 

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

476 

477 @overload 

478 def nodes_of_class( 

479 self, 

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

481 skip_klass: SkipKlassT = ..., 

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

483 

484 @overload 

485 def nodes_of_class( 

486 self, 

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

488 skip_klass: SkipKlassT = ..., 

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

490 

491 @overload 

492 def nodes_of_class( 

493 self, 

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

495 skip_klass: SkipKlassT = ..., 

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

497 

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

499 self, 

500 klass: ( 

501 type[_NodesT] 

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

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

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

505 ), 

506 skip_klass: SkipKlassT = None, 

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

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

509 

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

511 

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

513 subclasses of ``klass``. 

514 

515 :returns: The node of the given types. 

516 """ 

517 if isinstance(self, klass): 

518 yield self 

519 

520 if skip_klass is None: 

521 for child_node in self.get_children(): 

522 yield from child_node.nodes_of_class(klass, skip_klass) 

523 

524 return 

525 

526 for child_node in self.get_children(): 

527 if isinstance(child_node, skip_klass): 

528 continue 

529 yield from child_node.nodes_of_class(klass, skip_klass) 

530 

531 @cached_property 

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

533 return [] 

534 

535 def _get_name_nodes(self): 

536 for child_node in self.get_children(): 

537 yield from child_node._get_name_nodes() 

538 

539 def _get_return_nodes_skip_functions(self): 

540 yield from () 

541 

542 def _get_yield_nodes_skip_functions(self): 

543 yield from () 

544 

545 def _get_yield_nodes_skip_lambdas(self): 

546 yield from () 

547 

548 def _infer_name(self, frame, name): 

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

550 pass 

551 

552 def _infer( 

553 self, context: InferenceContext | None = None 

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

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

556 # this method is overridden by most concrete classes 

557 raise InferenceError( 

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

559 ) 

560 

561 def inferred(self): 

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

563 

564 .. seealso:: :ref:`inference` 

565 

566 :returns: The inferred values. 

567 :rtype: list 

568 """ 

569 return list(self.infer()) 

570 

571 def instantiate_class(self): 

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

573 

574 .. note:: 

575 

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

577 

578 :returns: An instance of the defined class. 

579 :rtype: object 

580 """ 

581 return self 

582 

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

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

585 

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

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

588 :type node: NodeNG 

589 """ 

590 return False 

591 

592 def callable(self) -> bool: 

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

594 

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

596 """ 

597 return False 

598 

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

600 return False 

601 

602 def as_string(self) -> str: 

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

604 return AsStringVisitor()(self) 

605 

606 def repr_tree( 

607 self, 

608 ids=False, 

609 include_linenos=False, 

610 ast_state=False, 

611 indent=" ", 

612 max_depth=0, 

613 max_width=80, 

614 ) -> str: 

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

616 

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

618 :type ids: bool 

619 

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

621 column offsets. 

622 :type include_linenos: bool 

623 

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

625 the whole AST like local and global variables. 

626 :type ast_state: bool 

627 

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

629 :type indent: str 

630 

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

632 nodes deeper than max_depth in the string. 

633 :type max_depth: int 

634 

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

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

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

638 :type max_width: int 

639 

640 :returns: The string representation of the AST. 

641 :rtype: str 

642 """ 

643 

644 # pylint: disable = too-many-statements 

645 import pprint # pylint: disable=import-outside-toplevel 

646 

647 @_singledispatch 

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

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

650 contained within an AST, including strings. 

651 """ 

652 lines = pprint.pformat( 

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

654 ).splitlines(True) 

655 result.append(lines[0]) 

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

657 return len(lines) != 1 

658 

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

660 @_repr_tree.register(tuple) 

661 @_repr_tree.register(list) 

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

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

664 AST. 

665 """ 

666 cur_indent += indent 

667 result.append("[") 

668 if not node: 

669 broken = False 

670 elif len(node) == 1: 

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

672 elif len(node) == 2: 

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

674 if not broken: 

675 result.append(", ") 

676 else: 

677 result.append(",\n") 

678 result.append(cur_indent) 

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

680 else: 

681 result.append("\n") 

682 result.append(cur_indent) 

683 for child in node[:-1]: 

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

685 result.append(",\n") 

686 result.append(cur_indent) 

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

688 broken = True 

689 result.append("]") 

690 return broken 

691 

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

693 @_repr_tree.register(NodeNG) 

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

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

696 if node in done: 

697 result.append( 

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

699 ) 

700 return False 

701 done.add(node) 

702 

703 if max_depth and depth > max_depth: 

704 result.append("...") 

705 return False 

706 depth += 1 

707 cur_indent += indent 

708 if ids: 

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

710 else: 

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

712 fields = [] 

713 if include_linenos: 

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

715 fields.extend(node._other_fields) 

716 fields.extend(node._astroid_fields) 

717 if ast_state: 

718 fields.extend(node._other_other_fields) 

719 if not fields: 

720 broken = False 

721 elif len(fields) == 1: 

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

723 broken = _repr_tree( 

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

725 ) 

726 else: 

727 result.append("\n") 

728 result.append(cur_indent) 

729 for field in fields[:-1]: 

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

731 if field == "doc": 

732 continue 

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

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

735 result.append(",\n") 

736 result.append(cur_indent) 

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

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

739 broken = True 

740 result.append(")") 

741 return broken 

742 

743 result: list[str] = [] 

744 _repr_tree(self, result, set()) 

745 return "".join(result) 

746 

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

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

749 

750 The boolean value of a node can have three 

751 possible values: 

752 

753 * False: For instance, empty data structures, 

754 False, empty strings, instances which return 

755 explicitly False from the __nonzero__ / __bool__ 

756 method. 

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

758 classes, functions, modules etc 

759 * Uninferable: The inference engine is uncertain of the 

760 node's value. 

761 

762 :returns: The boolean value of this node. 

763 :rtype: bool or Uninferable 

764 """ 

765 return util.Uninferable 

766 

767 def op_precedence(self) -> int: 

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

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

770 

771 def op_left_associative(self) -> bool: 

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

773 return True