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

494 statements  

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

1import re 

2from contextlib import contextmanager 

3from typing import Tuple 

4 

5from parso.python.errors import ErrorFinder, ErrorFinderConfig 

6from parso.normalizer import Rule 

7from parso.python.tree import Flow, Scope 

8 

9 

10_IMPORT_TYPES = ('import_name', 'import_from') 

11_SUITE_INTRODUCERS = ('classdef', 'funcdef', 'if_stmt', 'while_stmt', 

12 'for_stmt', 'try_stmt', 'with_stmt') 

13_NON_STAR_TYPES = ('term', 'import_from', 'power') 

14_OPENING_BRACKETS = '(', '[', '{' 

15_CLOSING_BRACKETS = ')', ']', '}' 

16_FACTOR = '+', '-', '~' 

17_ALLOW_SPACE = '*', '+', '-', '**', '/', '//', '@' 

18_BITWISE_OPERATOR = '<<', '>>', '|', '&', '^' 

19_NEEDS_SPACE: Tuple[str, ...] = ( 

20 '=', '%', '->', 

21 '<', '>', '==', '>=', '<=', '<>', '!=', 

22 '+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=', '<<=', 

23 '>>=', '**=', '//=') 

24_NEEDS_SPACE += _BITWISE_OPERATOR 

25_IMPLICIT_INDENTATION_TYPES = ('dictorsetmaker', 'argument') 

26_POSSIBLE_SLICE_PARENTS = ('subscript', 'subscriptlist', 'sliceop') 

27 

28 

29class IndentationTypes: 

30 VERTICAL_BRACKET = object() 

31 HANGING_BRACKET = object() 

32 BACKSLASH = object() 

33 SUITE = object() 

34 IMPLICIT = object() 

35 

36 

37class IndentationNode(object): 

38 type = IndentationTypes.SUITE 

39 

40 def __init__(self, config, indentation, parent=None): 

41 self.bracket_indentation = self.indentation = indentation 

42 self.parent = parent 

43 

44 def __repr__(self): 

45 return '<%s>' % self.__class__.__name__ 

46 

47 def get_latest_suite_node(self): 

48 n = self 

49 while n is not None: 

50 if n.type == IndentationTypes.SUITE: 

51 return n 

52 

53 n = n.parent 

54 

55 

56class BracketNode(IndentationNode): 

57 def __init__(self, config, leaf, parent, in_suite_introducer=False): 

58 self.leaf = leaf 

59 

60 # Figure out here what the indentation is. For chained brackets 

61 # we can basically use the previous indentation. 

62 previous_leaf = leaf 

63 n = parent 

64 if n.type == IndentationTypes.IMPLICIT: 

65 n = n.parent 

66 while True: 

67 if hasattr(n, 'leaf') and previous_leaf.line != n.leaf.line: 

68 break 

69 

70 previous_leaf = previous_leaf.get_previous_leaf() 

71 if not isinstance(n, BracketNode) or previous_leaf != n.leaf: 

72 break 

73 n = n.parent 

74 parent_indentation = n.indentation 

75 

76 next_leaf = leaf.get_next_leaf() 

77 if '\n' in next_leaf.prefix or '\r' in next_leaf.prefix: 

78 # This implies code like: 

79 # foobarbaz( 

80 # a, 

81 # b, 

82 # ) 

83 self.bracket_indentation = parent_indentation \ 

84 + config.closing_bracket_hanging_indentation 

85 self.indentation = parent_indentation + config.indentation 

86 self.type = IndentationTypes.HANGING_BRACKET 

87 else: 

88 # Implies code like: 

89 # foobarbaz( 

90 # a, 

91 # b, 

92 # ) 

93 expected_end_indent = leaf.end_pos[1] 

94 if '\t' in config.indentation: 

95 self.indentation = None 

96 else: 

97 self.indentation = ' ' * expected_end_indent 

98 self.bracket_indentation = self.indentation 

