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

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

1789 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 LazyImport(BaseSmallStatement): 

1430 """ 

1431 A ``lazy import x`` statement (PEP 810). 

1432 

1433 Lazy imports defer loading of the imported module until first use. 

1434 ``lazy`` is a soft keyword that is only special immediately before 

1435 ``import`` or ``from``. 

1436 """ 

1437 

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

1439 names: Sequence[ImportAlias] 

1440 

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

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

1443 

1444 #: The whitespace between ``lazy`` and ``import``. 

1445 whitespace_after_lazy: SimpleWhitespace = SimpleWhitespace.field(" ") 

1446 

1447 #: The whitespace after ``import`` and before the first alias. 

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

1449 

1450 def _validate(self) -> None: 

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

1452 raise CSTValidationError("A LazyImport must have at least one ImportAlias") 

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

1454 raise CSTValidationError("A LazyImport does not allow a trailing comma") 

1455 if self.whitespace_after_lazy.empty: 

1456 raise CSTValidationError("Must have at least one space after lazy.") 

1457 if self.whitespace_after_import.empty: 

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

1459 

1460 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "LazyImport": 

1461 return LazyImport( 

1462 whitespace_after_lazy=visit_required( 

1463 self, "whitespace_after_lazy", self.whitespace_after_lazy, visitor 

1464 ), 

1465 whitespace_after_import=visit_required( 

1466 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1467 ), 

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

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

1470 ) 

1471 

1472 def _codegen_impl( 

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

1474 ) -> None: 

1475 with state.record_syntactic_position(self): 

1476 state.add_token("lazy") 

1477 self.whitespace_after_lazy._codegen(state) 

1478 state.add_token("import") 

1479 self.whitespace_after_import._codegen(state) 

1480 lastname = len(self.names) - 1 

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

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

1483 

1484 semicolon = self.semicolon 

1485 if isinstance(semicolon, MaybeSentinel): 

1486 if default_semicolon: 

1487 state.add_token("; ") 

1488 elif isinstance(semicolon, Semicolon): 

1489 semicolon._codegen(state) 

1490 

1491 

1492@add_slots 

1493@dataclass(frozen=True) 

1494class LazyImportFrom(BaseSmallStatement): 

1495 """ 

1496 A ``lazy from x import y`` statement (PEP 810). 

1497 

1498 Lazy imports defer loading of the imported names until first use. 

1499 ``lazy`` is a soft keyword that is only special immediately before ``from``. 

1500 """ 

1501 

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

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

1504 

1505 #: One or more names being imported lazily. 

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

1507 

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

1509 relative: Sequence[Dot] = () 

1510 

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

1512 lpar: Optional[LeftParen] = None 

1513 

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

1515 rpar: Optional[RightParen] = None 

1516 

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

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

1519 

1520 #: The whitespace between ``lazy`` and ``from``. 

1521 whitespace_after_lazy: SimpleWhitespace = SimpleWhitespace.field(" ") 

1522 

1523 #: The whitespace after ``from`` and before the module / dots. 

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

1525 

1526 #: The whitespace before ``import``. 

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

1528 

1529 #: The whitespace after ``import`` and before the first name or left paren. 

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

1531 

1532 def _validate_module(self) -> None: 

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

1534 raise CSTValidationError( 

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

1536 ) 

1537 

1538 def _validate_names(self) -> None: 

1539 names = self.names 

1540 if isinstance(names, Sequence): 

1541 if len(names) == 0: 

1542 raise CSTValidationError( 

1543 "A LazyImportFrom must have at least one ImportAlias" 

1544 ) 

1545 for name in names[:-1]: 

1546 if name.comma is None: 

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

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

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

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

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

1552 

1553 def _validate_whitespace(self) -> None: 

1554 if self.whitespace_after_lazy.empty: 

1555 raise CSTValidationError("Must have at least one space after lazy.") 

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

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

1558 if self.whitespace_before_import.empty and not ( 

1559 self.relative and self.module is None 

1560 ): 

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

1562 if ( 

1563 self.whitespace_after_import.empty 

1564 and self.lpar is None 

1565 and not isinstance(self.names, ImportStar) 

1566 ): 

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

1568 

1569 def _validate(self) -> None: 

1570 self._validate_module() 

1571 self._validate_names() 

1572 self._validate_whitespace() 

1573 

1574 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "LazyImportFrom": 

1575 names = self.names 

1576 return LazyImportFrom( 

1577 whitespace_after_lazy=visit_required( 

1578 self, "whitespace_after_lazy", self.whitespace_after_lazy, visitor 

1579 ), 

1580 whitespace_after_from=visit_required( 

1581 self, "whitespace_after_from", self.whitespace_after_from, visitor 

1582 ), 

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

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

1585 whitespace_before_import=visit_required( 

1586 self, "whitespace_before_import", self.whitespace_before_import, visitor 

1587 ), 

1588 whitespace_after_import=visit_required( 

1589 self, "whitespace_after_import", self.whitespace_after_import, visitor 

1590 ), 

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

1592 names=( 

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

1594 if isinstance(names, ImportStar) 

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

1596 ), 

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

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

1599 ) 

1600 

1601 def _codegen_impl( 

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

1603 ) -> None: 

1604 names = self.names 

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

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

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

1608 state.add_token("lazy") 

1609 self.whitespace_after_lazy._codegen(state) 

1610 state.add_token("from") 

1611 self.whitespace_after_from._codegen(state) 

1612 for dot in self.relative: 

1613 dot._codegen(state) 

1614 module = self.module 

1615 if module is not None: 

1616 module._codegen(state) 

1617 self.whitespace_before_import._codegen(state) 

1618 state.add_token("import") 

1619 self.whitespace_after_import._codegen(state) 

1620 lpar = self.lpar 

1621 if lpar is not None: 

1622 lpar._codegen(state) 

1623 if isinstance(names, Sequence): 

1624 lastname = len(names) - 1 

1625 for i, name in enumerate(names): 

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

1627 if isinstance(names, ImportStar): 

1628 names._codegen(state) 

1629 rpar = self.rpar 

1630 if rpar is not None: 

1631 rpar._codegen(state) 

1632 

1633 semicolon = self.semicolon 

1634 if isinstance(semicolon, MaybeSentinel): 

1635 if default_semicolon: 

1636 state.add_token("; ") 

1637 elif isinstance(semicolon, Semicolon): 

1638 semicolon._codegen(state) 

1639 

1640 

1641@add_slots 

1642@dataclass(frozen=True) 

1643class AssignTarget(CSTNode): 

1644 """ 

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

1646 """ 

1647 

1648 #: The target expression being assigned to. 

1649 target: BaseAssignTargetExpression 

1650 

1651 #: The whitespace appearing before the equals sign. 

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

1653 

1654 #: The whitespace appearing after the equals sign. 

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

1656 

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

1658 return AssignTarget( 

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

1660 whitespace_before_equal=visit_required( 

1661 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

1662 ), 

1663 whitespace_after_equal=visit_required( 

1664 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

1665 ), 

1666 ) 

1667 

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

1669 with state.record_syntactic_position(self): 

1670 self.target._codegen(state) 

1671 

1672 self.whitespace_before_equal._codegen(state) 

1673 state.add_token("=") 

1674 self.whitespace_after_equal._codegen(state) 

1675 

1676 

1677@add_slots 

1678@dataclass(frozen=True) 

1679class Assign(BaseSmallStatement): 

1680 """ 

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

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

1683 allow for multiple targets. 

1684 """ 

1685 

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

1687 targets: Sequence[AssignTarget] 

1688 

1689 #: The expression being assigned to the targets. 

1690 value: BaseExpression 

1691 

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

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

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

1695 

1696 def _validate(self) -> None: 

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

1698 raise CSTValidationError( 

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

1700 ) 

1701 

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

1703 return Assign( 

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

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

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

1707 ) 

1708 

1709 def _codegen_impl( 

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

1711 ) -> None: 

1712 with state.record_syntactic_position(self): 

1713 for target in self.targets: 

1714 target._codegen(state) 

1715 self.value._codegen(state) 

1716 

1717 semicolon = self.semicolon 

1718 if isinstance(semicolon, MaybeSentinel): 

1719 if default_semicolon: 

1720 state.add_token("; ") 

1721 elif isinstance(semicolon, Semicolon): 

1722 semicolon._codegen(state) 

1723 

1724 

1725@add_slots 

1726@dataclass(frozen=True) 

1727class AnnAssign(BaseSmallStatement): 

1728 """ 

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

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

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

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

1733 to it. 

1734 """ 

1735 

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

1737 target: BaseAssignTargetExpression 

1738 

1739 #: The annotation for the target. 

1740 annotation: Annotation 

1741 

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

1743 value: Optional[BaseExpression] = None 

1744 

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

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

1747 

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

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

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

1751 

1752 def _validate(self) -> None: 

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

1754 raise CSTValidationError( 

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

1756 ) 

1757 

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

1759 return AnnAssign( 

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

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

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

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

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

1765 ) 

1766 

1767 def _codegen_impl( 

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

1769 ) -> None: 

1770 with state.record_syntactic_position(self): 

1771 self.target._codegen(state) 

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

1773 equal = self.equal 

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

1775 state.add_token(" = ") 

1776 elif isinstance(equal, AssignEqual): 

1777 equal._codegen(state) 

1778 value = self.value 

1779 if value is not None: 

1780 value._codegen(state) 

1781 

1782 semicolon = self.semicolon 

1783 if isinstance(semicolon, MaybeSentinel): 

1784 if default_semicolon: 

1785 state.add_token("; ") 

1786 elif isinstance(semicolon, Semicolon): 

1787 semicolon._codegen(state) 

1788 

