Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/_nodes/statement.py: 45%

1647 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:43 +0000

1# Copyright (c) Meta Platforms, Inc. and affiliates. 

2# 

3# This source code is licensed under the MIT license found in the 

4# LICENSE file in the root directory of this source tree. 

5 

6import inspect 

7import re 

8from abc import ABC, abstractmethod 

9from dataclasses import dataclass, field 

10from typing import Optional, Pattern, Sequence, Union 

11 

12from libcst._add_slots import add_slots 

13from libcst._maybe_sentinel import MaybeSentinel 

14from libcst._nodes.base import CSTNode, CSTValidationError 

15from libcst._nodes.expression import ( 

16 _BaseParenthesizedNode, 

17 Annotation, 

18 Arg, 

19 Asynchronous, 

20 Attribute, 

21 BaseAssignTargetExpression, 

22 BaseDelTargetExpression, 

23 BaseExpression, 

24 ConcatenatedString, 

25 ExpressionPosition, 

26 From, 

27 LeftCurlyBrace, 

28 LeftParen, 

29 LeftSquareBracket, 

30 List, 

31 Name, 

32 Parameters, 

33 RightCurlyBrace, 

34 RightParen, 

35 RightSquareBracket, 

36 SimpleString, 

37 Tuple, 

38) 

39from libcst._nodes.internal import ( 

40 CodegenState, 

41 visit_body_sequence, 

42 visit_optional, 

43 visit_required, 

44 visit_sentinel, 

45 visit_sequence, 

46) 

47from libcst._nodes.op import ( 

48 AssignEqual, 

49 BaseAugOp, 

50 BitOr, 

51 Colon, 

52 Comma, 

53 Dot, 

54 ImportStar, 

55 Semicolon, 

56) 

57from libcst._nodes.whitespace import ( 

58 BaseParenthesizableWhitespace, 

59 EmptyLine, 

60 ParenthesizedWhitespace, 

61 SimpleWhitespace, 

62 TrailingWhitespace, 

63) 

64from libcst._visitors import CSTVisitorT 

65 

66_INDENT_WHITESPACE_RE: Pattern[str] = re.compile(r"[ \f\t]+", re.UNICODE) 

67 

68 

69class BaseSuite(CSTNode, ABC): 

70 """ 

71 A dummy base-class for both :class:`SimpleStatementSuite` and :class:`IndentedBlock`. 

72 This exists to simplify type definitions and isinstance checks. 

73 

74 A suite is a group of statements controlled by a clause. A suite can be one or 

75 more semicolon-separated simple statements on the same line as the header, 

76 following the header’s colon, or it can be one or more indented statements on 

77 subsequent lines. 

78 

79 -- https://docs.python.org/3/reference/compound_stmts.html 

80 """ 

81 

82 __slots__ = () 

83 

84 body: Union[Sequence["BaseStatement"], Sequence["BaseSmallStatement"]] 

85 

86 

87class BaseStatement(CSTNode, ABC): 

88 """ 

89 A class that exists to allow for typing to specify that any statement is allowed 

90 in a particular location. 

91 """ 

92 

93 __slots__ = () 

94 

95 

96class BaseSmallStatement(CSTNode, ABC): 

97 """ 

98 Encapsulates a small statement, like ``del`` or ``pass``, and optionally adds a 

99 trailing semicolon. A small statement is always contained inside a 

100 :class:`SimpleStatementLine` or :class:`SimpleStatementSuite`. This exists to 

101 simplify type definitions and isinstance checks. 

102 """ 

103 

104 __slots__ = () 

105 

106 #: An optional semicolon that appears after a small statement. This is optional 

107 #: for the last small statement in a :class:`SimpleStatementLine` or 

108 #: :class:`SimpleStatementSuite`, but all other small statements inside a simple 

109 #: statement must contain a semicolon to disambiguate multiple small statements 

110 #: on the same line. 

111 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

112 

113 @abstractmethod 

114 def _codegen_impl( 

115 self, state: CodegenState, default_semicolon: bool = False 

116 ) -> None: 

117 ... 

118 

119 

120@add_slots 

121@dataclass(frozen=True) 

122class Del(BaseSmallStatement): 

123 """ 

124 Represents a ``del`` statement. ``del`` is always followed by a target. 

125 """ 

126 

127 #: The target expression will be deleted. This can be a name, a tuple, 

128 #: an item of a list, an item of a dictionary, or an attribute. 

129 target: BaseDelTargetExpression 

130 

131 #: The whitespace after the ``del`` keyword. 

132 whitespace_after_del: SimpleWhitespace = SimpleWhitespace.field(" ") 

133 

134 #: Optional semicolon when this is used in a statement line. This semicolon 

135 #: owns the whitespace on both sides of it when it is used. 

136 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

137 

138 def _validate(self) -> None: 

139 if ( 

140 self.whitespace_after_del.empty 

141 and not self.target._safe_to_use_with_word_operator( 

142 ExpressionPosition.RIGHT 

143 ) 

144 ): 

145 raise CSTValidationError("Must have at least one space after 'del'.") 

146 

147 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Del": 

148 return Del( 

149 target=visit_required(self, "target", self.target, visitor), 

150 whitespace_after_del=visit_required( 

151 self, "whitespace_after_del", self.whitespace_after_del, visitor 

152 ), 

153 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

154 ) 

155 

156 def _codegen_impl( 

157 self, state: CodegenState, default_semicolon: bool = False 

158 ) -> None: 

159 with state.record_syntactic_position(self): 

160 state.add_token("del") 

161 self.whitespace_after_del._codegen(state) 

162 self.target._codegen(state) 

163 

164 semicolon = self.semicolon 

165 if isinstance(semicolon, MaybeSentinel): 

166 if default_semicolon: 

167 state.add_token("; ") 

168 elif isinstance(semicolon, Semicolon): 

169 semicolon._codegen(state) 

170 

171 

172@add_slots 

173@dataclass(frozen=True) 

174class Pass(BaseSmallStatement): 

175 """ 

176 Represents a ``pass`` statement. 

177 """ 

178 

179 #: Optional semicolon when this is used in a statement line. This semicolon 

180 #: owns the whitespace on both sides of it when it is used. 

181 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

182 

183 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Pass": 

184 return Pass( 

185 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor) 

186 ) 

187 

188 def _codegen_impl( 

189 self, state: CodegenState, default_semicolon: bool = False 

190 ) -> None: 

191 with state.record_syntactic_position(self): 

192 state.add_token("pass") 

193 

194 semicolon = self.semicolon 

195 if isinstance(semicolon, MaybeSentinel): 

196 if default_semicolon: 

197 state.add_token("; ") 

198 elif isinstance(semicolon, Semicolon): 

199 semicolon._codegen(state) 

200 

201 

202@add_slots 

203@dataclass(frozen=True) 

204class Break(BaseSmallStatement): 

205 """ 

206 Represents a ``break`` statement, which is used to break out of a :class:`For` 

207 or :class:`While` loop early. 

208 """ 

209 

210 #: Optional semicolon when this is used in a statement line. This semicolon 

211 #: owns the whitespace on both sides of it when it is used. 

212 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

213 

214 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Break": 

215 return Break( 

216 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor) 

217 ) 

218 

219 def _codegen_impl( 

220 self, state: CodegenState, default_semicolon: bool = False 

221 ) -> None: 

222 with state.record_syntactic_position(self): 

223 state.add_token("break") 

224 

225 semicolon = self.semicolon 

226 if isinstance(semicolon, MaybeSentinel): 

227 if default_semicolon: 

228 state.add_token("; ") 

229 elif isinstance(semicolon, Semicolon): 

230 semicolon._codegen(state) 

231 

232 

233@add_slots 

234@dataclass(frozen=True) 

235class Continue(BaseSmallStatement): 

236 """ 

237 Represents a ``continue`` statement, which is used to skip to the next iteration 

238 in a :class:`For` or :class:`While` loop. 

239 """ 

240 

241 #: Optional semicolon when this is used in a statement line. This semicolon 

242 #: owns the whitespace on both sides of it when it is used. 

243 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

244 

245 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Continue": 

246 return Continue( 

247 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor) 

248 ) 

249 

250 def _codegen_impl( 

251 self, state: CodegenState, default_semicolon: bool = False 

252 ) -> None: 

253 with state.record_syntactic_position(self): 

254 state.add_token("continue") 

255 

256 semicolon = self.semicolon 

257 if isinstance(semicolon, MaybeSentinel): 

258 if default_semicolon: 

259 state.add_token("; ") 

260 elif isinstance(semicolon, Semicolon): 

261 semicolon._codegen(state) 

262 

263 

264@add_slots 

265@dataclass(frozen=True) 

266class Return(BaseSmallStatement): 

267 """ 

268 Represents a ``return`` or a ``return x`` statement. 

269 """ 

270 

271 #: The optional expression that will be evaluated and returned. 

272 value: Optional[BaseExpression] = None 

273 

274 #: Optional whitespace after the ``return`` keyword before the optional 

275 #: value expression. 

276 whitespace_after_return: Union[ 

277 SimpleWhitespace, MaybeSentinel 

278 ] = MaybeSentinel.DEFAULT 

279 

280 #: Optional semicolon when this is used in a statement line. This semicolon 

281 #: owns the whitespace on both sides of it when it is used. 

282 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

283 

284 def _validate(self) -> None: 

285 value = self.value 

286 if value is not None: 

287 whitespace_after_return = self.whitespace_after_return 

288 has_no_gap = ( 

289 not isinstance(whitespace_after_return, MaybeSentinel) 

290 and whitespace_after_return.empty 

291 ) 

292 if has_no_gap and not value._safe_to_use_with_word_operator( 

293 ExpressionPosition.RIGHT 

294 ): 

295 raise CSTValidationError("Must have at least one space after 'return'.") 

296 

297 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Return": 

298 return Return( 

299 whitespace_after_return=visit_sentinel( 

300 self, "whitespace_after_return", self.whitespace_after_return, visitor 

301 ), 

302 value=visit_optional(self, "value", self.value, visitor), 

303 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

304 ) 

305 

306 def _codegen_impl( 

307 self, state: CodegenState, default_semicolon: bool = False 

308 ) -> None: 

309 with state.record_syntactic_position(self): 

310 state.add_token("return") 

311 whitespace_after_return = self.whitespace_after_return 

312 value = self.value 

313 if isinstance(whitespace_after_return, MaybeSentinel): 

314 if value is not None: 

315 state.add_token(" ") 

316 else: 

317 whitespace_after_return._codegen(state) 

318 if value is not None: 

319 value._codegen(state) 

320 

321 semicolon = self.semicolon 

322 if isinstance(semicolon, MaybeSentinel): 

323 if default_semicolon: 

324 state.add_token("; ") 

325 elif isinstance(semicolon, Semicolon): 

326 semicolon._codegen(state) 

327 

328 

329@add_slots 

330@dataclass(frozen=True) 

331class Expr(BaseSmallStatement): 

332 """ 

333 An expression used as a statement, where the result is unused and unassigned. 

334 The most common place you will find this is in function calls where the return 

335 value is unneeded. 

336 """ 

337 

338 #: The expression itself. Python will evaluate the expression but not assign 

339 #: the result anywhere. 

340 value: BaseExpression 

341 

342 #: Optional semicolon when this is used in a statement line. This semicolon 

343 #: owns the whitespace on both sides of it when it is used. 

344 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

345 

346 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Expr": 

347 return Expr( 

348 value=visit_required(self, "value", self.value, visitor), 

349 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

350 ) 

351 

352 def _codegen_impl( 

353 self, state: CodegenState, default_semicolon: bool = False 

354 ) -> None: 

355 with state.record_syntactic_position(self): 

356 self.value._codegen(state) 

357 

358 semicolon = self.semicolon 

359 if isinstance(semicolon, MaybeSentinel): 

360 if default_semicolon: 

361 state.add_token("; ") 

362 elif isinstance(semicolon, Semicolon): 

363 semicolon._codegen(state) 

364 

365 

366class _BaseSimpleStatement(CSTNode, ABC): 

367 """ 

368 A simple statement is a series of small statements joined together by semicolons. 

369 

370 simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE 

371 

372 Whitespace between each small statement is owned by the small statements themselves. 

373 It can be found on the required semicolon that will be attached to each non-terminal 

374 small statement. 

375 """ 

376 

377 __slots__ = () 

378 

379 #: Sequence of small statements. All but the last statement are required to have 

380 #: a semicolon. 

381 body: Sequence[BaseSmallStatement] 

382 

383 #: Any trailing comment and the final ``NEWLINE``, which is part of small statement's 

384 #: grammar. 

385 trailing_whitespace: TrailingWhitespace 

386 

387 def _validate(self) -> None: 

388 body = self.body 

389 for small_stmt in body[:-1]: 

390 if small_stmt.semicolon is None: 

391 raise CSTValidationError( 

392 "All but the last SmallStatement in a SimpleStatementLine or " 

393 + "SimpleStatementSuite must have a trailing semicolon. Otherwise, " 

394 + "there's no way to syntatically disambiguate each SmallStatement " 

395 + "on the same line." 

396 ) 

397 

398 def _codegen_impl(self, state: CodegenState) -> None: 

399 body = self.body 

400 if body: 

401 laststmt = len(body) - 1 

402 with state.record_syntactic_position(self, end_node=body[laststmt]): 

403 for idx, stmt in enumerate(body): 

404 stmt._codegen(state, default_semicolon=(idx != laststmt)) 

405 else: 

406 # Empty simple statement blocks are not syntactically valid in Python 

407 # unless they contain a 'pass' statement, so add one here. 

408 with state.record_syntactic_position(self): 

409 state.add_token("pass") 

410 

411 self.trailing_whitespace._codegen(state) 

412 

413 

414@add_slots 

415@dataclass(frozen=True) 

416class SimpleStatementLine(_BaseSimpleStatement, BaseStatement): 

417 """ 

418 A simple statement that's part of an IndentedBlock or Module. A simple statement is 

419 a series of small statements joined together by semicolons. 

420 

421 This isn't differentiated from a :class:`SimpleStatementSuite` in the grammar, but 

422 because a :class:`SimpleStatementLine` can own additional whitespace that a 

423 :class:`SimpleStatementSuite` doesn't have, we're differentiating it in the CST. 

424 """ 

425 

426 #: Sequence of small statements. All but the last statement are required to have 

427 #: a semicolon. 

428 body: Sequence[BaseSmallStatement] 

429 

430 #: Sequence of empty lines appearing before this simple statement line. 

431 leading_lines: Sequence[EmptyLine] = () 

432 

433 #: Any optional trailing comment and the final ``NEWLINE`` at the end of the line. 

434 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

435 

436 def _visit_and_replace_children( 

437 self, visitor: CSTVisitorT 

438 ) -> "SimpleStatementLine": 

439 return SimpleStatementLine( 

440 leading_lines=visit_sequence( 

441 self, "leading_lines", self.leading_lines, visitor 

442 ), 

443 body=visit_sequence(self, "body", self.body, visitor), 

444 trailing_whitespace=visit_required( 

445 self, "trailing_whitespace", self.trailing_whitespace, visitor 

446 ), 

447 ) 

448 

449 def _is_removable(self) -> bool: 

450 # If we have an empty body, we are removable since we don't represent 

451 # anything concrete. 

452 return not self.body 

453 

454 def _codegen_impl(self, state: CodegenState) -> None: 

455 for ll in self.leading_lines: 

456 ll._codegen(state) 

457 state.add_indent_tokens() 

458 _BaseSimpleStatement._codegen_impl(self, state) 

459 

460 

461@add_slots 

462@dataclass(frozen=True) 

463class SimpleStatementSuite(_BaseSimpleStatement, BaseSuite): 

464 """ 

465 A simple statement that's used as a suite. A simple statement is a series of small 

466 statements joined together by semicolons. A suite is the thing that follows the 

467 colon in a compound statement. 

468 

469 .. code-block:: 

470 

471 if test:<leading_whitespace><body><trailing_whitespace> 

472 

473 This isn't differentiated from a :class:`SimpleStatementLine` in the grammar, but 

474 because the two classes need to track different whitespace, we're differentiating 

475 it in the CST. 

476 """ 

477 

478 #: Sequence of small statements. All but the last statement are required to have 

479 #: a semicolon. 

480 body: Sequence[BaseSmallStatement] 

481 

482 #: The whitespace between the colon in the parent statement and the body. 

483 leading_whitespace: SimpleWhitespace = SimpleWhitespace.field(" ") 

484 

485 #: Any optional trailing comment and the final ``NEWLINE`` at the end of the line. 

486 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

487 

488 def _visit_and_replace_children( 

489 self, visitor: CSTVisitorT 

490 ) -> "SimpleStatementSuite": 

491 return SimpleStatementSuite( 

492 leading_whitespace=visit_required( 

493 self, "leading_whitespace", self.leading_whitespace, visitor 

494 ), 

495 body=visit_sequence(self, "body", self.body, visitor), 

496 trailing_whitespace=visit_required( 

497 self, "trailing_whitespace", self.trailing_whitespace, visitor 

498 ), 

499 ) 

500 

501 def _codegen_impl(self, state: CodegenState) -> None: 

502 self.leading_whitespace._codegen(state) 

503 _BaseSimpleStatement._codegen_impl(self, state) 

504 

505 

506@add_slots 

507@dataclass(frozen=True) 

508class Else(CSTNode): 

509 """ 

510 An ``else`` clause that appears optionally after an :class:`If`, :class:`While`, 

511 :class:`Try`, or :class:`For` statement. 

512 

513 This node does not match ``elif`` clauses in :class:`If` statements. It also 

514 does not match the required ``else`` clause in an :class:`IfExp` expression 

515 (``a = if b else c``). 

516 """ 

517 

518 #: The body of else clause. 

519 body: BaseSuite 

520 

521 #: Sequence of empty lines appearing before this compound statement line. 

522 leading_lines: Sequence[EmptyLine] = () 

523 

524 #: The whitespace appearing after the ``else`` keyword but before the colon. 

525 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

526 

527 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Else": 

