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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1679 statements  

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 Literal, Optional, Pattern, Sequence, Union 

11 

12from libcst import CSTLogicError 

13 

14from libcst._add_slots import add_slots 

15from libcst._maybe_sentinel import MaybeSentinel 

16from libcst._nodes.base import CSTNode, CSTValidationError 

17from libcst._nodes.expression import ( 

18 _BaseParenthesizedNode, 

19 Annotation, 

20 Arg, 

21 Asynchronous, 

22 Attribute, 

23 BaseAssignTargetExpression, 

24 BaseDelTargetExpression, 

25 BaseExpression, 

26 ConcatenatedString, 

27 ExpressionPosition, 

28 From, 

29 LeftCurlyBrace, 

30 LeftParen, 

31 LeftSquareBracket, 

32 List, 

33 Name, 

34 Parameters, 

35 RightCurlyBrace, 

36 RightParen, 

37 RightSquareBracket, 

38 SimpleString, 

39 Tuple, 

40) 

41from libcst._nodes.internal import ( 

42 CodegenState, 

43 visit_body_sequence, 

44 visit_optional, 

45 visit_required, 

46 visit_sentinel, 

47 visit_sequence, 

48) 

49from libcst._nodes.op import ( 

50 AssignEqual, 

51 BaseAugOp, 

52 BitOr, 

53 Colon, 

54 Comma, 

55 Dot, 

56 ImportStar, 

57 Semicolon, 

58) 

59from libcst._nodes.whitespace import ( 

60 BaseParenthesizableWhitespace, 

61 EmptyLine, 

62 ParenthesizedWhitespace, 

63 SimpleWhitespace, 

64 TrailingWhitespace, 

65) 

66from libcst._visitors import CSTVisitorT 

67 

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

69 

70 

71class BaseSuite(CSTNode, ABC): 

72 """ 

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

74 This exists to simplify type definitions and isinstance checks. 

75 

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

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

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

79 subsequent lines. 

80 

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

82 """ 

83 

84 __slots__ = () 

85 

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

87 

88 

89class BaseStatement(CSTNode, ABC): 

90 """ 

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

92 in a particular location. 

93 """ 

94 

95 __slots__ = () 

96 

97 

98class BaseSmallStatement(CSTNode, ABC): 

99 """ 

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

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

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

103 simplify type definitions and isinstance checks. 

104 """ 

105 

106 __slots__ = () 

107 

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

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

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

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

112 #: on the same line. 

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

114 

115 @abstractmethod 

116 def _codegen_impl( 

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

118 ) -> None: ... 

119 

120 

121@add_slots 

122@dataclass(frozen=True) 

123class Del(BaseSmallStatement): 

124 """ 

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

126 """ 

127 

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

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

130 target: BaseDelTargetExpression 

131 

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

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

134 

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

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

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

138 

139 def _validate(self) -> None: 

140 if ( 

141 self.whitespace_after_del.empty 

142 and not self.target._safe_to_use_with_word_operator( 

143 ExpressionPosition.RIGHT 

144 ) 

145 ): 

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

147 

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

149 return Del( 

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

151 whitespace_after_del=visit_required( 

152 self, "whitespace_after_del", self.whitespace_after_del, visitor 

153 ), 

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

155 ) 

156 

157 def _codegen_impl( 

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

159 ) -> None: 

160 with state.record_syntactic_position(self): 

161 state.add_token("del") 

162 self.whitespace_after_del._codegen(state) 

163 self.target._codegen(state) 

164 

165 semicolon = self.semicolon 

166 if isinstance(semicolon, MaybeSentinel): 

167 if default_semicolon: 

168 state.add_token("; ") 

169 elif isinstance(semicolon, Semicolon): 

170 semicolon._codegen(state) 

171 

172 

173@add_slots 

174@dataclass(frozen=True) 

175class Pass(BaseSmallStatement): 

176 """ 

177 Represents a ``pass`` statement. 

178 """ 

179 

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

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

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

183 

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

185 return Pass( 

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

187 ) 

188 

189 def _codegen_impl( 

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

191 ) -> None: 

192 with state.record_syntactic_position(self): 

193 state.add_token("pass") 

194 

195 semicolon = self.semicolon 

196 if isinstance(semicolon, MaybeSentinel): 

197 if default_semicolon: 

198 state.add_token("; ") 

199 elif isinstance(semicolon, Semicolon): 

200 semicolon._codegen(state) 

201 

202 

203@add_slots 

204@dataclass(frozen=True) 

205class Break(BaseSmallStatement): 

206 """ 

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

208 or :class:`While` loop early. 

209 """ 

210 

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

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

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

214 

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

216 return Break( 

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

218 ) 

219 

220 def _codegen_impl( 

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

222 ) -> None: 

223 with state.record_syntactic_position(self): 

224 state.add_token("break") 

225 

226 semicolon = self.semicolon 

227 if isinstance(semicolon, MaybeSentinel): 

228 if default_semicolon: 

229 state.add_token("; ") 

230 elif isinstance(semicolon, Semicolon): 

231 semicolon._codegen(state) 

232 

233 

234@add_slots 

235@dataclass(frozen=True) 

236class Continue(BaseSmallStatement): 

237 """ 

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

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

240 """ 

241 

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

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

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

245 

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

247 return Continue( 

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

249 ) 

250 

251 def _codegen_impl( 

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

253 ) -> None: 

254 with state.record_syntactic_position(self): 

255 state.add_token("continue") 

256 

257 semicolon = self.semicolon 

258 if isinstance(semicolon, MaybeSentinel): 

259 if default_semicolon: 

260 state.add_token("; ") 

261 elif isinstance(semicolon, Semicolon): 

262 semicolon._codegen(state) 

263 

264 

265@add_slots 

266@dataclass(frozen=True) 

267class Return(BaseSmallStatement): 

268 """ 

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

270 """ 

271 

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

273 value: Optional[BaseExpression] = None 

274 

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

276 #: value expression. 

277 whitespace_after_return: Union[SimpleWhitespace, MaybeSentinel] = ( 

278 MaybeSentinel.DEFAULT 

279 ) 

280 

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

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

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

284 

285 def _validate(self) -> None: 

286 value = self.value 

287 if value is not None: 

288 whitespace_after_return = self.whitespace_after_return 

289 has_no_gap = ( 

290 not isinstance(whitespace_after_return, MaybeSentinel) 

291 and whitespace_after_return.empty 

292 ) 

293 if has_no_gap and not value._safe_to_use_with_word_operator( 

294 ExpressionPosition.RIGHT 

295 ): 

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

297 

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

299 return Return( 

300 whitespace_after_return=visit_sentinel( 

301 self, "whitespace_after_return", self.whitespace_after_return, visitor 

302 ), 

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

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

305 ) 

306 

307 def _codegen_impl( 

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

309 ) -> None: 

310 with state.record_syntactic_position(self): 

311 state.add_token("return") 

312 whitespace_after_return = self.whitespace_after_return 

313 value = self.value 

314 if isinstance(whitespace_after_return, MaybeSentinel): 

315 if value is not None: 

316 state.add_token(" ") 

317 else: 

318 whitespace_after_return._codegen(state) 

319 if value is not None: 

320 value._codegen(state) 

321 

322 semicolon = self.semicolon 

323 if isinstance(semicolon, MaybeSentinel): 

324 if default_semicolon: 

325 state.add_token("; ") 

326 elif isinstance(semicolon, Semicolon): 

327 semicolon._codegen(state) 

328 

329 

330@add_slots 

331@dataclass(frozen=True) 

332class Expr(BaseSmallStatement): 

333 """ 

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

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

336 value is unneeded. 

337 """ 

338 

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

340 #: the result anywhere. 

341 value: BaseExpression 

342 

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

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

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

346 

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

348 return Expr( 

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

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

351 ) 

352 

353 def _codegen_impl( 

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

355 ) -> None: 

356 with state.record_syntactic_position(self): 

357 self.value._codegen(state) 

358 

359 semicolon = self.semicolon 

360 if isinstance(semicolon, MaybeSentinel): 

361 if default_semicolon: 

362 state.add_token("; ") 

363 elif isinstance(semicolon, Semicolon): 

364 semicolon._codegen(state) 

365 

366 

367class _BaseSimpleStatement(CSTNode, ABC): 

368 """ 

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

370 

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

372 

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

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

375 small statement. 

376 """ 

377 

378 __slots__ = () 

379 

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

381 #: a semicolon. 

382 body: Sequence[BaseSmallStatement] 

383 

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

385 #: grammar. 

386 trailing_whitespace: TrailingWhitespace 

387 

388 def _validate(self) -> None: 

389 body = self.body 

390 for small_stmt in body[:-1]: 

391 if small_stmt.semicolon is None: 

392 raise CSTValidationError( 

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

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

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

396 + "on the same line." 

397 ) 

398 

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

400 body = self.body 

401 if body: 

402 laststmt = len(body) - 1 

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

404 for idx, stmt in enumerate(body): 

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

406 else: 

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

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

409 with state.record_syntactic_position(self): 

410 state.add_token("pass") 

411 

412 self.trailing_whitespace._codegen(state) 

413 

414 

415@add_slots 

416@dataclass(frozen=True) 

417class SimpleStatementLine(_BaseSimpleStatement, BaseStatement): 

418 """ 

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

420 a series of small statements joined together by semicolons. 

421 

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

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

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

425 """ 

426 

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

428 #: a semicolon. 

429 body: Sequence[BaseSmallStatement] 

430 

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

432 leading_lines: Sequence[EmptyLine] = () 

433 

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

435 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

436 

437 def _visit_and_replace_children( 

438 self, visitor: CSTVisitorT 

439 ) -> "SimpleStatementLine": 

440 return SimpleStatementLine( 

441 leading_lines=visit_sequence( 

442 self, "leading_lines", self.leading_lines, visitor 

443 ), 

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

445 trailing_whitespace=visit_required( 

446 self, "trailing_whitespace", self.trailing_whitespace, visitor 

447 ), 

448 ) 

449 

450 def _is_removable(self) -> bool: 

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

452 # anything concrete. 

453 return not self.body 

454 

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

456 for ll in self.leading_lines: 

457 ll._codegen(state) 

458 state.add_indent_tokens() 

459 _BaseSimpleStatement._codegen_impl(self, state) 

460 

461 

462@add_slots 

463@dataclass(frozen=True) 

464class SimpleStatementSuite(_BaseSimpleStatement, BaseSuite): 

465 """ 

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

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

468 colon in a compound statement. 

469 

470 .. code-block:: 

471 

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

473 

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

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

476 it in the CST. 

477 """ 

478 

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

480 #: a semicolon. 

481 body: Sequence[BaseSmallStatement] 

482 

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

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

485 

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

487 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

488 

489 def _visit_and_replace_children( 

490 self, visitor: CSTVisitorT 

491 ) -> "SimpleStatementSuite": 

492 return SimpleStatementSuite( 

493 leading_whitespace=visit_required( 

494 self, "leading_whitespace", self.leading_whitespace, visitor 

495 ), 

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

497 trailing_whitespace=visit_required( 

498 self, "trailing_whitespace", self.trailing_whitespace, visitor 

499 ), 

500 ) 

501 

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

503 self.leading_whitespace._codegen(state) 

504 _BaseSimpleStatement._codegen_impl(self, state) 

505 

506 

507@add_slots 

508@dataclass(frozen=True) 

509class Else(CSTNode): 

510 """ 

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

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

513 

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

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

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

517 """ 

518 

519 #: The body of else clause. 

520 body: BaseSuite 

521 

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

523 leading_lines: Sequence[EmptyLine] = () 

524 

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

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

527 

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

529 return Else( 

530 leading_lines=visit_sequence( 

531 self, "leading_lines", self.leading_lines, visitor 

532 ), 

533 whitespace_before_colon=visit_required( 

534 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

535 ), 

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

537 ) 

538 

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

540 for ll in self.leading_lines: 

541 ll._codegen(state) 

542 state.add_indent_tokens() 

543 

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

545 state.add_token("else") 

546 self.whitespace_before_colon._codegen(state) 

547 state.add_token(":") 

548 self.body._codegen(state) 

549 

550 

551class BaseCompoundStatement(BaseStatement, ABC): 

552 """ 

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

554 This exists to simplify type definitions and isinstance checks. 

555 

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

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

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

559 statement may be contained in one line. 

560 

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

562 """ 

563 

564 __slots__ = () 

565 

566 #: The body of this compound statement. 

567 body: BaseSuite 

568 

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

570 leading_lines: Sequence[EmptyLine] 

571 

572 

573@add_slots 

574@dataclass(frozen=True) 

575class If(BaseCompoundStatement): 

576 """ 

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

578 

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

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

581 """ 

582 

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