1789 

1790@add_slots 

1791@dataclass(frozen=True) 

1792class AugAssign(BaseSmallStatement): 

1793 """ 

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

1795 """ 

1796 

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

1798 target: BaseAssignTargetExpression 

1799 

1800 #: The augmented assignment operation being performed. 

1801 operator: BaseAugOp 

1802 

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

1804 value: BaseExpression 

1805 

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

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

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

1809 

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

1811 return AugAssign( 

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

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

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

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

1816 ) 

1817 

1818 def _codegen_impl( 

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

1820 ) -> None: 

1821 with state.record_syntactic_position(self): 

1822 self.target._codegen(state) 

1823 self.operator._codegen(state) 

1824 self.value._codegen(state) 

1825 

1826 semicolon = self.semicolon 

1827 if isinstance(semicolon, MaybeSentinel): 

1828 if default_semicolon: 

1829 state.add_token("; ") 

1830 elif isinstance(semicolon, Semicolon): 

1831 semicolon._codegen(state) 

1832 

1833 

1834@add_slots 

1835@dataclass(frozen=True) 

1836class Decorator(CSTNode): 

1837 """ 

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

1839 """ 

1840 

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

1842 #: of this decorator. 

1843 decorator: BaseExpression 

1844 

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

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

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

1848 leading_lines: Sequence[EmptyLine] = () 

1849 

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

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

1852 

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

1854 trailing_whitespace: TrailingWhitespace = TrailingWhitespace.field() 

1855 

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

1857 return Decorator( 

1858 leading_lines=visit_sequence( 

1859 self, "leading_lines", self.leading_lines, visitor 

1860 ), 

1861 whitespace_after_at=visit_required( 

1862 self, "whitespace_after_at", self.whitespace_after_at, visitor 

1863 ), 

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

1865 trailing_whitespace=visit_required( 

1866 self, "trailing_whitespace", self.trailing_whitespace, visitor 

1867 ), 

1868 ) 

1869 

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

1871 for ll in self.leading_lines: 

1872 ll._codegen(state) 

1873 state.add_indent_tokens() 

1874 

1875 with state.record_syntactic_position(self): 

1876 state.add_token("@") 

1877 self.whitespace_after_at._codegen(state) 

1878 self.decorator._codegen(state) 

1879 

1880 self.trailing_whitespace._codegen(state) 

1881 

1882 

1883def get_docstring_impl( 

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

1885 clean: bool, 

1886) -> Optional[str]: 

1887 """ 

1888 Implementation Reference: 

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

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

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

1892 """ 

1893 if isinstance(body, Sequence): 

1894 if body: 

1895 expr = body[0] 

1896 else: 

1897 return None 

1898 else: 

1899 expr = body 

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

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

1902 return None 

1903 expr = expr.body[0] 

1904 if not isinstance(expr, Expr): 

1905 return None 

1906 val = expr.value 

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

1908 evaluated_value = val.evaluated_value 

1909 else: 

1910 return None 

1911 if isinstance(evaluated_value, bytes): 

1912 return None 

1913 

1914 if evaluated_value is not None and clean: 

1915 return inspect.cleandoc(evaluated_value) 

1916 return evaluated_value 

1917 

1918 

1919@add_slots 

1920@dataclass(frozen=True) 

1921class FunctionDef(BaseCompoundStatement): 

1922 """ 

1923 A function definition. 

1924 """ 

1925 

1926 #: The function name. 

1927 name: Name 

1928 

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

1930 params: Parameters 

1931 

1932 #: The function body. 

1933 body: BaseSuite 

1934 

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

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

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

1938 decorators: Sequence[Decorator] = () 

1939 

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

1941 returns: Optional[Annotation] = None 

1942 

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

1944 asynchronous: Optional[Asynchronous] = None 

1945 

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

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

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

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

1950 #: function definition. 

1951 leading_lines: Sequence[EmptyLine] = () 

1952 

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

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

1955 lines_after_decorators: Sequence[EmptyLine] = () 

1956 

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

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

1959 

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

1961 #: parenthesis for the parameters. 

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

1963 

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

1965 #: the first param itself. 

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

1967 

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

1969 #: the colon. 

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

1971 

1972 #: An optional declaration of type parameters. 

1973 type_parameters: Optional["TypeParameters"] = None 

1974 

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

1976 #: (non-type) parameters. 

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

1978 

1979 def _validate(self) -> None: 

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

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

1982 if self.whitespace_after_def.empty: 

1983 raise CSTValidationError( 

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

1985 ) 

1986 

1987 if ( 

1988 self.type_parameters is None 

1989 and not self.whitespace_after_type_parameters.empty 

1990 ): 

1991 raise CSTValidationError( 

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

1993 "parameters in FunctionDef" 

1994 ) 

1995 

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

1997 return FunctionDef( 

1998 leading_lines=visit_sequence( 

1999 self, "leading_lines", self.leading_lines, visitor 

2000 ), 

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

2002 lines_after_decorators=visit_sequence( 

2003 self, "lines_after_decorators", self.lines_after_decorators, visitor 

2004 ), 

2005 asynchronous=visit_optional( 

2006 self, "asynchronous", self.asynchronous, visitor 

2007 ), 

2008 whitespace_after_def=visit_required( 

2009 self, "whitespace_after_def", self.whitespace_after_def, visitor 

2010 ), 

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

2012 whitespace_after_name=visit_required( 

2013 self, "whitespace_after_name", self.whitespace_after_name, visitor 

2014 ), 

2015 type_parameters=visit_optional( 

2016 self, "type_parameters", self.type_parameters, visitor 

2017 ), 

2018 whitespace_after_type_parameters=visit_required( 

2019 self, 

2020 "whitespace_after_type_parameters", 

2021 self.whitespace_after_type_parameters, 

2022 visitor, 

2023 ), 

2024 whitespace_before_params=visit_required( 

2025 self, "whitespace_before_params", self.whitespace_before_params, visitor 

2026 ), 

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

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

2029 whitespace_before_colon=visit_required( 

2030 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2031 ), 

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

2033 ) 

2034 

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

2036 for ll in self.leading_lines: 

2037 ll._codegen(state) 

2038 for decorator in self.decorators: 

2039 decorator._codegen(state) 

2040 for lad in self.lines_after_decorators: 

2041 lad._codegen(state) 

2042 state.add_indent_tokens() 

2043 

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

2045 asynchronous = self.asynchronous 

2046 if asynchronous is not None: 

2047 asynchronous._codegen(state) 

2048 state.add_token("def") 

2049 self.whitespace_after_def._codegen(state) 

2050 self.name._codegen(state) 

2051 self.whitespace_after_name._codegen(state) 

2052 type_params = self.type_parameters 

2053 if type_params is not None: 

2054 type_params._codegen(state) 

2055 self.whitespace_after_type_parameters._codegen(state) 

2056 state.add_token("(") 

2057 self.whitespace_before_params._codegen(state) 

2058 self.params._codegen(state) 

2059 state.add_token(")") 

2060 returns = self.returns 

2061 if returns is not None: 

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

2063 self.whitespace_before_colon._codegen(state) 

2064 state.add_token(":") 

2065 self.body._codegen(state) 

2066 

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

2068 """ 

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

2070 Otherwise, returns ``None``. 

2071 """ 

2072 return get_docstring_impl(self.body, clean) 

2073 

2074 

2075@add_slots 

2076@dataclass(frozen=True) 

2077class ClassDef(BaseCompoundStatement): 

2078 """ 

2079 A class definition. 

2080 """ 

2081 

2082 #: The class name. 

2083 name: Name 

2084 

2085 #: The class body. 

2086 body: BaseSuite 

2087 

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

2089 bases: Sequence[Arg] = () 

2090 

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

2092 keywords: Sequence[Arg] = () 

2093 

2094 #: Sequence of decorators applied to this class. 

2095 decorators: Sequence[Decorator] = () 

2096 

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

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

2099 

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

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

2102 

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

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

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

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

2107 #: class definition. 

2108 leading_lines: Sequence[EmptyLine] = () 

2109 

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

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

2112 lines_after_decorators: Sequence[EmptyLine] = () 

2113 

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

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

2116 

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

2118 #: parenthesis for the bases and keywords. 

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

2120 

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

2122 #: the colon. 

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

2124 

2125 #: An optional declaration of type parameters. 

2126 type_parameters: Optional["TypeParameters"] = None 

2127 

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

2129 #: keywords. 

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

2131 

2132 def _validate_whitespace(self) -> None: 

2133 if self.whitespace_after_class.empty: 

2134 raise CSTValidationError( 

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

2136 ) 

2137 if ( 

2138 self.type_parameters is None 

2139 and not self.whitespace_after_type_parameters.empty 

2140 ): 

2141 raise CSTValidationError( 

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

2143 "parameters in a ClassDef" 

2144 ) 

2145 

2146 def _validate_parens(self) -> None: 

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

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

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

2150 raise CSTValidationError( 

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

2152 ) 

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

2154 raise CSTValidationError( 

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

2156 ) 

2157 

2158 def _validate_args(self) -> None: 

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

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

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

2162 raise CSTValidationError( 

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

2164 ) 

2165 

2166 def _validate(self) -> None: 

2167 self._validate_whitespace() 

2168 self._validate_parens() 

2169 self._validate_args() 

2170 

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