528 return Else( 

529 leading_lines=visit_sequence( 

530 self, "leading_lines", self.leading_lines, visitor 

531 ), 

532 whitespace_before_colon=visit_required( 

533 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

534 ), 

535 body=visit_required(self, "body", self.body, visitor), 

536 ) 

537 

538 def _codegen_impl(self, state: CodegenState) -> None: 

539 for ll in self.leading_lines: 

540 ll._codegen(state) 

541 state.add_indent_tokens() 

542 

543 with state.record_syntactic_position(self, end_node=self.body): 

544 state.add_token("else") 

545 self.whitespace_before_colon._codegen(state) 

546 state.add_token(":") 

547 self.body._codegen(state) 

548 

549 

550class BaseCompoundStatement(BaseStatement, ABC): 

551 """ 

552 Encapsulates a compound statement, like ``if True: pass`` or ``while True: pass``. 

553 This exists to simplify type definitions and isinstance checks. 

554 

555 Compound statements contain (groups of) other statements; they affect or control 

556 the execution of those other statements in some way. In general, compound 

557 statements span multiple lines, although in simple incarnations a whole compound 

558 statement may be contained in one line. 

559 

560 -- https://docs.python.org/3/reference/compound_stmts.html 

561 """ 

562 

563 __slots__ = () 

564 

565 #: The body of this compound statement. 

566 body: BaseSuite 

567 

568 #: Any empty lines or comments appearing before this statement. 

569 leading_lines: Sequence[EmptyLine] 

570 

571 

572@add_slots 

573@dataclass(frozen=True) 

574class If(BaseCompoundStatement): 

575 """ 

576 An ``if`` statement. ``test`` holds a single test expression. 

577 

578 ``elif`` clauses don’t have a special representation in the AST, but rather appear as 

579 extra :class:`If` nodes within the ``orelse`` section of the previous one. 

580 """ 

581 

582 #: The expression that, when evaluated, should give us a truthy/falsey value. 

583 test: BaseExpression # TODO: should be a test_nocond 

584 

585 #: The body of this compound statement. 

586 body: BaseSuite 

587 

588 #: An optional ``elif`` or ``else`` clause. :class:`If` signifies an ``elif`` block. 

589 #: :class:`Else` signifies an ``else`` block. ``None`` signifies no ``else`` or 

590 #:``elif`` block. 

591 orelse: Union["If", Else, None] = None 

592 

593 #: Sequence of empty lines appearing before this compound statement line. 

594 leading_lines: Sequence[EmptyLine] = () 

595 

596 #: The whitespace appearing after the ``if`` keyword but before the test expression. 

597 whitespace_before_test: SimpleWhitespace = SimpleWhitespace.field(" ") 

598 

599 #: The whitespace appearing after the test expression but before the colon. 

600 whitespace_after_test: SimpleWhitespace = SimpleWhitespace.field("") 

601 

602 # TODO: _validate 

603 

604 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "If": 

605 return If( 

606 leading_lines=visit_sequence( 

607 self, "leading_lines", self.leading_lines, visitor 

608 ), 

609 whitespace_before_test=visit_required( 

610 self, "whitespace_before_test", self.whitespace_before_test, visitor 

611 ), 

612 test=visit_required(self, "test", self.test, visitor), 

613 whitespace_after_test=visit_required( 

614 self, "whitespace_after_test", self.whitespace_after_test, visitor 

615 ), 

616 body=visit_required(self, "body", self.body, visitor), 

617 orelse=visit_optional(self, "orelse", self.orelse, visitor), 

618 ) 

619 

620 def _codegen_impl(self, state: CodegenState, is_elif: bool = False) -> None: 

621 for ll in self.leading_lines: 

622 ll._codegen(state) 

623 state.add_indent_tokens() 

624 

625 end_node = self.body if self.orelse is None else self.orelse 

626 with state.record_syntactic_position(self, end_node=end_node): 

627 state.add_token("elif" if is_elif else "if") 

628 self.whitespace_before_test._codegen(state) 

629 self.test._codegen(state) 

630 self.whitespace_after_test._codegen(state) 

631 state.add_token(":") 

632 self.body._codegen(state) 

633 orelse = self.orelse 

634 if orelse is not None: 

635 if isinstance(orelse, If): # special-case elif 

636 orelse._codegen(state, is_elif=True) 

637 else: # is an Else clause 

638 orelse._codegen(state) 

639 

640 

641@add_slots 

642@dataclass(frozen=True) 

643class IndentedBlock(BaseSuite): 

644 """ 

645 Represents a block of statements beginning with an ``INDENT`` token and ending in a 

646 ``DEDENT`` token. Used as the body of compound statements, such as an if statement's 

647 body. 

648 

649 A common alternative to an :class:`IndentedBlock` is a :class:`SimpleStatementSuite`, 

650 which can also be used as a :class:`BaseSuite`, meaning that it can be used as the 

651 body of many compound statements. 

652 

653 An :class:`IndentedBlock` always occurs after a colon in a 

654 :class:`BaseCompoundStatement`, so it owns the trailing whitespace for the compound 

655 statement's clause. 

656 

657 .. code-block:: 

658 

659 if test: # IndentedBlock's header 

660 body 

661 """ 

662 

663 #: Sequence of statements belonging to this indented block. 

664 body: Sequence[BaseStatement] 

665 

666 #: Any optional trailing comment and the final ``NEWLINE`` at the end of the line. 

667 header: TrailingWhitespace = TrailingWhitespace.field() 

668 

669 #: A string represents a specific indentation. A ``None`` value uses the modules's 

670 #: default indentation. This is included because indentation is allowed to be 

671 #: inconsistent across a file, just not ambiguously. 

672 indent: Optional[str] = None 

673 

674 #: Any trailing comments or lines after the dedent that are owned by this indented 

675 #: block. Statements own preceeding and same-line trailing comments, but not 

676 #: trailing lines, so it falls on :class:`IndentedBlock` to own it. In the case 

677 #: that a statement follows an :class:`IndentedBlock`, that statement will own the 

678 #: comments and lines that are at the same indent as the statement, and this 

679 #: :class:`IndentedBlock` will own the comments and lines that are indented further. 

680 footer: Sequence[EmptyLine] = () 

681 

682 def _validate(self) -> None: 

683 indent = self.indent 

684 if indent is not None: 

685 if len(indent) == 0: 

686 raise CSTValidationError( 

687 "An indented block must have a non-zero width indent." 

688 ) 

689 if _INDENT_WHITESPACE_RE.fullmatch(indent) is None: 

690 raise CSTValidationError( 

691 "An indent must be composed of only whitespace characters." 

692 ) 

693 

694 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "IndentedBlock": 

695 return IndentedBlock( 

696 header=visit_required(self, "header", self.header, visitor), 

697 indent=self.indent, 

698 body=visit_body_sequence(self, "body", self.body, visitor), 

699 footer=visit_sequence(self, "footer", self.footer, visitor), 

700 ) 

701 

702 def _codegen_impl(self, state: CodegenState) -> None: 

703 self.header._codegen(state) 

704 

705 indent = self.indent 

706 state.increase_indent(state.default_indent if indent is None else indent) 

707 

708 if self.body: 

709 with state.record_syntactic_position( 

710 self, start_node=self.body[0], end_node=self.body[-1] 

711 ): 

712 for stmt in self.body: 

713 # IndentedBlock is responsible for adjusting the current indentation level, 

714 # but its children are responsible for actually adding that indentation to 

715 # the token list. 

716 stmt._codegen(state) 

717 else: 

718 # Empty indented blocks are not syntactically valid in Python unless 

719 # they contain a 'pass' statement, so add one here. 

720 state.add_indent_tokens() 

721 with state.record_syntactic_position(self): 

722 state.add_token("pass") 

723 state.add_token(state.default_newline) 

724 

725 for f in self.footer: 

726 f._codegen(state) 

727 

728 state.decrease_indent() 

729 

730 

731@add_slots 

732@dataclass(frozen=True) 

733class AsName(CSTNode): 

734 """ 

735 An ``as name`` clause inside an :class:`ExceptHandler`, :class:`ImportAlias` or 

736 :class:`WithItem` node. 

737 """ 

738 

739 #: Identifier that the parent node will be aliased to. 

740 name: Union[Name, Tuple, List] 

741 

742 #: Whitespace between the parent node and the ``as`` keyword. 

743 whitespace_before_as: BaseParenthesizableWhitespace = SimpleWhitespace.field(" ") 

744 

745 #: Whitespace between the ``as`` keyword and the name. 

746 whitespace_after_as: BaseParenthesizableWhitespace = SimpleWhitespace.field(" ") 

747 

748 def _validate(self) -> None: 

749 if ( 

750 self.whitespace_after_as.empty 

751 and not self.name._safe_to_use_with_word_operator(ExpressionPosition.RIGHT) 

752 ): 

753 raise CSTValidationError( 

754 "There must be at least one space between 'as' and name." 

755 ) 

756 

757 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "AsName": 

758 return AsName( 

759 whitespace_before_as=visit_required( 

760 self, "whitespace_before_as", self.whitespace_before_as, visitor 

761 ), 

762 name=visit_required(self, "name", self.name, visitor), 

763 whitespace_after_as=visit_required( 

764 self, "whitespace_after_as", self.whitespace_after_as, visitor 

765 ), 

766 ) 

767 

768 def _codegen_impl(self, state: CodegenState) -> None: 

769 self.whitespace_before_as._codegen(state) 

770 state.add_token("as") 

771 self.whitespace_after_as._codegen(state) 

772 self.name._codegen(state) 

773 

774 

775@add_slots 

776@dataclass(frozen=True) 

777class ExceptHandler(CSTNode): 

778 """ 

779 An ``except`` clause that appears optionally after a :class:`Try` statement. 

780 """ 

781 

782 #: The body of the except. 

783 body: BaseSuite 

784 

785 #: The type of exception this catches. Can be a tuple in some cases, 

786 #: or ``None`` if the code is catching all exceptions. 

787 type: Optional[BaseExpression] = None 

788 

789 #: The optional name that a caught exception is assigned to. 

790 name: Optional[AsName] = None 

791 

792 #: Sequence of empty lines appearing before this compound statement line. 

793 leading_lines: Sequence[EmptyLine] = () 

794 

795 #: The whitespace between the ``except`` keyword and the type attribute. 

796 whitespace_after_except: SimpleWhitespace = SimpleWhitespace.field(" ") 

797 

798 #: The whitespace after any type or name node (whichever comes last) and 

799 #: the colon. 

800 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

801 

802 def _validate(self) -> None: 

803 name = self.name 

804 if self.type is None and name is not None: 

805 raise CSTValidationError("Cannot have a name for an empty type.") 

806 if name is not None and not isinstance(name.name, Name): 

807 raise CSTValidationError( 

808 "Must use a Name node for AsName name inside ExceptHandler." 

809 ) 

810 type_ = self.type 

811 if type_ is not None and self.whitespace_after_except.empty: 

812 # Space is only required when the first char in `type` could start 

813 # an identifier. In the most common cases, we want to allow 

814 # grouping or tuple parens. 

815 if isinstance(type_, Name) and not type_.lpar: 

816 raise CSTValidationError( 

817 "Must have at least one space after except when ExceptHandler has a type." 

818 ) 

819 name = self.name 

820 if ( 

821 type_ is not None 

822 and name is not None 

823 and name.whitespace_before_as.empty 

824 and not type_._safe_to_use_with_word_operator(ExpressionPosition.LEFT) 

825 ): 

826 raise CSTValidationError( 

827 "Must have at least one space before as keyword in an except handler." 

828 ) 

829 

830 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ExceptHandler": 

831 return ExceptHandler( 

832 leading_lines=visit_sequence( 

833 self, "leading_lines", self.leading_lines, visitor 

834 ), 

835 whitespace_after_except=visit_required( 

836 self, "whitespace_after_except", self.whitespace_after_except, visitor 

837 ), 

838 type=visit_optional(self, "type", self.type, visitor), 

839 name=visit_optional(self, "name", self.name, visitor), 

840 whitespace_before_colon=visit_required( 

841 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

842 ), 

843 body=visit_required(self, "body", self.body, visitor), 

844 ) 

845 

846 def _codegen_impl(self, state: CodegenState) -> None: 

847 for ll in self.leading_lines: 

848 ll._codegen(state) 

849 state.add_indent_tokens() 

850 

851 with state.record_syntactic_position(self, end_node=self.body): 

852 state.add_token("except") 

853 self.whitespace_after_except._codegen(state) 

854 typenode = self.type 

855 if typenode is not None: 

856 typenode._codegen(state) 

857 namenode = self.name 

858 if namenode is not None: 

859 namenode._codegen(state) 

860 self.whitespace_before_colon._codegen(state) 

861 state.add_token(":") 

862 self.body._codegen(state) 

863 

864 

865@add_slots 

866@dataclass(frozen=True) 

867class ExceptStarHandler(CSTNode): 

868 """ 

869 An ``except*`` clause that appears after a :class:`TryStar` statement. 

870 """ 

871 

872 #: The body of the except. 

873 body: BaseSuite 

874 

875 #: The type of exception this catches. Can be a tuple in some cases. 

876 type: BaseExpression 

877 

878 #: The optional name that a caught exception is assigned to. 

879 name: Optional[AsName] = None 

880 

881 #: Sequence of empty lines appearing before this compound statement line. 

882 leading_lines: Sequence[EmptyLine] = () 

883 

884 #: The whitespace between the ``except`` keyword and the star. 

885 whitespace_after_except: SimpleWhitespace = SimpleWhitespace.field("") 

886 

887 #: The whitespace between the star and the type. 

888 whitespace_after_star: SimpleWhitespace = SimpleWhitespace.field(" ") 

889 

890 #: The whitespace after any type or name node (whichever comes last) and 

891 #: the colon. 

892 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

893 

894 def _validate(self) -> None: 

895 name = self.name 

896 if name is not None and not isinstance(name.name, Name): 

897 raise CSTValidationError( 

898 "Must use a Name node for AsName name inside ExceptHandler." 

899 ) 

900 

901 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ExceptStarHandler": 

902 return ExceptStarHandler( 

903 leading_lines=visit_sequence( 

904 self, "leading_lines", self.leading_lines, visitor 

905 ), 

906 whitespace_after_except=visit_required( 

907 self, "whitespace_after_except", self.whitespace_after_except, visitor 

908 ), 

909 whitespace_after_star=visit_required( 

910 self, "whitespace_after_star", self.whitespace_after_star, visitor 

911 ), 

912 type=visit_required(self, "type", self.type, visitor), 

913 name=visit_optional(self, "name", self.name, visitor), 

914 whitespace_before_colon=visit_required( 

915 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

916 ), 

917 body=visit_required(self, "body", self.body, visitor), 

918 ) 

919 

920 def _codegen_impl(self, state: CodegenState) -> None: 

921 for ll in self.leading_lines: 

922 ll._codegen(state) 

923 state.add_indent_tokens() 

924 

925 with state.record_syntactic_position(self, end_node=self.body): 

926 state.add_token("except") 

927 self.whitespace_after_except._codegen(state) 

928 state.add_token("*") 

929 self.whitespace_after_star._codegen(state) 

930 typenode = self.type 

931 if typenode is not None: 

932 typenode._codegen(state) 

933 namenode = self.name 

934 if namenode is not None: 

935 namenode._codegen(state) 

936 self.whitespace_before_colon._codegen(state) 

937 state.add_token(":") 

938 self.body._codegen(state) 

939 

940 

941@add_slots 

942@dataclass(frozen=True) 

943class Finally(CSTNode): 

944 """ 

945 A ``finally`` clause that appears optionally after a :class:`Try` statement. 

946 """ 

947 

948 #: The body of the except. 

949 body: BaseSuite 

950 

951 #: Sequence of empty lines appearing before this compound statement line. 

952 leading_lines: Sequence[EmptyLine] = () 

953 

954 #: The whitespace that appears after the ``finally`` keyword but before 

955 #: the colon. 

956 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

957 

958 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Finally": 

959 return Finally( 

960 leading_lines=visit_sequence( 

961 self, "leading_lines", self.leading_lines, visitor 

962 ), 

963 whitespace_before_colon=visit_required( 

964 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

965 ), 

966 body=visit_required(self, "body", self.body, visitor), 

967 ) 

968 

969 def _codegen_impl(self, state: CodegenState) -> None: 

970 for ll in self.leading_lines: 

971 ll._codegen(state) 

972 state.add_indent_tokens() 

973 

974 with state.record_syntactic_position(self, end_node=self.body): 

975 state.add_token("finally") 

976 self.whitespace_before_colon._codegen(state) 

977 state.add_token(":") 

978 self.body._codegen(state) 

979 

980 

981@add_slots 

982@dataclass(frozen=True) 

983class Try(BaseCompoundStatement): 

984 """ 

985 A regular ``try`` statement that cannot contain :class:`ExceptStar` blocks. For 

986 ``try`` statements that can contain :class:`ExceptStar` blocks, see 

987 :class:`TryStar`. 

988 """ 

989 

990 #: The suite that is wrapped with a try statement. 

991 body: BaseSuite 

992 

993 #: A list of zero or more exception handlers. 

994 handlers: Sequence[ExceptHandler] = () 

995 

996 #: An optional else case. 

997 orelse: Optional[Else] = None 

998 

999 #: An optional finally case. 

1000 finalbody: Optional[Finally] = None 

1001 

1002 #: Sequence of empty lines appearing before this compound statement line. 

1003 leading_lines: Sequence[EmptyLine] = () 

1004 

1005 #: The whitespace that appears after the ``try`` keyword but before 

1006 #: the colon. 

1007 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

1008 

1009 def _validate(self) -> None: 

1010 if len(self.handlers) == 0 and self.finalbody is None: 

1011 raise CSTValidationError( 

1012 "A Try statement must have at least one ExceptHandler or Finally" 

1013 ) 

1014 if len(self.handlers) == 0 and self.orelse is not None: 

1015 raise CSTValidationError( 

1016 "A Try statement must have at least one ExceptHandler in order " 

1017 + "to have an Else." 

1018 ) 