584 test: BaseExpression # TODO: should be a test_nocond 

585 

586 #: The body of this compound statement. 

587 body: BaseSuite 

588 

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

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

591 #:``elif`` block. 

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

593 

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

595 leading_lines: Sequence[EmptyLine] = () 

596 

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

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

599 

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

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

602 

603 def _validate(self) -> None: 

604 if ( 

605 self.whitespace_before_test.empty 

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

607 ): 

608 raise CSTValidationError("Must have at least one space after 'if' keyword.") 

609 

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

611 return If( 

612 leading_lines=visit_sequence( 

613 self, "leading_lines", self.leading_lines, visitor 

614 ), 

615 whitespace_before_test=visit_required( 

616 self, "whitespace_before_test", self.whitespace_before_test, visitor 

617 ), 

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

619 whitespace_after_test=visit_required( 

620 self, "whitespace_after_test", self.whitespace_after_test, visitor 

621 ), 

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

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

624 ) 

625 

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

627 for ll in self.leading_lines: 

628 ll._codegen(state) 

629 state.add_indent_tokens() 

630 

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

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

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

634 self.whitespace_before_test._codegen(state) 

635 self.test._codegen(state) 

636 self.whitespace_after_test._codegen(state) 

637 state.add_token(":") 

638 self.body._codegen(state) 

639 orelse = self.orelse 

640 if orelse is not None: 

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

642 orelse._codegen(state, is_elif=True) 

643 else: # is an Else clause 

644 orelse._codegen(state) 

645 

646 

647@add_slots 

648@dataclass(frozen=True) 

649class IndentedBlock(BaseSuite): 

650 """ 

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

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

653 body. 

654 

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

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

657 body of many compound statements. 

658 

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

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

661 statement's clause. 

662 

663 .. code-block:: 

664 

665 if test: # IndentedBlock's header 

666 body 

667 """ 

668 

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

670 body: Sequence[BaseStatement] 

671 

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

673 header: TrailingWhitespace = TrailingWhitespace.field() 

674 

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

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

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

678 indent: Optional[str] = None 

679 

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

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

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

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

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

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

686 footer: Sequence[EmptyLine] = () 

687 

688 def _validate(self) -> None: 

689 indent = self.indent 

690 if indent is not None: 

691 if len(indent) == 0: 

692 raise CSTValidationError( 

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

694 ) 

695 if _INDENT_WHITESPACE_RE.fullmatch(indent) is None: 

696 raise CSTValidationError( 

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

698 ) 

699 

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

701 return IndentedBlock( 

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

703 indent=self.indent, 

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

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

706 ) 

707 

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

709 self.header._codegen(state) 

710 

711 indent = self.indent 

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

713 

714 if self.body: 

715 with state.record_syntactic_position( 

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

717 ): 

718 for stmt in self.body: 

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

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

721 # the token list. 

722 stmt._codegen(state) 

723 else: 

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

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

726 state.add_indent_tokens() 

727 with state.record_syntactic_position(self): 

728 state.add_token("pass") 

729 state.add_token(state.default_newline) 

730 

731 for f in self.footer: 

732 f._codegen(state) 

733 

734 state.decrease_indent() 

735 

736 

737@add_slots 

738@dataclass(frozen=True) 

739class AsName(CSTNode): 

740 """ 

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

742 :class:`WithItem` node. 

743 """ 

744 

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

746 name: Union[Name, Tuple, List] 

747 

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

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

750 

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

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

753 

754 def _validate(self) -> None: 

755 if ( 

756 self.whitespace_after_as.empty 

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

758 ): 

759 raise CSTValidationError( 

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

761 ) 

762 

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

764 return AsName( 

765 whitespace_before_as=visit_required( 

766 self, "whitespace_before_as", self.whitespace_before_as, visitor 

767 ), 

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

769 whitespace_after_as=visit_required( 

770 self, "whitespace_after_as", self.whitespace_after_as, visitor 

771 ), 

772 ) 

773 

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

775 self.whitespace_before_as._codegen(state) 

776 state.add_token("as") 

777 self.whitespace_after_as._codegen(state) 

778 self.name._codegen(state) 

779 

780 

781@add_slots 

782@dataclass(frozen=True) 

783class ExceptHandler(CSTNode): 

784 """ 

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

786 """ 

787 

788 #: The body of the except. 

789 body: BaseSuite 

790 

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

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

793 type: Optional[BaseExpression] = None 

794 

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

796 name: Optional[AsName] = None 

797 

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

799 leading_lines: Sequence[EmptyLine] = () 

800 

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

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

803 

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

805 #: the colon. 

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

807 

808 def _validate(self) -> None: 

809 name = self.name 

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

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

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

813 raise CSTValidationError( 

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

815 ) 

816 type_ = self.type 

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

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

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

820 # grouping or tuple parens. 

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

822 raise CSTValidationError( 

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

824 ) 

825 name = self.name 

826 if ( 

827 type_ is not None 

828 and name is not None 

829 and name.whitespace_before_as.empty 

830 and not type_._safe_to_use_with_word_operator(ExpressionPosition.LEFT) 

831 ): 

832 raise CSTValidationError( 

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

834 ) 

835 

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

837 return ExceptHandler( 

838 leading_lines=visit_sequence( 

839 self, "leading_lines", self.leading_lines, visitor 

840 ), 

841 whitespace_after_except=visit_required( 

842 self, "whitespace_after_except", self.whitespace_after_except, visitor 

843 ), 

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

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

846 whitespace_before_colon=visit_required( 

847 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

848 ), 

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

850 ) 

851 

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

853 for ll in self.leading_lines: 

854 ll._codegen(state) 

855 state.add_indent_tokens() 

856 

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

858 state.add_token("except") 

859 self.whitespace_after_except._codegen(state) 

860 typenode = self.type 

861 if typenode is not None: 

862 typenode._codegen(state) 

863 namenode = self.name 

864 if namenode is not None: 

865 namenode._codegen(state) 

866 self.whitespace_before_colon._codegen(state) 

867 state.add_token(":") 

868 self.body._codegen(state) 

869 

870 

871@add_slots 

872@dataclass(frozen=True) 

873class ExceptStarHandler(CSTNode): 

874 """ 

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

876 """ 

877 

878 #: The body of the except. 

879 body: BaseSuite 

880 

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

882 type: BaseExpression 

883 

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

885 name: Optional[AsName] = None 

886 

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

888 leading_lines: Sequence[EmptyLine] = () 

889 

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

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

892 

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

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

895 

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

897 #: the colon. 

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

899 

900 def _validate(self) -> None: 

901 name = self.name 

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

903 raise CSTValidationError( 

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

905 ) 

906 

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

908 return ExceptStarHandler( 

909 leading_lines=visit_sequence( 

910 self, "leading_lines", self.leading_lines, visitor 

911 ), 

912 whitespace_after_except=visit_required( 

913 self, "whitespace_after_except", self.whitespace_after_except, visitor 

914 ), 

915 whitespace_after_star=visit_required( 

916 self, "whitespace_after_star", self.whitespace_after_star, visitor 

917 ), 

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

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

920 whitespace_before_colon=visit_required( 

921 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

922 ), 

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

924 ) 

925 

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

927 for ll in self.leading_lines: 

928 ll._codegen(state) 

929 state.add_indent_tokens() 

930 

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

932 state.add_token("except") 

933 self.whitespace_after_except._codegen(state) 

934 state.add_token("*") 

935 self.whitespace_after_star._codegen(state) 

936 typenode = self.type 

937 if typenode is not None: 

938 typenode._codegen(state) 

939 namenode = self.name 

940 if namenode is not None: 

941 namenode._codegen(state) 

942 self.whitespace_before_colon._codegen(state) 

943 state.add_token(":") 

944 self.body._codegen(state) 

945 

946 

947@add_slots 

948@dataclass(frozen=True) 

949class Finally(CSTNode): 

950 """ 

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

952 """ 

953 

954 #: The body of the except. 

955 body: BaseSuite 

956 

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

958 leading_lines: Sequence[EmptyLine] = () 

959 

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

961 #: the colon. 

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

963 

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

965 return Finally( 

966 leading_lines=visit_sequence( 

967 self, "leading_lines", self.leading_lines, visitor 

968 ), 

969 whitespace_before_colon=visit_required( 

970 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

971 ), 

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

973 ) 

974 

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

976 for ll in self.leading_lines: 

977 ll._codegen(state) 

978 state.add_indent_tokens() 

979 

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

981 state.add_token("finally") 

982 self.whitespace_before_colon._codegen(state) 

983 state.add_token(":") 

984 self.body._codegen(state) 

985 

986 

987@add_slots 

988@dataclass(frozen=True) 

989class Try(BaseCompoundStatement): 

990 """ 

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

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

993 :class:`TryStar`. 

994 """ 

995 

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

997 body: BaseSuite 

998 

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

1000 handlers: Sequence[ExceptHandler] = () 

1001 

1002 #: An optional else case. 

1003 orelse: Optional[Else] = None 

1004 

1005 #: An optional finally case. 

1006 finalbody: Optional[Finally] = None 

1007 

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

1009 leading_lines: Sequence[EmptyLine] = () 

1010 

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

1012 #: the colon. 

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

1014 

1015 def _validate(self) -> None: 

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

1017 raise CSTValidationError( 

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

1019 ) 

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

1021 raise CSTValidationError( 

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

1023 + "to have an Else." 

1024 ) 

1025 # Check bare excepts are always at the last position 

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

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

1028 

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

1030 return Try( 

1031 leading_lines=visit_sequence( 

1032 self, "leading_lines", self.leading_lines, visitor 

1033 ), 

1034 whitespace_before_colon=visit_required( 

1035 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1036 ), 

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

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

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

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

1041 ) 

1042 

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

1044 for ll in self.leading_lines: 

1045 ll._codegen(state) 

1046 state.add_indent_tokens() 

1047 

1048 end_node = self.body 

1049 if len(self.handlers) > 0: 

1050 end_node = self.handlers[-1] 

1051 orelse = self.orelse 

1052 end_node = end_node if orelse is None else orelse 

1053 finalbody = self.finalbody 

1054 end_node = end_node if finalbody is None else finalbody 

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

1056 state.add_token("try") 

1057 self.whitespace_before_colon._codegen(state) 

1058 state.add_token(":") 

1059 self.body._codegen(state) 

1060 for handler in self.handlers: 

1061 handler._codegen(state) 

1062 if orelse is not None: 

1063 orelse._codegen(state) 

1064 if finalbody is not None: 

1065 finalbody._codegen(state) 

1066 

1067 

1068@add_slots 

1069@dataclass(frozen=True) 

1070class TryStar(BaseCompoundStatement): 

1071 """ 

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

1073 """ 

1074 

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

1076 body: BaseSuite 

1077 

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

1079 handlers: Sequence[ExceptStarHandler] 

1080 

1081 #: An optional else case. 

1082 orelse: Optional[Else] = None 

1083 

1084 #: An optional finally case. 

1085 finalbody: Optional[Finally] = None 

1086 

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

1088 leading_lines: Sequence[EmptyLine] = () 

1089 

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

1091 #: the colon. 

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

1093 

1094 def _validate(self) -> None: 

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

1096 raise CSTValidationError( 

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

1098 ) 

1099 

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

1101 return TryStar( 

1102 leading_lines=visit_sequence( 

1103 self, "leading_lines", self.leading_lines, visitor 

1104 ), 

1105 whitespace_before_colon=visit_required( 

1106 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1107 ), 

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

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

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

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

1112 ) 

1113 

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

1115 for ll in self.leading_lines: 

1116 ll._codegen(state) 

1117 state.add_indent_tokens() 

1118 

1119 end_node = self.handlers[-1] 

1120 orelse = self.orelse 

1121 end_node = end_node if orelse is None else orelse 

1122 finalbody = self.finalbody 

1123 end_node = end_node if finalbody is None else finalbody 

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

1125 state.add_token("try") 

1126 self.whitespace_before_colon._codegen(state) 

1127 state.add_token(":") 

1128 self.body._codegen(state) 

1129 for handler in self.handlers: 

1130 handler._codegen(state) 

1131 if orelse is not None: 

1132 orelse._codegen(state) 

1133 if finalbody is not None: 

1134 finalbody._codegen(state) 

1135 

1136 

1137@add_slots 

1138@dataclass(frozen=True) 

1139class ImportAlias(CSTNode): 

1140 """ 

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

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

1143 """ 

1144 

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

1146 name: Union[Attribute, Name] 

1147 

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

1149 asname: Optional[AsName] = None 

1150 

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

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

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

1154 #: multiple imports. 

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

1156 

1157 def _validate(self) -> None: 

1158 asname = self.asname 

1159 if asname is not None: 

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

1161 raise CSTValidationError( 

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

1163 ) 