2172 return ClassDef( 

2173 leading_lines=visit_sequence( 

2174 self, "leading_lines", self.leading_lines, visitor 

2175 ), 

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

2177 lines_after_decorators=visit_sequence( 

2178 self, "lines_after_decorators", self.lines_after_decorators, visitor 

2179 ), 

2180 whitespace_after_class=visit_required( 

2181 self, "whitespace_after_class", self.whitespace_after_class, visitor 

2182 ), 

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

2184 whitespace_after_name=visit_required( 

2185 self, "whitespace_after_name", self.whitespace_after_name, visitor 

2186 ), 

2187 type_parameters=visit_optional( 

2188 self, "type_parameters", self.type_parameters, visitor 

2189 ), 

2190 whitespace_after_type_parameters=visit_required( 

2191 self, 

2192 "whitespace_after_type_parameters", 

2193 self.whitespace_after_type_parameters, 

2194 visitor, 

2195 ), 

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

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

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

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

2200 whitespace_before_colon=visit_required( 

2201 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2202 ), 

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

2204 ) 

2205 

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

2207 for ll in self.leading_lines: 

2208 ll._codegen(state) 

2209 for decorator in self.decorators: 

2210 decorator._codegen(state) 

2211 for lad in self.lines_after_decorators: 

2212 lad._codegen(state) 

2213 state.add_indent_tokens() 

2214 

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

2216 state.add_token("class") 

2217 self.whitespace_after_class._codegen(state) 

2218 self.name._codegen(state) 

2219 self.whitespace_after_name._codegen(state) 

2220 type_params = self.type_parameters 

2221 if type_params is not None: 

2222 type_params._codegen(state) 

2223 self.whitespace_after_type_parameters._codegen(state) 

2224 lpar = self.lpar 

2225 if isinstance(lpar, MaybeSentinel): 

2226 if self.bases or self.keywords: 

2227 state.add_token("(") 

2228 elif isinstance(lpar, LeftParen): 

2229 lpar._codegen(state) 

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

2231 last_arg = len(args) - 1 

2232 for i, arg in enumerate(args): 

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

2234 rpar = self.rpar 

2235 if isinstance(rpar, MaybeSentinel): 

2236 if self.bases or self.keywords: 

2237 state.add_token(")") 

2238 elif isinstance(rpar, RightParen): 

2239 rpar._codegen(state) 

2240 self.whitespace_before_colon._codegen(state) 

2241 state.add_token(":") 

2242 self.body._codegen(state) 

2243 

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

2245 """ 

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

2247 """ 

2248 return get_docstring_impl(self.body, clean) 

2249 

2250 

2251@add_slots 

2252@dataclass(frozen=True) 

2253class WithItem(CSTNode): 

2254 """ 

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

2256 """ 

2257 

2258 #: Expression that evaluates to a context manager. 

2259 item: BaseExpression 

2260 

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

2262 #: :class:`With` body. 

2263 asname: Optional[AsName] = None 

2264 

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

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

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

2268 

2269 def _validate(self) -> None: 

2270 asname = self.asname 

2271 if ( 

2272 asname is not None 

2273 and asname.whitespace_before_as.empty 

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

2275 ): 

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

2277 

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

2279 return WithItem( 

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

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

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

2283 ) 

2284 

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

2286 with state.record_syntactic_position(self): 

2287 self.item._codegen(state) 

2288 asname = self.asname 

2289 if asname is not None: 

2290 asname._codegen(state) 

2291 

2292 comma = self.comma 

2293 if comma is MaybeSentinel.DEFAULT and default_comma: 

2294 state.add_token(", ") 

2295 elif isinstance(comma, Comma): 

2296 comma._codegen(state) 

2297 

2298 

2299@add_slots 

2300@dataclass(frozen=True) 

2301class With(BaseCompoundStatement): 

2302 """ 

2303 A ``with`` statement. 

2304 """ 

2305 

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

2307 items: Sequence[WithItem] 

2308 

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

2310 body: BaseSuite 

2311 

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

2313 asynchronous: Optional[Asynchronous] = None 

2314 

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

2316 leading_lines: Sequence[EmptyLine] = () 

2317 

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

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

2320 

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

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

2323 

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

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

2326 

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

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

2329 

2330 def _validate_parens(self) -> None: 

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

2332 raise CSTValidationError( 

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

2334 ) 

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

2336 raise CSTValidationError( 

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

2338 ) 

2339 

2340 def _validate(self) -> None: 

2341 self._validate_parens() 

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

2343 raise CSTValidationError( 

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

2345 ) 

2346 if ( 

2347 isinstance(self.rpar, MaybeSentinel) 

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

2349 ): 

2350 raise CSTValidationError( 

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

2352 ) 

2353 if self.whitespace_after_with.empty and not ( 

2354 isinstance(self.lpar, LeftParen) 

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

2356 ExpressionPosition.RIGHT 

2357 ) 

2358 ): 

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

2360 

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

2362 return With( 

2363 leading_lines=visit_sequence( 

2364 self, "leading_lines", self.leading_lines, visitor 

2365 ), 

2366 asynchronous=visit_optional( 

2367 self, "asynchronous", self.asynchronous, visitor 

2368 ), 

2369 whitespace_after_with=visit_required( 

2370 self, "whitespace_after_with", self.whitespace_after_with, visitor 

2371 ), 

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

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

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

2375 whitespace_before_colon=visit_required( 

2376 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2377 ), 

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

2379 ) 

2380 

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

2382 for ll in self.leading_lines: 

2383 ll._codegen(state) 

2384 state.add_indent_tokens() 

2385 

2386 needs_paren = False 

2387 for item in self.items: 

2388 comma = item.comma 

2389 if isinstance(comma, Comma): 

2390 if isinstance( 

2391 comma.whitespace_after, 

2392 (EmptyLine, TrailingWhitespace, ParenthesizedWhitespace), 

2393 ): 

2394 needs_paren = True 

2395 break 

2396 

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

2398 asynchronous = self.asynchronous 

2399 if asynchronous is not None: 

2400 asynchronous._codegen(state) 

2401 state.add_token("with") 

2402 self.whitespace_after_with._codegen(state) 

2403 lpar = self.lpar 

2404 if isinstance(lpar, LeftParen): 

2405 lpar._codegen(state) 

2406 elif needs_paren: 

2407 state.add_token("(") 

2408 last_item = len(self.items) - 1 

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

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

2411 rpar = self.rpar 

2412 if isinstance(rpar, RightParen): 

2413 rpar._codegen(state) 

2414 elif needs_paren: 

2415 state.add_token(")") 

2416 self.whitespace_before_colon._codegen(state) 

2417 state.add_token(":") 

2418 self.body._codegen(state) 

2419 

2420 

2421@add_slots 

2422@dataclass(frozen=True) 

2423class For(BaseCompoundStatement): 

2424 """ 

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

2426 """ 

2427 

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

2429 target: BaseAssignTargetExpression 

2430 

2431 #: The iterable expression we will loop over. 

2432 iter: BaseExpression 

2433 

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

2435 body: BaseSuite 

2436 

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

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

2439 orelse: Optional[Else] = None 

2440 

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

2442 asynchronous: Optional[Asynchronous] = None 

2443 

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

2445 leading_lines: Sequence[EmptyLine] = () 

2446 

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

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

2449 

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

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

2452 

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

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

2455 

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

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

2458 

2459 def _validate(self) -> None: 

2460 if ( 

2461 self.whitespace_after_for.empty 

2462 and not self.target._safe_to_use_with_word_operator( 

2463 ExpressionPosition.RIGHT 

2464 ) 

2465 ): 

2466 raise CSTValidationError( 

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

2468 ) 

2469 

2470 if ( 

2471 self.whitespace_before_in.empty 

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

2473 ): 

2474 raise CSTValidationError( 

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

2476 ) 

2477 

2478 if ( 

2479 self.whitespace_after_in.empty 

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

2481 ): 

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

2483 

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

2485 return For( 

2486 leading_lines=visit_sequence( 

2487 self, "leading_lines", self.leading_lines, visitor 

2488 ), 

2489 asynchronous=visit_optional( 

2490 self, "asynchronous", self.asynchronous, visitor 

2491 ), 

2492 whitespace_after_for=visit_required( 

2493 self, "whitespace_after_for", self.whitespace_after_for, visitor 

2494 ), 

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

2496 whitespace_before_in=visit_required( 

2497 self, "whitespace_before_in", self.whitespace_before_in, visitor 

2498 ), 

2499 whitespace_after_in=visit_required( 

2500 self, "whitespace_after_in", self.whitespace_after_in, visitor 

2501 ), 

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

2503 whitespace_before_colon=visit_required( 

2504 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2505 ), 

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

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

2508 ) 

2509 

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

2511 for ll in self.leading_lines: 

2512 ll._codegen(state) 

2513 state.add_indent_tokens() 

2514 

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

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

2517 asynchronous = self.asynchronous 

2518 if asynchronous is not None: 

2519 asynchronous._codegen(state) 

2520 state.add_token("for") 

2521 self.whitespace_after_for._codegen(state) 

2522 self.target._codegen(state) 

2523 self.whitespace_before_in._codegen(state) 

2524 state.add_token("in") 

2525 self.whitespace_after_in._codegen(state) 

2526 self.iter._codegen(state) 

2527 self.whitespace_before_colon._codegen(state) 

2528 state.add_token(":") 

2529 self.body._codegen(state) 

2530 orelse = self.orelse 

2531 if orelse is not None: 

2532 orelse._codegen(state) 

2533 

2534 

2535@add_slots 

2536@dataclass(frozen=True) 

2537class While(BaseCompoundStatement): 

2538 """ 

2539 A ``while`` statement. 

2540 """ 

2541 

2542 #: The test we will loop against. 

2543 test: BaseExpression 

2544 

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

2546 body: BaseSuite 

2547 

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

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

2550 orelse: Optional[Else] = None 

2551 

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

2553 leading_lines: Sequence[EmptyLine] = () 

2554 

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

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

2557 

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

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

2560 

2561 def _validate(self) -> None: 