1019 # Check bare excepts are always at the last position 

1020 if any(handler.type is None for handler in self.handlers[:-1]): 

1021 raise CSTValidationError("The bare except: handler must be the last one.") 

1022 

1023 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Try": 

1024 return Try( 

1025 leading_lines=visit_sequence( 

1026 self, "leading_lines", self.leading_lines, visitor 

1027 ), 

1028 whitespace_before_colon=visit_required( 

1029 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1030 ), 

1031 body=visit_required(self, "body", self.body, visitor), 

1032 handlers=visit_sequence(self, "handlers", self.handlers, visitor), 

1033 orelse=visit_optional(self, "orelse", self.orelse, visitor), 

1034 finalbody=visit_optional(self, "finalbody", self.finalbody, visitor), 

1035 ) 

1036 

1037 def _codegen_impl(self, state: CodegenState) -> None: 

1038 for ll in self.leading_lines: 

1039 ll._codegen(state) 

1040 state.add_indent_tokens() 

1041 

1042 end_node = self.body 

1043 if len(self.handlers) > 0: 

1044 end_node = self.handlers[-1] 

1045 orelse = self.orelse 

1046 end_node = end_node if orelse is None else orelse 

1047 finalbody = self.finalbody 

1048 end_node = end_node if finalbody is None else finalbody 

1049 with state.record_syntactic_position(self, end_node=end_node): 

1050 state.add_token("try") 

1051 self.whitespace_before_colon._codegen(state) 

1052 state.add_token(":") 

1053 self.body._codegen(state) 

1054 for handler in self.handlers: 

1055 handler._codegen(state) 

1056 if orelse is not None: 

1057 orelse._codegen(state) 

1058 if finalbody is not None: 

1059 finalbody._codegen(state) 

1060 

1061 

1062@add_slots 

1063@dataclass(frozen=True) 

1064class TryStar(BaseCompoundStatement): 

1065 """ 

1066 A ``try`` statement with ``except*`` blocks. 

1067 """ 

1068 

1069 #: The suite that is wrapped with a try statement. 

1070 body: BaseSuite 

1071 

1072 #: A list of one or more exception handlers. 

1073 handlers: Sequence[ExceptStarHandler] 

1074 

1075 #: An optional else case. 

1076 orelse: Optional[Else] = None 

1077 

1078 #: An optional finally case. 

1079 finalbody: Optional[Finally] = None 

1080 

1081 #: Sequence of empty lines appearing before this compound statement line. 

1082 leading_lines: Sequence[EmptyLine] = () 

1083 

1084 #: The whitespace that appears after the ``try`` keyword but before 

1085 #: the colon. 

1086 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

1087 

1088 def _validate(self) -> None: 

1089 if len(self.handlers) == 0: 

1090 raise CSTValidationError( 

1091 "A TryStar statement must have at least one ExceptHandler" 

1092 ) 

1093 

1094 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TryStar": 

1095 return TryStar( 

1096 leading_lines=visit_sequence( 

1097 self, "leading_lines", self.leading_lines, visitor 

1098 ), 

1099 whitespace_before_colon=visit_required( 

1100 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1101 ), 

1102 body=visit_required(self, "body", self.body, visitor), 

1103 handlers=visit_sequence(self, "handlers", self.handlers, visitor), 

1104 orelse=visit_optional(self, "orelse", self.orelse, visitor), 

1105 finalbody=visit_optional(self, "finalbody", self.finalbody, visitor), 

1106 ) 

1107 

1108 def _codegen_impl(self, state: CodegenState) -> None: 

1109 for ll in self.leading_lines: 

1110 ll._codegen(state) 

1111 state.add_indent_tokens() 

1112 

1113 end_node = self.handlers[-1] 

1114 orelse = self.orelse 

1115 end_node = end_node if orelse is None else orelse 

1116 finalbody = self.finalbody 

1117 end_node = end_node if finalbody is None else finalbody 

1118 with state.record_syntactic_position(self, end_node=end_node): 

1119 state.add_token("try") 

1120 self.whitespace_before_colon._codegen(state) 

1121 state.add_token(":") 

1122 self.body._codegen(state) 

1123 for handler in self.handlers: 

1124 handler._codegen(state) 

1125 if orelse is not None: 

1126 orelse._codegen(state) 

1127 if finalbody is not None: 

1128 finalbody._codegen(state) 

1129 

1130 

1131@add_slots 

1132@dataclass(frozen=True) 

1133class ImportAlias(CSTNode): 

1134 """ 

1135 An import, with an optional :class:`AsName`. Used in both :class:`Import` and 

1136 :class:`ImportFrom` to specify a single import out of another module. 

1137 """ 

1138 

1139 #: Name or Attribute node representing the object we are importing. 

1140 name: Union[Attribute, Name] 

1141 

1142 #: Local alias we will import the above object as. 

1143 asname: Optional[AsName] = None 

1144 

1145 #: Any trailing comma that appears after this import. This is optional for the 

1146 #: last :class:`ImportAlias` in a :class:`Import` or :class:`ImportFrom`, but all 

1147 #: other import aliases inside an import must contain a comma to disambiguate 

1148 #: multiple imports. 

1149 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

1150 

1151 def _validate(self) -> None: 

1152 asname = self.asname 

1153 if asname is not None: 

1154 if not isinstance(asname.name, Name): 

1155 raise CSTValidationError( 

1156 "Must use a Name node for AsName name inside ImportAlias." 

1157 ) 

1158 if asname.whitespace_before_as.empty: 

1159 raise CSTValidationError( 

1160 "Must have at least one space before as keyword in an ImportAlias." 

1161 ) 

1162 try: 

1163 self.evaluated_name 

1164 except Exception as e: 

1165 if str(e) == "Logic error!": 

1166 raise CSTValidationError( 

1167 "The imported name must be a valid qualified name." 

1168 ) 

1169 raise e 

1170 

1171 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ImportAlias": 

1172 return ImportAlias( 

1173 name=visit_required(self, "name", self.name, visitor), 

1174 asname=visit_optional(self, "asname", self.asname, visitor), 

1175 comma=visit_sentinel(self, "comma", self.comma, visitor), 

1176 ) 

1177 

1178 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

1179 with state.record_syntactic_position(self): 

1180 self.name._codegen(state) 

1181 asname = self.asname 

1182 if asname is not None: 

1183 asname._codegen(state) 

1184 

1185 comma = self.comma 

1186 if comma is MaybeSentinel.DEFAULT and default_comma: 

1187 state.add_token(", ") 

1188 elif isinstance(comma, Comma): 

1189 comma._codegen(state) 

1190 

1191 def _name(self, node: CSTNode) -> str: 

1192 # Unrolled version of get_full_name_for_node to avoid circular imports. 

1193 if isinstance(node, Name): 

1194 return node.value 

1195 elif isinstance(node, Attribute): 

1196 return f"{self._name(node.value)}.{node.attr.value}" 

1197 else: 

1198 raise Exception("Logic error!") 

1199 

1200 @property 

1201 def evaluated_name(self) -> str: 

1202 """ 

1203 Returns the string name this :class:`ImportAlias` represents. 

1204 """ 

1205 return self._name(self.name) 

1206 

1207 @property 

1208 def evaluated_alias(self) -> Optional[str]: 

1209 """ 

1210 Returns the string name for any alias that this :class:`ImportAlias` 

1211 has. If there is no ``asname`` attribute, this returns ``None``. 

1212 """ 

1213 asname = self.asname 

1214 if asname is not None: 

1215 return self._name(asname.name) 

1216 return None 

1217 

1218 

1219@add_slots 

1220@dataclass(frozen=True) 

1221class Import(BaseSmallStatement): 

1222 """ 

1223 An ``import`` statement. 

1224 """ 

1225 

1226 #: One or more names that are being imported, with optional local aliases. 

1227 names: Sequence[ImportAlias] 

1228 

1229 #: Optional semicolon when this is used in a statement line. This semicolon 

1230 #: owns the whitespace on both sides of it when it is used. 

1231 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

1232 

1233 #: The whitespace that appears after the ``import`` keyword but before 

1234 #: the first import alias. 

1235 whitespace_after_import: SimpleWhitespace = SimpleWhitespace.field(" ") 

1236 

1237 def _validate(self) -> None: 

1238 if len(self.names) == 0: 

1239 raise CSTValidationError( 

1240 "An ImportStatement must have at least one ImportAlias" 

1241 ) 

1242 if isinstance(self.names[-1].comma, Comma): 

1243 raise CSTValidationError( 

1244 "An ImportStatement does not allow a trailing comma" 

1245 ) 

1246 if self.whitespace_after_import.empty: 

1247 raise CSTValidationError("Must have at least one space after import.") 

1248 

1249 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Import": 

1250 return Import( 

1251 whitespace_after_import=visit_required( 

1252 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1253 ), 

1254 names=visit_sequence(self, "names", self.names, visitor), 

1255 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

1256 ) 

1257 

1258 def _codegen_impl( 

1259 self, state: CodegenState, default_semicolon: bool = False 

1260 ) -> None: 

1261 with state.record_syntactic_position(self): 

1262 state.add_token("import") 

1263 self.whitespace_after_import._codegen(state) 

1264 lastname = len(self.names) - 1 

1265 for i, name in enumerate(self.names): 

1266 name._codegen(state, default_comma=(i != lastname)) 

1267 

1268 semicolon = self.semicolon 

1269 if isinstance(semicolon, MaybeSentinel): 

1270 if default_semicolon: 

1271 state.add_token("; ") 

1272 elif isinstance(semicolon, Semicolon): 

1273 semicolon._codegen(state) 

1274 

1275 

1276@add_slots 

1277@dataclass(frozen=True) 

1278class ImportFrom(BaseSmallStatement): 

1279 """ 

1280 A ``from x import y`` statement. 

1281 """ 

1282 

1283 #: Name or Attribute node representing the module we're importing from. 

1284 #: This is optional as :class:`ImportFrom` allows purely relative imports. 

1285 module: Optional[Union[Attribute, Name]] 

1286 

1287 #: One or more names that are being imported from the specified module, 

1288 #: with optional local aliases. 

1289 names: Union[Sequence[ImportAlias], ImportStar] 

1290 

1291 #: Sequence of :class:`Dot` nodes indicating relative import level. 

1292 relative: Sequence[Dot] = () 

1293 

1294 #: Optional open parenthesis for multi-line import continuation. 

1295 lpar: Optional[LeftParen] = None 

1296 

1297 #: Optional close parenthesis for multi-line import continuation. 

1298 rpar: Optional[RightParen] = None 

1299 

1300 #: Optional semicolon when this is used in a statement line. This semicolon 

1301 #: owns the whitespace on both sides of it when it is used. 

1302 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

1303 

1304 #: The whitespace that appears after the ``from`` keyword but before 

1305 #: the module and any relative import dots. 

1306 whitespace_after_from: SimpleWhitespace = SimpleWhitespace.field(" ") 

1307 

1308 #: The whitespace that appears after the module but before the 

1309 #: ``import`` keyword. 

1310 whitespace_before_import: SimpleWhitespace = SimpleWhitespace.field(" ") 

1311 

1312 #: The whitespace that appears after the ``import`` keyword but 

1313 #: before the first import name or optional left paren. 

1314 whitespace_after_import: SimpleWhitespace = SimpleWhitespace.field(" ") 

1315 

1316 def _validate_module(self) -> None: 

1317 if self.module is None and len(self.relative) == 0: 

1318 raise CSTValidationError( 

1319 "Must have a module specified if there is no relative import." 

1320 ) 

1321 

1322 def _validate_names(self) -> None: 

1323 names = self.names 

1324 if isinstance(names, Sequence): 

1325 if len(names) == 0: 

1326 raise CSTValidationError( 

1327 "An ImportFrom must have at least one ImportAlias" 

1328 ) 

1329 for name in names[:-1]: 

1330 if name.comma is None: 

1331 raise CSTValidationError("Non-final ImportAliases require a comma") 

1332 if self.lpar is not None and self.rpar is None: 

1333 raise CSTValidationError("Cannot have left paren without right paren.") 

1334 if self.lpar is None and self.rpar is not None: 

1335 raise CSTValidationError("Cannot have right paren without left paren.") 

1336 if isinstance(names, ImportStar): 

1337 if self.lpar is not None or self.rpar is not None: 

1338 raise CSTValidationError( 

1339 "An ImportFrom using ImportStar cannot have parens" 

1340 ) 

1341 

1342 def _validate_whitespace(self) -> None: 

1343 if self.whitespace_after_from.empty and not self.relative: 

1344 raise CSTValidationError("Must have at least one space after from.") 

1345 if self.whitespace_before_import.empty and not ( 

1346 self.relative and self.module is None 

1347 ): 

1348 raise CSTValidationError("Must have at least one space before import.") 

1349 if ( 

1350 self.whitespace_after_import.empty 

1351 and self.lpar is None 

1352 and not isinstance(self.names, ImportStar) 

1353 ): 

1354 raise CSTValidationError("Must have at least one space after import.") 

1355 

1356 def _validate(self) -> None: 

1357 self._validate_module() 

1358 self._validate_names() 

1359 self._validate_whitespace() 

1360 

1361 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ImportFrom": 

1362 names = self.names 

1363 return ImportFrom( 

1364 whitespace_after_from=visit_required( 

1365 self, "whitespace_after_from", self.whitespace_after_from, visitor 

1366 ), 

1367 relative=visit_sequence(self, "relative", self.relative, visitor), 

1368 module=visit_optional(self, "module", self.module, visitor), 

1369 whitespace_before_import=visit_required( 

1370 self, "whitespace_before_import", self.whitespace_before_import, visitor 

1371 ), 

1372 whitespace_after_import=visit_required( 

1373 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1374 ), 

1375 lpar=visit_optional(self, "lpar", self.lpar, visitor), 

1376 names=( 

1377 visit_required(self, "names", names, visitor) 

1378 if isinstance(names, ImportStar) 

1379 else visit_sequence(self, "names", names, visitor) 

1380 ), 

1381 rpar=visit_optional(self, "rpar", self.rpar, visitor), 

1382 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

1383 ) 

1384 

1385 def _codegen_impl( 

1386 self, state: CodegenState, default_semicolon: bool = False 

1387 ) -> None: 

1388 names = self.names 

1389 end_node = names[-1] if isinstance(names, Sequence) else names 

1390 end_node = end_node if self.rpar is None else self.rpar 

1391 with state.record_syntactic_position(self, end_node=end_node): 

1392 state.add_token("from") 

1393 self.whitespace_after_from._codegen(state) 

1394 for dot in self.relative: 

1395 dot._codegen(state) 

1396 module = self.module 

1397 if module is not None: 

1398 module._codegen(state) 

1399 self.whitespace_before_import._codegen(state) 

1400 state.add_token("import") 

1401 self.whitespace_after_import._codegen(state) 

1402 lpar = self.lpar 

1403 if lpar is not None: 

1404 lpar._codegen(state) 

1405 if isinstance(names, Sequence): 

1406 lastname = len(names) - 1 

1407 for i, name in enumerate(names): 

1408 name._codegen(state, default_comma=(i != lastname)) 

1409 if isinstance(names, ImportStar): 

1410 names._codegen(state) 

1411 rpar = self.rpar 

1412 if rpar is not None: 

1413 rpar._codegen(state) 

1414 

1415 semicolon = self.semicolon 

1416 if isinstance(semicolon, MaybeSentinel): 

1417 if default_semicolon: 

1418 state.add_token("; ") 

1419 elif isinstance(semicolon, Semicolon): 

1420 semicolon._codegen(state) 

1421 

1422 

1423@add_slots 

1424@dataclass(frozen=True) 

1425class AssignTarget(CSTNode): 

1426 """ 

1427 A target for an :class:`Assign`. Owns the equals sign and the whitespace around it. 

1428 """ 

1429 

1430 #: The target expression being assigned to. 

1431 target: BaseAssignTargetExpression 

1432 

1433 #: The whitespace appearing before the equals sign. 

1434 whitespace_before_equal: SimpleWhitespace = SimpleWhitespace.field(" ") 

1435 

1436 #: The whitespace appearing after the equals sign. 

1437 whitespace_after_equal: SimpleWhitespace = SimpleWhitespace.field(" ") 

1438 

1439 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "AssignTarget": 

1440 return AssignTarget( 

1441 target=visit_required(self, "target", self.target, visitor), 

1442 whitespace_before_equal=visit_required( 

1443 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

1444 ), 

1445 whitespace_after_equal=visit_required( 

1446 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

1447 ), 

1448 ) 

1449 

1450 def _codegen_impl(self, state: CodegenState) -> None: 

1451 with state.record_syntactic_position(self): 

1452 self.target._codegen(state) 

1453 

1454 self.whitespace_before_equal._codegen(state) 

1455 state.add_token("=") 

1456 self.whitespace_after_equal._codegen(state) 

1457 

1458 

1459@add_slots 

1460@dataclass(frozen=True) 

1461class Assign(BaseSmallStatement): 

1462 """ 

1463 An assignment statement such as ``x = y`` or ``x = y = z``. Unlike 

1464 :class:`AnnAssign`, this does not allow type annotations but does 

1465 allow for multiple targets. 

1466 """ 

1467 

1468 #: One or more targets that are being assigned to. 

1469 targets: Sequence[AssignTarget] 

1470 

1471 #: The expression being assigned to the targets. 

1472 value: BaseExpression 

1473 

1474 #: Optional semicolon when this is used in a statement line. This semicolon 

1475 #: owns the whitespace on both sides of it when it is used. 

1476 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

1477 

1478 def _validate(self) -> None: 

1479 if len(self.targets) == 0: 

1480 raise CSTValidationError( 

1481 "An Assign statement must have at least one AssignTarget" 

1482 ) 

1483 

1484 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Assign": 

1485 return Assign( 

1486 targets=visit_sequence(self, "targets", self.targets, visitor), 

1487 value=visit_required(self, "value", self.value, visitor), 

1488 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

1489 ) 

1490 