1164 if asname.whitespace_before_as.empty: 

1165 raise CSTValidationError( 

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

1167 ) 

1168 try: 

1169 self.evaluated_name 

1170 except CSTLogicError as e: 

1171 raise CSTValidationError( 

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

1173 ) from e 

1174 

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

1176 return ImportAlias( 

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

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

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

1180 ) 

1181 

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

1183 with state.record_syntactic_position(self): 

1184 self.name._codegen(state) 

1185 asname = self.asname 

1186 if asname is not None: 

1187 asname._codegen(state) 

1188 

1189 comma = self.comma 

1190 if comma is MaybeSentinel.DEFAULT and default_comma: 

1191 state.add_token(", ") 

1192 elif isinstance(comma, Comma): 

1193 comma._codegen(state) 

1194 

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

1196 # Unrolled version of get_full_name_for_node to avoid circular imports. 

1197 if isinstance(node, Name): 

1198 return node.value 

1199 elif isinstance(node, Attribute): 

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

1201 else: 

1202 raise CSTLogicError("Logic error!") 

1203 

1204 @property 

1205 def evaluated_name(self) -> str: 

1206 """ 

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

1208 """ 

1209 return self._name(self.name) 

1210 

1211 @property 

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

1213 """ 

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

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

1216 """ 

1217 asname = self.asname 

1218 if asname is not None: 

1219 return self._name(asname.name) 

1220 return None 

1221 

1222 

1223@add_slots 

1224@dataclass(frozen=True) 

1225class Import(BaseSmallStatement): 

1226 """ 

1227 An ``import`` statement. 

1228 """ 

1229 

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

1231 names: Sequence[ImportAlias] 

1232 

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

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

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

1236 

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

1238 #: the first import alias. 

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

1240 

1241 def _validate(self) -> None: 

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

1243 raise CSTValidationError( 

1244 "An ImportStatement must have at least one ImportAlias" 

1245 ) 

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

1247 raise CSTValidationError( 

1248 "An ImportStatement does not allow a trailing comma" 

1249 ) 

1250 if self.whitespace_after_import.empty: 

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

1252 

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

1254 return Import( 

1255 whitespace_after_import=visit_required( 

1256 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1257 ), 

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

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

1260 ) 

1261 

1262 def _codegen_impl( 

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

1264 ) -> None: 

1265 with state.record_syntactic_position(self): 

1266 state.add_token("import") 

1267 self.whitespace_after_import._codegen(state) 

1268 lastname = len(self.names) - 1 

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

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

1271 

1272 semicolon = self.semicolon 

1273 if isinstance(semicolon, MaybeSentinel): 

1274 if default_semicolon: 

1275 state.add_token("; ") 

1276 elif isinstance(semicolon, Semicolon): 

1277 semicolon._codegen(state) 

1278 

1279 

1280@add_slots 

1281@dataclass(frozen=True) 

1282class ImportFrom(BaseSmallStatement): 

1283 """ 

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

1285 """ 

1286 

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

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

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

1290 

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

1292 #: with optional local aliases. 

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

1294 

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

1296 relative: Sequence[Dot] = () 

1297 

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

1299 lpar: Optional[LeftParen] = None 

1300 

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

1302 rpar: Optional[RightParen] = None 

1303 

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

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

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

1307 

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

1309 #: the module and any relative import dots. 

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

1311 

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

1313 #: ``import`` keyword. 

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

1315 

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

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

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

1319 

1320 def _validate_module(self) -> None: 

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

1322 raise CSTValidationError( 

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

1324 ) 

1325 

1326 def _validate_names(self) -> None: 

1327 names = self.names 

1328 if isinstance(names, Sequence): 

1329 if len(names) == 0: 

1330 raise CSTValidationError( 

1331 "An ImportFrom must have at least one ImportAlias" 

1332 ) 

1333 for name in names[:-1]: 

1334 if name.comma is None: 

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

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

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

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

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

1340 if isinstance(names, ImportStar): 

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

1342 raise CSTValidationError( 

1343 "An ImportFrom using ImportStar cannot have parens" 

1344 ) 

1345 

1346 def _validate_whitespace(self) -> None: 

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

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

1349 if self.whitespace_before_import.empty and not ( 

1350 self.relative and self.module is None 

1351 ): 

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

1353 if ( 

1354 self.whitespace_after_import.empty 

1355 and self.lpar is None 

1356 and not isinstance(self.names, ImportStar) 

1357 ): 

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

1359 

1360 def _validate(self) -> None: 

1361 self._validate_module() 

1362 self._validate_names() 

1363 self._validate_whitespace() 

1364 

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

1366 names = self.names 

1367 return ImportFrom( 

1368 whitespace_after_from=visit_required( 

1369 self, "whitespace_after_from", self.whitespace_after_from, visitor 

1370 ), 

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

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

1373 whitespace_before_import=visit_required( 

1374 self, "whitespace_before_import", self.whitespace_before_import, visitor 

1375 ), 

1376 whitespace_after_import=visit_required( 

1377 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1378 ), 

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

1380 names=( 

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

1382 if isinstance(names, ImportStar) 

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

1384 ), 

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

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

1387 ) 

1388 

1389 def _codegen_impl( 

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

1391 ) -> None: 

1392 names = self.names 

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

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

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

1396 state.add_token("from") 

1397 self.whitespace_after_from._codegen(state) 

1398 for dot in self.relative: 

1399 dot._codegen(state) 

1400 module = self.module 

1401 if module is not None: 

1402 module._codegen(state) 

1403 self.whitespace_before_import._codegen(state) 

1404 state.add_token("import") 

1405 self.whitespace_after_import._codegen(state) 

1406 lpar = self.lpar 

1407 if lpar is not None: 

1408 lpar._codegen(state) 

1409 if isinstance(names, Sequence): 

1410 lastname = len(names) - 1 

1411 for i, name in enumerate(names): 

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

1413 if isinstance(names, ImportStar): 

1414 names._codegen(state) 

1415 rpar = self.rpar 

1416 if rpar is not None: 

1417 rpar._codegen(state) 

1418 

1419 semicolon = self.semicolon 

1420 if isinstance(semicolon, MaybeSentinel): 

1421 if default_semicolon: 

1422 state.add_token("; ") 

1423 elif isinstance(semicolon, Semicolon): 

1424 semicolon._codegen(state) 

1425 

1426 

1427@add_slots 

1428@dataclass(frozen=True) 

1429class AssignTarget(CSTNode): 

1430 """ 

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

1432 """ 

1433 

1434 #: The target expression being assigned to. 

1435 target: BaseAssignTargetExpression 

1436 

1437 #: The whitespace appearing before the equals sign. 

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

1439 

1440 #: The whitespace appearing after the equals sign. 

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

1442 

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

1444 return AssignTarget( 

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

1446 whitespace_before_equal=visit_required( 

1447 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

1448 ), 

1449 whitespace_after_equal=visit_required( 

1450 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

1451 ), 

1452 ) 

1453 

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

1455 with state.record_syntactic_position(self): 

1456 self.target._codegen(state) 

1457 

1458 self.whitespace_before_equal._codegen(state) 

1459 state.add_token("=") 

1460 self.whitespace_after_equal._codegen(state) 

1461 

1462 

1463@add_slots 

1464@dataclass(frozen=True) 

1465class Assign(BaseSmallStatement): 

1466 """ 

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

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

1469 allow for multiple targets. 

1470 """ 

1471 

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

1473 targets: Sequence[AssignTarget] 

1474 

1475 #: The expression being assigned to the targets. 

1476 value: BaseExpression 

1477 

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

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

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

1481 

1482 def _validate(self) -> None: 

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

1484 raise CSTValidationError( 

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

1486 ) 

1487 

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

1489 return Assign( 

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

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

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

1493 ) 

1494 

1495 def _codegen_impl( 

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

1497 ) -> None: 

1498 with state.record_syntactic_position(self): 

1499 for target in self.targets: 

1500 target._codegen(state) 

1501 self.value._codegen(state) 

1502 

1503 semicolon = self.semicolon 

1504 if isinstance(semicolon, MaybeSentinel): 

1505 if default_semicolon: 

1506 state.add_token("; ") 

1507 elif isinstance(semicolon, Semicolon): 

1508 semicolon._codegen(state) 

1509 

1510 

1511@add_slots 

1512@dataclass(frozen=True) 

1513class AnnAssign(BaseSmallStatement): 

1514 """ 

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

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

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

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

1519 to it. 

1520 """ 

1521 

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

1523 target: BaseAssignTargetExpression 

1524 

1525 #: The annotation for the target. 

1526 annotation: Annotation 

1527 

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

1529 value: Optional[BaseExpression] = None 

1530 

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

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

1533 

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

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

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

1537 

1538 def _validate(self) -> None: 

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

1540 raise CSTValidationError( 

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

1542 ) 

1543 

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

1545 return AnnAssign( 

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

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

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

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

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

1551 ) 

1552 

1553 def _codegen_impl( 

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

1555 ) -> None: 

1556 with state.record_syntactic_position(self): 

1557 self.target._codegen(state) 

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

1559 equal = self.equal 

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

1561 state.add_token(" = ") 

1562 elif isinstance(equal, AssignEqual): 

1563 equal._codegen(state) 

1564 value = self.value 

1565 if value is not None: 

1566 value._codegen(state) 

1567 

1568 semicolon = self.semicolon 

1569 if isinstance(semicolon, MaybeSentinel): 

1570 if default_semicolon: 

1571 state.add_token("; ") 

1572 elif isinstance(semicolon, Semicolon): 

1573 semicolon._codegen(state) 

1574 

1575 

1576@add_slots 

1577@dataclass(frozen=True) 

1578class AugAssign(BaseSmallStatement): 

1579 """ 

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

1581 """ 

1582 

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

1584 target: BaseAssignTargetExpression 

1585 

1586 #: The augmented assignment operation being performed. 

1587 operator: BaseAugOp 

1588 

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

1590 value: BaseExpression 

1591 

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

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

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

1595 

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

1597 return AugAssign( 

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

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

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

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

1602 ) 

1603 

1604 def _codegen_impl( 

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

1606 ) -> None: 

1607 with state.record_syntactic_position(self): 

1608 self.target._codegen(state) 

1609 self.operator._codegen(state) 

1610 self.value._codegen(state) 

1611 

1612 semicolon = self.semicolon 

1613 if isinstance(semicolon, MaybeSentinel): 

1614 if default_semicolon: 

1615 state.add_token("; ") 

1616 elif isinstance(semicolon, Semicolon): 

1617 semicolon._codegen(state) 

1618 

1619 

1620@add_slots 

1621@dataclass(frozen=True) 

1622class Decorator(CSTNode): 

1623 """ 

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

1625 """ 

1626 

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

1628 #: of this decorator. 

1629 decorator: BaseExpression 

1630 

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

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

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

1634 leading_lines: Sequence[EmptyLine] = () 

1635 

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

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

1638 

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

1640 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

1641 

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

1643 return Decorator( 

1644 leading_lines=visit_sequence( 

1645 self, "leading_lines", self.leading_lines, visitor 

1646 ), 

1647 whitespace_after_at=visit_required( 

1648 self, "whitespace_after_at", self.whitespace_after_at, visitor 

1649 ), 

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

1651 trailing_whitespace=visit_required( 

1652 self, "trailing_whitespace", self.trailing_whitespace, visitor 

1653 ), 

1654 ) 

1655 

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

1657 for ll in self.leading_lines: 

1658 ll._codegen(state) 

1659 state.add_indent_tokens() 

1660 

1661 with state.record_syntactic_position(self): 

1662 state.add_token("@") 

1663 self.whitespace_after_at._codegen(state) 

1664 self.decorator._codegen(state) 

1665 

1666 self.trailing_whitespace._codegen(state) 

1667 

1668 

1669def get_docstring_impl( 

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

1671 clean: bool, 

1672) -> Optional[str]: 

1673 """ 

1674 Implementation Reference: 

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

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

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

1678 """ 

1679 if isinstance(body, Sequence): 

1680 if body: 

1681 expr = body[0] 

1682 else: 

1683 return None 

1684 else: 

1685 expr = body 

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

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

1688 return None 

1689 expr = expr.body[0] 

1690 if not isinstance(expr, Expr): 

1691 return None 

1692 val = expr.value 

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

1694 evaluated_value = val.evaluated_value 

1695 else: 

1696 return None 

1697 if isinstance(evaluated_value, bytes): 

1698 return None 

1699 

1700 if evaluated_value is not None and clean: 

1701 return inspect.cleandoc(evaluated_value) 

1702 return evaluated_value 

1703 

1704 

1705@add_slots 

1706@dataclass(frozen=True) 

1707class FunctionDef(BaseCompoundStatement): 