2562 if ( 

2563 self.whitespace_after_while.empty 

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

2565 ): 

2566 raise CSTValidationError( 

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

2568 ) 

2569 

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

2571 return While( 

2572 leading_lines=visit_sequence( 

2573 self, "leading_lines", self.leading_lines, visitor 

2574 ), 

2575 whitespace_after_while=visit_required( 

2576 self, "whitespace_after_while", self.whitespace_after_while, visitor 

2577 ), 

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

2579 whitespace_before_colon=visit_required( 

2580 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

2581 ), 

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

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

2584 ) 

2585 

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

2587 for ll in self.leading_lines: 

2588 ll._codegen(state) 

2589 state.add_indent_tokens() 

2590 

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

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

2593 state.add_token("while") 

2594 self.whitespace_after_while._codegen(state) 

2595 self.test._codegen(state) 

2596 self.whitespace_before_colon._codegen(state) 

2597 state.add_token(":") 

2598 self.body._codegen(state) 

2599 orelse = self.orelse 

2600 if orelse is not None: 

2601 orelse._codegen(state) 

2602 

2603 

2604@add_slots 

2605@dataclass(frozen=True) 

2606class Raise(BaseSmallStatement): 

2607 """ 

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

2609 """ 

2610 

2611 #: The exception that we should raise. 

2612 exc: Optional[BaseExpression] = None 

2613 

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

2615 #: out of another exception's context. 

2616 cause: Optional[From] = None 

2617 

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

2619 whitespace_after_raise: Union[SimpleWhitespace, MaybeSentinel] = ( 

2620 MaybeSentinel.DEFAULT 

2621 ) 

2622 

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

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

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

2626 

2627 def _validate(self) -> None: 

2628 # Validate correct construction 

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

2630 raise CSTValidationError( 

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

2632 ) 

2633 

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

2635 exc = self.exc 

2636 if exc is not None: 

2637 whitespace_after_raise = self.whitespace_after_raise 

2638 has_no_gap = ( 

2639 not isinstance(whitespace_after_raise, MaybeSentinel) 

2640 and whitespace_after_raise.empty 

2641 ) 

2642 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2643 ExpressionPosition.RIGHT 

2644 ): 

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

2646 

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

2648 cause = self.cause 

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

2650 whitespace_before_from = cause.whitespace_before_from 

2651 has_no_gap = ( 

2652 not isinstance(whitespace_before_from, MaybeSentinel) 

2653 and whitespace_before_from.empty 

2654 ) 

2655 if has_no_gap and not exc._safe_to_use_with_word_operator( 

2656 ExpressionPosition.LEFT 

2657 ): 

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

2659 

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

2661 return Raise( 

2662 whitespace_after_raise=visit_sentinel( 

2663 self, "whitespace_after_raise", self.whitespace_after_raise, visitor 

2664 ), 

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

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

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

2668 ) 

2669 

2670 def _codegen_impl( 

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

2672 ) -> None: 

2673 with state.record_syntactic_position(self): 

2674 exc = self.exc 

2675 cause = self.cause 

2676 state.add_token("raise") 

2677 whitespace_after_raise = self.whitespace_after_raise 

2678 if isinstance(whitespace_after_raise, MaybeSentinel): 

2679 if exc is not None: 

2680 state.add_token(" ") 

2681 else: 

2682 whitespace_after_raise._codegen(state) 

2683 if exc is not None: 

2684 exc._codegen(state) 

2685 if cause is not None: 

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

2687 

2688 semicolon = self.semicolon 

2689 if isinstance(semicolon, MaybeSentinel): 

2690 if default_semicolon: 

2691 state.add_token("; ") 

2692 elif isinstance(semicolon, Semicolon): 

2693 semicolon._codegen(state) 

2694 

2695 

2696@add_slots 

2697@dataclass(frozen=True) 

2698class Assert(BaseSmallStatement): 

2699 """ 

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

2701 """ 

2702 

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

2704 test: BaseExpression 

2705 

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

2707 msg: Optional[BaseExpression] = None 

2708 

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

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

2711 

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

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

2714 

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

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

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

2718 

2719 def _validate(self) -> None: 

2720 # Validate whitespace 

2721 if ( 

2722 self.whitespace_after_assert.empty 

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

2724 ): 

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

2726 

2727 # Validate comma rules 

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

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

2730 

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

2732 return Assert( 

2733 whitespace_after_assert=visit_required( 

2734 self, "whitespace_after_assert", self.whitespace_after_assert, visitor 

2735 ), 

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

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

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

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

2740 ) 

2741 

2742 def _codegen_impl( 

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

2744 ) -> None: 

2745 with state.record_syntactic_position(self): 

2746 state.add_token("assert") 

2747 self.whitespace_after_assert._codegen(state) 

2748 self.test._codegen(state) 

2749 

2750 comma = self.comma 

2751 msg = self.msg 

2752 if isinstance(comma, MaybeSentinel): 

2753 if msg is not None: 

2754 state.add_token(", ") 

2755 else: 

2756 comma._codegen(state) 

2757 if msg is not None: 

2758 msg._codegen(state) 

2759 

2760 semicolon = self.semicolon 

2761 if isinstance(semicolon, MaybeSentinel): 

2762 if default_semicolon: 

2763 state.add_token("; ") 

2764 elif isinstance(semicolon, Semicolon): 

2765 semicolon._codegen(state) 

2766 

2767 

2768@add_slots 

2769@dataclass(frozen=True) 

2770class NameItem(CSTNode): 

2771 """ 

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

2773 

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

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

2776 """ 

2777 

2778 #: Identifier name. 

2779 name: Name 

2780 

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

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

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

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

2785 

2786 def _validate(self) -> None: 

2787 # No parens around names here 

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

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

2790 

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

2792 return NameItem( 

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

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

2795 ) 

2796 

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

2798 with state.record_syntactic_position(self): 

2799 self.name._codegen(state) 

2800 

2801 comma = self.comma 

2802 if comma is MaybeSentinel.DEFAULT and default_comma: 

2803 state.add_token(", ") 

2804 elif isinstance(comma, Comma): 

2805 comma._codegen(state) 

2806 

2807 

2808@add_slots 

2809@dataclass(frozen=True) 

2810class Global(BaseSmallStatement): 

2811 """ 

2812 A ``global`` statement. 

2813 """ 

2814 

2815 #: A list of one or more names. 

2816 names: Sequence[NameItem] 

2817 

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

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

2820 

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

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

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

2824 

2825 def _validate(self) -> None: 

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

2827 raise CSTValidationError( 

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

2829 ) 

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

2831 raise CSTValidationError( 

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

2833 ) 

2834 if self.whitespace_after_global.empty: 

2835 raise CSTValidationError( 

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

2837 ) 

2838 

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

2840 return Global( 

2841 whitespace_after_global=visit_required( 

2842 self, "whitespace_after_global", self.whitespace_after_global, visitor 

2843 ), 

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

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

2846 ) 

2847 

2848 def _codegen_impl( 

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

2850 ) -> None: 

2851 with state.record_syntactic_position(self): 

2852 state.add_token("global") 

2853 self.whitespace_after_global._codegen(state) 

2854 last_name = len(self.names) - 1 

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

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

2857 

2858 semicolon = self.semicolon 

2859 if isinstance(semicolon, MaybeSentinel): 

2860 if default_semicolon: 

2861 state.add_token("; ") 

2862 elif isinstance(semicolon, Semicolon): 

2863 semicolon._codegen(state) 

2864 

2865 

2866@add_slots 

2867@dataclass(frozen=True) 

2868class Nonlocal(BaseSmallStatement): 

2869 """ 

2870 A ``nonlocal`` statement. 

2871 """ 

2872 

2873 #: A list of one or more names. 

2874 names: Sequence[NameItem] 

2875 

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

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

2878 

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

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

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

2882 

2883 def _validate(self) -> None: 

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

2885 raise CSTValidationError( 

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

2887 ) 

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

2889 raise CSTValidationError( 

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

2891 ) 

2892 if self.whitespace_after_nonlocal.empty: 

2893 raise CSTValidationError( 

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

2895 ) 

2896 

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

2898 return Nonlocal( 

2899 whitespace_after_nonlocal=visit_required( 

2900 self, 

2901 "whitespace_after_nonlocal", 

2902 self.whitespace_after_nonlocal, 

2903 visitor, 

2904 ), 

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

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

2907 ) 

2908 

2909 def _codegen_impl( 

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

2911 ) -> None: 

2912 with state.record_syntactic_position(self): 

2913 state.add_token("nonlocal") 

2914 self.whitespace_after_nonlocal._codegen(state) 

2915 last_name = len(self.names) - 1 

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

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

2918 

2919 semicolon = self.semicolon 

2920 if isinstance(semicolon, MaybeSentinel): 

2921 if default_semicolon: 

2922 state.add_token("; ") 

2923 elif isinstance(semicolon, Semicolon): 

2924 semicolon._codegen(state) 

2925 

2926 

2927class MatchPattern(_BaseParenthesizedNode, ABC): 

2928 """ 

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

2930 statement. 

2931 """ 

2932 

2933 __slots__ = () 

2934 

2935 

2936@add_slots 

2937@dataclass(frozen=True) 

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

2939class Match(BaseCompoundStatement): 

2940 """ 

2941 A ``match`` statement. 

2942 """ 

2943 

2944 #: The subject of the match. 

2945 subject: BaseExpression 

2946 

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

2948 cases: Sequence["MatchCase"] 

2949 

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

2951 leading_lines: Sequence[EmptyLine] = () 

2952 

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

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

2955 

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

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

2958 

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

2960 whitespace_after_colon: TrailingWhitespace = TrailingWhitespace.field() 