1491 def _codegen_impl( 

1492 self, state: CodegenState, default_semicolon: bool = False 

1493 ) -> None: 

1494 with state.record_syntactic_position(self): 

1495 for target in self.targets: 

1496 target._codegen(state) 

1497 self.value._codegen(state) 

1498 

1499 semicolon = self.semicolon 

1500 if isinstance(semicolon, MaybeSentinel): 

1501 if default_semicolon: 

1502 state.add_token("; ") 

1503 elif isinstance(semicolon, Semicolon): 

1504 semicolon._codegen(state) 

1505 

1506 

1507@add_slots 

1508@dataclass(frozen=True) 

1509class AnnAssign(BaseSmallStatement): 

1510 """ 

1511 An assignment statement such as ``x: int = 5`` or ``x: int``. This only 

1512 allows for one assignment target unlike :class:`Assign` but it includes 

1513 a variable annotation. Also unlike :class:`Assign`, the assignment target 

1514 is optional, as it is possible to annotate an expression without assigning 

1515 to it. 

1516 """ 

1517 

1518 #: The target that is being annotated and possibly assigned to. 

1519 target: BaseAssignTargetExpression 

1520 

1521 #: The annotation for the target. 

1522 annotation: Annotation 

1523 

1524 #: The optional expression being assigned to the target. 

1525 value: Optional[BaseExpression] = None 

1526 

1527 #: The equals sign used to denote assignment if there is a value. 

1528 equal: Union[AssignEqual, MaybeSentinel] = MaybeSentinel.DEFAULT 

1529 

1530 #: Optional semicolon when this is used in a statement line. This semicolon 

1531 #: owns the whitespace on both sides of it when it is used. 

1532 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

1533 

1534 def _validate(self) -> None: 

1535 if self.value is None and isinstance(self.equal, AssignEqual): 

1536 raise CSTValidationError( 

1537 "Must have a value when specifying an AssignEqual." 

1538 ) 

1539 

1540 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "AnnAssign": 

1541 return AnnAssign( 

1542 target=visit_required(self, "target", self.target, visitor), 

1543 annotation=visit_required(self, "annotation", self.annotation, visitor), 

1544 equal=visit_sentinel(self, "equal", self.equal, visitor), 

1545 value=visit_optional(self, "value", self.value, visitor), 

1546 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

1547 ) 

1548 

1549 def _codegen_impl( 

1550 self, state: CodegenState, default_semicolon: bool = False 

1551 ) -> None: 

1552 with state.record_syntactic_position(self): 

1553 self.target._codegen(state) 

1554 self.annotation._codegen(state, default_indicator=":") 

1555 equal = self.equal 

1556 if equal is MaybeSentinel.DEFAULT and self.value is not None: 

1557 state.add_token(" = ") 

1558 elif isinstance(equal, AssignEqual): 

1559 equal._codegen(state) 

1560 value = self.value 

1561 if value is not None: 

1562 value._codegen(state) 

1563 

1564 semicolon = self.semicolon 

1565 if isinstance(semicolon, MaybeSentinel): 

1566 if default_semicolon: 

1567 state.add_token("; ") 

1568 elif isinstance(semicolon, Semicolon): 

1569 semicolon._codegen(state) 

1570 

1571 

1572@add_slots 

1573@dataclass(frozen=True) 

1574class AugAssign(BaseSmallStatement): 

1575 """ 

1576 An augmented assignment statement, such as ``x += 5``. 

1577 """ 

1578 

1579 #: Target that is being operated on and assigned to. 

1580 target: BaseAssignTargetExpression 

1581 

1582 #: The augmented assignment operation being performed. 

1583 operator: BaseAugOp 

1584 

1585 #: The value used with the above operator to calculate the new assignment. 

1586 value: BaseExpression 

1587 

1588 #: Optional semicolon when this is used in a statement line. This semicolon 

1589 #: owns the whitespace on both sides of it when it is used. 

1590 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

1591 

1592 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "AugAssign": 

1593 return AugAssign( 

1594 target=visit_required(self, "target", self.target, visitor), 

1595 operator=visit_required(self, "operator", self.operator, visitor), 

1596 value=visit_required(self, "value", self.value, visitor), 

1597 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

1598 ) 

1599 

1600 def _codegen_impl( 

1601 self, state: CodegenState, default_semicolon: bool = False 

1602 ) -> None: 

1603 with state.record_syntactic_position(self): 

1604 self.target._codegen(state) 

1605 self.operator._codegen(state) 

1606 self.value._codegen(state) 

1607 

1608 semicolon = self.semicolon 

1609 if isinstance(semicolon, MaybeSentinel): 

1610 if default_semicolon: 

1611 state.add_token("; ") 

1612 elif isinstance(semicolon, Semicolon): 

1613 semicolon._codegen(state) 

1614 

1615 

1616@add_slots 

1617@dataclass(frozen=True) 

1618class Decorator(CSTNode): 

1619 """ 

1620 A single decorator that decorates a :class:`FunctionDef` or a :class:`ClassDef`. 

1621 """ 

1622 

1623 #: The decorator that will return a new function wrapping the parent 

1624 #: of this decorator. 

1625 decorator: BaseExpression 

1626 

1627 #: Line comments and empty lines before this decorator. The parent 

1628 #: :class:`FunctionDef` or :class:`ClassDef` node owns leading lines before 

1629 #: the first decorator so that if the first decorator is removed, spacing is preserved. 

1630 leading_lines: Sequence[EmptyLine] = () 

1631 

1632 #: Whitespace after the ``@`` and before the decorator expression itself. 

1633 whitespace_after_at: SimpleWhitespace = SimpleWhitespace.field("") 

1634 

1635 #: Optional trailing comment and newline following the decorator before the next line. 

1636 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

1637 

1638 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Decorator": 

1639 return Decorator( 

1640 leading_lines=visit_sequence( 

1641 self, "leading_lines", self.leading_lines, visitor 

1642 ), 

1643 whitespace_after_at=visit_required( 

1644 self, "whitespace_after_at", self.whitespace_after_at, visitor 

1645 ), 

1646 decorator=visit_required(self, "decorator", self.decorator, visitor), 

1647 trailing_whitespace=visit_required( 

1648 self, "trailing_whitespace", self.trailing_whitespace, visitor 

1649 ), 

1650 ) 

1651 

1652 def _codegen_impl(self, state: CodegenState) -> None: 

1653 for ll in self.leading_lines: 

1654 ll._codegen(state) 

1655 state.add_indent_tokens() 

1656 

1657 with state.record_syntactic_position(self): 

1658 state.add_token("@") 

1659 self.whitespace_after_at._codegen(state) 

1660 self.decorator._codegen(state) 

1661 

1662 self.trailing_whitespace._codegen(state) 

1663 

1664 

1665def get_docstring_impl( 

1666 body: Union[BaseSuite, Sequence[Union[SimpleStatementLine, BaseCompoundStatement]]], 

1667 clean: bool, 

1668) -> Optional[str]: 

1669 """ 

1670 Implementation Reference: 

1671 - :func:`ast.get_docstring` https://docs.python.org/3/library/ast.html#ast.get_docstring 

1672 and https://github.com/python/cpython/blob/89aa4694fc8c6d190325ef8ed6ce6a6b8efb3e50/Lib/ast.py#L254 

1673 - PEP 257 https://www.python.org/dev/peps/pep-0257/ 

1674 """ 

1675 if isinstance(body, Sequence): 

1676 if body: 

1677 expr = body[0] 

1678 else: 

1679 return None 

1680 else: 

1681 expr = body 

1682 while isinstance(expr, (BaseSuite, SimpleStatementLine)): 

1683 if len(expr.body) == 0: 

1684 return None 

1685 expr = expr.body[0] 

1686 if not isinstance(expr, Expr): 

1687 return None 

1688 val = expr.value 

1689 if isinstance(val, (SimpleString, ConcatenatedString)): 

1690 evaluated_value = val.evaluated_value 

1691 else: 

1692 return None 

1693 if isinstance(evaluated_value, bytes): 

1694 return None 

1695 

1696 if evaluated_value is not None and clean: 

1697 return inspect.cleandoc(evaluated_value) 

1698 return evaluated_value 

1699 

1700 

1701@add_slots 

1702@dataclass(frozen=True) 

1703class FunctionDef(BaseCompoundStatement): 

1704 """ 

1705 A function definition. 

1706 """ 

1707 

1708 #: The function name. 

1709 name: Name 

1710 

1711 #: The function parameters. Present even if there are no params. 

1712 params: Parameters 

1713 

1714 #: The function body. 

1715 body: BaseSuite 

1716 

1717 #: Sequence of decorators applied to this function. Decorators are listed in 

1718 #: order that they appear in source (top to bottom) as apposed to the order 

1719 #: that they are applied to the function at runtime. 

1720 decorators: Sequence[Decorator] = () 

1721 

1722 #: An optional return annotation, if the function is annotated. 

1723 returns: Optional[Annotation] = None 

1724 

1725 #: Optional async modifier, if this is an async function. 

1726 asynchronous: Optional[Asynchronous] = None 

1727 

1728 #: Leading empty lines and comments before the first decorator. We 

1729 #: assume any comments before the first decorator are owned by the 

1730 #: function definition itself. If there are no decorators, this will 

1731 #: still contain all of the empty lines and comments before the 

1732 #: function definition. 

1733 leading_lines: Sequence[EmptyLine] = () 

1734 

1735 #: Empty lines and comments between the final decorator and the 

1736 #: :class:`FunctionDef` node. In the case of no decorators, this will be empty. 

1737 lines_after_decorators: Sequence[EmptyLine] = () 

1738 

1739 #: Whitespace after the ``def`` keyword and before the function name. 

1740 whitespace_after_def: SimpleWhitespace = SimpleWhitespace.field(" ") 

1741 

1742 #: Whitespace after the function name and before the type parameters or the opening 

1743 #: parenthesis for the parameters. 

1744 whitespace_after_name: SimpleWhitespace = SimpleWhitespace.field("") 

1745 

1746 #: Whitespace after the opening parenthesis for the parameters but before 

1747 #: the first param itself. 

1748 whitespace_before_params: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

1749 

1750 #: Whitespace after the closing parenthesis or return annotation and before 

1751 #: the colon. 

1752 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

1753 

1754 #: An optional declaration of type parameters. 

1755 type_parameters: Optional["TypeParameters"] = None 

1756 

1757 #: Whitespace between the type parameters and the opening parenthesis for the 

1758 #: (non-type) parameters. 

1759 whitespace_after_type_parameters: SimpleWhitespace = SimpleWhitespace.field("") 

1760 

1761 def _validate(self) -> None: 

1762 if len(self.name.lpar) > 0 or len(self.name.rpar) > 0: 

1763 raise CSTValidationError("Cannot have parens around Name in a FunctionDef.") 

1764 if self.whitespace_after_def.empty: 

1765 raise CSTValidationError( 

1766 "There must be at least one space between 'def' and name." 

1767 ) 

1768 

1769 if ( 

1770 self.type_parameters is None 

1771 and not self.whitespace_after_type_parameters.empty 

1772 ): 

1773 raise CSTValidationError( 

1774 "whitespace_after_type_parameters must be empty if there are no type " 

1775 "parameters in FunctionDef" 

1776 ) 

1777 

1778 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "FunctionDef": 

1779 return FunctionDef( 

1780 leading_lines=visit_sequence( 

1781 self, "leading_lines", self.leading_lines, visitor 

1782 ), 

1783 decorators=visit_sequence(self, "decorators", self.decorators, visitor), 

1784 lines_after_decorators=visit_sequence( 

1785 self, "lines_after_decorators", self.lines_after_decorators, visitor 

1786 ), 

1787 asynchronous=visit_optional( 

1788 self, "asynchronous", self.asynchronous, visitor 

1789 ), 

1790 whitespace_after_def=visit_required( 

1791 self, "whitespace_after_def", self.whitespace_after_def, visitor 

1792 ), 

1793 name=visit_required(self, "name", self.name, visitor), 

1794 whitespace_after_name=visit_required( 

1795 self, "whitespace_after_name", self.whitespace_after_name, visitor 

1796 ), 

1797 type_parameters=visit_optional( 

1798 self, "type_parameters", self.type_parameters, visitor 

1799 ), 

1800 whitespace_after_type_parameters=visit_required( 

1801 self, 

1802 "whitespace_after_type_parameters", 

1803 self.whitespace_after_type_parameters, 

1804 visitor, 

1805 ), 

1806 whitespace_before_params=visit_required( 

1807 self, "whitespace_before_params", self.whitespace_before_params, visitor 

1808 ), 

1809 params=visit_required(self, "params", self.params, visitor), 

1810 returns=visit_optional(self, "returns", self.returns, visitor), 

1811 whitespace_before_colon=visit_required( 

1812 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1813 ), 

1814 body=visit_required(self, "body", self.body, visitor), 

1815 ) 

1816 

1817 def _codegen_impl(self, state: CodegenState) -> None: 

1818 for ll in self.leading_lines: 

1819 ll._codegen(state) 

1820 for decorator in self.decorators: 

1821 decorator._codegen(state) 

1822 for lad in self.lines_after_decorators: 

1823 lad._codegen(state) 

1824 state.add_indent_tokens() 

1825 

1826 with state.record_syntactic_position(self, end_node=self.body): 

1827 asynchronous = self.asynchronous 

1828 if asynchronous is not None: 

1829 asynchronous._codegen(state) 

1830 state.add_token("def") 

1831 self.whitespace_after_def._codegen(state) 

1832 self.name._codegen(state) 

1833 self.whitespace_after_name._codegen(state) 

1834 type_params = self.type_parameters 

1835 if type_params is not None: 

1836 type_params._codegen(state) 

1837 self.whitespace_after_type_parameters._codegen(state) 

1838 state.add_token("(") 

1839 self.whitespace_before_params._codegen(state) 

1840 self.params._codegen(state) 

1841 state.add_token(")") 

1842 returns = self.returns 

1843 if returns is not None: 

1844 returns._codegen(state, default_indicator="->") 

1845 self.whitespace_before_colon._codegen(state) 

1846 state.add_token(":") 

1847 self.body._codegen(state) 

1848 

1849 def get_docstring(self, clean: bool = True) -> Optional[str]: 

1850 """ 

1851 When docstring is available, returns a :func:`inspect.cleandoc` cleaned docstring. 

1852 Otherwise, returns ``None``. 

1853 """ 

1854 return get_docstring_impl(self.body, clean) 

1855 

1856 

1857@add_slots 

1858@dataclass(frozen=True) 

1859class ClassDef(BaseCompoundStatement): 

1860 """ 

1861 A class definition. 

1862 """ 

1863 

1864 #: The class name. 

1865 name: Name 

1866 

1867 #: The class body. 

1868 body: BaseSuite 

1869 

1870 #: Sequence of base classes this class inherits from. 

1871 bases: Sequence[Arg] = () 

1872 

1873 #: Sequence of keywords, such as "metaclass". 

1874 keywords: Sequence[Arg] = () 

1875 

1876 #: Sequence of decorators applied to this class. 

1877 decorators: Sequence[Decorator] = () 

1878 

1879 #: Optional open parenthesis used when there are bases or keywords. 

1880 lpar: Union[LeftParen, MaybeSentinel] = MaybeSentinel.DEFAULT 

1881 

1882 #: Optional close parenthesis used when there are bases or keywords. 

1883 rpar: Union[RightParen, MaybeSentinel] = MaybeSentinel.DEFAULT 

1884 

1885 #: Leading empty lines and comments before the first decorator. We 

1886 #: assume any comments before the first decorator are owned by the 

1887 #: class definition itself. If there are no decorators, this will 

1888 #: still contain all of the empty lines and comments before the 

1889 #: class definition. 

1890 leading_lines: Sequence[EmptyLine] = () 

1891 

1892 #: Empty lines and comments between the final decorator and the 

1893 #: :class:`ClassDef` node. In the case of no decorators, this will be empty. 

1894 lines_after_decorators: Sequence[EmptyLine] = () 

1895 

1896 #: Whitespace after the ``class`` keyword and before the class name. 

1897 whitespace_after_class: SimpleWhitespace = SimpleWhitespace.field(" ") 

1898 

1899 #: Whitespace after the class name and before the type parameters or the opening 

1900 #: parenthesis for the bases and keywords. 

1901 whitespace_after_name: SimpleWhitespace = SimpleWhitespace.field("") 

1902 

1903 #: Whitespace after the closing parenthesis or class name and before 

1904 #: the colon. 

1905 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

1906 

1907 #: An optional declaration of type parameters. 

1908 type_parameters: Optional["TypeParameters"] = None 

1909 

1910 #: Whitespace between type parameters and opening parenthesis for the bases and 

1911 #: keywords. 

1912 whitespace_after_type_parameters: SimpleWhitespace = SimpleWhitespace.field("") 

1913 

1914 def _validate_whitespace(self) -> None: 

1915 if self.whitespace_after_class.empty: 

1916 raise CSTValidationError( 

1917 "There must be at least one space between 'class' and name." 

1918 ) 

1919 if ( 

1920 self.type_parameters is None 

1921 and not self.whitespace_after_type_parameters.empty 

1922 ): 

1923 raise CSTValidationError( 

1924 "whitespace_after_type_parameters must be empty if there are no type" 

1925 "parameters in a ClassDef" 

1926 ) 

1927 

1928 def _validate_parens(self) -> None: 

1929 if len(self.name.lpar) > 0 or len(self.name.rpar) > 0: 

1930 raise CSTValidationError("Cannot have parens around Name in a ClassDef.") 

1931 if isinstance(self.lpar, MaybeSentinel) and isinstance(self.rpar, RightParen): 

1932 raise CSTValidationError( 

1933 "Do not mix concrete LeftParen/RightParen with MaybeSentinel." 

1934 ) 

1935 if isinstance(self.lpar, LeftParen) and isinstance(self.rpar, MaybeSentinel): 

1936 raise CSTValidationError( 

1937 "Do not mix concrete LeftParen/RightParen with MaybeSentinel." 

1938 ) 