99 self.type = IndentationTypes.VERTICAL_BRACKET 

100 

101 if in_suite_introducer and parent.type == IndentationTypes.SUITE \ 

102 and self.indentation == parent_indentation + config.indentation: 

103 self.indentation += config.indentation 

104 # The closing bracket should have the same indentation. 

105 self.bracket_indentation = self.indentation 

106 self.parent = parent 

107 

108 

109class ImplicitNode(BracketNode): 

110 """ 

111 Implicit indentation after keyword arguments, default arguments, 

112 annotations and dict values. 

113 """ 

114 def __init__(self, config, leaf, parent): 

115 super().__init__(config, leaf, parent) 

116 self.type = IndentationTypes.IMPLICIT 

117 

118 next_leaf = leaf.get_next_leaf() 

119 if leaf == ':' and '\n' not in next_leaf.prefix and '\r' not in next_leaf.prefix: 

120 self.indentation += ' ' 

121 

122 

123class BackslashNode(IndentationNode): 

124 type = IndentationTypes.BACKSLASH 

125 

126 def __init__(self, config, parent_indentation, containing_leaf, spacing, parent=None): 

127 expr_stmt = containing_leaf.search_ancestor('expr_stmt') 

128 if expr_stmt is not None: 

129 equals = expr_stmt.children[-2] 

130 

131 if '\t' in config.indentation: 

132 # TODO unite with the code of BracketNode 

133 self.indentation = None 

134 else: 

135 # If the backslash follows the equals, use normal indentation 

136 # otherwise it should align with the equals. 

137 if equals.end_pos == spacing.start_pos: 

138 self.indentation = parent_indentation + config.indentation 

139 else: 

140 # +1 because there is a space. 

141 self.indentation = ' ' * (equals.end_pos[1] + 1) 

142 else: 

143 self.indentation = parent_indentation + config.indentation 

144 self.bracket_indentation = self.indentation 

145 self.parent = parent 

146 

147 

148def _is_magic_name(name): 

149 return name.value.startswith('__') and name.value.endswith('__') 

150 

151 

152class PEP8Normalizer(ErrorFinder): 

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

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

155 self._previous_part = None 

156 self._previous_leaf = None 

157 self._on_newline = True 

158 self._newline_count = 0 

159 self._wanted_newline_count = None 

160 self._max_new_lines_in_prefix = 0 

161 self._new_statement = True 

162 self._implicit_indentation_possible = False 

163 # The top of stack of the indentation nodes. 

164 self._indentation_tos = self._last_indentation_tos = \ 

165 IndentationNode(self._config, indentation='') 

166 self._in_suite_introducer = False 

167 

168 if ' ' in self._config.indentation: 

169 self._indentation_type = 'spaces' 

170 self._wrong_indentation_char = '\t' 

171 else: 

172 self._indentation_type = 'tabs' 

173 self._wrong_indentation_char = ' ' 

174 

175 @contextmanager 

176 def visit_node(self, node): 

177 with super().visit_node(node): 

178 with self._visit_node(node): 

179 yield 

180 

181 @contextmanager 

182 def _visit_node(self, node): 

183 typ = node.type 

184 

185 if typ in 'import_name': 

186 names = node.get_defined_names() 

187 if len(names) > 1: 

188 for name in names[:1]: 

189 self.add_issue(name, 401, 'Multiple imports on one line') 

190 elif typ == 'lambdef': 

191 expr_stmt = node.parent 

192 # Check if it's simply defining a single name, not something like 

193 # foo.bar or x[1], where using a lambda could make more sense. 

194 if expr_stmt.type == 'expr_stmt' and any(n.type == 'name' 

195 for n in expr_stmt.children[:-2:2]): 

196 self.add_issue(node, 731, 'Do not assign a lambda expression, use a def') 

197 elif typ == 'try_stmt': 

198 for child in node.children: 

199 # Here we can simply check if it's an except, because otherwise 

200 # it would be an except_clause. 