2961 

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

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

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

2965 indent: Optional[str] = None 

2966 

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

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

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

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

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

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

2973 footer: Sequence[EmptyLine] = () 

2974 

2975 def _validate(self) -> None: 

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

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

2978 

2979 indent = self.indent 

2980 if indent is not None: 

2981 if len(indent) == 0: 

2982 raise CSTValidationError( 

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

2984 ) 

2985 if _INDENT_WHITESPACE_RE.fullmatch(indent) is None: 

2986 raise CSTValidationError( 

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

2988 ) 

2989 

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

2991 return Match( 

2992 leading_lines=visit_sequence( 

2993 self, "leading_lines", self.leading_lines, visitor 

2994 ), 

2995 whitespace_after_match=visit_required( 

2996 self, "whitespace_after_match", self.whitespace_after_match, visitor 

2997 ), 

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

2999 whitespace_before_colon=visit_required( 

3000 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

3001 ), 

3002 whitespace_after_colon=visit_required( 

3003 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

3004 ), 

3005 indent=self.indent, 

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

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

3008 ) 

3009 

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

3011 for ll in self.leading_lines: 

3012 ll._codegen(state) 

3013 state.add_indent_tokens() 

3014 

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

3016 state.add_token("match") 

3017 self.whitespace_after_match._codegen(state) 

3018 self.subject._codegen(state) 

3019 self.whitespace_before_colon._codegen(state) 

3020 state.add_token(":") 

3021 self.whitespace_after_colon._codegen(state) 

3022 

3023 indent = self.indent 

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

3025 for c in self.cases: 

3026 c._codegen(state) 

3027 

3028 for f in self.footer: 

3029 f._codegen(state) 

3030 

3031 state.decrease_indent() 

3032 

3033 

3034@add_slots 

3035@dataclass(frozen=True) 

3036class MatchCase(CSTNode): 

3037 """ 

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

3039 """ 

3040 

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

3042 pattern: MatchPattern 

3043 

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

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

3046 body: BaseSuite 

3047 

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

3049 guard: Optional[BaseExpression] = None 

3050 

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

3052 leading_lines: Sequence[EmptyLine] = () 

3053 

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

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

3056 

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

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

3059 

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

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

3062 

3063 #: Whitespace before the colon. 

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

3065 

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

3067 return MatchCase( 

3068 leading_lines=visit_sequence( 

3069 self, "leading_lines", self.leading_lines, visitor 

3070 ), 

3071 whitespace_after_case=visit_required( 

3072 self, "whitespace_after_case", self.whitespace_after_case, visitor 

3073 ), 

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

3075 whitespace_before_if=visit_required( 

3076 self, "whitespace_before_if", self.whitespace_before_if, visitor 

3077 ), 

3078 whitespace_after_if=visit_required( 

3079 self, "whitespace_after_if", self.whitespace_after_if, visitor 

3080 ), 

3081 guard=visit_optional(self, "guard", self.guard, visitor), 

3082 whitespace_before_colon=visit_required( 

3083 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

3084 ), 

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

3086 ) 

3087 

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

3089 for ll in self.leading_lines: 

3090 ll._codegen(state) 

3091 state.add_indent_tokens() 

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

3093 state.add_token("case") 

3094 self.whitespace_after_case._codegen(state) 

3095 self.pattern._codegen(state) 

3096 

3097 guard = self.guard 

3098 if guard is not None: 

3099 self.whitespace_before_if._codegen(state) 

3100 state.add_token("if") 

3101 self.whitespace_after_if._codegen(state) 

3102 guard._codegen(state) 

3103 else: 

3104 self.whitespace_before_if._codegen(state) 

3105 self.whitespace_after_if._codegen(state) 

3106 

3107 self.whitespace_before_colon._codegen(state) 

3108 state.add_token(":") 

3109 self.body._codegen(state) 

3110 

3111 

3112@add_slots 

3113@dataclass(frozen=True) 

3114class MatchValue(MatchPattern): 

3115 """ 

3116 A match literal or value pattern that compares by equality. 

3117 """ 

3118 

3119 #: an expression to compare to 

3120 value: BaseExpression 

3121 

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

3123 return MatchValue(value=visit_required(self, "value", self.value, visitor)) 

3124 

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

3126 with state.record_syntactic_position(self): 

3127 self.value._codegen(state) 

3128 

3129 @property 

3130 def lpar(self) -> Sequence[LeftParen]: 

3131 return self.value.lpar 

3132 

3133 @lpar.setter 

3134 def lpar(self, value: Sequence[LeftParen]) -> None: 

3135 self.value.lpar = value 

3136 

3137 @property 

3138 def rpar(self) -> Sequence[RightParen]: 

3139 return self.value.rpar 

3140 

3141 @rpar.setter 

3142 def rpar(self, value: Sequence[RightParen]) -> None: 

3143 self.value.rpar = value 

3144 

3145 

3146@add_slots 

3147@dataclass(frozen=True) 

3148class MatchSingleton(MatchPattern): 

3149 """ 

3150 A match literal pattern that compares by identity. 

3151 """ 

3152 

3153 #: a literal to compare to 

3154 value: Name 

3155 

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

3157 return MatchSingleton(value=visit_required(self, "value", self.value, visitor)) 

3158 

3159 def _validate(self) -> None: 

3160 if self.value.value not in {"True", "False", "None"}: 

3161 raise CSTValidationError( 

3162 "A match singleton can only be True, False, or None" 

3163 ) 

3164 

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

3166 with state.record_syntactic_position(self): 

3167 self.value._codegen(state) 

3168 

3169 @property 

3170 def lpar(self) -> Sequence[LeftParen]: 

3171 return self.value.lpar 

3172 

3173 @lpar.setter 

3174 def lpar(self, value: Sequence[LeftParen]) -> None: 

3175 # pyre-fixme[41]: Cannot reassign final attribute `lpar`. 

3176 self.value.lpar = value 

3177 

3178 @property 

3179 def rpar(self) -> Sequence[RightParen]: 

3180 return self.value.rpar 

3181 

3182 @rpar.setter 

3183 def rpar(self, value: Sequence[RightParen]) -> None: 

3184 # pyre-fixme[41]: Cannot reassign final attribute `rpar`. 

3185 self.value.rpar = value 

3186 

3187 

3188@add_slots 

3189@dataclass(frozen=True) 

3190class MatchSequenceElement(CSTNode): 

3191 """ 

3192 An element in a sequence match pattern. 

3193 """ 

3194 

3195 value: MatchPattern 

3196 

3197 #: An optional trailing comma. 

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

3199 

3200 def _visit_and_replace_children( 

3201 self, visitor: CSTVisitorT 

3202 ) -> "MatchSequenceElement": 

3203 return MatchSequenceElement( 

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

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

3206 ) 

3207 

3208 def _codegen_impl( 

3209 self, 

3210 state: CodegenState, 

3211 default_comma: bool = False, 

3212 default_comma_whitespace: bool = True, 

3213 ) -> None: 

3214 with state.record_syntactic_position(self): 

3215 self.value._codegen(state) 

3216 comma = self.comma 

3217 if comma is MaybeSentinel.DEFAULT and default_comma: 

3218 state.add_token(", " if default_comma_whitespace else ",") 

3219 elif isinstance(comma, Comma): 

3220 comma._codegen(state) 

3221 

3222 

3223@add_slots 

3224@dataclass(frozen=True) 

3225class MatchStar(CSTNode): 

3226 """ 

3227 A starred element in a sequence match pattern. Matches the rest of the sequence. 

3228 """ 

3229 

3230 #: The name of the pattern binding. A ``None`` value represents ``*_``. 

3231 name: Optional[Name] = None 

3232 

3233 #: An optional trailing comma. 

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

3235 

3236 #: Optional whitespace between the star and the name. 

3237 whitespace_before_name: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3238 

3239 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchStar": 

3240 return MatchStar( 

3241 whitespace_before_name=visit_required( 

3242 self, "whitespace_before_name", self.whitespace_before_name, visitor 

3243 ), 

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

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

3246 ) 

3247 

3248 def _codegen_impl( 

3249 self, 

3250 state: CodegenState, 

3251 default_comma: bool = False, 

3252 default_comma_whitespace: bool = True, 

3253 ) -> None: 

3254 with state.record_syntactic_position(self): 

3255 state.add_token("*") 

3256 self.whitespace_before_name._codegen(state) 

3257 name = self.name 

3258 if name is None: 

3259 state.add_token("_") 

3260 else: 

3261 name._codegen(state) 

3262 comma = self.comma 

3263 if comma is MaybeSentinel.DEFAULT and default_comma: 

3264 state.add_token(", " if default_comma_whitespace else ",") 

3265 elif isinstance(comma, Comma): 

3266 comma._codegen(state) 

3267 

3268 

3269class MatchSequence(MatchPattern, ABC): 

3270 """ 

3271 A match sequence pattern. It's either a :class:`MatchList` or a :class:`MatchTuple`. 

3272 Matches a variable length sequence if one of the patterns is a :class:`MatchStar`, 

3273 otherwise matches a fixed length sequence. 

3274 """ 

3275 

3276 __slots__ = () 

3277 

3278 #: Patterns to be matched against the subject elements if it is a sequence. 

3279 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3280 

3281 

3282@add_slots 

3283@dataclass(frozen=True) 

3284class MatchList(MatchSequence): 

3285 """ 

3286 A list match pattern. It's either an "open sequence pattern" (without brackets) or a 

3287 regular list literal (with brackets). 

3288 """ 

3289 

3290 #: Patterns to be matched against the subject elements if it is a sequence. 

3291 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3292 

