Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/parso/python/errors.py: 74%

905 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 07:36 +0000

1# -*- coding: utf-8 -*- 

2import codecs 

3import sys 

4import warnings 

5import re 

6from contextlib import contextmanager 

7 

8from parso.normalizer import Normalizer, NormalizerConfig, Issue, Rule 

9from parso.python.tokenize import _get_token_collection 

10 

11_BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt') 

12_STAR_EXPR_PARENTS = ('testlist_star_expr', 'testlist_comp', 'exprlist') 

13# This is the maximal block size given by python. 

14_MAX_BLOCK_SIZE = 20 

15_MAX_INDENT_COUNT = 100 

16ALLOWED_FUTURES = ( 

17 'nested_scopes', 'generators', 'division', 'absolute_import', 

18 'with_statement', 'print_function', 'unicode_literals', 'generator_stop', 

19) 

20_COMP_FOR_TYPES = ('comp_for', 'sync_comp_for') 

21 

22 

23def _get_rhs_name(node, version): 

24 type_ = node.type 

25 if type_ == "lambdef": 

26 return "lambda" 

27 elif type_ == "atom": 

28 comprehension = _get_comprehension_type(node) 

29 first, second = node.children[:2] 

30 if comprehension is not None: 

31 return comprehension 

32 elif second.type == "dictorsetmaker": 

33 if version < (3, 8): 

34 return "literal" 

35 else: 

36 if second.children[1] == ":" or second.children[0] == "**": 

37 if version < (3, 10): 

38 return "dict display" 

39 else: 

40 return "dict literal" 

41 else: 

42 return "set display" 

43 elif ( 

44 first == "(" 

45 and (second == ")" 

46 or (len(node.children) == 3 and node.children[1].type == "testlist_comp")) 

47 ): 

48 return "tuple" 

49 elif first == "(": 

50 return _get_rhs_name(_remove_parens(node), version=version) 

51 elif first == "[": 

52 return "list" 

53 elif first == "{" and second == "}": 

54 if version < (3, 10): 

55 return "dict display" 

56 else: 

57 return "dict literal" 

58 elif first == "{" and len(node.children) > 2: 

59 return "set display" 

60 elif type_ == "keyword": 

61 if "yield" in node.value: 

62 return "yield expression" 

63 if version < (3, 8): 

64 return "keyword" 

65 else: 

66 return str(node.value) 

67 elif type_ == "operator" and node.value == "...": 

68 if version < (3, 10): 

69 return "Ellipsis" 

70 else: 

71 return "ellipsis" 

72 elif type_ == "comparison": 

73 return "comparison" 

74 elif type_ in ("string", "number", "strings"): 

75 return "literal" 

76 elif type_ == "yield_expr": 

77 return "yield expression" 

78 elif type_ == "test": 

79 return "conditional expression" 

80 elif type_ in ("atom_expr", "power"): 

81 if node.children[0] == "await": 

82 return "await expression" 

83 elif node.children[-1].type == "trailer": 

84 trailer = node.children[-1] 

85 if trailer.children[0] == "(": 

86 return "function call" 

87 elif trailer.children[0] == "[": 

88 return "subscript" 

89 elif trailer.children[0] == ".": 

90 return "attribute" 

91 elif ( 

92 ("expr" in type_ and "star_expr" not in type_) # is a substring 

93 or "_test" in type_ 

94 or type_ in ("term", "factor") 

95 ): 

96 if version < (3, 10): 

97 return "operator" 

98 else: 

99 return "expression" 

100 elif type_ == "star_expr": 

101 return "starred" 

102 elif type_ == "testlist_star_expr": 

103 return "tuple" 

104 elif type_ == "fstring": 

105 return "f-string expression" 

106 return type_ # shouldn't reach here 

107 

108 

109def _iter_stmts(scope): 

110 """ 

111 Iterates over all statements and splits up simple_stmt. 

112 """ 

113 for child in scope.children: 

114 if child.type == 'simple_stmt': 

115 for child2 in child.children: 

116 if child2.type == 'newline' or child2 == ';': 

117 continue 

118 yield child2 

119 else: 

120 yield child 

121 

122 

123def _get_comprehension_type(atom): 

124 first, second = atom.children[:2] 

125 if second.type == 'testlist_comp' and second.children[1].type in _COMP_FOR_TYPES: 

126 if first == '[': 

127 return 'list comprehension' 

128 else: 

129 return 'generator expression' 

130 elif second.type == 'dictorsetmaker' and second.children[-1].type in _COMP_FOR_TYPES: 

131 if second.children[1] == ':': 

132 return 'dict comprehension' 

133 else: 

134 return 'set comprehension' 

135 return None 

136 

137 

138def _is_future_import(import_from): 

139 # It looks like a __future__ import that is relative is still a future 

140 # import. That feels kind of odd, but whatever. 

141 # if import_from.level != 0: 

142 # return False 

143 from_names = import_from.get_from_names() 

144 return [n.value for n in from_names] == ['__future__'] 

145 

146 

147def _remove_parens(atom): 

148 """ 

149 Returns the inner part of an expression like `(foo)`. Also removes nested 

150 parens. 

151 """ 

152 try: 

153 children = atom.children 

154 except AttributeError: 

155 pass 

156 else: 

157 if len(children) == 3 and children[0] == '(': 

158 return _remove_parens(atom.children[1]) 

159 return atom 

160 

161 

162def _skip_parens_bottom_up(node): 

163 """ 

164 Returns an ancestor node of an expression, skipping all levels of parens 

165 bottom-up. 

166 """ 

167 while node.parent is not None: 

168 node = node.parent 

169 if node.type != 'atom' or node.children[0] != '(': 

170 return node 

171 return None 

172 

173 

174def _iter_params(parent_node): 

175 return (n for n in parent_node.children if n.type == 'param' or n.type == 'operator') 

176 

177 

178def _is_future_import_first(import_from): 

179 """ 

180 Checks if the import is the first statement of a file. 

181 """ 

182 found_docstring = False 

183 for stmt in _iter_stmts(import_from.get_root_node()): 

184 if stmt.type == 'string' and not found_docstring: 