1939 

1940 def _validate_args(self) -> None: 

1941 if any((arg.keyword is not None) for arg in self.bases): 

1942 raise CSTValidationError("Bases must be arguments without keywords.") 

1943 if any((arg.keyword is None and arg.star != "**") for arg in self.keywords): 

1944 raise CSTValidationError( 

1945 "Keywords must be arguments with keywords or dictionary expansions." 

1946 ) 

1947 

1948 def _validate(self) -> None: 

1949 self._validate_whitespace() 

1950 self._validate_parens() 

1951 self._validate_args() 

1952 

1953 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ClassDef": 

1954 return ClassDef( 

1955 leading_lines=visit_sequence( 

1956 self, "leading_lines", self.leading_lines, visitor 

1957 ), 

1958 decorators=visit_sequence(self, "decorators", self.decorators, visitor), 

1959 lines_after_decorators=visit_sequence( 

1960 self, "lines_after_decorators", self.lines_after_decorators, visitor 

1961 ), 

1962 whitespace_after_class=visit_required( 

1963 self, "whitespace_after_class", self.whitespace_after_class, visitor 

1964 ), 

1965 name=visit_required(self, "name", self.name, visitor), 

1966 whitespace_after_name=visit_required( 

1967 self, "whitespace_after_name", self.whitespace_after_name, visitor 

1968 ), 

1969 type_parameters=visit_optional( 

1970 self, "type_parameters", self.type_parameters, visitor 

1971 ), 

1972 whitespace_after_type_parameters=visit_required( 

1973 self, 

1974 "whitespace_after_type_parameters", 

1975 self.whitespace_after_type_parameters, 

1976 visitor, 

1977 ), 

1978 lpar=visit_sentinel(self, "lpar", self.lpar, visitor), 

1979 bases=visit_sequence(self, "bases", self.bases, visitor), 

1980 keywords=visit_sequence(self, "keywords", self.keywords, visitor), 

1981 rpar=visit_sentinel(self, "rpar", self.rpar, visitor), 

1982 whitespace_before_colon=visit_required( 

1983 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1984 ), 

1985 body=visit_required(self, "body", self.body, visitor), 

1986 ) 

1987 

1988 def _codegen_impl(self, state: CodegenState) -> None: # noqa: C901 

1989 for ll in self.leading_lines: 

1990 ll._codegen(state) 

1991 for decorator in self.decorators: 

1992 decorator._codegen(state) 

1993 for lad in self.lines_after_decorators: 

1994 lad._codegen(state) 

1995 state.add_indent_tokens() 

1996 

1997 with state.record_syntactic_position(self, end_node=self.body): 

1998 state.add_token("class") 

1999 self.whitespace_after_class._codegen(state) 

2000 self.name._codegen(state) 

2001 self.whitespace_after_name._codegen(state) 

2002 type_params = self.type_parameters 

2003 if type_params is not None: 

2004 type_params._codegen(state) 

2005 self.whitespace_after_type_parameters._codegen(state) 

2006 lpar = self.lpar 

2007 if isinstance(lpar, MaybeSentinel): 

2008 if self.bases or self.keywords: 

2009 state.add_token("(") 

2010 elif isinstance(lpar, LeftParen): 

2011 lpar._codegen(state) 

2012 args = [*self.bases, *self.keywords] 

2013 last_arg = len(args) - 1 

2014 for i, arg in enumerate(args): 

2015 arg._codegen(state, default_comma=(i != last_arg)) 

2016 rpar = self.rpar 

2017 if isinstance(rpar, MaybeSentinel): 

2018 if self.bases or self.keywords: 

2019 state.add_token(")") 

2020 elif isinstance(rpar, RightParen): 

2021 rpar._codegen(state) 

2022 self.whitespace_before_colon._codegen(state) 

2023 state.add_token(":") 

2024 self.body._codegen(state) 

2025 

2026 def get_docstring(self, clean: bool = True) -> Optional[str]: 

2027 """ 

2028 Returns a :func:`inspect.cleandoc` cleaned docstring if the docstring is available, ``None`` otherwise. 

2029 """ 

2030 return get_docstring_impl(self.body, clean) 

2031 

2032 

2033@add_slots 

2034@dataclass(frozen=True) 

2035class WithItem(CSTNode): 

2036 """ 

2037 A single context manager in a :class:`With` block, with an optional variable name. 

2038 """ 

2039 

2040 #: Expression that evaluates to a context manager. 

2041 item: BaseExpression 

2042 

2043 #: Variable to assign the context manager to, if it is needed in the 

2044 #: :class:`With` body. 

2045 asname: Optional[AsName] = None 

2046 

2047 #: This is forbidden for the last :class:`WithItem` in a :class:`With`, but all 

2048 #: other items inside a with block must contain a comma to separate them. 

2049 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

2050 

2051 def _validate(self) -> None: 

2052 asname = self.asname 

2053 if ( 

2054 asname is not None 

2055 and asname.whitespace_before_as.empty 

2056 and not self.item._safe_to_use_with_word_operator(ExpressionPosition.LEFT) 

2057 ): 

2058 raise CSTValidationError("Must have at least one space before as keyword.") 

2059 

2060 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "WithItem": 

2061 return WithItem( 

2062 item=visit_required(self, "item", self.item, visitor), 

2063 asname=visit_optional(self, "asname", self.asname, visitor), 

2064 comma=visit_sentinel(self, "comma", self.comma, visitor), 

2065 ) 

2066 

2067 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

2068 with state.record_syntactic_position(self): 

2069 self.item._codegen(state) 

2070 asname = self.asname 

2071 if asname is not None: 

2072 asname._codegen(state) 

2073 

2074 comma = self.comma 

2075 if comma is MaybeSentinel.DEFAULT and default_comma: 

2076 state.add_token(", ") 

2077 elif isinstance(comma, Comma): 

2078 comma._codegen(state) 

2079 

2080 

2081@add_slots 

2082@dataclass(frozen=True) 

2083class With(BaseCompoundStatement): 

2084 """ 

2085 A ``with`` statement. 

2086 """ 

2087 

2088 #: A sequence of one or more items that evaluate to context managers. 

2089 items: Sequence[WithItem] 

2090 

2091 #: The suite that is wrapped with this statement. 

2092 body: BaseSuite 

2093 

2094 #: Optional async modifier if this is an ``async with`` statement. 

2095 asynchronous: Optional[Asynchronous] = None 

2096 

2097 #: Sequence of empty lines appearing before this with statement. 

2098 leading_lines: Sequence[EmptyLine] = () 

2099 

2100 #: Optional open parenthesis for multi-line with bindings 

2101 lpar: Union[LeftParen, MaybeSentinel] = MaybeSentinel.DEFAULT 

2102 

2103 #: Optional close parenthesis for multi-line with bindings 

2104 rpar: Union[RightParen, MaybeSentinel] = MaybeSentinel.DEFAULT 

2105 

2106 #: Whitespace after the ``with`` keyword and before the first item. 

2107 whitespace_after_with: SimpleWhitespace = SimpleWhitespace.field(" ") 

2108 

2109 #: Whitespace after the last item and before the colon. 

2110 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

2111 

2112 def _validate_parens(self) -> None: 

2113 if isinstance(self.lpar, MaybeSentinel) and isinstance(self.rpar, RightParen): 

2114 raise CSTValidationError( 

2115 "Do not mix concrete LeftParen/RightParen with MaybeSentinel." 

2116 ) 

2117 if isinstance(self.lpar, LeftParen) and isinstance(self.rpar, MaybeSentinel): 

2118 raise CSTValidationError( 

2119 "Do not mix concrete LeftParen/RightParen with MaybeSentinel." 

2120 ) 

2121 

2122 def _validate(self) -> None: 

2123 self._validate_parens() 

2124 if len(self.items) == 0: 

2125 raise CSTValidationError( 

2126 "A With statement must have at least one WithItem." 

2127 ) 

2128 if ( 

2129 isinstance(self.rpar, MaybeSentinel) 

2130 and self.items[-1].comma != MaybeSentinel.DEFAULT 

2131 ): 

2132 raise CSTValidationError( 

2133 "The last WithItem in an unparenthesized With cannot have a trailing comma." 

2134 ) 

2135 if self.whitespace_after_with.empty and not ( 

2136 isinstance(self.lpar, LeftParen) 

2137 or self.items[0].item._safe_to_use_with_word_operator( 

2138 ExpressionPosition.RIGHT 

2139 ) 

2140 ): 

2141 raise CSTValidationError("Must have at least one space after with keyword.") 

2142 

2143 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "With": 

2144 return With( 

2145 leading_lines=visit_sequence( 

2146 self, "leading_lines", self.leading_lines, visitor 

2147 ), 

2148 asynchronous=visit_optional( 

2149 self, "asynchronous", self.asynchronous, visitor 

2150 ), 

2151 whitespace_after_with=visit_required( 

2152 self, "whitespace_after_with", self.whitespace_after_with, visitor 

2153 ), 

2154 lpar=visit_sentinel(self, "lpar", self.lpar, visitor), 

2155 items=visit_sequence(self, "items", self.items, visitor), 

2156 rpar=visit_sentinel(self, "rpar", self.rpar, visitor), 

2157 whitespace_before_colon=visit_required( 

2158 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2159 ), 

2160 body=visit_required(self, "body", self.body, visitor), 

2161 ) 

2162 

2163 def _codegen_impl(self, state: CodegenState) -> None: 

2164 for ll in self.leading_lines: 

2165 ll._codegen(state) 

2166 state.add_indent_tokens() 

2167 

2168 needs_paren = False 

2169 for item in self.items: 

2170 comma = item.comma 

2171 if isinstance(comma, Comma): 

2172 if isinstance( 

2173 comma.whitespace_after, 

2174 (EmptyLine, TrailingWhitespace, ParenthesizedWhitespace), 

2175 ): 

2176 needs_paren = True 

2177 break 

2178 

2179 with state.record_syntactic_position(self, end_node=self.body): 

2180 asynchronous = self.asynchronous 

2181 if asynchronous is not None: 

2182 asynchronous._codegen(state) 

2183 state.add_token("with") 

2184 self.whitespace_after_with._codegen(state) 

2185 lpar = self.lpar 

2186 if isinstance(lpar, LeftParen): 

2187 lpar._codegen(state) 

2188 elif needs_paren: 

2189 state.add_token("(") 

2190 last_item = len(self.items) - 1 

2191 for i, item in enumerate(self.items): 

2192 item._codegen(state, default_comma=(i != last_item)) 

2193 rpar = self.rpar 

2194 if isinstance(rpar, RightParen): 

2195 rpar._codegen(state) 

2196 elif needs_paren: 

2197 state.add_token(")") 

2198 self.whitespace_before_colon._codegen(state) 

2199 state.add_token(":") 

2200 self.body._codegen(state) 

2201 

2202 

2203@add_slots 

2204@dataclass(frozen=True) 

2205class For(BaseCompoundStatement): 

2206 """ 

2207 A ``for target in iter`` statement. 

2208 """ 

2209 

2210 #: The target of the iterator in the for statement. 

2211 target: BaseAssignTargetExpression 

2212 

2213 #: The iterable expression we will loop over. 

2214 iter: BaseExpression 

2215 

2216 #: The suite that is wrapped with this statement. 

2217 body: BaseSuite 

2218 

2219 #: An optional else case which will be executed if there is no 

2220 #: :class:`Break` statement encountered while looping. 

2221 orelse: Optional[Else] = None 

2222 

2223 #: Optional async modifier, if this is an `async for` statement. 

2224 asynchronous: Optional[Asynchronous] = None 

2225 

2226 #: Sequence of empty lines appearing before this for statement. 

2227 leading_lines: Sequence[EmptyLine] = () 

2228 

2229 #: Whitespace after the ``for`` keyword and before the target. 

2230 whitespace_after_for: SimpleWhitespace = SimpleWhitespace.field(" ") 

2231 

2232 #: Whitespace after the target and before the ``in`` keyword. 

2233 whitespace_before_in: SimpleWhitespace = SimpleWhitespace.field(" ") 

2234 

2235 #: Whitespace after the ``in`` keyword and before the iter. 

2236 whitespace_after_in: SimpleWhitespace = SimpleWhitespace.field(" ") 

2237 

2238 #: Whitespace after the iter and before the colon. 

2239 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

2240 

2241 def _validate(self) -> None: 

2242 if ( 

2243 self.whitespace_after_for.empty 

2244 and not self.target._safe_to_use_with_word_operator( 

2245 ExpressionPosition.RIGHT 

2246 ) 

2247 ): 

2248 raise CSTValidationError( 

2249 "Must have at least one space after 'for' keyword." 

2250 ) 

2251 

2252 if ( 

2253 self.whitespace_before_in.empty 

2254 and not self.target._safe_to_use_with_word_operator(ExpressionPosition.LEFT) 

2255 ): 

2256 raise CSTValidationError( 

2257 "Must have at least one space before 'in' keyword." 

2258 ) 

2259 

2260 if ( 

2261 self.whitespace_after_in.empty 

2262 and not self.iter._safe_to_use_with_word_operator(ExpressionPosition.RIGHT) 

2263 ): 

2264 raise CSTValidationError("Must have at least one space after 'in' keyword.") 

2265 

2266 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "For": 

2267 return For( 

2268 leading_lines=visit_sequence( 

2269 self, "leading_lines", self.leading_lines, visitor 

2270 ), 

2271 asynchronous=visit_optional( 

2272 self, "asynchronous", self.asynchronous, visitor 

2273 ), 

2274 whitespace_after_for=visit_required( 

2275 self, "whitespace_after_for", self.whitespace_after_for, visitor 

2276 ), 

2277 target=visit_required(self, "target", self.target, visitor), 

2278 whitespace_before_in=visit_required( 

2279 self, "whitespace_before_in", self.whitespace_before_in, visitor 

2280 ), 

2281 whitespace_after_in=visit_required( 

2282 self, "whitespace_after_in", self.whitespace_after_in, visitor 

2283 ), 

2284 iter=visit_required(self, "iter", self.iter, visitor), 

2285 whitespace_before_colon=visit_required( 

2286 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2287 ), 

2288 body=visit_required(self, "body", self.body, visitor), 

2289 orelse=visit_optional(self, "orelse", self.orelse, visitor), 

2290 ) 

2291 

2292 def _codegen_impl(self, state: CodegenState) -> None: 

2293 for ll in self.leading_lines: 

2294 ll._codegen(state) 

2295 state.add_indent_tokens() 

2296 

2297 end_node = self.body if self.orelse is None else self.orelse 

2298 with state.record_syntactic_position(self, end_node=end_node): 

2299 asynchronous = self.asynchronous 

2300 if asynchronous is not None: 

2301 asynchronous._codegen(state) 

2302 state.add_token("for") 

2303 self.whitespace_after_for._codegen(state) 

2304 self.target._codegen(state) 

2305 self.whitespace_before_in._codegen(state) 

2306 state.add_token("in") 

2307 self.whitespace_after_in._codegen(state) 

2308 self.iter._codegen(state) 

2309 self.whitespace_before_colon._codegen(state) 

2310 state.add_token(":") 

2311 self.body._codegen(state) 

2312 orelse = self.orelse 

2313 if orelse is not None: 

2314 orelse._codegen(state) 

2315 

2316 

2317@add_slots 

2318@dataclass(frozen=True) 

2319class While(BaseCompoundStatement): 

2320 """ 

2321 A ``while`` statement. 

2322 """ 

2323 

2324 #: The test we will loop against. 

2325 test: BaseExpression 

2326 

2327 #: The suite that is wrapped with this statement. 

2328 body: BaseSuite 

2329 

2330 #: An optional else case which will be executed if there is no 

2331 #: :class:`Break` statement encountered while looping. 

2332 orelse: Optional[Else] = None 

2333 

2334 #: Sequence of empty lines appearing before this while statement. 

2335 leading_lines: Sequence[EmptyLine] = () 

2336 

2337 #: Whitespace after the ``while`` keyword and before the test. 

2338 whitespace_after_while: SimpleWhitespace = SimpleWhitespace.field(" ") 

2339 

2340 #: Whitespace after the test and before the colon. 

2341 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

2342 

2343 def _validate(self) -> None: 

2344 if ( 

2345 self.whitespace_after_while.empty 

2346 and not self.test._safe_to_use_with_word_operator(ExpressionPosition.RIGHT) 

2347 ): 

2348 raise CSTValidationError( 

2349 "Must have at least one space after 'while' keyword." 

2350 ) 

2351 

2352 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "While": 

2353 return While( 

2354 leading_lines=visit_sequence( 

2355 self, "leading_lines", self.leading_lines, visitor 

2356 ), 

2357 whitespace_after_while=visit_required( 

2358 self, "whitespace_after_while", self.whitespace_after_while, visitor 

2359 ), 

2360 test=visit_required(self, "test", self.test, visitor), 

2361 whitespace_before_colon=visit_required( 

2362 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2363 ), 

2364 body=visit_required(self, "body", self.body, visitor), 

2365 orelse=visit_optional(self, "orelse", self.orelse, visitor), 

2366 ) 

2367 

2368 def _codegen_impl(self, state: CodegenState) -> None: 

2369 for ll in self.leading_lines: 

2370 ll._codegen(state) 

2371 state.add_indent_tokens() 

2372 

2373 end_node = self.body if self.orelse is None else self.orelse 

2374 with state.record_syntactic_position(self, end_node=end_node): 

2375 state.add_token("while") 

2376 self.whitespace_after_while._codegen(state) 

2377 self.test._codegen(state) 

2378 self.whitespace_before_colon._codegen(state) 

2379 state.add_token(":") 

2380 self.body._codegen(state) 

2381 orelse = self.orelse 

2382 if orelse is not None: 

2383 orelse._codegen(state) 

2384 

2385 

2386@add_slots 

2387@dataclass(frozen=True) 

2388class Raise(BaseSmallStatement): 

2389 """ 

2390 A ``raise exc`` or ``raise exc from cause`` statement. 

2391 """ 

2392 

2393 #: The exception that we should raise. 