1708 """ 

1709 A function definition. 

1710 """ 

1711 

1712 #: The function name. 

1713 name: Name 

1714 

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

1716 params: Parameters 

1717 

1718 #: The function body. 

1719 body: BaseSuite 

1720 

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

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

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

1724 decorators: Sequence[Decorator] = () 

1725 

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

1727 returns: Optional[Annotation] = None 

1728 

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

1730 asynchronous: Optional[Asynchronous] = None 

1731 

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

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

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

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

1736 #: function definition. 

1737 leading_lines: Sequence[EmptyLine] = () 

1738 

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

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

1741 lines_after_decorators: Sequence[EmptyLine] = () 

1742 

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

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

1745 

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

1747 #: parenthesis for the parameters. 

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

1749 

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

1751 #: the first param itself. 

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

1753 

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

1755 #: the colon. 

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

1757 

1758 #: An optional declaration of type parameters. 

1759 type_parameters: Optional["TypeParameters"] = None 

1760 

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

1762 #: (non-type) parameters. 

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

1764 

1765 def _validate(self) -> None: 

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

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

1768 if self.whitespace_after_def.empty: 

1769 raise CSTValidationError( 

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

1771 ) 

1772 

1773 if ( 

1774 self.type_parameters is None 

1775 and not self.whitespace_after_type_parameters.empty 

1776 ): 

1777 raise CSTValidationError( 

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

1779 "parameters in FunctionDef" 

1780 ) 

1781 

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

1783 return FunctionDef( 

1784 leading_lines=visit_sequence( 

1785 self, "leading_lines", self.leading_lines, visitor 

1786 ), 

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

1788 lines_after_decorators=visit_sequence( 

1789 self, "lines_after_decorators", self.lines_after_decorators, visitor 

1790 ), 

1791 asynchronous=visit_optional( 

1792 self, "asynchronous", self.asynchronous, visitor 

1793 ), 

1794 whitespace_after_def=visit_required( 

1795 self, "whitespace_after_def", self.whitespace_after_def, visitor 

1796 ), 

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

1798 whitespace_after_name=visit_required( 

1799 self, "whitespace_after_name", self.whitespace_after_name, visitor 

1800 ), 

1801 type_parameters=visit_optional( 

1802 self, "type_parameters", self.type_parameters, visitor 

1803 ), 

1804 whitespace_after_type_parameters=visit_required( 

1805 self, 

1806 "whitespace_after_type_parameters", 

1807 self.whitespace_after_type_parameters, 

1808 visitor, 

1809 ), 

1810 whitespace_before_params=visit_required( 

1811 self, "whitespace_before_params", self.whitespace_before_params, visitor 

1812 ), 

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

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

1815 whitespace_before_colon=visit_required( 

1816 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1817 ), 

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

1819 ) 

1820 

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

1822 for ll in self.leading_lines: 

1823 ll._codegen(state) 

1824 for decorator in self.decorators: 

1825 decorator._codegen(state) 

1826 for lad in self.lines_after_decorators: 

1827 lad._codegen(state) 

1828 state.add_indent_tokens() 

1829 

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

1831 asynchronous = self.asynchronous 

1832 if asynchronous is not None: 

1833 asynchronous._codegen(state) 

1834 state.add_token("def") 

1835 self.whitespace_after_def._codegen(state) 

1836 self.name._codegen(state) 

1837 self.whitespace_after_name._codegen(state) 

1838 type_params = self.type_parameters 

1839 if type_params is not None: 

1840 type_params._codegen(state) 

1841 self.whitespace_after_type_parameters._codegen(state) 

1842 state.add_token("(") 

1843 self.whitespace_before_params._codegen(state) 

1844 self.params._codegen(state) 

1845 state.add_token(")") 

1846 returns = self.returns 

1847 if returns is not None: 

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

1849 self.whitespace_before_colon._codegen(state) 

1850 state.add_token(":") 

1851 self.body._codegen(state) 

1852 

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

1854 """ 

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

1856 Otherwise, returns ``None``. 

1857 """ 

1858 return get_docstring_impl(self.body, clean) 

1859 

1860 

1861@add_slots 

1862@dataclass(frozen=True) 

1863class ClassDef(BaseCompoundStatement): 

1864 """ 

1865 A class definition. 

1866 """ 

1867 

1868 #: The class name. 

1869 name: Name 

1870 

1871 #: The class body. 

1872 body: BaseSuite 

1873 

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

1875 bases: Sequence[Arg] = () 

1876 

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

1878 keywords: Sequence[Arg] = () 

1879 

1880 #: Sequence of decorators applied to this class. 

1881 decorators: Sequence[Decorator] = () 

1882 

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

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

1885 

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

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

1888 

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

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

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

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

1893 #: class definition. 

1894 leading_lines: Sequence[EmptyLine] = () 

1895 

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

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

1898 lines_after_decorators: Sequence[EmptyLine] = () 

1899 

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

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

1902 

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

1904 #: parenthesis for the bases and keywords. 

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

1906 

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

1908 #: the colon. 

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

1910 

1911 #: An optional declaration of type parameters. 

1912 type_parameters: Optional["TypeParameters"] = None 

1913 

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

1915 #: keywords. 

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

1917 

1918 def _validate_whitespace(self) -> None: 

1919 if self.whitespace_after_class.empty: 

1920 raise CSTValidationError( 

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

1922 ) 

1923 if ( 

1924 self.type_parameters is None 

1925 and not self.whitespace_after_type_parameters.empty 

1926 ): 

1927 raise CSTValidationError( 

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

1929 "parameters in a ClassDef" 

1930 ) 

1931 

1932 def _validate_parens(self) -> None: 

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

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

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

1936 raise CSTValidationError( 

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

1938 ) 

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

1940 raise CSTValidationError( 

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

1942 ) 

1943 

1944 def _validate_args(self) -> None: 

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

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

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

1948 raise CSTValidationError( 

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

1950 ) 

1951 

1952 def _validate(self) -> None: 

1953 self._validate_whitespace() 

1954 self._validate_parens() 

1955 self._validate_args() 

1956 

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

1958 return ClassDef( 

1959 leading_lines=visit_sequence( 

1960 self, "leading_lines", self.leading_lines, visitor 

1961 ), 

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

1963 lines_after_decorators=visit_sequence( 

1964 self, "lines_after_decorators", self.lines_after_decorators, visitor 

1965 ), 

1966 whitespace_after_class=visit_required( 

1967 self, "whitespace_after_class", self.whitespace_after_class, visitor 

1968 ), 

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

1970 whitespace_after_name=visit_required( 

1971 self, "whitespace_after_name", self.whitespace_after_name, visitor 

1972 ), 

1973 type_parameters=visit_optional( 

1974 self, "type_parameters", self.type_parameters, visitor 

1975 ), 

1976 whitespace_after_type_parameters=visit_required( 

1977 self, 

1978 "whitespace_after_type_parameters", 

1979 self.whitespace_after_type_parameters, 

1980 visitor, 

1981 ), 

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

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

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

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

1986 whitespace_before_colon=visit_required( 

1987 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

1988 ), 

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

1990 ) 

1991 

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

1993 for ll in self.leading_lines: 

1994 ll._codegen(state) 

1995 for decorator in self.decorators: 

1996 decorator._codegen(state) 

1997 for lad in self.lines_after_decorators: 

1998 lad._codegen(state) 

1999 state.add_indent_tokens() 

2000 

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

2002 state.add_token("class") 

2003 self.whitespace_after_class._codegen(state) 

2004 self.name._codegen(state) 

2005 self.whitespace_after_name._codegen(state) 

2006 type_params = self.type_parameters 

2007 if type_params is not None: 

2008 type_params._codegen(state) 

2009 self.whitespace_after_type_parameters._codegen(state) 

2010 lpar = self.lpar 

2011 if isinstance(lpar, MaybeSentinel): 

2012 if self.bases or self.keywords: 

2013 state.add_token("(") 

2014 elif isinstance(lpar, LeftParen): 

2015 lpar._codegen(state) 

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

2017 last_arg = len(args) - 1 

2018 for i, arg in enumerate(args): 

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

2020 rpar = self.rpar 

2021 if isinstance(rpar, MaybeSentinel): 

2022 if self.bases or self.keywords: 

2023 state.add_token(")") 

2024 elif isinstance(rpar, RightParen): 

2025 rpar._codegen(state) 

2026 self.whitespace_before_colon._codegen(state) 

2027 state.add_token(":") 

2028 self.body._codegen(state) 

2029 

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

2031 """ 

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

2033 """ 

2034 return get_docstring_impl(self.body, clean) 

2035 

2036 

2037@add_slots 

2038@dataclass(frozen=True) 

2039class WithItem(CSTNode): 

2040 """ 

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

2042 """ 

2043 

2044 #: Expression that evaluates to a context manager. 

2045 item: BaseExpression 

2046 

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

2048 #: :class:`With` body. 

2049 asname: Optional[AsName] = None 

2050 

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

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

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

2054 

2055 def _validate(self) -> None: 

2056 asname = self.asname 

2057 if ( 

2058 asname is not None 

2059 and asname.whitespace_before_as.empty 

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

2061 ): 

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

2063 

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

2065 return WithItem( 

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

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

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

2069 ) 

2070 

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

2072 with state.record_syntactic_position(self): 

2073 self.item._codegen(state) 

2074 asname = self.asname 

2075 if asname is not None: 

2076 asname._codegen(state) 

2077 

2078 comma = self.comma 

2079 if comma is MaybeSentinel.DEFAULT and default_comma: 

2080 state.add_token(", ") 

2081 elif isinstance(comma, Comma): 

2082 comma._codegen(state) 

2083 

2084 

2085@add_slots 

2086@dataclass(frozen=True) 

2087class With(BaseCompoundStatement): 

2088 """ 

2089 A ``with`` statement. 

2090 """ 

2091 

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

2093 items: Sequence[WithItem] 

2094 

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

2096 body: BaseSuite 

2097 

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

2099 asynchronous: Optional[Asynchronous] = None 

2100 

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

2102 leading_lines: Sequence[EmptyLine] = () 

2103 

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

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

2106 

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

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

2109 

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

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

2112 

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

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

2115 

2116 def _validate_parens(self) -> None: 

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

2118 raise CSTValidationError( 

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

2120 ) 

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

2122 raise CSTValidationError( 

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

2124 ) 

2125 

2126 def _validate(self) -> None: 

2127 self._validate_parens() 

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

2129 raise CSTValidationError( 

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

2131 ) 

2132 if ( 

2133 isinstance(self.rpar, MaybeSentinel) 

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

2135 ): 

2136 raise CSTValidationError( 

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

2138 ) 

2139 if self.whitespace_after_with.empty and not ( 

2140 isinstance(self.lpar, LeftParen) 

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

2142 ExpressionPosition.RIGHT 

2143 ) 

2144 ): 

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

2146 

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

2148 return With( 

2149 leading_lines=visit_sequence( 

2150 self, "leading_lines", self.leading_lines, visitor 

2151 ), 

2152 asynchronous=visit_optional( 

2153 self, "asynchronous", self.asynchronous, visitor 

2154 ), 

2155 whitespace_after_with=visit_required( 

2156 self, "whitespace_after_with", self.whitespace_after_with, visitor 

2157 ), 

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

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

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

2161 whitespace_before_colon=visit_required( 

2162 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2163 ), 

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

2165 ) 

2166 

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

2168 for ll in self.leading_lines: 

2169 ll._codegen(state) 

2170 state.add_indent_tokens() 

2171 

2172 needs_paren = False 

2173 for item in self.items: 

2174 comma = item.comma 

2175 if isinstance(comma, Comma): 

2176 if isinstance( 

2177 comma.whitespace_after, 

2178 (EmptyLine, TrailingWhitespace, ParenthesizedWhitespace), 

2179 ): 

2180 needs_paren = True 

2181 break 

2182 

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

2184 asynchronous = self.asynchronous 

2185 if asynchronous is not None: 

2186 asynchronous._codegen(state) 

2187 state.add_token("with") 

2188 self.whitespace_after_with._codegen(state) 

2189 lpar = self.lpar 

2190 if isinstance(lpar, LeftParen): 

2191 lpar._codegen(state) 

2192 elif needs_paren: 

2193 state.add_token("(") 

2194 last_item = len(self.items) - 1 

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

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

2197 rpar = self.rpar 

2198 if isinstance(rpar, RightParen): 

2199 rpar._codegen(state) 

2200 elif needs_paren: 

2201 state.add_token(")") 

2202 self.whitespace_before_colon._codegen(state) 

2203 state.add_token(":") 

2204 self.body._codegen(state) 

2205 

2206 

2207@add_slots 

2208@dataclass(frozen=True) 

2209class For(BaseCompoundStatement): 