185 continue 

186 found_docstring = True 

187 

188 if stmt == import_from: 

189 return True 

190 if stmt.type == 'import_from' and _is_future_import(stmt): 

191 continue 

192 return False 

193 

194 

195def _iter_definition_exprs_from_lists(exprlist): 

196 def check_expr(child): 

197 if child.type == 'atom': 

198 if child.children[0] == '(': 

199 testlist_comp = child.children[1] 

200 if testlist_comp.type == 'testlist_comp': 

201 yield from _iter_definition_exprs_from_lists(testlist_comp) 

202 return 

203 else: 

204 # It's a paren that doesn't do anything, like 1 + (1) 

205 yield from check_expr(testlist_comp) 

206 return 

207 elif child.children[0] == '[': 

208 yield testlist_comp 

209 return 

210 yield child 

211 

212 if exprlist.type in _STAR_EXPR_PARENTS: 

213 for child in exprlist.children[::2]: 

214 yield from check_expr(child) 

215 else: 

216 yield from check_expr(exprlist) 

217 

218 

219def _get_expr_stmt_definition_exprs(expr_stmt): 

220 exprs = [] 

221 for list_ in expr_stmt.children[:-2:2]: 

222 if list_.type in ('testlist_star_expr', 'testlist'): 

223 exprs += _iter_definition_exprs_from_lists(list_) 

224 else: 

225 exprs.append(list_) 

226 return exprs 

227 

228 

229def _get_for_stmt_definition_exprs(for_stmt): 

230 exprlist = for_stmt.children[1] 

231 return list(_iter_definition_exprs_from_lists(exprlist)) 

232 

233 

234def _is_argument_comprehension(argument): 

235 return argument.children[1].type in _COMP_FOR_TYPES 

236 

237 

238def _any_fstring_error(version, node): 

239 if version < (3, 9) or node is None: 

240 return False 

241 if node.type == "error_node": 

242 return any(child.type == "fstring_start" for child in node.children) 

243 elif node.type == "fstring": 

244 return True 

245 else: 

246 return node.search_ancestor("fstring") 

247 

248 

249class _Context: 

250 def __init__(self, node, add_syntax_error, parent_context=None): 

251 self.node = node 

252 self.blocks = [] 

253 self.parent_context = parent_context 

254 self._used_name_dict = {} 

255 self._global_names = [] 

256 self._local_params_names = [] 

257 self._nonlocal_names = [] 

258 self._nonlocal_names_in_subscopes = [] 

259 self._add_syntax_error = add_syntax_error 

260 

261 def is_async_funcdef(self): 

262 # Stupidly enough async funcdefs can have two different forms, 

263 # depending if a decorator is used or not. 

264 return self.is_function() \ 

265 and self.node.parent.type in ('async_funcdef', 'async_stmt') 

266 

267 def is_function(self): 

268 return self.node.type == 'funcdef' 

269 

270 def add_name(self, name): 

271 parent_type = name.parent.type 

272 if parent_type == 'trailer': 

273 # We are only interested in first level names. 

274 return 

275 

276 if parent_type == 'global_stmt': 

277 self._global_names.append(name) 

278 elif parent_type == 'nonlocal_stmt': 

279 self._nonlocal_names.append(name) 

280 elif parent_type == 'funcdef': 

281 self._local_params_names.extend( 

282 [param.name.value for param in name.parent.get_params()] 

283 ) 

284 else: 

285 self._used_name_dict.setdefault(name.value, []).append(name) 

286 

287 def finalize(self): 

288 """ 

289 Returns a list of nonlocal names that need to be part of that scope. 

290 """ 

291 self._analyze_names(self._global_names, 'global') 

292 self._analyze_names(self._nonlocal_names, 'nonlocal') 

293 

294 global_name_strs = {n.value: n for n in self._global_names} 

295 for nonlocal_name in self._nonlocal_names: 

296 try: 

297 global_name = global_name_strs[nonlocal_name.value] 

298 except KeyError: 

299 continue 

300 

301 message = "name '%s' is nonlocal and global" % global_name.value 

302 if global_name.start_pos < nonlocal_name.start_pos: 

303 error_name = global_name 

304 else: 

305 error_name = nonlocal_name 

306 self._add_syntax_error(error_name, message) 

307 

308 nonlocals_not_handled = [] 

309 for nonlocal_name in self._nonlocal_names_in_subscopes: 

310 search = nonlocal_name.value 

311 if search in self._local_params_names: 

312 continue 

313 if search in global_name_strs or self.parent_context is None: 

314 message = "no binding for nonlocal '%s' found" % nonlocal_name.value 

315 self._add_syntax_error(nonlocal_name, message) 

316 elif not self.is_function() or \ 

317 nonlocal_name.value not in self._used_name_dict: 

318 nonlocals_not_handled.append(nonlocal_name) 

319 return self._nonlocal_names + nonlocals_not_handled 

320 

321 def _analyze_names(self, globals_or_nonlocals, type_): 

322 def raise_(message): 

323 self._add_syntax_error(base_name, message % (base_name.value, type_)) 

324 

325 params = [] 

326 if self.node.type == 'funcdef': 

327 params = self.node.get_params() 

328 

329 for base_name in globals_or_nonlocals: 

330 found_global_or_nonlocal = False 

331 # Somehow Python does it the reversed way. 

332 for name in reversed(self._used_name_dict.get(base_name.value, [])): 

333 if name.start_pos > base_name.start_pos: 

334 # All following names don't have to be checked. 

335 found_global_or_nonlocal = True 

336 

337 parent = name.parent 

338 if parent.type == 'param' and parent.name == name: 

339 # Skip those here, these definitions belong to the next 

340 # scope. 

341 continue 

342 

343 if name.is_definition(): 

344 if parent.type == 'expr_stmt' \ 

345 and parent.children[1].type == 'annassign': 

346 if found_global_or_nonlocal: 

347 # If it's after the global the error seems to be 

348 # placed there. 

349 base_name = name 

350 raise_("annotated name '%s' can't be %s") 

351 break 

352 else: 

353 message = "name '%s' is assigned to before %s declaration" 