2394 exc: Optional[BaseExpression] = None 

2395 

2396 #: Optionally, a ``from cause`` clause to allow us to raise an exception 

2397 #: out of another exception's context. 

2398 cause: Optional[From] = None 

2399 

2400 #: Any whitespace appearing between the ``raise`` keyword and the exception. 

2401 whitespace_after_raise: Union[ 

2402 SimpleWhitespace, MaybeSentinel 

2403 ] = MaybeSentinel.DEFAULT 

2404 

2405 #: Optional semicolon when this is used in a statement line. This semicolon 

2406 #: owns the whitespace on both sides of it when it is used. 

2407 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

2408 

2409 def _validate(self) -> None: 

2410 # Validate correct construction 

2411 if self.exc is None and self.cause is not None: 

2412 raise CSTValidationError( 

2413 "Must have an 'exc' when specifying 'clause'. on Raise." 

2414 ) 

2415 

2416 # Validate spacing between "raise" and "exc" 

2417 exc = self.exc 

2418 if exc is not None: 

2419 whitespace_after_raise = self.whitespace_after_raise 

2420 has_no_gap = ( 

2421 not isinstance(whitespace_after_raise, MaybeSentinel) 

2422 and whitespace_after_raise.empty 

2423 ) 

2424 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2425 ExpressionPosition.RIGHT 

2426 ): 

2427 raise CSTValidationError("Must have at least one space after 'raise'.") 

2428 

2429 # Validate spacing between "exc" and "from" 

2430 cause = self.cause 

2431 if exc is not None and cause is not None: 

2432 whitespace_before_from = cause.whitespace_before_from 

2433 has_no_gap = ( 

2434 not isinstance(whitespace_before_from, MaybeSentinel) 

2435 and whitespace_before_from.empty 

2436 ) 

2437 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2438 ExpressionPosition.LEFT 

2439 ): 

2440 raise CSTValidationError("Must have at least one space before 'from'.") 

2441 

2442 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Raise": 

2443 return Raise( 

2444 whitespace_after_raise=visit_sentinel( 

2445 self, "whitespace_after_raise", self.whitespace_after_raise, visitor 

2446 ), 

2447 exc=visit_optional(self, "exc", self.exc, visitor), 

2448 cause=visit_optional(self, "cause", self.cause, visitor), 

2449 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

2450 ) 

2451 

2452 def _codegen_impl( 

2453 self, state: CodegenState, default_semicolon: bool = False 

2454 ) -> None: 

2455 with state.record_syntactic_position(self): 

2456 exc = self.exc 

2457 cause = self.cause 

2458 state.add_token("raise") 

2459 whitespace_after_raise = self.whitespace_after_raise 

2460 if isinstance(whitespace_after_raise, MaybeSentinel): 

2461 if exc is not None: 

2462 state.add_token(" ") 

2463 else: 

2464 whitespace_after_raise._codegen(state) 

2465 if exc is not None: 

2466 exc._codegen(state) 

2467 if cause is not None: 

2468 cause._codegen(state, default_space=" ") 

2469 

2470 semicolon = self.semicolon 

2471 if isinstance(semicolon, MaybeSentinel): 

2472 if default_semicolon: 

2473 state.add_token("; ") 

2474 elif isinstance(semicolon, Semicolon): 

2475 semicolon._codegen(state) 

2476 

2477 

2478@add_slots 

2479@dataclass(frozen=True) 

2480class Assert(BaseSmallStatement): 

2481 """ 

2482 An assert statement such as ``assert x > 5`` or ``assert x > 5, 'Uh oh!'`` 

2483 """ 

2484 

2485 #: The test we are going to assert on. 

2486 test: BaseExpression 

2487 

2488 #: The optional message to display if the test evaluates to a falsey value. 

2489 msg: Optional[BaseExpression] = None 

2490 

2491 #: A comma separating test and message, if there is a message. 

2492 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

2493 

2494 #: Whitespace appearing after the ``assert`` keyword and before the test. 

2495 whitespace_after_assert: SimpleWhitespace = SimpleWhitespace.field(" ") 

2496 

2497 #: Optional semicolon when this is used in a statement line. This semicolon 

2498 #: owns the whitespace on both sides of it when it is used. 

2499 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

2500 

2501 def _validate(self) -> None: 

2502 # Validate whitespace 

2503 if ( 

2504 self.whitespace_after_assert.empty 

2505 and not self.test._safe_to_use_with_word_operator(ExpressionPosition.RIGHT) 

2506 ): 

2507 raise CSTValidationError("Must have at least one space after 'assert'.") 

2508 

2509 # Validate comma rules 

2510 if self.msg is None and isinstance(self.comma, Comma): 

2511 raise CSTValidationError("Cannot have trailing comma after 'test'.") 

2512 

2513 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Assert": 

2514 return Assert( 

2515 whitespace_after_assert=visit_required( 

2516 self, "whitespace_after_assert", self.whitespace_after_assert, visitor 

2517 ), 

2518 test=visit_required(self, "test", self.test, visitor), 

2519 comma=visit_sentinel(self, "comma", self.comma, visitor), 

2520 msg=visit_optional(self, "msg", self.msg, visitor), 

2521 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

2522 ) 

2523 

2524 def _codegen_impl( 

2525 self, state: CodegenState, default_semicolon: bool = False 

2526 ) -> None: 

2527 with state.record_syntactic_position(self): 

2528 state.add_token("assert") 

2529 self.whitespace_after_assert._codegen(state) 

2530 self.test._codegen(state) 

2531 

2532 comma = self.comma 

2533 msg = self.msg 

2534 if isinstance(comma, MaybeSentinel): 

2535 if msg is not None: 

2536 state.add_token(", ") 

2537 else: 

2538 comma._codegen(state) 

2539 if msg is not None: 

2540 msg._codegen(state) 

2541 

2542 semicolon = self.semicolon 

2543 if isinstance(semicolon, MaybeSentinel): 

2544 if default_semicolon: 

2545 state.add_token("; ") 

2546 elif isinstance(semicolon, Semicolon): 

2547 semicolon._codegen(state) 

2548 

2549 

2550@add_slots 

2551@dataclass(frozen=True) 

2552class NameItem(CSTNode): 

2553 """ 

2554 A single identifier name inside a :class:`Global` or :class:`Nonlocal` statement. 

2555 

2556 This exists because a list of names in a ``global`` or ``nonlocal`` statement need 

2557 to be separated by a comma, which ends up owned by the :class:`NameItem` node. 

2558 """ 

2559 

2560 #: Identifier name. 

2561 name: Name 

2562 

2563 #: This is forbidden for the last :class:`NameItem` in a 

2564 #: :class:`Global`/:class:`Nonlocal`, but all other tems inside a ``global`` or 

2565 #: ``nonlocal`` statement must contain a comma to separate them. 

2566 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

2567 

2568 def _validate(self) -> None: 

2569 # No parens around names here 

2570 if len(self.name.lpar) > 0 or len(self.name.rpar) > 0: 

2571 raise CSTValidationError("Cannot have parens around names in NameItem.") 

2572 

2573 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "NameItem": 

2574 return NameItem( 

2575 name=visit_required(self, "name", self.name, visitor), 

2576 comma=visit_sentinel(self, "comma", self.comma, visitor), 

2577 ) 

2578 

2579 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

2580 with state.record_syntactic_position(self): 

2581 self.name._codegen(state) 

2582 

2583 comma = self.comma 

2584 if comma is MaybeSentinel.DEFAULT and default_comma: 

2585 state.add_token(", ") 

2586 elif isinstance(comma, Comma): 

2587 comma._codegen(state) 

2588 

2589 

2590@add_slots 

2591@dataclass(frozen=True) 

2592class Global(BaseSmallStatement): 

2593 """ 

2594 A ``global`` statement. 

2595 """ 

2596 

2597 #: A list of one or more names. 

2598 names: Sequence[NameItem] 

2599 

2600 #: Whitespace appearing after the ``global`` keyword and before the first name. 

2601 whitespace_after_global: SimpleWhitespace = SimpleWhitespace.field(" ") 

2602 

2603 #: Optional semicolon when this is used in a statement line. This semicolon 

2604 #: owns the whitespace on both sides of it when it is used. 

2605 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

2606 

2607 def _validate(self) -> None: 

2608 if len(self.names) == 0: 

2609 raise CSTValidationError( 

2610 "A Global statement must have at least one NameItem." 

2611 ) 

2612 if self.names[-1].comma != MaybeSentinel.DEFAULT: 

2613 raise CSTValidationError( 

2614 "The last NameItem in a Global cannot have a trailing comma." 

2615 ) 

2616 if self.whitespace_after_global.empty: 

2617 raise CSTValidationError( 

2618 "Must have at least one space after 'global' keyword." 

2619 ) 

2620 

2621 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Global": 

2622 return Global( 

2623 whitespace_after_global=visit_required( 

2624 self, "whitespace_after_global", self.whitespace_after_global, visitor 

2625 ), 

2626 names=visit_sequence(self, "names", self.names, visitor), 

2627 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

2628 ) 

2629 

2630 def _codegen_impl( 

2631 self, state: CodegenState, default_semicolon: bool = False 

2632 ) -> None: 

2633 with state.record_syntactic_position(self): 

2634 state.add_token("global") 

2635 self.whitespace_after_global._codegen(state) 

2636 last_name = len(self.names) - 1 

2637 for i, name in enumerate(self.names): 

2638 name._codegen(state, default_comma=(i != last_name)) 

2639 

2640 semicolon = self.semicolon 

2641 if isinstance(semicolon, MaybeSentinel): 

2642 if default_semicolon: 

2643 state.add_token("; ") 

2644 elif isinstance(semicolon, Semicolon): 

2645 semicolon._codegen(state) 

2646 

2647 

2648@add_slots 

2649@dataclass(frozen=True) 

2650class Nonlocal(BaseSmallStatement): 

2651 """ 

2652 A ``nonlocal`` statement. 

2653 """ 

2654 

2655 #: A list of one or more names. 

2656 names: Sequence[NameItem] 

2657 

2658 #: Whitespace appearing after the ``global`` keyword and before the first name. 

2659 whitespace_after_nonlocal: SimpleWhitespace = SimpleWhitespace.field(" ") 

2660 

2661 #: Optional semicolon when this is used in a statement line. This semicolon 

2662 #: owns the whitespace on both sides of it when it is used. 

2663 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

2664 

2665 def _validate(self) -> None: 

2666 if len(self.names) == 0: 

2667 raise CSTValidationError( 

2668 "A Nonlocal statement must have at least one NameItem." 

2669 ) 

2670 if self.names[-1].comma != MaybeSentinel.DEFAULT: 

2671 raise CSTValidationError( 

2672 "The last NameItem in a Nonlocal cannot have a trailing comma." 

2673 ) 

2674 if self.whitespace_after_nonlocal.empty: 

2675 raise CSTValidationError( 

2676 "Must have at least one space after 'nonlocal' keyword." 

2677 ) 

2678 

2679 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Nonlocal": 

2680 return Nonlocal( 

2681 whitespace_after_nonlocal=visit_required( 

2682 self, 

2683 "whitespace_after_nonlocal", 

2684 self.whitespace_after_nonlocal, 

2685 visitor, 

2686 ), 

2687 names=visit_sequence(self, "names", self.names, visitor), 

2688 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

2689 ) 

2690 

2691 def _codegen_impl( 

2692 self, state: CodegenState, default_semicolon: bool = False 

2693 ) -> None: 

2694 with state.record_syntactic_position(self): 

2695 state.add_token("nonlocal") 

2696 self.whitespace_after_nonlocal._codegen(state) 

2697 last_name = len(self.names) - 1 

2698 for i, name in enumerate(self.names): 

2699 name._codegen(state, default_comma=(i != last_name)) 

2700 

2701 semicolon = self.semicolon 

2702 if isinstance(semicolon, MaybeSentinel): 

2703 if default_semicolon: 

2704 state.add_token("; ") 

2705 elif isinstance(semicolon, Semicolon): 

2706 semicolon._codegen(state) 

2707 

2708 

2709class MatchPattern(_BaseParenthesizedNode, ABC): 

2710 """ 

2711 A base class for anything that can appear as a pattern in a :class:`Match` 

2712 statement. 

2713 """ 

2714 

2715 __slots__ = () 

2716 

2717 

2718@add_slots 

2719@dataclass(frozen=True) 

2720# pyre-fixme[13]: Attribute `body` is never initialized. 

2721class Match(BaseCompoundStatement): 

2722 """ 

2723 A ``match`` statement. 

2724 """ 

2725 

2726 #: The subject of the match. 

2727 subject: BaseExpression 

2728 

2729 #: A non-empty list of match cases. 

2730 cases: Sequence["MatchCase"] 

2731 

2732 #: Sequence of empty lines appearing before this compound statement line. 

2733 leading_lines: Sequence[EmptyLine] = () 

2734 

2735 #: Whitespace between the ``match`` keyword and the subject. 

2736 whitespace_after_match: SimpleWhitespace = SimpleWhitespace.field(" ") 

2737 

2738 #: Whitespace after the subject but before the colon. 

2739 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

2740 

2741 #: Any optional trailing comment and the final ``NEWLINE`` at the end of the line. 

2742 whitespace_after_colon: TrailingWhitespace = TrailingWhitespace.field() 

2743 

2744 #: A string represents a specific indentation. A ``None`` value uses the modules's 

2745 #: default indentation. This is included because indentation is allowed to be 

2746 #: inconsistent across a file, just not ambiguously. 

2747 indent: Optional[str] = None 

2748 

2749 #: Any trailing comments or lines after the dedent that are owned by this match 

2750 #: block. Statements own preceeding and same-line trailing comments, but not 

2751 #: trailing lines, so it falls on :class:`Match` to own it. In the case 

2752 #: that a statement follows a :class:`Match` block, that statement will own the 

2753 #: comments and lines that are at the same indent as the statement, and this 

2754 #: :class:`Match` will own the comments and lines that are indented further. 

2755 footer: Sequence[EmptyLine] = () 

2756 

2757 def _validate(self) -> None: 

2758 if len(self.cases) == 0: 

2759 raise CSTValidationError("A match statement must have at least one case.") 

2760 

2761 indent = self.indent 

2762 if indent is not None: 

2763 if len(indent) == 0: 

2764 raise CSTValidationError( 

2765 "A match statement must have a non-zero width indent." 

2766 ) 

2767 if _INDENT_WHITESPACE_RE.fullmatch(indent) is None: 

2768 raise CSTValidationError( 

2769 "An indent must be composed of only whitespace characters." 

2770 ) 

2771 

2772 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "Match": 

2773 return Match( 

2774 leading_lines=visit_sequence( 

2775 self, "leading_lines", self.leading_lines, visitor 

2776 ), 

2777 whitespace_after_match=visit_required( 

2778 self, "whitespace_after_match", self.whitespace_after_match, visitor 

2779 ), 

2780 subject=visit_required(self, "subject", self.subject, visitor), 

2781 whitespace_before_colon=visit_required( 

2782 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2783 ), 

2784 whitespace_after_colon=visit_required( 

2785 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

2786 ), 

2787 indent=self.indent, 

2788 cases=visit_sequence(self, "cases", self.cases, visitor), 

2789 footer=visit_sequence(self, "footer", self.footer, visitor), 

2790 ) 

2791 

2792 def _codegen_impl(self, state: CodegenState) -> None: 

2793 for ll in self.leading_lines: 

2794 ll._codegen(state) 

2795 state.add_indent_tokens() 

2796 

2797 with state.record_syntactic_position(self, end_node=self.cases[-1]): 

2798 state.add_token("match") 

2799 self.whitespace_after_match._codegen(state) 

2800 self.subject._codegen(state) 

2801 self.whitespace_before_colon._codegen(state) 

2802 state.add_token(":") 

2803 self.whitespace_after_colon._codegen(state) 

2804 

2805 indent = self.indent 

2806 state.increase_indent(state.default_indent if indent is None else indent) 

2807 for c in self.cases: 

2808 c._codegen(state) 

2809 

2810 for f in self.footer: 

2811 f._codegen(state) 

2812 

2813 state.decrease_indent() 

2814 

2815 

2816@add_slots 

2817@dataclass(frozen=True) 

2818class MatchCase(CSTNode): 

2819 """ 

2820 A single ``case`` block of a :class:`Match` statement. 

2821 """ 

2822 

2823 #: The pattern that ``subject`` will be matched against. 

2824 pattern: MatchPattern 

2825 

2826 #: The body of this case block, to be evaluated if ``pattern`` matches ``subject`` 

2827 #: and ``guard`` evaluates to a truthy value. 

2828 body: BaseSuite 

2829 

2830 #: Optional expression that will be evaluated if ``pattern`` matches ``subject``. 

2831 guard: Optional[BaseExpression] = None 

2832 

2833 #: Sequence of empty lines appearing before this case block. 

2834 leading_lines: Sequence[EmptyLine] = () 

2835 

2836 #: Whitespace directly after the ``case`` keyword. 

2837 whitespace_after_case: SimpleWhitespace = SimpleWhitespace.field(" ") 

2838 

2839 #: Whitespace before the ``if`` keyword in case there's a guard expression. 

2840 whitespace_before_if: SimpleWhitespace = SimpleWhitespace.field("") 

2841 

2842 #: Whitespace after the ``if`` keyword in case there's a guard expression. 

2843 whitespace_after_if: SimpleWhitespace = SimpleWhitespace.field("") 

2844 

2845 #: Whitespace before the colon. 

2846 whitespace_before_colon: SimpleWhitespace = SimpleWhitespace.field("") 

2847 

2848 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "CSTNode": 