2210 """ 

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

2212 """ 

2213 

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

2215 target: BaseAssignTargetExpression 

2216 

2217 #: The iterable expression we will loop over. 

2218 iter: BaseExpression 

2219 

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

2221 body: BaseSuite 

2222 

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

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

2225 orelse: Optional[Else] = None 

2226 

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

2228 asynchronous: Optional[Asynchronous] = None 

2229 

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

2231 leading_lines: Sequence[EmptyLine] = () 

2232 

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

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

2235 

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

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

2238 

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

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

2241 

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

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

2244 

2245 def _validate(self) -> None: 

2246 if ( 

2247 self.whitespace_after_for.empty 

2248 and not self.target._safe_to_use_with_word_operator( 

2249 ExpressionPosition.RIGHT 

2250 ) 

2251 ): 

2252 raise CSTValidationError( 

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

2254 ) 

2255 

2256 if ( 

2257 self.whitespace_before_in.empty 

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

2259 ): 

2260 raise CSTValidationError( 

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

2262 ) 

2263 

2264 if ( 

2265 self.whitespace_after_in.empty 

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

2267 ): 

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

2269 

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

2271 return For( 

2272 leading_lines=visit_sequence( 

2273 self, "leading_lines", self.leading_lines, visitor 

2274 ), 

2275 asynchronous=visit_optional( 

2276 self, "asynchronous", self.asynchronous, visitor 

2277 ), 

2278 whitespace_after_for=visit_required( 

2279 self, "whitespace_after_for", self.whitespace_after_for, visitor 

2280 ), 

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

2282 whitespace_before_in=visit_required( 

2283 self, "whitespace_before_in", self.whitespace_before_in, visitor 

2284 ), 

2285 whitespace_after_in=visit_required( 

2286 self, "whitespace_after_in", self.whitespace_after_in, visitor 

2287 ), 

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

2289 whitespace_before_colon=visit_required( 

2290 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2291 ), 

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

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

2294 ) 

2295 

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

2297 for ll in self.leading_lines: 

2298 ll._codegen(state) 

2299 state.add_indent_tokens() 

2300 

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

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

2303 asynchronous = self.asynchronous 

2304 if asynchronous is not None: 

2305 asynchronous._codegen(state) 

2306 state.add_token("for") 

2307 self.whitespace_after_for._codegen(state) 

2308 self.target._codegen(state) 

2309 self.whitespace_before_in._codegen(state) 

2310 state.add_token("in") 

2311 self.whitespace_after_in._codegen(state) 

2312 self.iter._codegen(state) 

2313 self.whitespace_before_colon._codegen(state) 

2314 state.add_token(":") 

2315 self.body._codegen(state) 

2316 orelse = self.orelse 

2317 if orelse is not None: 

2318 orelse._codegen(state) 

2319 

2320 

2321@add_slots 

2322@dataclass(frozen=True) 

2323class While(BaseCompoundStatement): 

2324 """ 

2325 A ``while`` statement. 

2326 """ 

2327 

2328 #: The test we will loop against. 

2329 test: BaseExpression 

2330 

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

2332 body: BaseSuite 

2333 

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

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

2336 orelse: Optional[Else] = None 

2337 

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

2339 leading_lines: Sequence[EmptyLine] = () 

2340 

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

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

2343 

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

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

2346 

2347 def _validate(self) -> None: 

2348 if ( 

2349 self.whitespace_after_while.empty 

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

2351 ): 

2352 raise CSTValidationError( 

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

2354 ) 

2355 

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

2357 return While( 

2358 leading_lines=visit_sequence( 

2359 self, "leading_lines", self.leading_lines, visitor 

2360 ), 

2361 whitespace_after_while=visit_required( 

2362 self, "whitespace_after_while", self.whitespace_after_while, visitor 

2363 ), 

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

2365 whitespace_before_colon=visit_required( 

2366 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2367 ), 

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

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

2370 ) 

2371 

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

2373 for ll in self.leading_lines: 

2374 ll._codegen(state) 

2375 state.add_indent_tokens() 

2376 

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

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

2379 state.add_token("while") 

2380 self.whitespace_after_while._codegen(state) 

2381 self.test._codegen(state) 

2382 self.whitespace_before_colon._codegen(state) 

2383 state.add_token(":") 

2384 self.body._codegen(state) 

2385 orelse = self.orelse 

2386 if orelse is not None: 

2387 orelse._codegen(state) 

2388 

2389 

2390@add_slots 

2391@dataclass(frozen=True) 

2392class Raise(BaseSmallStatement): 

2393 """ 

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

2395 """ 

2396 

2397 #: The exception that we should raise. 

2398 exc: Optional[BaseExpression] = None 

2399 

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

2401 #: out of another exception's context. 

2402 cause: Optional[From] = None 

2403 

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

2405 whitespace_after_raise: Union[SimpleWhitespace, MaybeSentinel] = ( 

2406 MaybeSentinel.DEFAULT 

2407 ) 

2408 

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

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

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

2412 

2413 def _validate(self) -> None: 

2414 # Validate correct construction 

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

2416 raise CSTValidationError( 

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

2418 ) 

2419 

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

2421 exc = self.exc 

2422 if exc is not None: 

2423 whitespace_after_raise = self.whitespace_after_raise 

2424 has_no_gap = ( 

2425 not isinstance(whitespace_after_raise, MaybeSentinel) 

2426 and whitespace_after_raise.empty 

2427 ) 

2428 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2429 ExpressionPosition.RIGHT 

2430 ): 

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

2432 

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

2434 cause = self.cause 

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

2436 whitespace_before_from = cause.whitespace_before_from 

2437 has_no_gap = ( 

2438 not isinstance(whitespace_before_from, MaybeSentinel) 

2439 and whitespace_before_from.empty 

2440 ) 

2441 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2442 ExpressionPosition.LEFT 

2443 ): 

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

2445 

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

2447 return Raise( 

2448 whitespace_after_raise=visit_sentinel( 

2449 self, "whitespace_after_raise", self.whitespace_after_raise, visitor 

2450 ), 

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

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

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

2454 ) 

2455 

2456 def _codegen_impl( 

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

2458 ) -> None: 

2459 with state.record_syntactic_position(self): 

2460 exc = self.exc 

2461 cause = self.cause 

2462 state.add_token("raise") 

2463 whitespace_after_raise = self.whitespace_after_raise 

2464 if isinstance(whitespace_after_raise, MaybeSentinel): 

2465 if exc is not None: 

2466 state.add_token(" ") 

2467 else: 

2468 whitespace_after_raise._codegen(state) 

2469 if exc is not None: 

2470 exc._codegen(state) 

2471 if cause is not None: 

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

2473 

2474 semicolon = self.semicolon 

2475 if isinstance(semicolon, MaybeSentinel): 

2476 if default_semicolon: 

2477 state.add_token("; ") 

2478 elif isinstance(semicolon, Semicolon): 

2479 semicolon._codegen(state) 

2480 

2481 

2482@add_slots 

2483@dataclass(frozen=True) 

2484class Assert(BaseSmallStatement): 

2485 """ 

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

2487 """ 

2488 

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

2490 test: BaseExpression 

2491 

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

2493 msg: Optional[BaseExpression] = None 

2494 

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

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

2497 

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

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

2500 

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

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

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

2504 

2505 def _validate(self) -> None: 

2506 # Validate whitespace 

2507 if ( 

2508 self.whitespace_after_assert.empty 

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

2510 ): 

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

2512 

2513 # Validate comma rules 

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

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

2516 

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

2518 return Assert( 

2519 whitespace_after_assert=visit_required( 

2520 self, "whitespace_after_assert", self.whitespace_after_assert, visitor 

2521 ), 

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

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

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

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

2526 ) 

2527 

2528 def _codegen_impl( 

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

2530 ) -> None: 

2531 with state.record_syntactic_position(self): 

2532 state.add_token("assert") 

2533 self.whitespace_after_assert._codegen(state) 

2534 self.test._codegen(state) 

2535 

2536 comma = self.comma 

2537 msg = self.msg 

2538 if isinstance(comma, MaybeSentinel): 

2539 if msg is not None: 

2540 state.add_token(", ") 

2541 else: 

2542 comma._codegen(state) 

2543 if msg is not None: 

2544 msg._codegen(state) 

2545 

2546 semicolon = self.semicolon 

2547 if isinstance(semicolon, MaybeSentinel): 

2548 if default_semicolon: 

2549 state.add_token("; ") 

2550 elif isinstance(semicolon, Semicolon): 

2551 semicolon._codegen(state) 

2552 

2553 

2554@add_slots 

2555@dataclass(frozen=True) 

2556class NameItem(CSTNode): 

2557 """ 

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

2559 

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

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

2562 """ 

2563 

2564 #: Identifier name. 

2565 name: Name 

2566 

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

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

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

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

2571 

2572 def _validate(self) -> None: 

2573 # No parens around names here 

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

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

2576 

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

2578 return NameItem( 

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

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

2581 ) 

2582 

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

2584 with state.record_syntactic_position(self): 

2585 self.name._codegen(state) 

2586 

2587 comma = self.comma 

2588 if comma is MaybeSentinel.DEFAULT and default_comma: 

2589 state.add_token(", ") 

2590 elif isinstance(comma, Comma): 

2591 comma._codegen(state) 

2592 

2593 

2594@add_slots 

2595@dataclass(frozen=True) 

2596class Global(BaseSmallStatement): 

2597 """ 

2598 A ``global`` statement. 

2599 """ 

2600 

2601 #: A list of one or more names. 

2602 names: Sequence[NameItem] 

2603 

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

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

2606 

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

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

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

2610 

2611 def _validate(self) -> None: 

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

2613 raise CSTValidationError( 

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

2615 ) 

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

2617 raise CSTValidationError( 

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

2619 ) 

2620 if self.whitespace_after_global.empty: 

2621 raise CSTValidationError( 

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

2623 ) 

2624 

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

2626 return Global( 

2627 whitespace_after_global=visit_required( 

2628 self, "whitespace_after_global", self.whitespace_after_global, visitor 

2629 ), 

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

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

2632 ) 

2633 

2634 def _codegen_impl( 

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

2636 ) -> None: 

2637 with state.record_syntactic_position(self): 

2638 state.add_token("global") 

2639 self.whitespace_after_global._codegen(state) 

2640 last_name = len(self.names) - 1 

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

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

2643 

2644 semicolon = self.semicolon 

2645 if isinstance(semicolon, MaybeSentinel): 

2646 if default_semicolon: 

2647 state.add_token("; ") 

2648 elif isinstance(semicolon, Semicolon): 

2649 semicolon._codegen(state) 

2650 

2651 

2652@add_slots 

2653@dataclass(frozen=True) 

2654class Nonlocal(BaseSmallStatement): 

2655 """ 

2656 A ``nonlocal`` statement. 

2657 """ 

2658 

2659 #: A list of one or more names. 

2660 names: Sequence[NameItem] 

2661 

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

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

2664 

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

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

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

2668 

2669 def _validate(self) -> None: 

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

2671 raise CSTValidationError( 

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

2673 ) 

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

2675 raise CSTValidationError( 

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

2677 ) 

2678 if self.whitespace_after_nonlocal.empty: 

2679 raise CSTValidationError( 

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

2681 ) 

2682 

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

2684 return Nonlocal( 

2685 whitespace_after_nonlocal=visit_required( 

2686 self, 

2687 "whitespace_after_nonlocal", 

2688 self.whitespace_after_nonlocal, 

2689 visitor, 

2690 ), 

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

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

2693 ) 

2694 

2695 def _codegen_impl( 

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

2697 ) -> None: 

2698 with state.record_syntactic_position(self): 

2699 state.add_token("nonlocal") 

2700 self.whitespace_after_nonlocal._codegen(state) 

2701 last_name = len(self.names) - 1 

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

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

2704 

2705 semicolon = self.semicolon 

2706 if isinstance(semicolon, MaybeSentinel): 

2707 if default_semicolon: 

2708 state.add_token("; ") 

2709 elif isinstance(semicolon, Semicolon): 

2710 semicolon._codegen(state) 

2711 

2712 

2713class MatchPattern(_BaseParenthesizedNode, ABC): 

2714 """ 

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

2716 statement. 

2717 """ 

2718 

2719 __slots__ = () 

2720 

2721 

2722@add_slots 

2723@dataclass(frozen=True) 

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

2725class Match(BaseCompoundStatement): 

2726 """ 

2727 A ``match`` statement. 

2728 """ 

2729 

2730 #: The subject of the match. 

2731 subject: BaseExpression 

2732 

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

2734 cases: Sequence["MatchCase"] 

2735 

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

2737 leading_lines: Sequence[EmptyLine] = () 

2738 

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

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

2741 

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

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