354 else: 

355 message = "name '%s' is used prior to %s declaration" 

356 

357 if not found_global_or_nonlocal: 

358 raise_(message) 

359 # Only add an error for the first occurence. 

360 break 

361 

362 for param in params: 

363 if param.name.value == base_name.value: 

364 raise_("name '%s' is parameter and %s"), 

365 

366 @contextmanager 

367 def add_block(self, node): 

368 self.blocks.append(node) 

369 yield 

370 self.blocks.pop() 

371 

372 def add_context(self, node): 

373 return _Context(node, self._add_syntax_error, parent_context=self) 

374 

375 def close_child_context(self, child_context): 

376 self._nonlocal_names_in_subscopes += child_context.finalize() 

377 

378 

379class ErrorFinder(Normalizer): 

380 """ 

381 Searches for errors in the syntax tree. 

382 """ 

383 def __init__(self, *args, **kwargs): 

384 super().__init__(*args, **kwargs) 

385 self._error_dict = {} 

386 self.version = self.grammar.version_info 

387 

388 def initialize(self, node): 

389 def create_context(node): 

390 if node is None: 

391 return None 

392 

393 parent_context = create_context(node.parent) 

394 if node.type in ('classdef', 'funcdef', 'file_input'): 

395 return _Context(node, self._add_syntax_error, parent_context) 

396 return parent_context 

397 

398 self.context = create_context(node) or _Context(node, self._add_syntax_error) 

399 self._indentation_count = 0 

400 

401 def visit(self, node): 

402 if node.type == 'error_node': 

403 with self.visit_node(node): 

404 # Don't need to investigate the inners of an error node. We 

405 # might find errors in there that should be ignored, because 

406 # the error node itself already shows that there's an issue. 

407 return '' 

408 return super().visit(node) 

409 

410 @contextmanager 

411 def visit_node(self, node): 

412 self._check_type_rules(node) 

413 

414 if node.type in _BLOCK_STMTS: 

415 with self.context.add_block(node): 

416 if len(self.context.blocks) == _MAX_BLOCK_SIZE: 

417 self._add_syntax_error(node, "too many statically nested blocks") 

418 yield 

419 return 

420 elif node.type == 'suite': 

421 self._indentation_count += 1 

422 if self._indentation_count == _MAX_INDENT_COUNT: 

423 self._add_indentation_error(node.children[1], "too many levels of indentation") 

424 

425 yield 

426 

427 if node.type == 'suite': 

428 self._indentation_count -= 1 

429 elif node.type in ('classdef', 'funcdef'): 

430 context = self.context 

431 self.context = context.parent_context 

432 self.context.close_child_context(context) 

433 

434 def visit_leaf(self, leaf): 

435 if leaf.type == 'error_leaf': 

436 if leaf.token_type in ('INDENT', 'ERROR_DEDENT'): 

437 # Indents/Dedents itself never have a prefix. They are just 

438 # "pseudo" tokens that get removed by the syntax tree later. 

439 # Therefore in case of an error we also have to check for this. 

440 spacing = list(leaf.get_next_leaf()._split_prefix())[-1] 

441 if leaf.token_type == 'INDENT': 

442 message = 'unexpected indent' 

443 else: 

444 message = 'unindent does not match any outer indentation level' 

445 self._add_indentation_error(spacing, message) 

446 else: 

447 if leaf.value.startswith('\\'): 

448 message = 'unexpected character after line continuation character' 

449 else: 

450 match = re.match('\\w{,2}("{1,3}|\'{1,3})', leaf.value) 

451 if match is None: 

452 message = 'invalid syntax' 

453 if ( 

454 self.version >= (3, 9) 

455 and leaf.value in _get_token_collection( 

456 self.version 

457 ).always_break_tokens 

458 ): 

459 message = "f-string: " + message 

460 else: 

461 if len(match.group(1)) == 1: 

462 message = 'EOL while scanning string literal' 

463 else: 

464 message = 'EOF while scanning triple-quoted string literal' 

465 self._add_syntax_error(leaf, message) 

466 return '' 

467 elif leaf.value == ':': 

468 parent = leaf.parent 

469 if parent.type in ('classdef', 'funcdef'): 

470 self.context = self.context.add_context(parent) 

471 

472 # The rest is rule based. 

473 return super().visit_leaf(leaf) 

474 

475 def _add_indentation_error(self, spacing, message): 

476 self.add_issue(spacing, 903, "IndentationError: " + message) 

477 

478 def _add_syntax_error(self, node, message): 

479 self.add_issue(node, 901, "SyntaxError: " + message) 

480 

481 def add_issue(self, node, code, message): 

482 # Overwrite the default behavior. 

483 # Check if the issues are on the same line. 

484 line = node.start_pos[0] 

485 args = (code, message, node) 

486 self._error_dict.setdefault(line, args) 

487 

488 def finalize(self): 

489 self.context.finalize() 

490 

491 for code, message, node in self._error_dict.values(): 

492 self.issues.append(Issue(node, code, message)) 

493 

494 

495class IndentationRule(Rule): 

496 code = 903 

497 

498 def _get_message(self, message, node): 

499 message = super()._get_message(message, node) 

500 return "IndentationError: " + message 

501 

502 

503@ErrorFinder.register_rule(type='error_node') 

504class _ExpectIndentedBlock(IndentationRule): 

505 message = 'expected an indented block' 

506 

507 def get_node(self, node): 

508 leaf = node.get_next_leaf() 

509 return list(leaf._split_prefix())[-1] 

510 

511 def is_issue(self, node): 

512 # This is the beginning of a suite that is not indented. 

513 return node.children[-1].type == 'newline' 

514 

515 

516class ErrorFinderConfig(NormalizerConfig): 

517 normalizer_class = ErrorFinder 

518 

519 

520class SyntaxRule(Rule): 

521 code = 901 

522 

523 def _get_message(self, message, node): 

524 message = super()._get_message(message, node) 

525 if ( 

526 "f-string" not in message 

527 and _any_fstring_error(self._normalizer.version, node) 

528 ): 

529 message = "f-string: " + message 

530 return "SyntaxError: " + message 