201 if child.type == 'keyword' and child.value == 'except': 

202 self.add_issue(child, 722, 'Do not use bare except, specify exception instead') 

203 elif typ == 'comparison': 

204 for child in node.children: 

205 if child.type not in ('atom_expr', 'power'): 

206 continue 

207 if len(child.children) > 2: 

208 continue 

209 trailer = child.children[1] 

210 atom = child.children[0] 

211 if trailer.type == 'trailer' and atom.type == 'name' \ 

212 and atom.value == 'type': 

213 self.add_issue(node, 721, "Do not compare types, use 'isinstance()") 

214 break 

215 elif typ == 'file_input': 

216 endmarker = node.children[-1] 

217 prev = endmarker.get_previous_leaf() 

218 prefix = endmarker.prefix 

219 if (not prefix.endswith('\n') and not prefix.endswith('\r') and ( 

220 prefix or prev is None or prev.value not in {'\n', '\r\n', '\r'})): 

221 self.add_issue(endmarker, 292, "No newline at end of file") 

222 

223 if typ in _IMPORT_TYPES: 

224 simple_stmt = node.parent 

225 module = simple_stmt.parent 

226 if module.type == 'file_input': 

227 index = module.children.index(simple_stmt) 

228 for child in module.children[:index]: 

229 children = [child] 

230 if child.type == 'simple_stmt': 

231 # Remove the newline. 

232 children = child.children[:-1] 

233 

234 found_docstring = False 

235 for c in children: 

236 if c.type == 'string' and not found_docstring: 

237 continue 

238 found_docstring = True 

239 

240 if c.type == 'expr_stmt' and \ 

241 all(_is_magic_name(n) for n in c.get_defined_names()): 

242 continue 

243 

244 if c.type in _IMPORT_TYPES or isinstance(c, Flow): 

245 continue 

246 

247 self.add_issue(node, 402, 'Module level import not at top of file') 

248 break 

249 else: 

250 continue 

251 break 

252 

253 implicit_indentation_possible = typ in _IMPLICIT_INDENTATION_TYPES 

254 in_introducer = typ in _SUITE_INTRODUCERS 

255 if in_introducer: 

256 self._in_suite_introducer = True 

257 elif typ == 'suite': 

258 if self._indentation_tos.type == IndentationTypes.BACKSLASH: 

259 self._indentation_tos = self._indentation_tos.parent 

260 

261 self._indentation_tos = IndentationNode( 

262 self._config, 

263 self._indentation_tos.indentation + self._config.indentation, 

264 parent=self._indentation_tos 

265 ) 

266 elif implicit_indentation_possible: 

267 self._implicit_indentation_possible = True 

268 yield 

269 if typ == 'suite': 

270 assert self._indentation_tos.type == IndentationTypes.SUITE 

271 self._indentation_tos = self._indentation_tos.parent 

272 # If we dedent, no lines are needed anymore. 

273 self._wanted_newline_count = None 

274 elif implicit_indentation_possible: 

275 self._implicit_indentation_possible = False 

276 if self._indentation_tos.type == IndentationTypes.IMPLICIT: 

277 self._indentation_tos = self._indentation_tos.parent 

278 elif in_introducer: 

279 self._in_suite_introducer = False 

280 if typ in ('classdef', 'funcdef'): 

281 self._wanted_newline_count = self._get_wanted_blank_lines_count() 

282 

283 def _check_tabs_spaces(self, spacing): 

284 if self._wrong_indentation_char in spacing.value: 

285 self.add_issue(spacing, 101, 'Indentation contains ' + self._indentation_type) 

286 return True 

287 return False 

288 

289 def _get_wanted_blank_lines_count(self): 

290 suite_node = self._indentation_tos.get_latest_suite_node() 

291 return int(suite_node.parent is None) + 1 

292 

293 def _reset_newlines(self, spacing, leaf, is_comment=False): 

294 self._max_new_lines_in_prefix = \ 