2849 return MatchCase( 

2850 leading_lines=visit_sequence( 

2851 self, "leading_lines", self.leading_lines, visitor 

2852 ), 

2853 whitespace_after_case=visit_required( 

2854 self, "whitespace_after_case", self.whitespace_after_case, visitor 

2855 ), 

2856 pattern=visit_required(self, "pattern", self.pattern, visitor), 

2857 # pyre-fixme[6]: Expected `SimpleWhitespace` for 4th param but got 

2858 # `Optional[SimpleWhitespace]`. 

2859 whitespace_before_if=visit_optional( 

2860 self, "whitespace_before_if", self.whitespace_before_if, visitor 

2861 ), 

2862 # pyre-fixme[6]: Expected `SimpleWhitespace` for 5th param but got 

2863 # `Optional[SimpleWhitespace]`. 

2864 whitespace_after_if=visit_optional( 

2865 self, "whitespace_after_if", self.whitespace_after_if, visitor 

2866 ), 

2867 guard=visit_optional(self, "guard", self.guard, visitor), 

2868 body=visit_required(self, "body", self.body, visitor), 

2869 ) 

2870 

2871 def _codegen_impl(self, state: CodegenState) -> None: 

2872 for ll in self.leading_lines: 

2873 ll._codegen(state) 

2874 state.add_indent_tokens() 

2875 with state.record_syntactic_position(self, end_node=self.body): 

2876 state.add_token("case") 

2877 self.whitespace_after_case._codegen(state) 

2878 self.pattern._codegen(state) 

2879 

2880 guard = self.guard 

2881 if guard is not None: 

2882 self.whitespace_before_if._codegen(state) 

2883 state.add_token("if") 

2884 self.whitespace_after_if._codegen(state) 

2885 guard._codegen(state) 

2886 

2887 self.whitespace_before_colon._codegen(state) 

2888 state.add_token(":") 

2889 self.body._codegen(state) 

2890 

2891 

2892@add_slots 

2893@dataclass(frozen=True) 

2894class MatchValue(MatchPattern): 

2895 """ 

2896 A match literal or value pattern that compares by equality. 

2897 """ 

2898 

2899 #: an expression to compare to 

2900 value: BaseExpression 

2901 

2902 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "CSTNode": 

2903 return MatchValue(value=visit_required(self, "value", self.value, visitor)) 

2904 

2905 def _codegen_impl(self, state: CodegenState) -> None: 

2906 with state.record_syntactic_position(self): 

2907 self.value._codegen(state) 

2908 

2909 @property 

2910 def lpar(self) -> Sequence[LeftParen]: 

2911 return self.value.lpar 

2912 

2913 @lpar.setter 

2914 def lpar(self, value: Sequence[LeftParen]) -> None: 

2915 self.value.lpar = value 

2916 

2917 @property 

2918 def rpar(self) -> Sequence[RightParen]: 

2919 return self.value.rpar 

2920 

2921 @rpar.setter 

2922 def rpar(self, value: Sequence[RightParen]) -> None: 

2923 self.value.rpar = value 

2924 

2925 

2926@add_slots 

2927@dataclass(frozen=True) 

2928class MatchSingleton(MatchPattern): 

2929 """ 

2930 A match literal pattern that compares by identity. 

2931 """ 

2932 

2933 #: a literal to compare to 

2934 value: Name 

2935 

2936 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "CSTNode": 

2937 return MatchSingleton(value=visit_required(self, "value", self.value, visitor)) 

2938 

2939 def _validate(self) -> None: 

2940 if self.value.value not in {"True", "False", "None"}: 

2941 raise CSTValidationError( 

2942 "A match singleton can only be True, False, or None" 

2943 ) 

2944 

2945 def _codegen_impl(self, state: CodegenState) -> None: 

2946 with state.record_syntactic_position(self): 

2947 self.value._codegen(state) 

2948 

2949 @property 

2950 def lpar(self) -> Sequence[LeftParen]: 

2951 return self.value.lpar 

2952 

2953 @lpar.setter 

2954 def lpar(self, value: Sequence[LeftParen]) -> None: 

2955 # pyre-fixme[41]: Cannot reassign final attribute `lpar`. 

2956 self.value.lpar = value 

2957 

2958 @property 

2959 def rpar(self) -> Sequence[RightParen]: 

2960 return self.value.rpar 

2961 

2962 @rpar.setter 

2963 def rpar(self, value: Sequence[RightParen]) -> None: 

2964 # pyre-fixme[41]: Cannot reassign final attribute `rpar`. 

2965 self.value.rpar = value 

2966 

2967 

2968@add_slots 

2969@dataclass(frozen=True) 

2970class MatchSequenceElement(CSTNode): 

2971 """ 

2972 An element in a sequence match pattern. 

2973 """ 

2974 

2975 value: MatchPattern 

2976 

2977 #: An optional trailing comma. 

2978 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

2979 

2980 def _visit_and_replace_children( 

2981 self, visitor: CSTVisitorT 

2982 ) -> "MatchSequenceElement": 

2983 return MatchSequenceElement( 

2984 value=visit_required(self, "value", self.value, visitor), 

2985 comma=visit_sentinel(self, "comma", self.comma, visitor), 

2986 ) 

2987 

2988 def _codegen_impl( 

2989 self, 

2990 state: CodegenState, 

2991 default_comma: bool = False, 

2992 default_comma_whitespace: bool = True, 

2993 ) -> None: 

2994 with state.record_syntactic_position(self): 

2995 self.value._codegen(state) 

2996 comma = self.comma 

2997 if comma is MaybeSentinel.DEFAULT and default_comma: 

2998 state.add_token(", " if default_comma_whitespace else ",") 

2999 elif isinstance(comma, Comma): 

3000 comma._codegen(state) 

3001 

3002 

3003@add_slots 

3004@dataclass(frozen=True) 

3005class MatchStar(CSTNode): 

3006 """ 

3007 A starred element in a sequence match pattern. Matches the rest of the sequence. 

3008 """ 

3009 

3010 #: The name of the pattern binding. A ``None`` value represents ``*_``. 

3011 name: Optional[Name] = None 

3012 

3013 #: An optional trailing comma. 

3014 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

3015 

3016 #: Optional whitespace between the star and the name. 

3017 whitespace_before_name: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3018 

3019 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchStar": 

3020 return MatchStar( 

3021 whitespace_before_name=visit_required( 

3022 self, "whitespace_before_name", self.whitespace_before_name, visitor 

3023 ), 

3024 name=visit_optional(self, "name", self.name, visitor), 

3025 comma=visit_sentinel(self, "comma", self.comma, visitor), 

3026 ) 

3027 

3028 def _codegen_impl( 

3029 self, 

3030 state: CodegenState, 

3031 default_comma: bool = False, 

3032 default_comma_whitespace: bool = True, 

3033 ) -> None: 

3034 with state.record_syntactic_position(self): 

3035 state.add_token("*") 

3036 self.whitespace_before_name._codegen(state) 

3037 name = self.name 

3038 if name is None: 

3039 state.add_token("_") 

3040 else: 

3041 name._codegen(state) 

3042 comma = self.comma 

3043 if comma is MaybeSentinel.DEFAULT and default_comma: 

3044 state.add_token(", " if default_comma_whitespace else ",") 

3045 elif isinstance(comma, Comma): 

3046 comma._codegen(state) 

3047 

3048 

3049class MatchSequence(MatchPattern, ABC): 

3050 """ 

3051 A match sequence pattern. It's either a :class:`MatchList` or a :class:`MatchTuple`. 

3052 Matches a variable length sequence if one of the patterns is a :class:`MatchStar`, 

3053 otherwise matches a fixed length sequence. 

3054 """ 

3055 

3056 __slots__ = () 

3057 

3058 #: Patterns to be matched against the subject elements if it is a sequence. 

3059 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3060 

3061 

3062@add_slots 

3063@dataclass(frozen=True) 

3064class MatchList(MatchSequence): 

3065 """ 

3066 A list match pattern. It's either an "open sequence pattern" (without brackets) or a 

3067 regular list literal (with brackets). 

3068 """ 

3069 

3070 #: Patterns to be matched against the subject elements if it is a sequence. 

3071 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3072 

3073 #: An optional left bracket. If missing, this is an open sequence pattern. 

3074 lbracket: Optional[LeftSquareBracket] = LeftSquareBracket.field() 

3075 

3076 #: An optional left bracket. If missing, this is an open sequence pattern. 

3077 rbracket: Optional[RightSquareBracket] = RightSquareBracket.field() 

3078 

3079 #: Parenthesis at the beginning of the node 

3080 lpar: Sequence[LeftParen] = () 

3081 #: Parentheses after the pattern, but before a comma (if there is one). 

3082 rpar: Sequence[RightParen] = () 

3083 

3084 def _validate(self) -> None: 

3085 if self.lbracket and not self.rbracket: 

3086 raise CSTValidationError("Cannot have left bracket without right bracket") 

3087 if self.rbracket and not self.lbracket: 

3088 raise CSTValidationError("Cannot have right bracket without left bracket") 

3089 

3090 if not self.patterns and not self.lbracket: 

3091 raise CSTValidationError( 

3092 "Must have brackets if matching against empty list" 

3093 ) 

3094 

3095 super(MatchList, self)._validate() 

3096 

3097 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchList": 

3098 return MatchList( 

3099 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3100 lbracket=visit_optional(self, "lbracket", self.lbracket, visitor), 

3101 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3102 rbracket=visit_optional(self, "rbracket", self.rbracket, visitor), 

3103 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3104 ) 

3105 

3106 def _codegen_impl(self, state: CodegenState) -> None: 

3107 with self._parenthesize(state): 

3108 lbracket = self.lbracket 

3109 if lbracket is not None: 

3110 lbracket._codegen(state) 

3111 pats = self.patterns 

3112 for idx, pat in enumerate(pats): 

3113 pat._codegen(state, default_comma=(idx < len(pats) - 1)) 

3114 rbracket = self.rbracket 

3115 if rbracket is not None: 

3116 rbracket._codegen(state) 

3117 

3118 

3119@add_slots 

3120@dataclass(frozen=True) 

3121class MatchTuple(MatchSequence): 

3122 """ 

3123 A tuple match pattern. 

3124 """ 

3125 

3126 #: Patterns to be matched against the subject elements if it is a sequence. 

3127 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3128 

3129 #: Parenthesis at the beginning of the node 

3130 lpar: Sequence[LeftParen] = field(default_factory=lambda: (LeftParen(),)) 

3131 #: Parentheses after the pattern, but before a comma (if there is one). 

3132 rpar: Sequence[RightParen] = field(default_factory=lambda: (RightParen(),)) 

3133 

3134 def _validate(self) -> None: 

3135 if len(self.lpar) < 1: 

3136 raise CSTValidationError( 

3137 "Tuple patterns must have at least pair of parenthesis" 

3138 ) 

3139 

3140 super(MatchTuple, self)._validate() 

3141 

3142 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchTuple": 

3143 return MatchTuple( 

3144 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3145 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3146 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3147 ) 

3148 

3149 def _codegen_impl(self, state: CodegenState) -> None: 

3150 with self._parenthesize(state): 

3151 pats = self.patterns 

3152 patlen = len(pats) 

3153 for idx, pat in enumerate(pats): 

3154 pat._codegen( 

3155 state, 

3156 default_comma=patlen == 1 or (idx < patlen - 1), 

3157 default_comma_whitespace=patlen != 1, 

3158 ) 

3159 

3160 

3161@add_slots 

3162@dataclass(frozen=True) 

3163class MatchMappingElement(CSTNode): 

3164 """ 

3165 A ``key: value`` pair in a match mapping pattern. 

3166 """ 

3167 

3168 key: BaseExpression 

3169 

3170 #: The pattern to be matched corresponding to ``key``. 

3171 pattern: MatchPattern 

3172 

3173 #: An optional trailing comma. 

3174 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

3175 

3176 #: Whitespace between ``key`` and the colon. 

3177 whitespace_before_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3178 

3179 #: Whitespace between the colon and ``pattern``. 

3180 whitespace_after_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field(" ") 

3181 

3182 def _visit_and_replace_children( 

3183 self, visitor: CSTVisitorT 

3184 ) -> "MatchMappingElement": 

3185 return MatchMappingElement( 

3186 key=visit_required(self, "key", self.key, visitor), 

3187 whitespace_before_colon=visit_required( 

3188 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

3189 ), 

3190 whitespace_after_colon=visit_required( 

3191 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

3192 ), 

3193 pattern=visit_required(self, "pattern", self.pattern, visitor), 

3194 comma=visit_sentinel(self, "comma", self.comma, visitor), 

3195 ) 

3196 

3197 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

3198 with state.record_syntactic_position(self): 

3199 self.key._codegen(state) 

3200 self.whitespace_before_colon._codegen(state) 

3201 state.add_token(":") 

3202 self.whitespace_after_colon._codegen(state) 

3203 self.pattern._codegen(state) 

3204 comma = self.comma 

3205 if comma is MaybeSentinel.DEFAULT and default_comma: 

3206 state.add_token(", ") 

3207 elif isinstance(comma, Comma): 

3208 comma._codegen(state) 

3209 

3210 

3211@add_slots 

3212@dataclass(frozen=True) 

3213class MatchMapping(MatchPattern): 

3214 """ 

3215 A match mapping pattern. 

3216 """ 

3217 

3218 #: A sequence of mapping elements. 

3219 elements: Sequence[MatchMappingElement] = () 

3220 

3221 #: Left curly brace at the beginning of the pattern. 

3222 lbrace: LeftCurlyBrace = LeftCurlyBrace.field() 

3223 

3224 #: Right curly brace at the end of the pattern. 

3225 rbrace: RightCurlyBrace = RightCurlyBrace.field() 

3226 

3227 #: An optional name to capture the remaining elements of the mapping. 

3228 rest: Optional[Name] = None 

3229 

3230 #: Optional whitespace between stars and ``rest``. 

3231 whitespace_before_rest: SimpleWhitespace = SimpleWhitespace.field("") 

3232 

3233 #: An optional trailing comma attached to ``rest``. 

3234 trailing_comma: Optional[Comma] = None 

3235 

3236 #: Parenthesis at the beginning of the node 

3237 lpar: Sequence[LeftParen] = () 

3238 #: Parentheses after the pattern 

3239 rpar: Sequence[RightParen] = () 

3240 

3241 def _validate(self) -> None: 

3242 if isinstance(self.trailing_comma, Comma) and self.rest is not None: 

3243 raise CSTValidationError("Cannot have a trailing comma without **rest") 

3244 super(MatchMapping, self)._validate() 

3245 

3246 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchMapping": 

3247 return MatchMapping( 

3248 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3249 lbrace=visit_required(self, "lbrace", self.lbrace, visitor), 

3250 elements=visit_sequence(self, "elements", self.elements, visitor), 

3251 whitespace_before_rest=visit_required( 

3252 self, "whitespace_before_rest", self.whitespace_before_rest, visitor 

3253 ), 

3254 rest=visit_optional(self, "rest", self.rest, visitor), 

3255 trailing_comma=visit_optional( 

3256 self, "trailing_comma", self.trailing_comma, visitor 

3257 ), 

3258 rbrace=visit_required(self, "rbrace", self.rbrace, visitor), 

3259 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3260 ) 

3261 

3262 def _codegen_impl(self, state: CodegenState) -> None: 

3263 with self._parenthesize(state): 

3264 self.lbrace._codegen(state) 

3265 elems = self.elements 

3266 rest = self.rest 

3267 for idx, el in enumerate(elems): 

3268 el._codegen( 

3269 state, default_comma=rest is not None or idx < len(elems) - 1 

3270 ) 

3271 

3272 if rest is not None: 

3273 state.add_token("**") 

3274 self.whitespace_before_rest._codegen(state) 

3275 rest._codegen(state) 

3276 comma = self.trailing_comma 

3277 if comma is not None: 

3278 comma._codegen(state) 

3279 

3280 self.rbrace._codegen(state) 

3281 

3282 

3283@add_slots 

3284@dataclass(frozen=True) 

3285class MatchKeywordElement(CSTNode): 

3286 """ 

3287 A key=value pair in a :class:`MatchClass`. 

3288 """ 

3289 

3290 key: Name 

3291 

3292 #: The pattern to be matched against the attribute named ``key``. 

3293 pattern: MatchPattern 

3294 

3295 #: An optional trailing comma. 

3296 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

3297 

3298 #: Whitespace between ``key`` and the equals sign. 

3299 whitespace_before_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3300 

3301 #: Whitespace between the equals sign and ``pattern``. 

3302 whitespace_after_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3303 

3304 def _visit_and_replace_children( 

3305 self, visitor: CSTVisitorT 

3306 ) -> "MatchKeywordElement": 

3307 return MatchKeywordElement( 

3308 key=visit_required(self, "key", self.key, visitor), 

3309 whitespace_before_equal=visit_required( 

3310 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

3311 ), 

3312 whitespace_after_equal=visit_required( 

3313 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

3314 ), 

3315 pattern=visit_required(self, "pattern", self.pattern, visitor), 

3316 comma=visit_sentinel(self, "comma", self.comma, visitor), 

3317 ) 

3318 

3319 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

3320 with state.record_syntactic_position(self): 

3321 self.key._codegen(state) 

3322 self.whitespace_before_equal._codegen(state) 

3323 state.add_token("=") 

3324 self.whitespace_after_equal._codegen(state) 

3325 self.pattern._codegen(state) 

3326 comma = self.comma 

3327 if comma is MaybeSentinel.DEFAULT and default_comma: 

3328 state.add_token(", ") 

3329 elif isinstance(comma, Comma): 

3330 comma._codegen(state) 

3331 

3332 

3333@add_slots 

3334@dataclass(frozen=True) 

3335class MatchClass(MatchPattern): 

3336 """ 

3337 A match class pattern. 

3338 """ 

3339 

3340 #: An expression giving the nominal class to be matched. 

3341 cls: BaseExpression 

3342 

3343 #: A sequence of patterns to be matched against the class defined sequence of 

3344 #: pattern matching attributes. 

3345 patterns: Sequence[MatchSequenceElement] = () 

3346 

3347 #: A sequence of additional attribute names and corresponding patterns to be 

3348 #: matched. 

3349 kwds: Sequence[MatchKeywordElement] = () 

3350 

3351 #: Whitespace between the class name and the left parenthesis. 

3352 whitespace_after_cls: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3353 

3354 #: Whitespace between the left parenthesis and the first pattern. 