531 

532 

533@ErrorFinder.register_rule(type='error_node') 

534class _InvalidSyntaxRule(SyntaxRule): 

535 message = "invalid syntax" 

536 fstring_message = "f-string: invalid syntax" 

537 

538 def get_node(self, node): 

539 return node.get_next_leaf() 

540 

541 def is_issue(self, node): 

542 error = node.get_next_leaf().type != 'error_leaf' 

543 if ( 

544 error 

545 and _any_fstring_error(self._normalizer.version, node) 

546 ): 

547 self.add_issue(node, message=self.fstring_message) 

548 else: 

549 # Error leafs will be added later as an error. 

550 return error 

551 

552 

553@ErrorFinder.register_rule(value='await') 

554class _AwaitOutsideAsync(SyntaxRule): 

555 message = "'await' outside async function" 

556 

557 def is_issue(self, leaf): 

558 return not self._normalizer.context.is_async_funcdef() 

559 

560 def get_error_node(self, node): 

561 # Return the whole await statement. 

562 return node.parent 

563 

564 

565@ErrorFinder.register_rule(value='break') 

566class _BreakOutsideLoop(SyntaxRule): 

567 message = "'break' outside loop" 

568 

569 def is_issue(self, leaf): 

570 in_loop = False 

571 for block in self._normalizer.context.blocks: 

572 if block.type in ('for_stmt', 'while_stmt'): 

573 in_loop = True 

574 return not in_loop 

575 

576 

577@ErrorFinder.register_rule(value='continue') 

578class _ContinueChecks(SyntaxRule): 

579 message = "'continue' not properly in loop" 

580 message_in_finally = "'continue' not supported inside 'finally' clause" 

581 

582 def is_issue(self, leaf): 

583 in_loop = False 

584 for block in self._normalizer.context.blocks: 

585 if block.type in ('for_stmt', 'while_stmt'): 

586 in_loop = True 

587 if block.type == 'try_stmt': 

588 last_block = block.children[-3] 

589 if ( 

590 last_block == "finally" 

591 and leaf.start_pos > last_block.start_pos 

592 and self._normalizer.version < (3, 8) 

593 ): 

594 self.add_issue(leaf, message=self.message_in_finally) 

595 return False # Error already added 

596 if not in_loop: 

597 return True 

598 

599 

600@ErrorFinder.register_rule(value='from') 

601class _YieldFromCheck(SyntaxRule): 

602 message = "'yield from' inside async function" 

603 

604 def get_node(self, leaf): 

605 return leaf.parent.parent # This is the actual yield statement. 

606 

607 def is_issue(self, leaf): 

608 return leaf.parent.type == 'yield_arg' \ 

609 and self._normalizer.context.is_async_funcdef() 

610 

611 

612@ErrorFinder.register_rule(type='name') 

613class _NameChecks(SyntaxRule): 

614 message = 'cannot assign to __debug__' 

615 message_none = 'cannot assign to None' 

616 

617 def is_issue(self, leaf): 

618 self._normalizer.context.add_name(leaf) 

619 

620 if leaf.value == '__debug__' and leaf.is_definition(): 

621 return True 

622 

623 

624@ErrorFinder.register_rule(type='string') 

625class _StringChecks(SyntaxRule): 

626 if sys.version_info < (3, 10): 

627 message = "bytes can only contain ASCII literal characters." 

628 else: 

629 message = "bytes can only contain ASCII literal characters" 

630 

631 def is_issue(self, leaf): 

632 string_prefix = leaf.string_prefix.lower() 

633 if 'b' in string_prefix \ 

634 and any(c for c in leaf.value if ord(c) > 127): 

635 # b'ä' 

636 return True 

637 

638 if 'r' not in string_prefix: 

639 # Raw strings don't need to be checked if they have proper 

640 # escaping. 

641 

642 payload = leaf._get_payload() 

643 if 'b' in string_prefix: 

644 payload = payload.encode('utf-8') 

645 func = codecs.escape_decode 

646 else: 

647 func = codecs.unicode_escape_decode 

648 

649 try: 

650 with warnings.catch_warnings(): 

651 # The warnings from parsing strings are not relevant. 

652 warnings.filterwarnings('ignore') 

653 func(payload) 

654 except UnicodeDecodeError as e: 

655 self.add_issue(leaf, message='(unicode error) ' + str(e)) 

656 except ValueError as e: 

657 self.add_issue(leaf, message='(value error) ' + str(e)) 

658 

659 

660@ErrorFinder.register_rule(value='*') 

661class _StarCheck(SyntaxRule): 

662 message = "named arguments must follow bare *" 

663 

664 def is_issue(self, leaf): 

665 params = leaf.parent 

666 if params.type == 'parameters' and params: 

667 after = params.children[params.children.index(leaf) + 1:] 

668 after = [child for child in after 

669 if child not in (',', ')') and not child.star_count] 

670 return len(after) == 0 

671 

672 

673@ErrorFinder.register_rule(value='**') 

674class _StarStarCheck(SyntaxRule): 

675 # e.g. {**{} for a in [1]} 

676 # TODO this should probably get a better end_pos including 

677 # the next sibling of leaf. 

678 message = "dict unpacking cannot be used in dict comprehension" 

679 

680 def is_issue(self, leaf): 

681 if leaf.parent.type == 'dictorsetmaker': 

682 comp_for = leaf.get_next_sibling().get_next_sibling() 

683 return comp_for is not None and comp_for.type in _COMP_FOR_TYPES 

684 

685 

686@ErrorFinder.register_rule(value='yield') 

687@ErrorFinder.register_rule(value='return') 

688class _ReturnAndYieldChecks(SyntaxRule): 

689 message = "'return' with value in async generator" 

690 message_async_yield = "'yield' inside async function" 

691 

692 def get_node(self, leaf): 

693 return leaf.parent 

694 

695 def is_issue(self, leaf): 

696 if self._normalizer.context.node.type != 'funcdef': 

697 self.add_issue(self.get_node(leaf), message="'%s' outside function" % leaf.value) 

698 elif self._normalizer.context.is_async_funcdef() \ 