3293 #: An optional left bracket. If missing, this is an open sequence pattern. 

3294 lbracket: Optional[LeftSquareBracket] = None 

3295 

3296 #: An optional left bracket. If missing, this is an open sequence pattern. 

3297 rbracket: Optional[RightSquareBracket] = None 

3298 

3299 #: Parenthesis at the beginning of the node 

3300 lpar: Sequence[LeftParen] = () 

3301 #: Parentheses after the pattern, but before a comma (if there is one). 

3302 rpar: Sequence[RightParen] = () 

3303 

3304 def _validate(self) -> None: 

3305 if self.lbracket and not self.rbracket: 

3306 raise CSTValidationError("Cannot have left bracket without right bracket") 

3307 if self.rbracket and not self.lbracket: 

3308 raise CSTValidationError("Cannot have right bracket without left bracket") 

3309 

3310 if not self.patterns and not self.lbracket: 

3311 raise CSTValidationError( 

3312 "Must have brackets if matching against empty list" 

3313 ) 

3314 

3315 super(MatchList, self)._validate() 

3316 

3317 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchList": 

3318 return MatchList( 

3319 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3320 lbracket=visit_optional(self, "lbracket", self.lbracket, visitor), 

3321 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3322 rbracket=visit_optional(self, "rbracket", self.rbracket, visitor), 

3323 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3324 ) 

3325 

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

3327 with self._parenthesize(state): 

3328 lbracket = self.lbracket 

3329 if lbracket is not None: 

3330 lbracket._codegen(state) 

3331 pats = self.patterns 

3332 for idx, pat in enumerate(pats): 

3333 pat._codegen(state, default_comma=(idx < len(pats) - 1)) 

3334 rbracket = self.rbracket 

3335 if rbracket is not None: 

3336 rbracket._codegen(state) 

3337 

3338 

3339@add_slots 

3340@dataclass(frozen=True) 

3341class MatchTuple(MatchSequence): 

3342 """ 

3343 A tuple match pattern. 

3344 """ 

3345 

3346 #: Patterns to be matched against the subject elements if it is a sequence. 

3347 patterns: Sequence[Union[MatchSequenceElement, MatchStar]] 

3348 

3349 #: Parenthesis at the beginning of the node 

3350 lpar: Sequence[LeftParen] = field(default_factory=lambda: (LeftParen(),)) 

3351 #: Parentheses after the pattern, but before a comma (if there is one). 

3352 rpar: Sequence[RightParen] = field(default_factory=lambda: (RightParen(),)) 

3353 

3354 def _validate(self) -> None: 

3355 if len(self.lpar) < 1: 

3356 raise CSTValidationError( 

3357 "Tuple patterns must have at least pair of parenthesis" 

3358 ) 

3359 

3360 super(MatchTuple, self)._validate() 

3361 

3362 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchTuple": 

3363 return MatchTuple( 

3364 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3365 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3366 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3367 ) 

3368 

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

3370 with self._parenthesize(state): 

3371 pats = self.patterns 

3372 patlen = len(pats) 

3373 for idx, pat in enumerate(pats): 

3374 pat._codegen( 

3375 state, 

3376 default_comma=patlen == 1 or (idx < patlen - 1), 

3377 default_comma_whitespace=patlen != 1, 

3378 ) 

3379 

3380 

3381@add_slots 

3382@dataclass(frozen=True) 

3383class MatchMappingElement(CSTNode): 

3384 """ 

3385 A ``key: value`` pair in a match mapping pattern. 

3386 """ 

3387 

3388 key: BaseExpression 

3389 

3390 #: The pattern to be matched corresponding to ``key``. 

3391 pattern: MatchPattern 

3392 

3393 #: An optional trailing comma. 

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

3395 

3396 #: Whitespace between ``key`` and the colon. 

3397 whitespace_before_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3398 

3399 #: Whitespace between the colon and ``pattern``. 

3400 whitespace_after_colon: BaseParenthesizableWhitespace = SimpleWhitespace.field(" ") 

3401 

3402 def _visit_and_replace_children( 

3403 self, visitor: CSTVisitorT 

3404 ) -> "MatchMappingElement": 

3405 return MatchMappingElement( 

3406 key=visit_required(self, "key", self.key, visitor), 

3407 whitespace_before_colon=visit_required( 

3408 self, "whitespace_before_colon", self.whitespace_before_colon, visitor 

3409 ), 

3410 whitespace_after_colon=visit_required( 

3411 self, "whitespace_after_colon", self.whitespace_after_colon, visitor 

3412 ), 

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

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

3415 ) 

3416 

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

3418 with state.record_syntactic_position(self): 

3419 self.key._codegen(state) 

3420 self.whitespace_before_colon._codegen(state) 

3421 state.add_token(":") 

3422 self.whitespace_after_colon._codegen(state) 

3423 self.pattern._codegen(state) 

3424 comma = self.comma 

3425 if comma is MaybeSentinel.DEFAULT and default_comma: 

3426 state.add_token(", ") 

3427 elif isinstance(comma, Comma): 

3428 comma._codegen(state) 

3429 

3430 

3431@add_slots 

3432@dataclass(frozen=True) 

3433class MatchMapping(MatchPattern): 

3434 """ 

3435 A match mapping pattern. 

3436 """ 

3437 

3438 #: A sequence of mapping elements. 

3439 elements: Sequence[MatchMappingElement] = () 

3440 

3441 #: Left curly brace at the beginning of the pattern. 

3442 lbrace: LeftCurlyBrace = LeftCurlyBrace.field() 

3443 

3444 #: Right curly brace at the end of the pattern. 

3445 rbrace: RightCurlyBrace = RightCurlyBrace.field() 

3446 

3447 #: An optional name to capture the remaining elements of the mapping. 

3448 rest: Optional[Name] = None 

3449 

3450 #: Optional whitespace between stars and ``rest``. 

3451 whitespace_before_rest: SimpleWhitespace = SimpleWhitespace.field("") 

3452 

3453 #: An optional trailing comma attached to ``rest``. 

3454 trailing_comma: Optional[Comma] = None 

3455 

3456 #: Parenthesis at the beginning of the node 

3457 lpar: Sequence[LeftParen] = () 

3458 #: Parentheses after the pattern 

3459 rpar: Sequence[RightParen] = () 

3460 

3461 def _validate(self) -> None: 

3462 super(MatchMapping, self)._validate() 

3463 

3464 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchMapping": 

3465 return MatchMapping( 

3466 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3467 lbrace=visit_required(self, "lbrace", self.lbrace, visitor), 

3468 elements=visit_sequence(self, "elements", self.elements, visitor), 

3469 whitespace_before_rest=visit_required( 

3470 self, "whitespace_before_rest", self.whitespace_before_rest, visitor 

3471 ), 

3472 rest=visit_optional(self, "rest", self.rest, visitor), 

3473 trailing_comma=visit_optional( 

3474 self, "trailing_comma", self.trailing_comma, visitor 

3475 ), 

3476 rbrace=visit_required(self, "rbrace", self.rbrace, visitor), 

3477 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3478 ) 

3479 

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

3481 with self._parenthesize(state): 

3482 self.lbrace._codegen(state) 

3483 elems = self.elements 

3484 rest = self.rest 

3485 for idx, el in enumerate(elems): 

3486 el._codegen( 

3487 state, default_comma=rest is not None or idx < len(elems) - 1 

3488 ) 

3489 

3490 if rest is not None: 

3491 state.add_token("**") 

3492 self.whitespace_before_rest._codegen(state) 

3493 rest._codegen(state) 

3494 comma = self.trailing_comma 

3495 if comma is not None: 

3496 comma._codegen(state) 

3497 

3498 self.rbrace._codegen(state) 

3499 

3500 

3501@add_slots 

3502@dataclass(frozen=True) 

3503class MatchKeywordElement(CSTNode): 

3504 """ 

3505 A key=value pair in a :class:`MatchClass`. 

3506 """ 

3507 

3508 key: Name 

3509 

3510 #: The pattern to be matched against the attribute named ``key``. 

3511 pattern: MatchPattern 

3512 

3513 #: An optional trailing comma. 

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

3515 

3516 #: Whitespace between ``key`` and the equals sign. 

3517 whitespace_before_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3518 

3519 #: Whitespace between the equals sign and ``pattern``. 

3520 whitespace_after_equal: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3521 

3522 def _visit_and_replace_children( 

3523 self, visitor: CSTVisitorT 

3524 ) -> "MatchKeywordElement": 

3525 return MatchKeywordElement( 

3526 key=visit_required(self, "key", self.key, visitor), 

3527 whitespace_before_equal=visit_required( 

3528 self, "whitespace_before_equal", self.whitespace_before_equal, visitor 

3529 ), 

3530 whitespace_after_equal=visit_required( 

3531 self, "whitespace_after_equal", self.whitespace_after_equal, visitor 

3532 ), 

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

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

3535 ) 

3536 

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

3538 with state.record_syntactic_position(self): 

3539 self.key._codegen(state) 

3540 self.whitespace_before_equal._codegen(state) 

3541 state.add_token("=") 

3542 self.whitespace_after_equal._codegen(state) 

3543 self.pattern._codegen(state) 

3544 comma = self.comma 

3545 if comma is MaybeSentinel.DEFAULT and default_comma: 

3546 state.add_token(", ") 

3547 elif isinstance(comma, Comma): 

3548 comma._codegen(state) 

3549 

3550 

3551@add_slots 

3552@dataclass(frozen=True) 

3553class MatchClass(MatchPattern): 

3554 """ 

3555 A match class pattern. 

3556 """ 

3557 

3558 #: An expression giving the nominal class to be matched. 

3559 cls: BaseExpression 

3560 