295 max(self._max_new_lines_in_prefix, self._newline_count) 

296 

297 wanted = self._wanted_newline_count 

298 if wanted is not None: 

299 # Need to substract one 

300 blank_lines = self._newline_count - 1 

301 if wanted > blank_lines and leaf.type != 'endmarker': 

302 # In case of a comment we don't need to add the issue, yet. 

303 if not is_comment: 

304 # TODO end_pos wrong. 

305 code = 302 if wanted == 2 else 301 

306 message = "expected %s blank line, found %s" \ 

307 % (wanted, blank_lines) 

308 self.add_issue(spacing, code, message) 

309 self._wanted_newline_count = None 

310 else: 

311 self._wanted_newline_count = None 

312 

313 if not is_comment: 

314 wanted = self._get_wanted_blank_lines_count() 

315 actual = self._max_new_lines_in_prefix - 1 

316 

317 val = leaf.value 

318 needs_lines = ( 

319 val == '@' and leaf.parent.type == 'decorator' 

320 or ( 

321 val == 'class' 

322 or val == 'async' and leaf.get_next_leaf() == 'def' 

323 or val == 'def' and self._previous_leaf != 'async' 

324 ) and leaf.parent.parent.type != 'decorated' 

325 ) 

326 if needs_lines and actual < wanted: 

327 func_or_cls = leaf.parent 

328 suite = func_or_cls.parent 

329 if suite.type == 'decorated': 

330 suite = suite.parent 

331 

332 # The first leaf of a file or a suite should not need blank 

333 # lines. 

334 if suite.children[int(suite.type == 'suite')] != func_or_cls: 

335 code = 302 if wanted == 2 else 301 

336 message = "expected %s blank line, found %s" \ 

337 % (wanted, actual) 

338 self.add_issue(spacing, code, message) 

339 

340 self._max_new_lines_in_prefix = 0 

341 

342 self._newline_count = 0 

343 

344 def visit_leaf(self, leaf): 

345 super().visit_leaf(leaf) 

346 for part in leaf._split_prefix(): 

347 if part.type == 'spacing': 

348 # This part is used for the part call after for. 

349 break 

350 self._visit_part(part, part.create_spacing_part(), leaf) 

351 

352 self._analyse_non_prefix(leaf) 

353 self._visit_part(leaf, part, leaf) 

354 

355 # Cleanup 

356 self._last_indentation_tos = self._indentation_tos 

357 

358 self._new_statement = leaf.type == 'newline' 

359 

360 # TODO does this work? with brackets and stuff? 

361 if leaf.type == 'newline' and \ 

362 self._indentation_tos.type == IndentationTypes.BACKSLASH: 

363 self._indentation_tos = self._indentation_tos.parent 

364 

365 if leaf.value == ':' and leaf.parent.type in _SUITE_INTRODUCERS: 

366 self._in_suite_introducer = False 

367 elif leaf.value == 'elif': 

368 self._in_suite_introducer = True 

369 

370 if not self._new_statement: 

371 self._reset_newlines(part, leaf) 

372 self._max_blank_lines = 0 

373 

374 self._previous_leaf = leaf 

375 

376 return leaf.value 

377 

378 def _visit_part(self, part, spacing, leaf): 

379 value = part.value 

380 type_ = part.type 

381 if type_ == 'error_leaf': 

382 return 

383 

384 if value == ',' and part.parent.type == 'dictorsetmaker': 

385 self._indentation_tos = self._indentation_tos.parent 

386 

387 node = self._indentation_tos 

388 

389 if type_ == 'comment': 

390 if value.startswith('##'): 

391 # Whole blocks of # should not raise an error. 

392 if value.lstrip('#'): 

393 self.add_issue(part, 266, "Too many leading '#' for block comment.") 

394 elif self._on_newline: 

395 if not re.match(r'#:? ', value) and not value == '#' \ 

396 and not (value.startswith('#!') and part.start_pos == (1, 0)): 