699 and any(self._normalizer.context.node.iter_yield_exprs()): 

700 if leaf.value == 'return' and leaf.parent.type == 'return_stmt': 

701 return True 

702 

703 

704@ErrorFinder.register_rule(type='strings') 

705class _BytesAndStringMix(SyntaxRule): 

706 # e.g. 's' b'' 

707 message = "cannot mix bytes and nonbytes literals" 

708 

709 def _is_bytes_literal(self, string): 

710 if string.type == 'fstring': 

711 return False 

712 return 'b' in string.string_prefix.lower() 

713 

714 def is_issue(self, node): 

715 first = node.children[0] 

716 first_is_bytes = self._is_bytes_literal(first) 

717 for string in node.children[1:]: 

718 if first_is_bytes != self._is_bytes_literal(string): 

719 return True 

720 

721 

722@ErrorFinder.register_rule(type='import_as_names') 

723class _TrailingImportComma(SyntaxRule): 

724 # e.g. from foo import a, 

725 message = "trailing comma not allowed without surrounding parentheses" 

726 

727 def is_issue(self, node): 

728 if node.children[-1] == ',' and node.parent.children[-1] != ')': 

729 return True 

730 

731 

732@ErrorFinder.register_rule(type='import_from') 

733class _ImportStarInFunction(SyntaxRule): 

734 message = "import * only allowed at module level" 

735 

736 def is_issue(self, node): 

737 return node.is_star_import() and self._normalizer.context.parent_context is not None 

738 

739 

740@ErrorFinder.register_rule(type='import_from') 

741class _FutureImportRule(SyntaxRule): 

742 message = "from __future__ imports must occur at the beginning of the file" 

743 

744 def is_issue(self, node): 

745 if _is_future_import(node): 

746 if not _is_future_import_first(node): 

747 return True 

748 

749 for from_name, future_name in node.get_paths(): 

750 name = future_name.value 

751 allowed_futures = list(ALLOWED_FUTURES) 

752 if self._normalizer.version >= (3, 7): 

753 allowed_futures.append('annotations') 

754 if name == 'braces': 

755 self.add_issue(node, message="not a chance") 

756 elif name == 'barry_as_FLUFL': 

757 m = "Seriously I'm not implementing this :) ~ Dave" 

758 self.add_issue(node, message=m) 

759 elif name not in allowed_futures: 

760 message = "future feature %s is not defined" % name 

761 self.add_issue(node, message=message) 

762 

763 

764@ErrorFinder.register_rule(type='star_expr') 

765class _StarExprRule(SyntaxRule): 

766 message_iterable_unpacking = "iterable unpacking cannot be used in comprehension" 

767 

768 def is_issue(self, node): 

769 def check_delete_starred(node): 

770 while node.parent is not None: 

771 node = node.parent 

772 if node.type == 'del_stmt': 

773 return True 

774 if node.type not in (*_STAR_EXPR_PARENTS, 'atom'): 

775 return False 

776 return False 

777 

778 if self._normalizer.version >= (3, 9): 

779 ancestor = node.parent 

780 else: 

781 ancestor = _skip_parens_bottom_up(node) 

782 # starred expression not in tuple/list/set 

783 if ancestor.type not in (*_STAR_EXPR_PARENTS, 'dictorsetmaker') \ 

784 and not (ancestor.type == 'atom' and ancestor.children[0] != '('): 

785 self.add_issue(node, message="can't use starred expression here") 

786 return 

787 

788 if check_delete_starred(node): 

789 if self._normalizer.version >= (3, 9): 

790 self.add_issue(node, message="cannot delete starred") 

791 else: 

792 self.add_issue(node, message="can't use starred expression here") 

793 return 

794 

795 if node.parent.type == 'testlist_comp': 

796 # [*[] for a in [1]] 

797 if node.parent.children[1].type in _COMP_FOR_TYPES: 

798 self.add_issue(node, message=self.message_iterable_unpacking) 

799 

800 

801@ErrorFinder.register_rule(types=_STAR_EXPR_PARENTS) 

802class _StarExprParentRule(SyntaxRule): 

803 def is_issue(self, node): 

804 def is_definition(node, ancestor): 

805 if ancestor is None: 

806 return False 

807 

808 type_ = ancestor.type 

809 if type_ == 'trailer': 

810 return False 

811 

812 if type_ == 'expr_stmt': 

813 return node.start_pos < ancestor.children[-1].start_pos 

814 

815 return is_definition(node, ancestor.parent) 

816 

817 if is_definition(node, node.parent): 

818 args = [c for c in node.children if c != ','] 

819 starred = [c for c in args if c.type == 'star_expr'] 

820 if len(starred) > 1: 

821 if self._normalizer.version < (3, 9): 

822 message = "two starred expressions in assignment" 

823 else: 

824 message = "multiple starred expressions in assignment" 

825 self.add_issue(starred[1], message=message) 

826 elif starred: 

827 count = args.index(starred[0]) 

828 if count >= 256: 

829 message = "too many expressions in star-unpacking assignment" 

830 self.add_issue(starred[0], message=message) 

831 

832 

833@ErrorFinder.register_rule(type='annassign') 

834class _AnnotatorRule(SyntaxRule): 

835 # True: int 

836 # {}: float 

837 message = "illegal target for annotation" 

838 

839 def get_node(self, node): 

840 return node.parent 

841 

842 def is_issue(self, node): 

843 type_ = None 

844 lhs = node.parent.children[0] 

845 lhs = _remove_parens(lhs) 

846 try: 

847 children = lhs.children 

848 except AttributeError: 

849 pass 

850 else: 

851 if ',' in children or lhs.type == 'atom' and children[0] == '(': 

852 type_ = 'tuple' 

853 elif lhs.type == 'atom' and children[0] == '[': 

854 type_ = 'list' 

855 trailer = children[-1] 

856 

857 if type_ is None: 

858 if not (lhs.type == 'name' 

859 # subscript/attributes are allowed 

860 or lhs.type in ('atom_expr', 'power') 

861 and trailer.type == 'trailer' 

862 and trailer.children[0] != '('): 

863 return True 

864 else: 