2744 

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

2746 whitespace_after_colon: TrailingWhitespace = TrailingWhitespace.field() 

2747 

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

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

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

2751 indent: Optional[str] = None 

2752 

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

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

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

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

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

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

2759 footer: Sequence[EmptyLine] = () 

2760 

2761 def _validate(self) -> None: 

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

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

2764 

2765 indent = self.indent 

2766 if indent is not None: 

2767 if len(indent) == 0: 

2768 raise CSTValidationError( 

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

2770 ) 

2771 if _INDENT_WHITESPACE_RE.fullmatch(indent) is None: 

2772 raise CSTValidationError( 

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

2774 ) 

2775 

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

2777 return Match( 

2778 leading_lines=visit_sequence( 

2779 self, "leading_lines", self.leading_lines, visitor 

2780 ), 

2781 whitespace_after_match=visit_required( 

2782 self, "whitespace_after_match", self.whitespace_after_match, visitor 

2783 ), 

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

2785 whitespace_before_colon=visit_required( 

2786 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2787 ), 

2788 whitespace_after_colon=visit_required( 

2789 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

2790 ), 

2791 indent=self.indent, 

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

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

2794 ) 

2795 

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

2797 for ll in self.leading_lines: 

2798 ll._codegen(state) 

2799 state.add_indent_tokens() 

2800 

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

2802 state.add_token("match") 

2803 self.whitespace_after_match._codegen(state) 

2804 self.subject._codegen(state) 

2805 self.whitespace_before_colon._codegen(state) 

2806 state.add_token(":") 

2807 self.whitespace_after_colon._codegen(state) 

2808 

2809 indent = self.indent 

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

2811 for c in self.cases: 

2812 c._codegen(state) 

2813 

2814 for f in self.footer: 

2815 f._codegen(state) 

2816 

2817 state.decrease_indent() 

2818 

2819 

2820@add_slots 

2821@dataclass(frozen=True) 

2822class MatchCase(CSTNode): 

2823 """ 

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

2825 """ 

2826 

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

2828 pattern: MatchPattern 

2829 

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

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

2832 body: BaseSuite 

2833 

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

2835 guard: Optional[BaseExpression] = None 

2836 

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

2838 leading_lines: Sequence[EmptyLine] = () 

2839 

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

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

2842 

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

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

2845 

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

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

2848 

2849 #: Whitespace before the colon. 

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

2851 

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

2853 return MatchCase( 

2854 leading_lines=visit_sequence( 

2855 self, "leading_lines", self.leading_lines, visitor 

2856 ), 

2857 whitespace_after_case=visit_required( 

2858 self, "whitespace_after_case", self.whitespace_after_case, visitor 

2859 ), 

2860 pattern=visit_required(self, "pattern", self.pattern, visitor), 

2861 whitespace_before_if=visit_required( 

2862 self, "whitespace_before_if", self.whitespace_before_if, visitor 

2863 ), 

2864 whitespace_after_if=visit_required( 

2865 self, "whitespace_after_if", self.whitespace_after_if, visitor 

2866 ), 

2867 guard=visit_optional(self, "guard", self.guard, visitor), 

2868 whitespace_before_colon=visit_required( 

2869 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2870 ), 

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

2872 ) 

2873 

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

2875 for ll in self.leading_lines: 

2876 ll._codegen(state) 

2877 state.add_indent_tokens() 

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

2879 state.add_token("case") 

2880 self.whitespace_after_case._codegen(state) 

2881 self.pattern._codegen(state) 

2882 

2883 guard = self.guard 

2884 if guard is not None: 

2885 self.whitespace_before_if._codegen(state) 

2886 state.add_token("if") 

2887 self.whitespace_after_if._codegen(state) 

2888 guard._codegen(state) 

2889 else: 

2890 self.whitespace_before_if._codegen(state) 

2891 self.whitespace_after_if._codegen(state) 

2892 

2893 self.whitespace_before_colon._codegen(state) 

2894 state.add_token(":") 

2895 self.body._codegen(state) 

2896 

2897 

2898@add_slots 

2899@dataclass(frozen=True) 

2900class MatchValue(MatchPattern): 

2901 """ 

2902 A match literal or value pattern that compares by equality. 

2903 """ 

2904 

2905 #: an expression to compare to 

2906 value: BaseExpression 

2907 

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

2909 return MatchValue(value=visit_required(self, "value", self.value, visitor)) 

2910 

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

2912 with state.record_syntactic_position(self): 

2913 self.value._codegen(state) 

2914 

2915 @property 

2916 def lpar(self) -> Sequence[LeftParen]: 

2917 return self.value.lpar 

2918 

2919 @lpar.setter 

2920 def lpar(self, value: Sequence[LeftParen]) -> None: 

2921 self.value.lpar = value 

2922 

2923 @property 

2924 def rpar(self) -> Sequence[RightParen]: 

2925 return self.value.rpar 

2926 

2927 @rpar.setter 

2928 def rpar(self, value: Sequence[RightParen]) -> None: 

2929 self.value.rpar = value 

2930 

2931 

2932@add_slots 

2933@dataclass(frozen=True) 

2934class MatchSingleton(MatchPattern): 

2935 """ 

2936 A match literal pattern that compares by identity. 

2937 """ 

2938 

2939 #: a literal to compare to 

2940 value: Name 

2941 

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

2943 return MatchSingleton(value=visit_required(self, "value", self.value, visitor)) 

2944 

2945 def _validate(self) -> None: 

2946 if self.value.value not in {"True", "False", "None"}: 

2947 raise CSTValidationError( 

2948 "A match singleton can only be True, False, or None" 

2949 ) 

2950 

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

2952 with state.record_syntactic_position(self): 

2953 self.value._codegen(state) 

2954 

2955 @property 

2956 def lpar(self) -> Sequence[LeftParen]: 

2957 return self.value.lpar 

2958 

2959 @lpar.setter 

2960 def lpar(self, value: Sequence[LeftParen]) -> None: 

2961 # pyre-fixme[41]: Cannot reassign final attribute `lpar`. 

2962 self.value.lpar = value 

2963 

2964 @property 

2965 def rpar(self) -> Sequence[RightParen]: 

2966 return self.value.rpar 

2967 

2968 @rpar.setter 

2969 def rpar(self, value: Sequence[RightParen]) -> None: 

2970 # pyre-fixme[41]: Cannot reassign final attribute `rpar`. 

2971 self.value.rpar = value 

2972 

2973 

2974@add_slots 

2975@dataclass(frozen=True) 

2976class MatchSequenceElement(CSTNode): 

2977 """ 

2978 An element in a sequence match pattern. 

2979 """ 

2980 

2981 value: MatchPattern 

2982 

2983 #: An optional trailing comma. 

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

2985 

2986 def _visit_and_replace_children( 

2987 self, visitor: CSTVisitorT 

2988 ) -> "MatchSequenceElement": 

2989 return MatchSequenceElement( 

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

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

2992 ) 

2993 

2994 def _codegen_impl( 

2995 self, 

2996 state: CodegenState, 

2997 default_comma: bool = False, 

2998 default_comma_whitespace: bool = True, 

2999 ) -> None: 

3000 with state.record_syntactic_position(self): 

3001 self.value._codegen(state) 

3002 comma = self.comma 

3003 if comma is MaybeSentinel.DEFAULT and default_comma: 

3004 state.add_token(", " if default_comma_whitespace else ",") 

3005 elif isinstance(comma, Comma): 

3006 comma._codegen(state) 

3007 

3008 

3009@add_slots 

3010@dataclass(frozen=True) 

3011class MatchStar(CSTNode): 

3012 """ 

3013 A starred element in a sequence match pattern. Matches the rest of the sequence. 

3014 """ 

3015 

3016 #: The name of the pattern binding. A ``None`` value represents ``*_``. 

3017 name: Optional[Name] = None 

3018 

3019 #: An optional trailing comma. 

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

3021 

3022 #: Optional whitespace between the star and the name. 

3023 whitespace_before_name: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3024 

3025 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchStar": 

3026 return MatchStar( 

3027 whitespace_before_name=visit_required( 

3028 self, "whitespace_before_name", self.whitespace_before_name, visitor 

3029 ), 

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

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

3032 ) 

3033 

3034 def _codegen_impl( 

3035 self, 

3036 state: CodegenState, 

3037 default_comma: bool = False, 

3038 default_comma_whitespace: bool = True, 

3039 ) -> None: 

3040 with state.record_syntactic_position(self): 

3041 state.add_token("*") 

3042 self.whitespace_before_name._codegen(state) 

3043 name = self.name 

3044 if name is None: 

3045 state.add_token("_") 

3046 else: 

3047 name._codegen(state) 

3048 comma = self.comma 

3049 if comma is MaybeSentinel.DEFAULT and default_comma: 

3050 state.add_token(", " if default_comma_whitespace else ",") 

3051 elif isinstance(comma, Comma): 

3052 comma._codegen(state) 

3053 

3054 

3055class MatchSequence(MatchPattern, ABC): 

3056 """ 

3057 A match sequence pattern. It's either a :class:`MatchList` or a :class:`MatchTuple`. 

3058 Matches a variable length sequence if one of the patterns is a :class:`MatchStar`, 

3059 otherwise matches a fixed length sequence. 

3060 """ 

3061 

3062 __slots__ = () 

3063 

3064 #: Patterns to be matched against the subject elements if it is a sequence. 

3065 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3066 

3067 

3068@add_slots 

3069@dataclass(frozen=True) 

3070class MatchList(MatchSequence): 

3071 """ 

3072 A list match pattern. It's either an "open sequence pattern" (without brackets) or a 

3073 regular list literal (with brackets). 

3074 """ 

3075 

3076 #: Patterns to be matched against the subject elements if it is a sequence. 

3077 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3078 

3079 #: An optional left bracket. If missing, this is an open sequence pattern. 

3080 lbracket: Optional[LeftSquareBracket] = None 

3081 

3082 #: An optional left bracket. If missing, this is an open sequence pattern. 

3083 rbracket: Optional[RightSquareBracket] = None 

3084 

3085 #: Parenthesis at the beginning of the node 

3086 lpar: Sequence[LeftParen] = () 

3087 #: Parentheses after the pattern, but before a comma (if there is one). 

3088 rpar: Sequence[RightParen] = () 

3089 

3090 def _validate(self) -> None: 

3091 if self.lbracket and not self.rbracket: 

3092 raise CSTValidationError("Cannot have left bracket without right bracket") 

3093 if self.rbracket and not self.lbracket: 

3094 raise CSTValidationError("Cannot have right bracket without left bracket") 

3095 

3096 if not self.patterns and not self.lbracket: 

3097 raise CSTValidationError( 

3098 "Must have brackets if matching against empty list" 

3099 ) 

3100 

3101 super(MatchList, self)._validate() 

3102 

3103 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchList": 

3104 return MatchList( 

3105 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3106 lbracket=visit_optional(self, "lbracket", self.lbracket, visitor), 

3107 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3108 rbracket=visit_optional(self, "rbracket", self.rbracket, visitor), 

3109 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3110 ) 

3111 

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

3113 with self._parenthesize(state): 

3114 lbracket = self.lbracket 

3115 if lbracket is not None: 

3116 lbracket._codegen(state) 

3117 pats = self.patterns 

3118 for idx, pat in enumerate(pats): 

3119 pat._codegen(state, default_comma=(idx < len(pats) - 1)) 

3120 rbracket = self.rbracket 

3121 if rbracket is not None: 

3122 rbracket._codegen(state) 

3123 

3124 

3125@add_slots 

3126@dataclass(frozen=True) 

3127class MatchTuple(MatchSequence): 

3128 """ 

3129 A tuple match pattern. 

3130 """ 

3131 

3132 #: Patterns to be matched against the subject elements if it is a sequence. 

3133 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3134 

3135 #: Parenthesis at the beginning of the node 

3136 lpar: Sequence[LeftParen] = field(default_factory=lambda: (LeftParen(),)) 

3137 #: Parentheses after the pattern, but before a comma (if there is one). 

3138 rpar: Sequence[RightParen] = field(default_factory=lambda: (RightParen(),)) 

3139 

3140 def _validate(self) -> None: 

3141 if len(self.lpar) < 1: 

3142 raise CSTValidationError( 

3143 "Tuple patterns must have at least pair of parenthesis" 

3144 ) 

3145 

3146 super(MatchTuple, self)._validate() 

3147 

3148 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchTuple": 

3149 return MatchTuple( 

3150 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3151 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3152 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3153 ) 

3154 

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

3156 with self._parenthesize(state): 

3157 pats = self.patterns 

3158 patlen = len(pats) 

3159 for idx, pat in enumerate(pats): 