3355 whitespace_before_patterns: BaseParenthesizableWhitespace = SimpleWhitespace.field( 

3356 "" 

3357 ) 

3358 

3359 #: Whitespace between the last pattern and the right parenthesis. 

3360 whitespace_after_kwds: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3361 

3362 #: Parenthesis at the beginning of the node 

3363 lpar: Sequence[LeftParen] = () 

3364 #: Parentheses after the pattern 

3365 rpar: Sequence[RightParen] = () 

3366 

3367 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchClass": 

3368 return MatchClass( 

3369 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3370 cls=visit_required(self, "cls", self.cls, visitor), 

3371 whitespace_after_cls=visit_required( 

3372 self, "whitespace_after_cls", self.whitespace_after_cls, visitor 

3373 ), 

3374 whitespace_before_patterns=visit_required( 

3375 self, 

3376 "whitespace_before_patterns", 

3377 self.whitespace_before_patterns, 

3378 visitor, 

3379 ), 

3380 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3381 kwds=visit_sequence(self, "kwds", self.kwds, visitor), 

3382 whitespace_after_kwds=visit_required( 

3383 self, "whitespace_after_kwds", self.whitespace_after_kwds, visitor 

3384 ), 

3385 ) 

3386 

3387 def _codegen_impl(self, state: CodegenState) -> None: 

3388 with self._parenthesize(state): 

3389 self.cls._codegen(state) 

3390 self.whitespace_after_cls._codegen(state) 

3391 state.add_token("(") 

3392 self.whitespace_before_patterns._codegen(state) 

3393 pats = self.patterns 

3394 kwds = self.kwds 

3395 for idx, pat in enumerate(pats): 

3396 pat._codegen(state, default_comma=idx + 1 < len(pats) + len(kwds)) 

3397 for idx, kwd in enumerate(kwds): 

3398 kwd._codegen(state, default_comma=idx + 1 < len(kwds)) 

3399 self.whitespace_after_kwds._codegen(state) 

3400 state.add_token(")") 

3401 

3402 

3403@add_slots 

3404@dataclass(frozen=True) 

3405class MatchAs(MatchPattern): 

3406 """ 

3407 A match "as-pattern", capture pattern, or wildcard pattern. 

3408 """ 

3409 

3410 #: The match pattern that the subject will be matched against. If this is ``None``, 

3411 #: the node represents a capture pattern (i.e. a bare name) and will always succeed. 

3412 pattern: Optional[MatchPattern] = None 

3413 

3414 #: The name that will be bound if the pattern is successful. If this is ``None``, 

3415 #: ``pattern`` must also be ``None`` and the node represents the wildcard pattern 

3416 #: (i.e. ``_``). 

3417 name: Optional[Name] = None 

3418 

3419 #: Whitespace between ``pattern`` and the ``as`` keyword (if ``pattern`` is not 

3420 #: ``None``) 

3421 whitespace_before_as: Union[ 

3422 BaseParenthesizableWhitespace, MaybeSentinel 

3423 ] = MaybeSentinel.DEFAULT 

3424 

3425 #: Whitespace between the ``as`` keyword and ``name`` (if ``pattern`` is not 

3426 #: ``None``) 

3427 whitespace_after_as: Union[ 

3428 BaseParenthesizableWhitespace, MaybeSentinel 

3429 ] = MaybeSentinel.DEFAULT 

3430 

3431 #: Parenthesis at the beginning of the node 

3432 lpar: Sequence[LeftParen] = () 

3433 #: Parentheses after the pattern 

3434 rpar: Sequence[RightParen] = () 

3435 

3436 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchAs": 

3437 return MatchAs( 

3438 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3439 pattern=visit_optional(self, "pattern", self.pattern, visitor), 

3440 whitespace_before_as=visit_sentinel( 

3441 self, "whitespace_before_as", self.whitespace_before_as, visitor 

3442 ), 

3443 whitespace_after_as=visit_sentinel( 

3444 self, "whitespace_after_as", self.whitespace_after_as, visitor 

3445 ), 

3446 name=visit_optional(self, "name", self.name, visitor), 

3447 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3448 ) 

3449 

3450 def _validate(self) -> None: 

3451 if self.name is None and self.pattern is not None: 

3452 raise CSTValidationError("Pattern must be None if name is None") 

3453 super(MatchAs, self)._validate() 

3454 

3455 def _codegen_impl(self, state: CodegenState) -> None: 

3456 with self._parenthesize(state): 

3457 pat = self.pattern 

3458 name = self.name 

3459 if pat is not None: 

3460 pat._codegen(state) 

3461 ws_before = self.whitespace_before_as 

3462 if ws_before is MaybeSentinel.DEFAULT: 

3463 state.add_token(" ") 

3464 elif isinstance(ws_before, BaseParenthesizableWhitespace): 

3465 ws_before._codegen(state) 

3466 state.add_token("as") 

3467 ws_after = self.whitespace_after_as 

3468 if ws_after is MaybeSentinel.DEFAULT: 

3469 state.add_token(" ") 

3470 elif isinstance(ws_after, BaseParenthesizableWhitespace): 

3471 ws_after._codegen(state) 

3472 if name is None: 

3473 state.add_token("_") 

3474 else: 

3475 name._codegen(state) 

3476 

3477 

3478@add_slots 

3479@dataclass(frozen=True) 

3480class MatchOrElement(CSTNode): 

3481 """ 

3482 An element in a :class:`MatchOr` node. 

3483 """ 

3484 

3485 pattern: MatchPattern 

3486 

3487 #: An optional ``|`` separator. 

3488 separator: Union[BitOr, MaybeSentinel] = MaybeSentinel.DEFAULT 

3489 

3490 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOrElement": 

3491 return MatchOrElement( 

3492 pattern=visit_required(self, "pattern", self.pattern, visitor), 

3493 separator=visit_sentinel(self, "separator", self.separator, visitor), 

3494 ) 

3495 

3496 def _codegen_impl( 

3497 self, state: CodegenState, default_separator: bool = False 

3498 ) -> None: 

3499 with state.record_syntactic_position(self): 

3500 self.pattern._codegen(state) 

3501 sep = self.separator 

3502 if sep is MaybeSentinel.DEFAULT and default_separator: 

3503 state.add_token(" | ") 

3504 elif isinstance(sep, BitOr): 

3505 sep._codegen(state) 

3506 

3507 

3508@add_slots 

3509@dataclass(frozen=True) 

3510class MatchOr(MatchPattern): 

3511 """ 

3512 A match "or-pattern". It matches each of its subpatterns in turn to the subject, 

3513 until one succeeds. The or-pattern is then deemed to succeed. If none of the 

3514 subpatterns succeed the or-pattern fails. 

3515 """ 

3516 

3517 #: The subpatterns to be tried in turn. 

3518 patterns: Sequence[MatchOrElement] 

3519 

3520 #: Parenthesis at the beginning of the node 

3521 lpar: Sequence[LeftParen] = () 

3522 #: Parentheses after the pattern 

3523 rpar: Sequence[RightParen] = () 

3524 

3525 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOr": 

3526 return MatchOr( 

3527 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3528 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3529 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3530 ) 

3531 

3532 def _codegen_impl(self, state: CodegenState) -> None: 

3533 with self._parenthesize(state): 

3534 pats = self.patterns 

3535 for idx, pat in enumerate(pats): 

3536 pat._codegen(state, default_separator=idx + 1 < len(pats)) 

3537 

3538 

3539@add_slots 

3540@dataclass(frozen=True) 

3541class TypeVar(CSTNode): 

3542 """ 

3543 A simple (non-variadic) type variable. 

3544 

3545 Note: this node represents type a variable when declared using PEP-695 syntax. 

3546 """ 

3547 

3548 #: The name of the type variable. 

3549 name: Name 

3550 

3551 #: An optional bound on the type. 

3552 bound: Optional[BaseExpression] = None 

3553 

3554 #: The colon used to separate the name and bound. If not specified, 

3555 #: :class:`MaybeSentinel` will be replaced with a colon if there is a bound, 

3556 #: otherwise will be left empty. 

3557 colon: Union[Colon, MaybeSentinel] = MaybeSentinel.DEFAULT 

3558 

3559 def _codegen_impl(self, state: CodegenState) -> None: 

3560 with state.record_syntactic_position(self): 

3561 self.name._codegen(state) 

3562 bound = self.bound 

3563 colon = self.colon 

3564 if not isinstance(colon, MaybeSentinel): 

3565 colon._codegen(state) 

3566 else: 

3567 if bound is not None: 

3568 state.add_token(": ") 

3569 

3570 if bound is not None: 

3571 bound._codegen(state) 

3572 

3573 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVar": 

3574 return TypeVar( 

3575 name=visit_required(self, "name", self.name, visitor), 

3576 colon=visit_sentinel(self, "colon", self.colon, visitor), 

3577 bound=visit_optional(self, "bound", self.bound, visitor), 

3578 ) 

3579 

3580 

3581@add_slots 

3582@dataclass(frozen=True) 

3583class TypeVarTuple(CSTNode): 

3584 """ 

3585 A variadic type variable. 

3586 """ 

3587 

3588 #: The name of this type variable. 

3589 name: Name 

3590 

3591 #: The (optional) whitespace between the star declaring this type variable as 

3592 #: variadic, and the variable's name. 

3593 whitespace_after_star: SimpleWhitespace = SimpleWhitespace.field("") 

3594 

3595 def _codegen_impl(self, state: CodegenState) -> None: 

3596 with state.record_syntactic_position(self): 

3597 state.add_token("*") 

3598 self.whitespace_after_star._codegen(state) 

3599 self.name._codegen(state) 

3600 

3601 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVarTuple": 

3602 return TypeVarTuple( 

3603 name=visit_required(self, "name", self.name, visitor), 

3604 whitespace_after_star=visit_required( 

3605 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3606 ), 

3607 ) 

3608 

3609 

3610@add_slots 

3611@dataclass(frozen=True) 

3612class ParamSpec(CSTNode): 

3613 """ 

3614 A parameter specification. 

3615 

3616 Note: this node represents a parameter specification when declared using PEP-695 

3617 syntax. 

3618 """ 

3619 

3620 #: The name of this parameter specification. 

3621 name: Name 

3622 

3623 #: The (optional) whitespace between the double star declaring this type variable as 

3624 #: a parameter specification, and the name. 

3625 whitespace_after_star: SimpleWhitespace = SimpleWhitespace.field("") 

3626 

3627 def _codegen_impl(self, state: CodegenState) -> None: 

3628 with state.record_syntactic_position(self): 

3629 state.add_token("**") 

3630 self.whitespace_after_star._codegen(state) 

3631 self.name._codegen(state) 

3632 

3633 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ParamSpec": 

3634 return ParamSpec( 

3635 name=visit_required(self, "name", self.name, visitor), 

3636 whitespace_after_star=visit_required( 

3637 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3638 ), 

3639 ) 

3640 

3641 

3642@add_slots 

3643@dataclass(frozen=True) 

3644class TypeParam(CSTNode): 

3645 """ 

3646 A single type parameter that is contained in a :class:`TypeParameters` list. 

3647 """ 

3648 

3649 #: The actual parameter. 

3650 param: Union[TypeVar, TypeVarTuple, ParamSpec] 

3651 

3652 #: A trailing comma. If one is not provided, :class:`MaybeSentinel` will be replaced 

3653 #: with a comma only if a comma is required. 

3654 comma: Union[Comma, MaybeSentinel] = MaybeSentinel.DEFAULT 

3655 

3656 def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> None: 

3657 self.param._codegen(state) 

3658 comma = self.comma 

3659 if isinstance(comma, MaybeSentinel): 

3660 if default_comma: 

3661 state.add_token(", ") 

3662 else: 

3663 comma._codegen(state) 

3664 

3665 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParam": 

3666 return TypeParam( 

3667 param=visit_required(self, "param", self.param, visitor), 

3668 comma=visit_sentinel(self, "comma", self.comma, visitor), 

3669 ) 

3670 

3671 

3672@add_slots 

3673@dataclass(frozen=True) 

3674class TypeParameters(CSTNode): 

3675 """ 

3676 Type parameters when specified with PEP-695 syntax. 

3677 

3678 This node captures all specified parameters that are enclosed with square brackets. 

3679 """ 

3680 

3681 #: The parameters within the square brackets. 

3682 params: Sequence[TypeParam] = () 

3683 

3684 #: Opening square bracket that marks the start of these parameters. 

3685 lbracket: LeftSquareBracket = LeftSquareBracket.field() 

3686 #: Closing square bracket that marks the end of these parameters. 

3687 rbracket: RightSquareBracket = RightSquareBracket.field() 

3688 

3689 def _codegen_impl(self, state: CodegenState) -> None: 

3690 self.lbracket._codegen(state) 

3691 params_len = len(self.params) 

3692 for idx, param in enumerate(self.params): 

3693 param._codegen(state, default_comma=idx + 1 < params_len) 

3694 self.rbracket._codegen(state) 

3695 

3696 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParameters": 

3697 return TypeParameters( 

3698 lbracket=visit_required(self, "lbracket", self.lbracket, visitor), 

3699 params=visit_sequence(self, "params", self.params, visitor), 

3700 rbracket=visit_required(self, "rbracket", self.rbracket, visitor), 

3701 ) 

3702 

3703 

3704@add_slots 

3705@dataclass(frozen=True) 

3706class TypeAlias(BaseSmallStatement): 

3707 """ 

3708 A type alias statement. 

3709 

3710 This node represents the ``type`` statement as specified initially by PEP-695. 

3711 Example: ``type ListOrSet[T] = list[T] | set[T]``. 

3712 """ 

3713 

3714 #: The name being introduced in this statement. 

3715 name: Name 

3716 

3717 #: Everything on the right hand side of the ``=``. 

3718 value: BaseExpression 

3719 

3720 #: An optional list of type parameters, specified after the name. 

3721 type_parameters: Optional[TypeParameters] = None 

3722 

3723 #: Whitespace between the ``type`` soft keyword and the name. 

3724 whitespace_after_type: SimpleWhitespace = SimpleWhitespace.field(" ") 

3725 

3726 #: Whitespace between the name and the type parameters (if they exist) or the ``=``. 

3727 #: If not specified, :class:`MaybeSentinel` will be replaced with a single space if 

3728 #: there are no type parameters, otherwise no spaces. 

3729 whitespace_after_name: Union[ 

3730 SimpleWhitespace, MaybeSentinel 

3731 ] = MaybeSentinel.DEFAULT 

3732 

3733 #: Whitespace between the type parameters and the ``=``. Always empty if there are 

3734 #: no type parameters. If not specified, :class:`MaybeSentinel` will be replaced 

3735 #: with a single space if there are type parameters. 

3736 whitespace_after_type_parameters: Union[ 

3737 SimpleWhitespace, MaybeSentinel 

3738 ] = MaybeSentinel.DEFAULT 

3739 

3740 #: Whitespace between the ``=`` and the value. 

3741 whitespace_after_equals: SimpleWhitespace = SimpleWhitespace.field(" ") 

3742 

3743 #: Optional semicolon when this is used in a statement line. This semicolon 

3744 #: owns the whitespace on both sides of it when it is used. 

3745 semicolon: Union[Semicolon, MaybeSentinel] = MaybeSentinel.DEFAULT 

3746 

3747 def _validate(self) -> None: 

3748 if ( 

3749 self.type_parameters is None 

3750 and self.whitespace_after_type_parameters 

3751 not in { 

3752 SimpleWhitespace(""), 

3753 MaybeSentinel.DEFAULT, 

3754 } 

3755 ): 

3756 raise CSTValidationError( 

3757 "whitespace_after_type_parameters must be empty when there are no type parameters in a TypeAlias" 

3758 ) 

3759 

3760 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeAlias": 

3761 return TypeAlias( 

3762 whitespace_after_type=visit_required( 

3763 self, "whitespace_after_type", self.whitespace_after_type, visitor 

3764 ), 

3765 name=visit_required(self, "name", self.name, visitor), 

3766 whitespace_after_name=visit_sentinel( 

3767 self, "whitespace_after_name", self.whitespace_after_name, visitor 

3768 ), 

3769 type_parameters=visit_optional( 

3770 self, "type_parameters", self.type_parameters, visitor 

3771 ), 

3772 whitespace_after_type_parameters=visit_sentinel( 

3773 self, 

3774 "whitespace_after_type_parameters", 

3775 self.whitespace_after_type_parameters, 

3776 visitor, 

3777 ), 

3778 whitespace_after_equals=visit_required( 

3779 self, "whitespace_after_equals", self.whitespace_after_equals, visitor 

3780 ), 

3781 value=visit_required(self, "value", self.value, visitor), 

3782 semicolon=visit_sentinel(self, "semicolon", self.semicolon, visitor), 

3783 ) 

3784 

3785 def _codegen_impl( 

3786 self, state: CodegenState, default_semicolon: bool = False 

3787 ) -> None: 

3788 with state.record_syntactic_position(self): 

3789 state.add_token("type") 

3790 self.whitespace_after_type._codegen(state) 

3791 self.name._codegen(state) 

3792 ws_after_name = self.whitespace_after_name 

3793 if isinstance(ws_after_name, MaybeSentinel): 

3794 if self.type_parameters is None: 

3795 state.add_token(" ") 

3796 else: 

3797 ws_after_name._codegen(state) 

3798 

3799 ws_after_type_params = self.whitespace_after_type_parameters 

3800 if self.type_parameters is not None: 

3801 self.type_parameters._codegen(state) 

3802 if isinstance(ws_after_type_params, MaybeSentinel): 

3803 state.add_token(" ") 

3804 else: 

3805 ws_after_type_params._codegen(state) 

3806 

3807 state.add_token("=") 

3808 self.whitespace_after_equals._codegen(state) 

3809 self.value._codegen(state) 

3810 

3811 semi = self.semicolon 

3812 if isinstance(semi, MaybeSentinel): 

3813 if default_semicolon: 

3814 state.add_token("; ") 

3815 else: 

3816 semi._codegen(state)