865 # x, y: str 

866 message = "only single target (not %s) can be annotated" 

867 self.add_issue(lhs.parent, message=message % type_) 

868 

869 

870@ErrorFinder.register_rule(type='argument') 

871class _ArgumentRule(SyntaxRule): 

872 def is_issue(self, node): 

873 first = node.children[0] 

874 if self._normalizer.version < (3, 8): 

875 # a((b)=c) is valid in <3.8 

876 first = _remove_parens(first) 

877 if node.children[1] == '=' and first.type != 'name': 

878 if first.type == 'lambdef': 

879 # f(lambda: 1=1) 

880 if self._normalizer.version < (3, 8): 

881 message = "lambda cannot contain assignment" 

882 else: 

883 message = 'expression cannot contain assignment, perhaps you meant "=="?' 

884 else: 

885 # f(+x=1) 

886 if self._normalizer.version < (3, 8): 

887 message = "keyword can't be an expression" 

888 else: 

889 message = 'expression cannot contain assignment, perhaps you meant "=="?' 

890 self.add_issue(first, message=message) 

891 

892 if _is_argument_comprehension(node) and node.parent.type == 'classdef': 

893 self.add_issue(node, message='invalid syntax') 

894 

895 

896@ErrorFinder.register_rule(type='nonlocal_stmt') 

897class _NonlocalModuleLevelRule(SyntaxRule): 

898 message = "nonlocal declaration not allowed at module level" 

899 

900 def is_issue(self, node): 

901 return self._normalizer.context.parent_context is None 

902 

903 

904@ErrorFinder.register_rule(type='arglist') 

905class _ArglistRule(SyntaxRule): 

906 @property 

907 def message(self): 

908 if self._normalizer.version < (3, 7): 

909 return "Generator expression must be parenthesized if not sole argument" 

910 else: 

911 return "Generator expression must be parenthesized" 

912 

913 def is_issue(self, node): 

914 arg_set = set() 

915 kw_only = False 

916 kw_unpacking_only = False 

917 for argument in node.children: 

918 if argument == ',': 

919 continue 

920 

921 if argument.type == 'argument': 

922 first = argument.children[0] 

923 if _is_argument_comprehension(argument) and len(node.children) >= 2: 

924 # a(a, b for b in c) 

925 return True 

926 

927 if first in ('*', '**'): 

928 if first == '*': 

929 if kw_unpacking_only: 

930 # foo(**kwargs, *args) 

931 message = "iterable argument unpacking " \ 

932 "follows keyword argument unpacking" 

933 self.add_issue(argument, message=message) 

934 else: 

935 kw_unpacking_only = True 

936 else: # Is a keyword argument. 

937 kw_only = True 

938 if first.type == 'name': 

939 if first.value in arg_set: 

940 # f(x=1, x=2) 

941 message = "keyword argument repeated" 

942 if self._normalizer.version >= (3, 9): 

943 message += ": {}".format(first.value) 

944 self.add_issue(first, message=message) 

945 else: 

946 arg_set.add(first.value) 

947 else: 

948 if kw_unpacking_only: 

949 # f(**x, y) 

950 message = "positional argument follows keyword argument unpacking" 

951 self.add_issue(argument, message=message) 

952 elif kw_only: 

953 # f(x=2, y) 

954 message = "positional argument follows keyword argument" 

955 self.add_issue(argument, message=message) 

956 

957 

958@ErrorFinder.register_rule(type='parameters') 

959@ErrorFinder.register_rule(type='lambdef') 

960class _ParameterRule(SyntaxRule): 

961 # def f(x=3, y): pass 

962 message = "non-default argument follows default argument" 

963 

964 def is_issue(self, node): 

965 param_names = set() 

966 default_only = False 

967 star_seen = False 

968 for p in _iter_params(node): 

969 if p.type == 'operator': 

970 if p.value == '*': 

971 star_seen = True 

972 default_only = False 

973 continue 

974 

975 if p.name.value in param_names: 

976 message = "duplicate argument '%s' in function definition" 

977 self.add_issue(p.name, message=message % p.name.value) 

978 param_names.add(p.name.value) 

979 

980 if not star_seen: 

981 if p.default is None and not p.star_count: 

982 if default_only: 

983 return True 

984 elif p.star_count: 

985 star_seen = True 

986 default_only = False 

987 else: 

988 default_only = True 

989 

990 

991@ErrorFinder.register_rule(type='try_stmt') 

992class _TryStmtRule(SyntaxRule): 

993 message = "default 'except:' must be last" 

994 

995 def is_issue(self, try_stmt): 

996 default_except = None 

997 for except_clause in try_stmt.children[3::3]: 

998 if except_clause in ('else', 'finally'): 

999 break 

1000 if except_clause == 'except': 

1001 default_except = except_clause 

1002 elif default_except is not None: 

1003 self.add_issue(default_except, message=self.message) 

1004 

1005 

1006@ErrorFinder.register_rule(type='fstring') 

1007class _FStringRule(SyntaxRule): 

1008 _fstring_grammar = None 

1009 message_expr = "f-string expression part cannot include a backslash" 

1010 message_nested = "f-string: expressions nested too deeply" 

1011 message_conversion = "f-string: invalid conversion character: expected 's', 'r', or 'a'" 

1012 

1013 def _check_format_spec(self, format_spec, depth): 

1014 self._check_fstring_contents(format_spec.children[1:], depth) 

1015 

1016 def _check_fstring_expr(self, fstring_expr, depth): 

1017 if depth >= 2: 

1018 self.add_issue(fstring_expr, message=self.message_nested) 

1019 

1020 expr = fstring_expr.children[1] 

1021 if '\\' in expr.get_code(): 

1022 self.add_issue(expr, message=self.message_expr) 

1023 

1024 children_2 = fstring_expr.children[2] 

1025 if children_2.type == 'operator' and children_2.value == '=': 

1026 conversion = fstring_expr.children[3] 

1027 else: 

1028 conversion = children_2 

1029 if conversion.type == 'fstring_conversion': 

1030 name = conversion.children[1] 

1031 if name.value not in ('s', 'r', 'a'): 