3160 pat._codegen( 

3161 state, 

3162 default_comma=patlen == 1 or (idx < patlen - 1), 

3163 default_comma_whitespace=patlen != 1, 

3164 ) 

3165 

3166 

3167@add_slots 

3168@dataclass(frozen=True) 

3169class MatchMappingElement(CSTNode): 

3170 """ 

3171 A ``key: value`` pair in a match mapping pattern. 

3172 """ 

3173 

3174 key: BaseExpression 

3175 

3176 #: The pattern to be matched corresponding to ``key``. 

3177 pattern: MatchPattern 

3178 

3179 #: An optional trailing comma. 

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

3181 

3182 #: Whitespace between ``key`` and the colon. 

3183 whitespace_before_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3184 

3185 #: Whitespace between the colon and ``pattern``. 

3186 whitespace_after_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field(" ") 

3187 

3188 def _visit_and_replace_children( 

3189 self, visitor: CSTVisitorT 

3190 ) -> "MatchMappingElement": 

3191 return MatchMappingElement( 

3192 key=visit_required(self, "key", self.key, visitor), 

3193 whitespace_before_colon=visit_required( 

3194 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

3195 ), 

3196 whitespace_after_colon=visit_required( 

3197 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

3198 ), 

3199 pattern=visit_required(self, "pattern", self.pattern, visitor), 

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

3201 ) 

3202 

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

3204 with state.record_syntactic_position(self): 

3205 self.key._codegen(state) 

3206 self.whitespace_before_colon._codegen(state) 

3207 state.add_token(":") 

3208 self.whitespace_after_colon._codegen(state) 

3209 self.pattern._codegen(state) 

3210 comma = self.comma 

3211 if comma is MaybeSentinel.DEFAULT and default_comma: 

3212 state.add_token(", ") 

3213 elif isinstance(comma, Comma): 

3214 comma._codegen(state) 

3215 

3216 

3217@add_slots 

3218@dataclass(frozen=True) 

3219class MatchMapping(MatchPattern): 

3220 """ 

3221 A match mapping pattern. 

3222 """ 

3223 

3224 #: A sequence of mapping elements. 

3225 elements: Sequence[MatchMappingElement] = () 

3226 

3227 #: Left curly brace at the beginning of the pattern. 

3228 lbrace: LeftCurlyBrace = LeftCurlyBrace.field() 

3229 

3230 #: Right curly brace at the end of the pattern. 

3231 rbrace: RightCurlyBrace = RightCurlyBrace.field() 

3232 

3233 #: An optional name to capture the remaining elements of the mapping. 

3234 rest: Optional[Name] = None 

3235 

3236 #: Optional whitespace between stars and ``rest``. 

3237 whitespace_before_rest: SimpleWhitespace = SimpleWhitespace.field("") 

3238 

3239 #: An optional trailing comma attached to ``rest``. 

3240 trailing_comma: Optional[Comma] = None 

3241 

3242 #: Parenthesis at the beginning of the node 

3243 lpar: Sequence[LeftParen] = () 

3244 #: Parentheses after the pattern 

3245 rpar: Sequence[RightParen] = () 

3246 

3247 def _validate(self) -> None: 

3248 if isinstance(self.trailing_comma, Comma) and self.rest is not None: 

3249 raise CSTValidationError("Cannot have a trailing comma without **rest") 

3250 super(MatchMapping, self)._validate() 

3251 

3252 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchMapping": 

3253 return MatchMapping( 

3254 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3255 lbrace=visit_required(self, "lbrace", self.lbrace, visitor), 

3256 elements=visit_sequence(self, "elements", self.elements, visitor), 

3257 whitespace_before_rest=visit_required( 

3258 self, "whitespace_before_rest", self.whitespace_before_rest, visitor 

3259 ), 

3260 rest=visit_optional(self, "rest", self.rest, visitor), 

3261 trailing_comma=visit_optional( 

3262 self, "trailing_comma", self.trailing_comma, visitor 

3263 ), 

3264 rbrace=visit_required(self, "rbrace", self.rbrace, visitor), 

3265 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3266 ) 

3267 

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

3269 with self._parenthesize(state): 

3270 self.lbrace._codegen(state) 

3271 elems = self.elements 

3272 rest = self.rest 

3273 for idx, el in enumerate(elems): 

3274 el._codegen( 

3275 state, default_comma=rest is not None or idx < len(elems) - 1 

3276 ) 

3277 

3278 if rest is not None: 

3279 state.add_token("**") 

3280 self.whitespace_before_rest._codegen(state) 

3281 rest._codegen(state) 

3282 comma = self.trailing_comma 

3283 if comma is not None: 

3284 comma._codegen(state) 

3285 

3286 self.rbrace._codegen(state) 

3287 

3288 

3289@add_slots 

3290@dataclass(frozen=True) 

3291class MatchKeywordElement(CSTNode): 

3292 """ 

3293 A key=value pair in a :class:`MatchClass`. 

3294 """ 

3295 

3296 key: Name 

3297 

3298 #: The pattern to be matched against the attribute named ``key``. 

3299 pattern: MatchPattern 

3300 

3301 #: An optional trailing comma. 

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

3303 

3304 #: Whitespace between ``key`` and the equals sign. 

3305 whitespace_before_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3306 

3307 #: Whitespace between the equals sign and ``pattern``. 

3308 whitespace_after_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3309 

3310 def _visit_and_replace_children( 

3311 self, visitor: CSTVisitorT 

3312 ) -> "MatchKeywordElement": 

3313 return MatchKeywordElement( 

3314 key=visit_required(self, "key", self.key, visitor), 

3315 whitespace_before_equal=visit_required( 

3316 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

3317 ), 

3318 whitespace_after_equal=visit_required( 

3319 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

3320 ), 

3321 pattern=visit_required(self, "pattern", self.pattern, visitor), 

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

3323 ) 

3324 

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

3326 with state.record_syntactic_position(self): 

3327 self.key._codegen(state) 

3328 self.whitespace_before_equal._codegen(state) 

3329 state.add_token("=") 

3330 self.whitespace_after_equal._codegen(state) 

3331 self.pattern._codegen(state) 

3332 comma = self.comma 

3333 if comma is MaybeSentinel.DEFAULT and default_comma: 

3334 state.add_token(", ") 

3335 elif isinstance(comma, Comma): 

3336 comma._codegen(state) 

3337 

3338 

3339@add_slots 

3340@dataclass(frozen=True) 

3341class MatchClass(MatchPattern): 

3342 """ 

3343 A match class pattern. 

3344 """ 

3345 

3346 #: An expression giving the nominal class to be matched. 

3347 cls: BaseExpression 

3348 

3349 #: A sequence of patterns to be matched against the class defined sequence of 

3350 #: pattern matching attributes. 

3351 patterns: Sequence[MatchSequenceElement] = () 

3352 

3353 #: A sequence of additional attribute names and corresponding patterns to be 

3354 #: matched. 

3355 kwds: Sequence[MatchKeywordElement] = () 

3356 

3357 #: Whitespace between the class name and the left parenthesis. 

3358 whitespace_after_cls: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3359 

3360 #: Whitespace between the left parenthesis and the first pattern. 

3361 whitespace_before_patterns: BaseParenthesizableWhitespace = SimpleWhitespace.field( 

3362 "" 

3363 ) 

3364 

3365 #: Whitespace between the last pattern and the right parenthesis. 

3366 whitespace_after_kwds: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3367 

3368 #: Parenthesis at the beginning of the node 

3369 lpar: Sequence[LeftParen] = () 

3370 #: Parentheses after the pattern 

3371 rpar: Sequence[RightParen] = () 

3372 

3373 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchClass": 

3374 return MatchClass( 

3375 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3376 cls=visit_required(self, "cls", self.cls, visitor), 

3377 whitespace_after_cls=visit_required( 

3378 self, "whitespace_after_cls", self.whitespace_after_cls, visitor 

3379 ), 

3380 whitespace_before_patterns=visit_required( 

3381 self, 

3382 "whitespace_before_patterns", 

3383 self.whitespace_before_patterns, 

3384 visitor, 

3385 ), 

3386 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3387 kwds=visit_sequence(self, "kwds", self.kwds, visitor), 

3388 whitespace_after_kwds=visit_required( 

3389 self, "whitespace_after_kwds", self.whitespace_after_kwds, visitor 

3390 ), 

3391 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3392 ) 

3393 

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

3395 with self._parenthesize(state): 

3396 self.cls._codegen(state) 

3397 self.whitespace_after_cls._codegen(state) 

3398 state.add_token("(") 

3399 self.whitespace_before_patterns._codegen(state) 

3400 pats = self.patterns 

3401 kwds = self.kwds 

3402 for idx, pat in enumerate(pats): 

3403 pat._codegen(state, default_comma=idx + 1 < len(pats) + len(kwds)) 

3404 for idx, kwd in enumerate(kwds): 

3405 kwd._codegen(state, default_comma=idx + 1 < len(kwds)) 

3406 self.whitespace_after_kwds._codegen(state) 

3407 state.add_token(")") 

3408 

3409 

3410@add_slots 

3411@dataclass(frozen=True) 

3412class MatchAs(MatchPattern): 

3413 """ 

3414 A match "as-pattern", capture pattern, or wildcard pattern. 

3415 """ 

3416 

3417 #: The match pattern that the subject will be matched against. If this is ``None``, 

3418 #: the node represents a capture pattern (i.e. a bare name) and will always succeed. 

3419 pattern: Optional[MatchPattern] = None 

3420 

3421 #: The name that will be bound if the pattern is successful. If this is ``None``, 

3422 #: ``pattern`` must also be ``None`` and the node represents the wildcard pattern 

3423 #: (i.e. ``_``). 

3424 name: Optional[Name] = None 

3425 

3426 #: Whitespace between ``pattern`` and the ``as`` keyword (if ``pattern`` is not 

3427 #: ``None``) 

3428 whitespace_before_as: Union[BaseParenthesizableWhitespace, MaybeSentinel] = ( 

3429 MaybeSentinel.DEFAULT 

3430 ) 

3431 

3432 #: Whitespace between the ``as`` keyword and ``name`` (if ``pattern`` is not 

3433 #: ``None``) 

3434 whitespace_after_as: Union[BaseParenthesizableWhitespace, MaybeSentinel] = ( 

3435 MaybeSentinel.DEFAULT 

3436 ) 

3437 

3438 #: Parenthesis at the beginning of the node 

3439 lpar: Sequence[LeftParen] = () 

3440 #: Parentheses after the pattern 

3441 rpar: Sequence[RightParen] = () 

3442 

3443 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchAs": 

3444 return MatchAs( 

3445 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3446 pattern=visit_optional(self, "pattern", self.pattern, visitor), 

3447 whitespace_before_as=visit_sentinel( 

3448 self, "whitespace_before_as", self.whitespace_before_as, visitor 

3449 ), 

3450 whitespace_after_as=visit_sentinel( 

3451 self, "whitespace_after_as", self.whitespace_after_as, visitor 

3452 ), 

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

3454 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3455 ) 

3456 

3457 def _validate(self) -> None: 

3458 if self.name is None and self.pattern is not None: 

3459 raise CSTValidationError("Pattern must be None if name is None") 

3460 super(MatchAs, self)._validate() 

3461 

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

3463 with self._parenthesize(state): 

3464 pat = self.pattern 

3465 name = self.name 

3466 if pat is not None: 

3467 pat._codegen(state) 

3468 ws_before = self.whitespace_before_as 

3469 if ws_before is MaybeSentinel.DEFAULT: 

3470 state.add_token(" ") 

3471 elif isinstance(ws_before, BaseParenthesizableWhitespace): 

3472 ws_before._codegen(state) 

3473 state.add_token("as") 

3474 ws_after = self.whitespace_after_as 

3475 if ws_after is MaybeSentinel.DEFAULT: 

3476 state.add_token(" ") 

3477 elif isinstance(ws_after, BaseParenthesizableWhitespace): 

3478 ws_after._codegen(state) 

3479 else: 

3480 ws_before = self.whitespace_before_as 

3481 if isinstance(ws_before, BaseParenthesizableWhitespace): 

3482 ws_before._codegen(state) 

3483 ws_after = self.whitespace_after_as 

3484 if isinstance(ws_after, BaseParenthesizableWhitespace): 

3485 ws_after._codegen(state) 

3486 if name is None: 

3487 state.add_token("_") 

3488 else: 

3489 name._codegen(state) 

3490 

3491 

3492@add_slots 

3493@dataclass(frozen=True) 

3494class MatchOrElement(CSTNode): 

3495 """ 

3496 An element in a :class:`MatchOr` node. 

3497 """ 

3498 

3499 pattern: MatchPattern 

3500 

3501 #: An optional ``|`` separator. 

3502 separator: Union[BitOr, MaybeSentinel] = MaybeSentinel.DEFAULT 