397 self.add_issue(part, 265, "Block comment should start with '# '") 

398 else: 

399 if not re.match(r'#:? [^ ]', value): 

400 self.add_issue(part, 262, "Inline comment should start with '# '") 

401 

402 self._reset_newlines(spacing, leaf, is_comment=True) 

403 elif type_ == 'newline': 

404 if self._newline_count > self._get_wanted_blank_lines_count(): 

405 self.add_issue(part, 303, "Too many blank lines (%s)" % self._newline_count) 

406 elif leaf in ('def', 'class') \ 

407 and leaf.parent.parent.type == 'decorated': 

408 self.add_issue(part, 304, "Blank lines found after function decorator") 

409 

410 self._newline_count += 1 

411 

412 if type_ == 'backslash': 

413 # TODO is this enough checking? What about ==? 

414 if node.type != IndentationTypes.BACKSLASH: 

415 if node.type != IndentationTypes.SUITE: 

416 self.add_issue(part, 502, 'The backslash is redundant between brackets') 

417 else: 

418 indentation = node.indentation 

419 if self._in_suite_introducer and node.type == IndentationTypes.SUITE: 

420 indentation += self._config.indentation 

421 

422 self._indentation_tos = BackslashNode( 

423 self._config, 

424 indentation, 

425 part, 

426 spacing, 

427 parent=self._indentation_tos 

428 ) 

429 elif self._on_newline: 

430 indentation = spacing.value 

431 if node.type == IndentationTypes.BACKSLASH \ 

432 and self._previous_part.type == 'newline': 

433 self._indentation_tos = self._indentation_tos.parent 

434 

435 if not self._check_tabs_spaces(spacing): 

436 should_be_indentation = node.indentation 

437 if type_ == 'comment': 

438 # Comments can be dedented. So we have to care for that. 

439 n = self._last_indentation_tos 

440 while True: 

441 if len(indentation) > len(n.indentation): 

442 break 

443 

444 should_be_indentation = n.indentation 

445 

446 self._last_indentation_tos = n 

447 if n == node: 

448 break 

449 n = n.parent 

450 

451 if self._new_statement: 

452 if type_ == 'newline': 

453 if indentation: 

454 self.add_issue(spacing, 291, 'Trailing whitespace') 

455 elif indentation != should_be_indentation: 

456 s = '%s %s' % (len(self._config.indentation), self._indentation_type) 

457 self.add_issue(part, 111, 'Indentation is not a multiple of ' + s) 

458 else: 

459 if value in '])}': 

460 should_be_indentation = node.bracket_indentation 

461 else: 

462 should_be_indentation = node.indentation 

463 if self._in_suite_introducer and indentation == \ 

464 node.get_latest_suite_node().indentation \ 

465 + self._config.indentation: 

466 self.add_issue(part, 129, "Line with same indent as next logical block") 

467 elif indentation != should_be_indentation: 

468 if not self._check_tabs_spaces(spacing) and part.value not in \ 

469 {'\n', '\r\n', '\r'}: 

470 if value in '])}': 

471 if node.type == IndentationTypes.VERTICAL_BRACKET: 

472 self.add_issue( 

473 part, 

474 124, 

475 "Closing bracket does not match visual indentation" 

476 ) 

477 else: 

478 self.add_issue( 

479 part, 

480 123, 

481 "Losing bracket does not match " 

482 "indentation of opening bracket's line" 

483 ) 

484 else: 

485 if len(indentation) < len(should_be_indentation): 

486 if node.type == IndentationTypes.VERTICAL_BRACKET: 

487 self.add_issue( 

488 part, 

489 128, 

490 'Continuation line under-indented for visual indent' 

491 ) 

492 elif node.type == IndentationTypes.BACKSLASH: 

493 self.add_issue( 

494 part, 

495 122, 

496 'Continuation line missing indentation or outdented' 

497 ) 

498 elif node.type == IndentationTypes.IMPLICIT: 