1032 self.add_issue(name, message=self.message_conversion) 

1033 

1034 format_spec = fstring_expr.children[-2] 

1035 if format_spec.type == 'fstring_format_spec': 

1036 self._check_format_spec(format_spec, depth + 1) 

1037 

1038 def is_issue(self, fstring): 

1039 self._check_fstring_contents(fstring.children[1:-1]) 

1040 

1041 def _check_fstring_contents(self, children, depth=0): 

1042 for fstring_content in children: 

1043 if fstring_content.type == 'fstring_expr': 

1044 self._check_fstring_expr(fstring_content, depth) 

1045 

1046 

1047class _CheckAssignmentRule(SyntaxRule): 

1048 def _check_assignment(self, node, is_deletion=False, is_namedexpr=False, is_aug_assign=False): 

1049 error = None 

1050 type_ = node.type 

1051 if type_ == 'lambdef': 

1052 error = 'lambda' 

1053 elif type_ == 'atom': 

1054 first, second = node.children[:2] 

1055 error = _get_comprehension_type(node) 

1056 if error is None: 

1057 if second.type == 'dictorsetmaker': 

1058 if self._normalizer.version < (3, 8): 

1059 error = 'literal' 

1060 else: 

1061 if second.children[1] == ':': 

1062 if self._normalizer.version < (3, 10): 

1063 error = 'dict display' 

1064 else: 

1065 error = 'dict literal' 

1066 else: 

1067 error = 'set display' 

1068 elif first == "{" and second == "}": 

1069 if self._normalizer.version < (3, 8): 

1070 error = 'literal' 

1071 else: 

1072 if self._normalizer.version < (3, 10): 

1073 error = "dict display" 

1074 else: 

1075 error = "dict literal" 

1076 elif first == "{" and len(node.children) > 2: 

1077 if self._normalizer.version < (3, 8): 

1078 error = 'literal' 

1079 else: 

1080 error = "set display" 

1081 elif first in ('(', '['): 

1082 if second.type == 'yield_expr': 

1083 error = 'yield expression' 

1084 elif second.type == 'testlist_comp': 

1085 # ([a, b] := [1, 2]) 

1086 # ((a, b) := [1, 2]) 

1087 if is_namedexpr: 

1088 if first == '(': 

1089 error = 'tuple' 

1090 elif first == '[': 

1091 error = 'list' 

1092 

1093 # This is not a comprehension, they were handled 

1094 # further above. 

1095 for child in second.children[::2]: 

1096 self._check_assignment(child, is_deletion, is_namedexpr, is_aug_assign) 

1097 else: # Everything handled, must be useless brackets. 

1098 self._check_assignment(second, is_deletion, is_namedexpr, is_aug_assign) 

1099 elif type_ == 'keyword': 

1100 if node.value == "yield": 

1101 error = "yield expression" 

1102 elif self._normalizer.version < (3, 8): 

1103 error = 'keyword' 

1104 else: 

1105 error = str(node.value) 

1106 elif type_ == 'operator': 

1107 if node.value == '...': 

1108 if self._normalizer.version < (3, 10): 

1109 error = 'Ellipsis' 

1110 else: 

1111 error = 'ellipsis' 

1112 elif type_ == 'comparison': 

1113 error = 'comparison' 

1114 elif type_ in ('string', 'number', 'strings'): 

1115 error = 'literal' 

1116 elif type_ == 'yield_expr': 

1117 # This one seems to be a slightly different warning in Python. 

1118 message = 'assignment to yield expression not possible' 

1119 self.add_issue(node, message=message) 

1120 elif type_ == 'test': 

1121 error = 'conditional expression' 

1122 elif type_ in ('atom_expr', 'power'): 

1123 if node.children[0] == 'await': 

1124 error = 'await expression' 

1125 elif node.children[-2] == '**': 

1126 if self._normalizer.version < (3, 10): 

1127 error = 'operator' 

1128 else: 

1129 error = 'expression' 

1130 else: 

1131 # Has a trailer 

1132 trailer = node.children[-1] 

1133 assert trailer.type == 'trailer' 

1134 if trailer.children[0] == '(': 

1135 error = 'function call' 

1136 elif is_namedexpr and trailer.children[0] == '[': 

1137 error = 'subscript' 

1138 elif is_namedexpr and trailer.children[0] == '.': 

1139 error = 'attribute' 

1140 elif type_ == "fstring": 

1141 if self._normalizer.version < (3, 8): 

1142 error = 'literal' 

1143 else: 

1144 error = "f-string expression" 

1145 elif type_ in ('testlist_star_expr', 'exprlist', 'testlist'): 

1146 for child in node.children[::2]: 

1147 self._check_assignment(child, is_deletion, is_namedexpr, is_aug_assign) 

1148 elif ('expr' in type_ and type_ != 'star_expr' # is a substring 

1149 or '_test' in type_ 

1150 or type_ in ('term', 'factor')): 

1151 if self._normalizer.version < (3, 10): 

1152 error = 'operator' 

1153 else: 

1154 error = 'expression' 

1155 elif type_ == "star_expr": 

1156 if is_deletion: 

1157 if self._normalizer.version >= (3, 9): 

1158 error = "starred" 

1159 else: 

1160 self.add_issue(node, message="can't use starred expression here") 

1161 else: 

1162 if self._normalizer.version >= (3, 9): 

1163 ancestor = node.parent 

1164 else: 

1165 ancestor = _skip_parens_bottom_up(node) 

1166 if ancestor.type not in _STAR_EXPR_PARENTS and not is_aug_assign \ 

1167 and not (ancestor.type == 'atom' and ancestor.children[0] == '['): 

1168 message = "starred assignment target must be in a list or tuple" 

1169 self.add_issue(node, message=message) 

1170 

1171 self._check_assignment(node.children[1]) 

1172 

1173 if error is not None: 

1174 if is_namedexpr: 

1175 message = 'cannot use assignment expressions with %s' % error 

1176 else: 

1177 cannot = "can't" if self._normalizer.version < (3, 8) else "cannot" 

1178 message = ' '.join([cannot, "delete" if is_deletion else "assign to", error]) 