3503 

3504 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOrElement": 

3505 return MatchOrElement( 

3506 pattern=visit_required(self, "pattern", self.pattern, visitor), 

3507 separator=visit_sentinel(self, "separator", self.separator, visitor), 

3508 ) 

3509 

3510 def _codegen_impl( 

3511 self, state: CodegenState, default_separator: bool = False 

3512 ) -> None: 

3513 with state.record_syntactic_position(self): 

3514 self.pattern._codegen(state) 

3515 sep = self.separator 

3516 if sep is MaybeSentinel.DEFAULT and default_separator: 

3517 state.add_token(" | ") 

3518 elif isinstance(sep, BitOr): 

3519 sep._codegen(state) 

3520 

3521 

3522@add_slots 

3523@dataclass(frozen=True) 

3524class MatchOr(MatchPattern): 

3525 """ 

3526 A match "or-pattern". It matches each of its subpatterns in turn to the subject, 

3527 until one succeeds. The or-pattern is then deemed to succeed. If none of the 

3528 subpatterns succeed the or-pattern fails. 

3529 """ 

3530 

3531 #: The subpatterns to be tried in turn. 

3532 patterns: Sequence[MatchOrElement] 

3533 

3534 #: Parenthesis at the beginning of the node 

3535 lpar: Sequence[LeftParen] = () 

3536 #: Parentheses after the pattern 

3537 rpar: Sequence[RightParen] = () 

3538 

3539 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOr": 

3540 return MatchOr( 

3541 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3542 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3543 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3544 ) 

3545 

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

3547 with self._parenthesize(state): 

3548 pats = self.patterns 

3549 for idx, pat in enumerate(pats): 

3550 pat._codegen(state, default_separator=idx + 1 < len(pats)) 

3551 

3552 

3553@add_slots 

3554@dataclass(frozen=True) 

3555class TypeVar(CSTNode): 

3556 """ 

3557 A simple (non-variadic) type variable. 

3558 

3559 Note: this node represents type a variable when declared using PEP-695 syntax. 

3560 """ 

3561 

3562 #: The name of the type variable. 

3563 name: Name 

3564 

3565 #: An optional bound on the type. 

3566 bound: Optional[BaseExpression] = None 

3567 

3568 #: The colon used to separate the name and bound. If not specified, 

3569 #: :class:`MaybeSentinel` will be replaced with a colon if there is a bound, 

3570 #: otherwise will be left empty. 

3571 colon: Union[Colon, MaybeSentinel] = MaybeSentinel.DEFAULT 

3572 

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

3574 with state.record_syntactic_position(self): 

3575 self.name._codegen(state) 

3576 bound = self.bound 

3577 colon = self.colon 

3578 if not isinstance(colon, MaybeSentinel): 

3579 colon._codegen(state) 

3580 else: 

3581 if bound is not None: 

3582 state.add_token(": ") 

3583 

3584 if bound is not None: 

3585 bound._codegen(state) 

3586 

3587 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVar": 

3588 return TypeVar( 

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

3590 colon=visit_sentinel(self, "colon", self.colon, visitor), 

3591 bound=visit_optional(self, "bound", self.bound, visitor), 

3592 ) 

3593 

3594 

3595@add_slots 

3596@dataclass(frozen=True) 

3597class TypeVarTuple(CSTNode): 

3598 """ 

3599 A variadic type variable. 

3600 """ 

3601 

3602 #: The name of this type variable. 

3603 name: Name 

3604 

3605 #: The (optional) whitespace between the star declaring this type variable as 

3606 #: variadic, and the variable's name. 

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

3608 

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

3610 with state.record_syntactic_position(self): 

3611 state.add_token("*") 

3612 self.whitespace_after_star._codegen(state) 

3613 self.name._codegen(state) 

3614 

3615 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVarTuple": 

3616 return TypeVarTuple( 

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

3618 whitespace_after_star=visit_required( 

3619 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3620 ), 

3621 ) 

3622 

3623 

3624@add_slots 

3625@dataclass(frozen=True) 

3626class ParamSpec(CSTNode): 

3627 """ 

3628 A parameter specification. 

3629 

3630 Note: this node represents a parameter specification when declared using PEP-695 

3631 syntax. 

3632 """ 

3633 

3634 #: The name of this parameter specification. 

3635 name: Name 

3636 

3637 #: The (optional) whitespace between the double star declaring this type variable as 

3638 #: a parameter specification, and the name. 

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

3640 

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

3642 with state.record_syntactic_position(self): 

3643 state.add_token("**") 

3644 self.whitespace_after_star._codegen(state) 

3645 self.name._codegen(state) 

3646 

3647 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ParamSpec": 

3648 return ParamSpec( 

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

3650 whitespace_after_star=visit_required( 

3651 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3652 ), 

3653 ) 

3654 

3655 

3656@add_slots 

3657@dataclass(frozen=True) 

3658class TypeParam(CSTNode): 

3659 """ 

3660 A single type parameter that is contained in a :class:`TypeParameters` list. 

3661 """ 

3662 

3663 #: The actual parameter. 

3664 param: Union[TypeVar, TypeVarTuple, ParamSpec] 

3665 

3666 #: A trailing comma. If one is not provided, :class:`MaybeSentinel` will be replaced 

3667 #: with a comma only if a comma is required. 

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

3669 

3670 #: The equal sign used to denote assignment if there is a default. 

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

3672 

3673 #: The star used to denote a variadic default 

3674 star: Literal["", "*"] = "" 

3675 

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

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

3678 

3679 #: Any optional default value, used when the argument is not supplied. 

3680 default: Optional[BaseExpression] = None 

3681 

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

3683 self.param._codegen(state) 

3684 

3685 equal = self.equal 

3686 if equal is MaybeSentinel.DEFAULT and self.default is not None: 

3687 state.add_token(" = ") 

3688 elif isinstance(equal, AssignEqual): 

3689 equal._codegen(state) 

3690 

3691 state.add_token(self.star) 

3692 self.whitespace_after_star._codegen(state) 

3693 

3694 default = self.default 

3695 if default is not None: 

3696 default._codegen(state) 

3697 

3698 comma = self.comma 

3699 if isinstance(comma, MaybeSentinel): 

3700 if default_comma: 

3701 state.add_token(", ") 

3702 else: 

3703 comma._codegen(state) 

3704 

3705 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParam": 

3706 ret = TypeParam( 

3707 param=visit_required(self, "param", self.param, visitor), 

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

3709 star=self.star, 

3710 whitespace_after_star=visit_required( 

3711 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3712 ), 

3713 default=visit_optional(self, "default", self.default, visitor), 

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

3715 ) 

3716 return ret 

3717 

3718 def _validate(self) -> None: 

3719 if self.default is None and isinstance(self.equal, AssignEqual): 

3720 raise CSTValidationError( 

3721 "Must have a default when specifying an AssignEqual." 

3722 ) 

3723 if self.star and not (self.default or isinstance(self.equal, AssignEqual)): 

3724 raise CSTValidationError("Star can only be present if a default") 

3725 if isinstance(self.star, str) and self.star not in ("", "*"): 

3726 raise CSTValidationError("Must specify either '' or '*' for star.") 

3727 

3728 

3729@add_slots 

3730@dataclass(frozen=True) 

3731class TypeParameters(CSTNode): 

3732 """ 

3733 Type parameters when specified with PEP-695 syntax. 

3734 

3735 This node captures all specified parameters that are enclosed with square brackets. 

3736 """ 

3737 

3738 #: The parameters within the square brackets. 

3739 params: Sequence[TypeParam] = () 

3740 

3741 #: Opening square bracket that marks the start of these parameters. 

3742 lbracket: LeftSquareBracket = LeftSquareBracket.field() 

3743 #: Closing square bracket that marks the end of these parameters. 

3744 rbracket: RightSquareBracket = RightSquareBracket.field() 

3745 

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

3747 self.lbracket._codegen(state) 

3748 params_len = len(self.params) 

3749 for idx, param in enumerate(self.params): 

3750 param._codegen(state, default_comma=idx + 1 < params_len) 

3751 self.rbracket._codegen(state) 

3752 

3753 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParameters": 

3754 return TypeParameters( 

3755 lbracket=visit_required(self, "lbracket", self.lbracket, visitor), 

3756 params=visit_sequence(self, "params", self.params, visitor), 

3757 rbracket=visit_required(self, "rbracket", self.rbracket, visitor), 

3758 ) 

3759 

3760 

3761@add_slots 

3762@dataclass(frozen=True) 

3763class TypeAlias(BaseSmallStatement): 

3764 """ 

3765 A type alias statement. 

3766 

3767 This node represents the ``type`` statement as specified initially by PEP-695. 

3768 Example: ``type ListOrSet[T] = list[T] | set[T]``. 

3769 """ 

3770 

3771 #: The name being introduced in this statement. 

3772 name: Name 

3773 

3774 #: Everything on the right hand side of the ``=``. 

3775 value: BaseExpression 

3776 

3777 #: An optional list of type parameters, specified after the name. 

3778 type_parameters: Optional[TypeParameters] = None 

3779 

3780 #: Whitespace between the ``type`` soft keyword and the name. 

3781 whitespace_after_type: SimpleWhitespace = SimpleWhitespace.field(" ") 

3782 

3783 #: Whitespace between the name and the type parameters (if they exist) or the ``=``. 

3784 #: If not specified, :class:`MaybeSentinel` will be replaced with a single space if 

3785 #: there are no type parameters, otherwise no spaces. 

3786 whitespace_after_name: Union[SimpleWhitespace, MaybeSentinel] = ( 

3787 MaybeSentinel.DEFAULT 

3788 ) 

3789 

3790 #: Whitespace between the type parameters and the ``=``. Always empty if there are 

3791 #: no type parameters. If not specified, :class:`MaybeSentinel` will be replaced 

3792 #: with a single space if there are type parameters. 

3793 whitespace_after_type_parameters: Union[SimpleWhitespace, MaybeSentinel] = ( 

3794 MaybeSentinel.DEFAULT 

3795 ) 

3796 

3797 #: Whitespace between the ``=`` and the value. 

3798 whitespace_after_equals: SimpleWhitespace = SimpleWhitespace.field(" ") 

3799 

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

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

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

3803 

3804 def _validate(self) -> None: 

3805 if ( 

3806 self.type_parameters is None 

3807 and self.whitespace_after_type_parameters 

3808 not in { 

3809 SimpleWhitespace(""), 

3810 MaybeSentinel.DEFAULT, 

3811 } 

3812 ): 

3813 raise CSTValidationError( 

3814 "whitespace_after_type_parameters must be empty when there are no type parameters in a TypeAlias" 

3815 ) 

3816 

3817 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeAlias": 

3818 return TypeAlias( 

3819 whitespace_after_type=visit_required( 

3820 self, "whitespace_after_type", self.whitespace_after_type, visitor 

3821 ), 

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

3823 whitespace_after_name=visit_sentinel( 

3824 self, "whitespace_after_name", self.whitespace_after_name, visitor 

3825 ), 

3826 type_parameters=visit_optional( 

3827 self, "type_parameters", self.type_parameters, visitor 

3828 ), 

3829 whitespace_after_type_parameters=visit_sentinel( 

3830 self, 

3831 "whitespace_after_type_parameters", 

3832 self.whitespace_after_type_parameters, 

3833 visitor, 

3834 ), 

3835 whitespace_after_equals=visit_required( 

3836 self, "whitespace_after_equals", self.whitespace_after_equals, visitor 

3837 ), 

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

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

3840 ) 

3841 

3842 def _codegen_impl( 

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

3844 ) -> None: 

3845 with state.record_syntactic_position(self): 

3846 state.add_token("type") 

3847 self.whitespace_after_type._codegen(state) 

3848 self.name._codegen(state) 

3849 ws_after_name = self.whitespace_after_name 

3850 if isinstance(ws_after_name, MaybeSentinel): 

3851 if self.type_parameters is None: 

3852 state.add_token(" ") 

3853 else: 

3854 ws_after_name._codegen(state) 

3855 

3856 ws_after_type_params = self.whitespace_after_type_parameters 

3857 if self.type_parameters is not None: 

3858 self.type_parameters._codegen(state) 

3859 if isinstance(ws_after_type_params, MaybeSentinel): 

3860 state.add_token(" ") 

3861 else: 

3862 ws_after_type_params._codegen(state) 

3863 

3864 state.add_token("=") 

3865 self.whitespace_after_equals._codegen(state) 

3866 self.value._codegen(state) 

3867 

3868 semi = self.semicolon 

3869 if isinstance(semi, MaybeSentinel): 

3870 if default_semicolon: 

3871 state.add_token("; ") 

3872 else: 

3873 semi._codegen(state)