499 self.add_issue(part, 135, 'xxx') 

500 else: 

501 self.add_issue( 

502 part, 

503 121, 

504 'Continuation line under-indented for hanging indent' 

505 ) 

506 else: 

507 if node.type == IndentationTypes.VERTICAL_BRACKET: 

508 self.add_issue( 

509 part, 

510 127, 

511 'Continuation line over-indented for visual indent' 

512 ) 

513 elif node.type == IndentationTypes.IMPLICIT: 

514 self.add_issue(part, 136, 'xxx') 

515 else: 

516 self.add_issue( 

517 part, 

518 126, 

519 'Continuation line over-indented for hanging indent' 

520 ) 

521 else: 

522 self._check_spacing(part, spacing) 

523 

524 self._check_line_length(part, spacing) 

525 # ------------------------------- 

526 # Finalizing. Updating the state. 

527 # ------------------------------- 

528 if value and value in '()[]{}' and type_ != 'error_leaf' \ 

529 and part.parent.type != 'error_node': 

530 if value in _OPENING_BRACKETS: 

531 self._indentation_tos = BracketNode( 

532 self._config, part, 

533 parent=self._indentation_tos, 

534 in_suite_introducer=self._in_suite_introducer 

535 ) 

536 else: 

537 assert node.type != IndentationTypes.IMPLICIT 

538 self._indentation_tos = self._indentation_tos.parent 

539 elif value in ('=', ':') and self._implicit_indentation_possible \ 

540 and part.parent.type in _IMPLICIT_INDENTATION_TYPES: 

541 indentation = node.indentation 

542 self._indentation_tos = ImplicitNode( 

543 self._config, part, parent=self._indentation_tos 

544 ) 

545 

546 self._on_newline = type_ in ('newline', 'backslash', 'bom') 

547 

548 self._previous_part = part 

549 self._previous_spacing = spacing 

550 

551 def _check_line_length(self, part, spacing): 

552 if part.type == 'backslash': 

553 last_column = part.start_pos[1] + 1 

554 else: 

555 last_column = part.end_pos[1] 

556 if last_column > self._config.max_characters \ 

557 and spacing.start_pos[1] <= self._config.max_characters: 

558 # Special case for long URLs in multi-line docstrings or comments, 

559 # but still report the error when the 72 first chars are whitespaces. 

560 report = True 

561 if part.type == 'comment': 

562 splitted = part.value[1:].split() 

563 if len(splitted) == 1 \ 

564 and (part.end_pos[1] - len(splitted[0])) < 72: 

565 report = False 

566 if report: 

567 self.add_issue( 

568 part, 

569 501, 

570 'Line too long (%s > %s characters)' % 

571 (last_column, self._config.max_characters), 

572 ) 

573 

574 def _check_spacing(self, part, spacing): 

575 def add_if_spaces(*args): 

576 if spaces: 

577 return self.add_issue(*args) 

578 

579 def add_not_spaces(*args): 

580 if not spaces: 

581 return self.add_issue(*args) 

582 

583 spaces = spacing.value 

584 prev = self._previous_part 

585 if prev is not None and prev.type == 'error_leaf' or part.type == 'error_leaf': 

586 return 

587 

588 type_ = part.type 

589 if '\t' in spaces: 

590 self.add_issue(spacing, 223, 'Used tab to separate tokens') 

591 elif type_ == 'comment': 

592 if len(spaces) < self._config.spaces_before_comment: 

593 self.add_issue(spacing, 261, 'At least two spaces before inline comment') 

594 elif type_ == 'newline': 

595 add_if_spaces(spacing, 291, 'Trailing whitespace') 

596 elif len(spaces) > 1: 

597 self.add_issue(spacing, 221, 'Multiple spaces used') 

598 else: 

599 if prev in _OPENING_BRACKETS: 

600 message = "Whitespace after '%s'" % part.value 

601 add_if_spaces(spacing, 201, message) 

602 elif part in _CLOSING_BRACKETS: 