3561 #: A sequence of patterns to be matched against the class defined sequence of 

3562 #: pattern matching attributes. 

3563 patterns: Sequence[MatchSequenceElement] = () 

3564 

3565 #: A sequence of additional attribute names and corresponding patterns to be 

3566 #: matched. 

3567 kwds: Sequence[MatchKeywordElement] = () 

3568 

3569 #: Whitespace between the class name and the left parenthesis. 

3570 whitespace_after_cls: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3571 

3572 #: Whitespace between the left parenthesis and the first pattern. 

3573 whitespace_before_patterns: BaseParenthesizableWhitespace = SimpleWhitespace.field( 

3574 "" 

3575 ) 

3576 

3577 #: Whitespace between the last pattern and the right parenthesis. 

3578 whitespace_after_kwds: BaseParenthesizableWhitespace = SimpleWhitespace.field("") 

3579 

3580 #: Parenthesis at the beginning of the node 

3581 lpar: Sequence[LeftParen] = () 

3582 #: Parentheses after the pattern 

3583 rpar: Sequence[RightParen] = () 

3584 

3585 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchClass": 

3586 return MatchClass( 

3587 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3588 cls=visit_required(self, "cls", self.cls, visitor), 

3589 whitespace_after_cls=visit_required( 

3590 self, "whitespace_after_cls", self.whitespace_after_cls, visitor 

3591 ), 

3592 whitespace_before_patterns=visit_required( 

3593 self, 

3594 "whitespace_before_patterns", 

3595 self.whitespace_before_patterns, 

3596 visitor, 

3597 ), 

3598 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3599 kwds=visit_sequence(self, "kwds", self.kwds, visitor), 

3600 whitespace_after_kwds=visit_required( 

3601 self, "whitespace_after_kwds", self.whitespace_after_kwds, visitor 

3602 ), 

3603 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3604 ) 

3605 

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

3607 with self._parenthesize(state): 

3608 self.cls._codegen(state) 

3609 self.whitespace_after_cls._codegen(state) 

3610 state.add_token("(") 

3611 self.whitespace_before_patterns._codegen(state) 

3612 pats = self.patterns 

3613 kwds = self.kwds 

3614 for idx, pat in enumerate(pats): 

3615 pat._codegen(state, default_comma=idx + 1 < len(pats) + len(kwds)) 

3616 for idx, kwd in enumerate(kwds): 

3617 kwd._codegen(state, default_comma=idx + 1 < len(kwds)) 

3618 self.whitespace_after_kwds._codegen(state) 

3619 state.add_token(")") 

3620 

3621 

3622@add_slots 

3623@dataclass(frozen=True) 

3624class MatchAs(MatchPattern): 

3625 """ 

3626 A match "as-pattern", capture pattern, or wildcard pattern. 

3627 """ 

3628 

3629 #: The match pattern that the subject will be matched against. If this is ``None``, 

3630 #: the node represents a capture pattern (i.e. a bare name) and will always succeed. 

3631 pattern: Optional[MatchPattern] = None 

3632 

3633 #: The name that will be bound if the pattern is successful. If this is ``None``, 

3634 #: ``pattern`` must also be ``None`` and the node represents the wildcard pattern 

3635 #: (i.e. ``_``). 

3636 name: Optional[Name] = None 

3637 

3638 #: Whitespace between ``pattern`` and the ``as`` keyword (if ``pattern`` is not 

3639 #: ``None``) 

3640 whitespace_before_as: Union[BaseParenthesizableWhitespace, MaybeSentinel] = ( 

3641 MaybeSentinel.DEFAULT 

3642 ) 

3643 

3644 #: Whitespace between the ``as`` keyword and ``name`` (if ``pattern`` is not 

3645 #: ``None``) 

3646 whitespace_after_as: Union[BaseParenthesizableWhitespace, MaybeSentinel] = ( 

3647 MaybeSentinel.DEFAULT 

3648 ) 

3649 

3650 #: Parenthesis at the beginning of the node 

3651 lpar: Sequence[LeftParen] = () 

3652 #: Parentheses after the pattern 

3653 rpar: Sequence[RightParen] = () 

3654 

3655 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchAs": 

3656 return MatchAs( 

3657 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3658 pattern=visit_optional(self, "pattern", self.pattern, visitor), 

3659 whitespace_before_as=visit_sentinel( 

3660 self, "whitespace_before_as", self.whitespace_before_as, visitor 

3661 ), 

3662 whitespace_after_as=visit_sentinel( 

3663 self, "whitespace_after_as", self.whitespace_after_as, visitor 

3664 ), 

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

3666 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3667 ) 

3668 

3669 def _validate(self) -> None: 

3670 if self.name is None and self.pattern is not None: 

3671 raise CSTValidationError("Pattern must be None if name is None") 

3672 super(MatchAs, self)._validate() 

3673 

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

3675 with self._parenthesize(state): 

3676 pat = self.pattern 

3677 name = self.name 

3678 if pat is not None: 

3679 pat._codegen(state) 

3680 ws_before = self.whitespace_before_as 

3681 if ws_before is MaybeSentinel.DEFAULT: 

3682 state.add_token(" ") 

3683 elif isinstance(ws_before, BaseParenthesizableWhitespace): 

3684 ws_before._codegen(state) 

3685 state.add_token("as") 

3686 ws_after = self.whitespace_after_as 

3687 if ws_after is MaybeSentinel.DEFAULT: 

3688 state.add_token(" ") 

3689 elif isinstance(ws_after, BaseParenthesizableWhitespace): 

3690 ws_after._codegen(state) 

3691 else: 

3692 ws_before = self.whitespace_before_as 

3693 if isinstance(ws_before, BaseParenthesizableWhitespace): 

3694 ws_before._codegen(state) 

3695 ws_after = self.whitespace_after_as 

3696 if isinstance(ws_after, BaseParenthesizableWhitespace): 

3697 ws_after._codegen(state) 

3698 if name is None: 

3699 state.add_token("_") 

3700 else: 

3701 name._codegen(state) 

3702 

3703 

3704@add_slots 

3705@dataclass(frozen=True) 

3706class MatchOrElement(CSTNode): 

3707 """ 

3708 An element in a :class:`MatchOr` node. 

3709 """ 

3710 

3711 pattern: MatchPattern 

3712 

3713 #: An optional ``|`` separator. 

3714 separator: Union[BitOr, MaybeSentinel] = MaybeSentinel.DEFAULT 

3715 

3716 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOrElement": 

3717 return MatchOrElement( 

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

3719 separator=visit_sentinel(self, "separator", self.separator, visitor), 

3720 ) 

3721 

3722 def _codegen_impl( 

3723 self, state: CodegenState, default_separator: bool = False 

3724 ) -> None: 

3725 with state.record_syntactic_position(self): 

3726 self.pattern._codegen(state) 

3727 sep = self.separator 

3728 if sep is MaybeSentinel.DEFAULT and default_separator: 

3729 state.add_token(" | ") 

3730 elif isinstance(sep, BitOr): 

3731 sep._codegen(state) 

3732 

3733 

3734@add_slots 

3735@dataclass(frozen=True) 

3736class MatchOr(MatchPattern): 

3737 """ 

3738 A match "or-pattern". It matches each of its subpatterns in turn to the subject, 

3739 until one succeeds. The or-pattern is then deemed to succeed. If none of the 

3740 subpatterns succeed the or-pattern fails. 

3741 """ 

3742 

3743 #: The subpatterns to be tried in turn. 

3744 patterns: Sequence[MatchOrElement] 

3745 

3746 #: Parenthesis at the beginning of the node 

3747 lpar: Sequence[LeftParen] = () 

3748 #: Parentheses after the pattern 

3749 rpar: Sequence[RightParen] = () 

3750 

3751 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "MatchOr": 

3752 return MatchOr( 

3753 lpar=visit_sequence(self, "lpar", self.lpar, visitor), 

3754 patterns=visit_sequence(self, "patterns", self.patterns, visitor), 

3755 rpar=visit_sequence(self, "rpar", self.rpar, visitor), 

3756 ) 

3757 

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

3759 with self._parenthesize(state): 

3760 pats = self.patterns 

3761 for idx, pat in enumerate(pats): 

3762 pat._codegen(state, default_separator=idx + 1 < len(pats)) 

3763 

3764 

3765@add_slots 

3766@dataclass(frozen=True) 

3767class TypeVar(CSTNode): 

3768 """ 

3769 A simple (non-variadic) type variable. 

3770 

3771 Note: this node represents type a variable when declared using PEP-695 syntax. 

3772 """ 

3773 

3774 #: The name of the type variable. 

3775 name: Name 

3776 

3777 #: An optional bound on the type. 

3778 bound: Optional[BaseExpression] = None 

3779 

3780 #: The colon used to separate the name and bound. If not specified, 

3781 #: :class:`MaybeSentinel` will be replaced with a colon if there is a bound, 

3782 #: otherwise will be left empty. 

3783 colon: Union[Colon, MaybeSentinel] = MaybeSentinel.DEFAULT 

3784 

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

3786 with state.record_syntactic_position(self): 

3787 self.name._codegen(state) 

3788 bound = self.bound 

3789 colon = self.colon 

3790 if not isinstance(colon, MaybeSentinel): 

3791 colon._codegen(state) 

3792 else: 

3793 if bound is not None: 

3794 state.add_token(": ") 

3795 

3796 if bound is not None: 

3797 bound._codegen(state) 

3798 

3799 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVar": 

3800 return TypeVar( 

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

3802 colon=visit_sentinel(self, "colon", self.colon, visitor), 

3803 bound=visit_optional(self, "bound", self.bound, visitor), 

3804 ) 

3805 

3806 

3807@add_slots 