1179 self.add_issue(node, message=message) 

1180 

1181 

1182@ErrorFinder.register_rule(type='sync_comp_for') 

1183class _CompForRule(_CheckAssignmentRule): 

1184 message = "asynchronous comprehension outside of an asynchronous function" 

1185 

1186 def is_issue(self, node): 

1187 expr_list = node.children[1] 

1188 if expr_list.type != 'expr_list': # Already handled. 

1189 self._check_assignment(expr_list) 

1190 

1191 return node.parent.children[0] == 'async' \ 

1192 and not self._normalizer.context.is_async_funcdef() 

1193 

1194 

1195@ErrorFinder.register_rule(type='expr_stmt') 

1196class _ExprStmtRule(_CheckAssignmentRule): 

1197 message = "illegal expression for augmented assignment" 

1198 extended_message = "'{target}' is an " + message 

1199 

1200 def is_issue(self, node): 

1201 augassign = node.children[1] 

1202 is_aug_assign = augassign != '=' and augassign.type != 'annassign' 

1203 

1204 if self._normalizer.version <= (3, 8) or not is_aug_assign: 

1205 for before_equal in node.children[:-2:2]: 

1206 self._check_assignment(before_equal, is_aug_assign=is_aug_assign) 

1207 

1208 if is_aug_assign: 

1209 target = _remove_parens(node.children[0]) 

1210 # a, a[b], a.b 

1211 

1212 if target.type == "name" or ( 

1213 target.type in ("atom_expr", "power") 

1214 and target.children[1].type == "trailer" 

1215 and target.children[-1].children[0] != "(" 

1216 ): 

1217 return False 

1218 

1219 if self._normalizer.version <= (3, 8): 

1220 return True 

1221 else: 

1222 self.add_issue( 

1223 node, 

1224 message=self.extended_message.format( 

1225 target=_get_rhs_name(node.children[0], self._normalizer.version) 

1226 ), 

1227 ) 

1228 

1229 

1230@ErrorFinder.register_rule(type='with_item') 

1231class _WithItemRule(_CheckAssignmentRule): 

1232 def is_issue(self, with_item): 

1233 self._check_assignment(with_item.children[2]) 

1234 

1235 

1236@ErrorFinder.register_rule(type='del_stmt') 

1237class _DelStmtRule(_CheckAssignmentRule): 

1238 def is_issue(self, del_stmt): 

1239 child = del_stmt.children[1] 

1240 

1241 if child.type != 'expr_list': # Already handled. 

1242 self._check_assignment(child, is_deletion=True) 

1243 

1244 

1245@ErrorFinder.register_rule(type='expr_list') 

1246class _ExprListRule(_CheckAssignmentRule): 

1247 def is_issue(self, expr_list): 

1248 for expr in expr_list.children[::2]: 

1249 self._check_assignment(expr) 

1250 

1251 

1252@ErrorFinder.register_rule(type='for_stmt') 

1253class _ForStmtRule(_CheckAssignmentRule): 

1254 def is_issue(self, for_stmt): 

1255 # Some of the nodes here are already used, so no else if 

1256 expr_list = for_stmt.children[1] 

1257 if expr_list.type != 'expr_list': # Already handled. 

1258 self._check_assignment(expr_list) 

1259 

1260 

1261@ErrorFinder.register_rule(type='namedexpr_test') 

1262class _NamedExprRule(_CheckAssignmentRule): 

1263 # namedexpr_test: test [':=' test] 

1264 

1265 def is_issue(self, namedexpr_test): 

1266 # assigned name 

1267 first = namedexpr_test.children[0] 

1268 

1269 def search_namedexpr_in_comp_for(node): 

1270 while True: 

1271 parent = node.parent 

1272 if parent is None: 

1273 return parent 

1274 if parent.type == 'sync_comp_for' and parent.children[3] == node: 

1275 return parent 

1276 node = parent 

1277 

1278 if search_namedexpr_in_comp_for(namedexpr_test): 

1279 # [i+1 for i in (i := range(5))] 

1280 # [i+1 for i in (j := range(5))] 

1281 # [i+1 for i in (lambda: (j := range(5)))()] 

1282 message = 'assignment expression cannot be used in a comprehension iterable expression' 

1283 self.add_issue(namedexpr_test, message=message) 

1284 

1285 # defined names 

1286 exprlist = list() 

1287 

1288 def process_comp_for(comp_for): 

1289 if comp_for.type == 'sync_comp_for': 

1290 comp = comp_for 

1291 elif comp_for.type == 'comp_for': 

1292 comp = comp_for.children[1] 

1293 exprlist.extend(_get_for_stmt_definition_exprs(comp)) 

1294 

1295 def search_all_comp_ancestors(node): 

1296 has_ancestors = False 

1297 while True: 

1298 node = node.search_ancestor('testlist_comp', 'dictorsetmaker') 

1299 if node is None: 

1300 break 

1301 for child in node.children: 

1302 if child.type in _COMP_FOR_TYPES: 

1303 process_comp_for(child) 

1304 has_ancestors = True 

1305 break 

1306 return has_ancestors 

1307 

1308 # check assignment expressions in comprehensions 

1309 search_all = search_all_comp_ancestors(namedexpr_test) 

1310 if search_all: 

1311 if self._normalizer.context.node.type == 'classdef': 

1312 message = 'assignment expression within a comprehension ' \ 

1313 'cannot be used in a class body' 

1314 self.add_issue(namedexpr_test, message=message) 

1315 

1316 namelist = [expr.value for expr in exprlist if expr.type == 'name'] 

1317 if first.type == 'name' and first.value in namelist: 

1318 # [i := 0 for i, j in range(5)] 

1319 # [[(i := i) for j in range(5)] for i in range(5)] 

1320 # [i for i, j in range(5) if True or (i := 1)] 

1321 # [False and (i := 0) for i, j in range(5)] 

1322 message = 'assignment expression cannot rebind ' \ 

1323 'comprehension iteration variable %r' % first.value 

1324 self.add_issue(namedexpr_test, message=message) 

1325 

1326 self._check_assignment(first, is_namedexpr=True)