603 message = "Whitespace before '%s'" % part.value 

604 add_if_spaces(spacing, 202, message) 

605 elif part in (',', ';') or part == ':' \ 

606 and part.parent.type not in _POSSIBLE_SLICE_PARENTS: 

607 message = "Whitespace before '%s'" % part.value 

608 add_if_spaces(spacing, 203, message) 

609 elif prev == ':' and prev.parent.type in _POSSIBLE_SLICE_PARENTS: 

610 pass # TODO 

611 elif prev in (',', ';', ':'): 

612 add_not_spaces(spacing, 231, "missing whitespace after '%s'") 

613 elif part == ':': # Is a subscript 

614 # TODO 

615 pass 

616 elif part in ('*', '**') and part.parent.type not in _NON_STAR_TYPES \ 

617 or prev in ('*', '**') \ 

618 and prev.parent.type not in _NON_STAR_TYPES: 

619 # TODO 

620 pass 

621 elif prev in _FACTOR and prev.parent.type == 'factor': 

622 pass 

623 elif prev == '@' and prev.parent.type == 'decorator': 

624 pass # TODO should probably raise an error if there's a space here 

625 elif part in _NEEDS_SPACE or prev in _NEEDS_SPACE: 

626 if part == '=' and part.parent.type in ('argument', 'param') \ 

627 or prev == '=' and prev.parent.type in ('argument', 'param'): 

628 if part == '=': 

629 param = part.parent 

630 else: 

631 param = prev.parent 

632 if param.type == 'param' and param.annotation: 

633 add_not_spaces(spacing, 252, 'Expected spaces around annotation equals') 

634 else: 

635 add_if_spaces( 

636 spacing, 

637 251, 

638 'Unexpected spaces around keyword / parameter equals' 

639 ) 

640 elif part in _BITWISE_OPERATOR or prev in _BITWISE_OPERATOR: 

641 add_not_spaces( 

642 spacing, 

643 227, 

644 'Missing whitespace around bitwise or shift operator' 

645 ) 

646 elif part == '%' or prev == '%': 

647 add_not_spaces(spacing, 228, 'Missing whitespace around modulo operator') 

648 else: 

649 message_225 = 'Missing whitespace between tokens' 

650 add_not_spaces(spacing, 225, message_225) 

651 elif type_ == 'keyword' or prev.type == 'keyword': 

652 add_not_spaces(spacing, 275, 'Missing whitespace around keyword') 

653 else: 

654 prev_spacing = self._previous_spacing 

655 if prev in _ALLOW_SPACE and spaces != prev_spacing.value \ 

656 and '\n' not in self._previous_leaf.prefix \ 

657 and '\r' not in self._previous_leaf.prefix: 

658 message = "Whitespace before operator doesn't match with whitespace after" 

659 self.add_issue(spacing, 229, message) 

660 

661 if spaces and part not in _ALLOW_SPACE and prev not in _ALLOW_SPACE: 

662 message_225 = 'Missing whitespace between tokens' 

663 # self.add_issue(spacing, 225, message_225) 

664 # TODO why only brackets? 

665 if part in _OPENING_BRACKETS: 

666 message = "Whitespace before '%s'" % part.value 

667 add_if_spaces(spacing, 211, message) 

668 

669 def _analyse_non_prefix(self, leaf): 

670 typ = leaf.type 

671 if typ == 'name' and leaf.value in ('l', 'O', 'I'): 

672 if leaf.is_definition(): 

673 message = "Do not define %s named 'l', 'O', or 'I' one line" 

674 if leaf.parent.type == 'class' and leaf.parent.name == leaf: 

675 self.add_issue(leaf, 742, message % 'classes') 

676 elif leaf.parent.type == 'function' and leaf.parent.name == leaf: 

677 self.add_issue(leaf, 743, message % 'function') 

678 else: 

679 self.add_issuadd_issue(741, message % 'variables', leaf) 