3808@dataclass(frozen=True) 

3809class TypeVarTuple(CSTNode): 

3810 """ 

3811 A variadic type variable. 

3812 """ 

3813 

3814 #: The name of this type variable. 

3815 name: Name 

3816 

3817 #: The (optional) whitespace between the star declaring this type variable as 

3818 #: variadic, and the variable's name. 

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

3820 

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

3822 with state.record_syntactic_position(self): 

3823 state.add_token("*") 

3824 self.whitespace_after_star._codegen(state) 

3825 self.name._codegen(state) 

3826 

3827 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVarTuple": 

3828 return TypeVarTuple( 

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

3830 whitespace_after_star=visit_required( 

3831 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3832 ), 

3833 ) 

3834 

3835 

3836@add_slots 

3837@dataclass(frozen=True) 

3838class ParamSpec(CSTNode): 

3839 """ 

3840 A parameter specification. 

3841 

3842 Note: this node represents a parameter specification when declared using PEP-695 

3843 syntax. 

3844 """ 

3845 

3846 #: The name of this parameter specification. 

3847 name: Name 

3848 

3849 #: The (optional) whitespace between the double star declaring this type variable as 

3850 #: a parameter specification, and the name. 

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

3852 

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

3854 with state.record_syntactic_position(self): 

3855 state.add_token("**") 

3856 self.whitespace_after_star._codegen(state) 

3857 self.name._codegen(state) 

3858 

3859 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ParamSpec": 

3860 return ParamSpec( 

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

3862 whitespace_after_star=visit_required( 

3863 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3864 ), 

3865 ) 

3866 

3867 

3868@add_slots 

3869@dataclass(frozen=True) 

3870class TypeParam(CSTNode): 

3871 """ 

3872 A single type parameter that is contained in a :class:`TypeParameters` list. 

3873 """ 

3874 

3875 #: The actual parameter. 

3876 param: Union[TypeVar, TypeVarTuple, ParamSpec] 

3877 

3878 #: A trailing comma. If one is not provided, :class:`MaybeSentinel` will be replaced 

3879 #: with a comma only if a comma is required. 

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

3881 

3882 #: The equal sign used to denote assignment if there is a default. 

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

3884 

3885 #: The star used to denote a variadic default 

3886 star: Literal["", "*"] = "" 

3887 

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

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

3890 

3891 #: Any optional default value, used when the argument is not supplied. 

3892 default: Optional[BaseExpression] = None 

3893 

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

3895 self.param._codegen(state) 

3896 

3897 equal = self.equal 

3898 if equal is MaybeSentinel.DEFAULT and self.default is not None: 

3899 state.add_token(" = ") 

3900 elif isinstance(equal, AssignEqual): 

3901 equal._codegen(state) 

3902 

3903 state.add_token(self.star) 

3904 self.whitespace_after_star._codegen(state) 

3905 

3906 default = self.default 

3907 if default is not None: 

3908 default._codegen(state) 

3909 

3910 comma = self.comma 

3911 if isinstance(comma, MaybeSentinel): 

3912 if default_comma: 

3913 state.add_token(", ") 

3914 else: 

3915 comma._codegen(state) 

3916 

3917 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParam": 

3918 ret = TypeParam( 

3919 param=visit_required(self, "param", self.param, visitor), 

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

3921 star=self.star, 

3922 whitespace_after_star=visit_required( 

3923 self, "whitespace_after_star", self.whitespace_after_star, visitor 

3924 ), 

3925 default=visit_optional(self, "default", self.default, visitor), 

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

3927 ) 

3928 return ret 

3929 

3930 def _validate(self) -> None: 

3931 if self.default is None and isinstance(self.equal, AssignEqual): 

3932 raise CSTValidationError( 

3933 "Must have a default when specifying an AssignEqual." 

3934 ) 

3935 if self.star and not (self.default or isinstance(self.equal, AssignEqual)): 

3936 raise CSTValidationError("Star can only be present if a default") 

3937 if isinstance(self.star, str) and self.star not in ("", "*"): 

3938 raise CSTValidationError("Must specify either '' or '*' for star.") 

3939 

3940 

3941@add_slots 

3942@dataclass(frozen=True) 

3943class TypeParameters(CSTNode): 

3944 """ 

3945 Type parameters when specified with PEP-695 syntax. 

3946 

3947 This node captures all specified parameters that are enclosed with square brackets. 

3948 """ 

3949 

3950 #: The parameters within the square brackets. 

3951 params: Sequence[TypeParam] = () 

3952 

3953 #: Opening square bracket that marks the start of these parameters. 

3954 lbracket: LeftSquareBracket = LeftSquareBracket.field() 

3955 #: Closing square bracket that marks the end of these parameters. 

3956 rbracket: RightSquareBracket = RightSquareBracket.field() 

3957 

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

3959 self.lbracket._codegen(state) 

3960 params_len = len(self.params) 

3961 for idx, param in enumerate(self.params): 

3962 param._codegen(state, default_comma=idx + 1 < params_len) 

3963 self.rbracket._codegen(state) 

3964 

3965 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParameters": 

3966 return TypeParameters( 

3967 lbracket=visit_required(self, "lbracket", self.lbracket, visitor), 

3968 params=visit_sequence(self, "params", self.params, visitor), 

3969 rbracket=visit_required(self, "rbracket", self.rbracket, visitor), 

3970 ) 

3971 

3972 

3973@add_slots 

3974@dataclass(frozen=True) 

3975class TypeAlias(BaseSmallStatement): 

3976 """ 

3977 A type alias statement. 

3978 

3979 This node represents the ``type`` statement as specified initially by PEP-695. 

3980 Example: ``type ListOrSet[T] = list[T] | set[T]``. 

3981 """ 

3982 

3983 #: The name being introduced in this statement. 

3984 name: Name 

3985 

3986 #: Everything on the right hand side of the ``=``. 

3987 value: BaseExpression 

3988 

3989 #: An optional list of type parameters, specified after the name. 

3990 type_parameters: Optional[TypeParameters] = None 

3991 

3992 #: Whitespace between the ``type`` soft keyword and the name. 

3993 whitespace_after_type: SimpleWhitespace = SimpleWhitespace.field(" ") 

3994 

3995 #: Whitespace between the name and the type parameters (if they exist) or the ``=``. 

3996 #: If not specified, :class:`MaybeSentinel` will be replaced with a single space if 

3997 #: there are no type parameters, otherwise no spaces. 

3998 whitespace_after_name: Union[SimpleWhitespace, MaybeSentinel] = ( 

3999 MaybeSentinel.DEFAULT 

4000 ) 

4001 

4002 #: Whitespace between the type parameters and the ``=``. Always empty if there are 

4003 #: no type parameters. If not specified, :class:`MaybeSentinel` will be replaced 

4004 #: with a single space if there are type parameters. 

4005 whitespace_after_type_parameters: Union[SimpleWhitespace, MaybeSentinel] = ( 

4006 MaybeSentinel.DEFAULT 

4007 ) 

4008 

4009 #: Whitespace between the ``=`` and the value. 

4010 whitespace_after_equals: SimpleWhitespace = SimpleWhitespace.field(" ") 

4011 

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

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

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

4015 

4016 def _validate(self) -> None: 

4017 if ( 

4018 self.type_parameters is None 

4019 and self.whitespace_after_type_parameters 

4020 not in { 

4021 SimpleWhitespace(""), 

4022 MaybeSentinel.DEFAULT, 

4023 } 

4024 ): 

4025 raise CSTValidationError( 

4026 "whitespace_after_type_parameters must be empty when there are no type parameters in a TypeAlias" 

4027 ) 

4028 

4029 def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeAlias": 

4030 return TypeAlias( 

4031 whitespace_after_type=visit_required( 

4032 self, "whitespace_after_type", self.whitespace_after_type, visitor 

4033 ), 

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

4035 whitespace_after_name=visit_sentinel( 

4036 self, "whitespace_after_name", self.whitespace_after_name, visitor 

4037 ), 

4038 type_parameters=visit_optional( 

4039 self, "type_parameters", self.type_parameters, visitor 

4040 ), 

4041 whitespace_after_type_parameters=visit_sentinel( 

4042 self, 

4043 "whitespace_after_type_parameters", 

4044 self.whitespace_after_type_parameters, 

4045 visitor, 

4046 ), 

4047 whitespace_after_equals=visit_required( 

4048 self, "whitespace_after_equals", self.whitespace_after_equals, visitor 

4049 ), 

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

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

4052 ) 

4053 

4054 def _codegen_impl( 

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

4056 ) -> None: 

4057 with state.record_syntactic_position(self): 

4058 state.add_token("type") 

4059 self.whitespace_after_type._codegen(state) 

4060 self.name._codegen(state) 

4061 ws_after_name = self.whitespace_after_name 

4062 if isinstance(ws_after_name, MaybeSentinel): 

4063 if self.type_parameters is None: 

4064 state.add_token(" ") 

4065 else: 

4066 ws_after_name._codegen(state) 

4067 

4068 ws_after_type_params = self.whitespace_after_type_parameters 

4069 if self.type_parameters is not None: 

4070 self.type_parameters._codegen(state) 

4071 if isinstance(ws_after_type_params, MaybeSentinel): 

4072 state.add_token(" ") 

4073 else: 

4074 ws_after_type_params._codegen(state) 

4075 

4076 state.add_token("=") 

4077 self.whitespace_after_equals._codegen(state) 

4078 self.value._codegen(state) 

4079 

4080 semi = self.semicolon 

4081 if isinstance(semi, MaybeSentinel): 

4082 if default_semicolon: 

4083 state.add_token("; ") 

4084 else: 

4085 semi._codegen(state)