680 elif leaf.value == ':': 

681 if isinstance(leaf.parent, (Flow, Scope)) and leaf.parent.type != 'lambdef': 

682 next_leaf = leaf.get_next_leaf() 

683 if next_leaf.type != 'newline': 

684 if leaf.parent.type == 'funcdef': 

685 self.add_issue(next_leaf, 704, 'Multiple statements on one line (def)') 

686 else: 

687 self.add_issue(next_leaf, 701, 'Multiple statements on one line (colon)') 

688 elif leaf.value == ';': 

689 if leaf.get_next_leaf().type in ('newline', 'endmarker'): 

690 self.add_issue(leaf, 703, 'Statement ends with a semicolon') 

691 else: 

692 self.add_issue(leaf, 702, 'Multiple statements on one line (semicolon)') 

693 elif leaf.value in ('==', '!='): 

694 comparison = leaf.parent 

695 index = comparison.children.index(leaf) 

696 left = comparison.children[index - 1] 

697 right = comparison.children[index + 1] 

698 for node in left, right: 

699 if node.type == 'keyword' or node.type == 'name': 

700 if node.value == 'None': 

701 message = "comparison to None should be 'if cond is None:'" 

702 self.add_issue(leaf, 711, message) 

703 break 

704 elif node.value in ('True', 'False'): 

705 message = "comparison to False/True should be " \ 

706 "'if cond is True:' or 'if cond:'" 

707 self.add_issue(leaf, 712, message) 

708 break 

709 elif leaf.value in ('in', 'is'): 

710 comparison = leaf.parent 

711 if comparison.type == 'comparison' and comparison.parent.type == 'not_test': 

712 if leaf.value == 'in': 

713 self.add_issue(leaf, 713, "test for membership should be 'not in'") 

714 else: 

715 self.add_issue(leaf, 714, "test for object identity should be 'is not'") 

716 elif typ == 'string': 

717 # Checking multiline strings 

718 for i, line in enumerate(leaf.value.splitlines()[1:]): 

719 indentation = re.match(r'[ \t]*', line).group(0) 

720 start_pos = leaf.line + i, len(indentation) 

721 # TODO check multiline indentation. 

722 start_pos 

723 elif typ == 'endmarker': 

724 if self._newline_count >= 2: 

725 self.add_issue(leaf, 391, 'Blank line at end of file') 

726 

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

728 if self._previous_leaf is not None: 

729 if self._previous_leaf.search_ancestor('error_node') is not None: 

730 return 

731 if self._previous_leaf.type == 'error_leaf': 

732 return 

733 if node.search_ancestor('error_node') is not None: 

734 return 

735 if code in (901, 903): 

736 # 901 and 903 are raised by the ErrorFinder. 

737 super().add_issue(node, code, message) 

738 else: 

739 # Skip ErrorFinder here, because it has custom behavior. 

740 super(ErrorFinder, self).add_issue(node, code, message) 

741 

742 

743class PEP8NormalizerConfig(ErrorFinderConfig): 

744 normalizer_class = PEP8Normalizer 

745 """ 

746 Normalizing to PEP8. Not really implemented, yet. 

747 """ 

748 def __init__(self, indentation=' ' * 4, hanging_indentation=None, 

749 max_characters=79, spaces_before_comment=2): 

750 self.indentation = indentation 

751 if hanging_indentation is None: 

752 hanging_indentation = indentation 

753 self.hanging_indentation = hanging_indentation 

754 self.closing_bracket_hanging_indentation = '' 

755 self.break_after_binary = False 

756 self.max_characters = max_characters 

757 self.spaces_before_comment = spaces_before_comment 

758 

759 

760# TODO this is not yet ready. 

761# @PEP8Normalizer.register_rule(type='endmarker') 

762class BlankLineAtEnd(Rule): 

763 code = 392 

764 message = 'Blank line at end of file' 

765 

766 def is_issue(self, leaf): 

767 return self._newline_count >= 2