Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleFixer.py

branch
Py2 comp.
changeset 3456
96232974dcdb
parent 3178
f25fc1364c88
parent 3413
5e63f809732a
child 3484
645c12de6b0c
equal deleted inserted replaced
3178:f25fc1364c88 3456:96232974dcdb
5 5
6 """ 6 """
7 Module implementing a class to fix certain code style issues. 7 Module implementing a class to fix certain code style issues.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 try:
11 11 # Python 2
12 from StringIO import StringIO # __IGNORE_EXCEPTION__
13 except ImportError:
14 # Python 3
15 from io import StringIO # __IGNORE_WARNING__
12 import os 16 import os
13 import re 17 import re
18 import sys
14 import tokenize 19 import tokenize
15 import io 20
16 21 # CodeStyleCheckerDialog tries to import FixableCodeStyleIssues what fail under
17 from PyQt4.QtCore import QObject 22 # Python3. So ignore it.
18 23 try:
19 from E5Gui import E5MessageBox 24 import pep8
20 25 except ImportError:
21 from . import pep8 26 pass
22
23 import Utilities
24 27
25 FixableCodeStyleIssues = [ 28 FixableCodeStyleIssues = [
26 "D111", "D112", "D113", "D121", "D131", "D141", 29 "D111", "D112", "D113", "D121", "D131", "D141",
27 "D142", "D143", "D144", "D145", 30 "D142", "D143", "D144", "D145",
28 "D221", "D222", "D231", "D242", "D243", "D244", 31 "D221", "D222", "D231", "D242", "D243", "D244",
38 "N804", "N805", "N806", 41 "N804", "N805", "N806",
39 "W191", "W291", "W292", "W293", "W391", "W603", 42 "W191", "W291", "W292", "W293", "W391", "W603",
40 ] 43 ]
41 44
42 45
43 class CodeStyleFixer(QObject): 46 class CodeStyleFixer(object):
44 """ 47 """
45 Class implementing a fixer for certain code style issues. 48 Class implementing a fixer for certain code style issues.
46 """ 49 """
47 def __init__(self, project, filename, sourceLines, fixCodes, noFixCodes, 50 def __init__(self, filename, sourceLines, fixCodes, noFixCodes,
48 maxLineLength, inPlace): 51 maxLineLength, inPlace, eol):
49 """ 52 """
50 Constructor 53 Constructor
51 54
52 @param project reference to the project object (Project)
53 @param filename name of the file to be fixed (string) 55 @param filename name of the file to be fixed (string)
54 @param sourceLines list of source lines including eol marker 56 @param sourceLines list of source lines including eol marker
55 (list of string) 57 (list of string)
56 @param fixCodes list of codes to be fixed as a comma separated 58 @param fixCodes list of codes to be fixed as a comma separated
57 string (string) 59 string (string)
58 @param noFixCodes list of codes not to be fixed as a comma 60 @param noFixCodes list of codes not to be fixed as a comma
59 separated string (string) 61 separated string (string)
60 @param maxLineLength maximum allowed line length (integer) 62 @param maxLineLength maximum allowed line length (integer)
61 @param inPlace flag indicating to modify the file in place (boolean) 63 @param inPlace flag indicating to modify the file in place (boolean)
64 @param eol end of line character(s) (string)
62 """ 65 """
63 super(CodeStyleFixer, self).__init__() 66 super(CodeStyleFixer, self).__init__()
64 67
65 self.__project = project
66 self.__filename = filename 68 self.__filename = filename
67 self.__origName = "" 69 self.__origName = ""
68 self.__source = sourceLines[:] # save a copy 70 self.__source = sourceLines[:] # save a copy
69 self.__fixCodes = [c.strip() for c in fixCodes.split(",") if c.strip()] 71 self.__fixCodes = [c.strip() for c in fixCodes.split(",") if c.strip()]
70 self.__noFixCodes = [ 72 self.__noFixCodes = [
71 c.strip() for c in noFixCodes.split(",") if c.strip()] 73 c.strip() for c in noFixCodes.split(",") if c.strip()]
72 self.__maxLineLength = maxLineLength 74 self.__maxLineLength = maxLineLength
73 self.fixed = 0 75 self.fixed = 0
74 76
75 self.__reindenter = None 77 self.__reindenter = None
76 self.__eol = ""
77 self.__indentWord = self.__getIndentWord() 78 self.__indentWord = self.__getIndentWord()
78 79
79 if not inPlace: 80 if inPlace:
81 # TODO: Do a backup before any changes
82 pass
83 else:
80 self.__origName = self.__filename 84 self.__origName = self.__filename
81 self.__filename = os.path.join( 85 self.__filename = os.path.join(
82 os.path.dirname(self.__filename), 86 os.path.dirname(self.__filename),
83 "fixed_" + os.path.basename(self.__filename)) 87 "fixed_" + os.path.basename(self.__filename))
84 88 self.__eol = eol
89
85 self.__fixes = { 90 self.__fixes = {
86 "D111": self.__fixD111, 91 "D111": self.__fixD111,
87 "D112": self.__fixD112, 92 "D112": self.__fixD112,
88 "D113": self.__fixD112, 93 "D113": self.__fixD112,
89 "D121": self.__fixD121, 94 "D121": self.__fixD121,
172 def saveFile(self, encoding): 177 def saveFile(self, encoding):
173 """ 178 """
174 Public method to save the modified file. 179 Public method to save the modified file.
175 180
176 @param encoding encoding of the source file (string) 181 @param encoding encoding of the source file (string)
177 @return flag indicating success (boolean) 182 @return error message on failure (tuple of str)
178 """ 183 """
184 import codecs
185
179 if not self.__modified: 186 if not self.__modified:
180 # no need to write 187 # no need to write
181 return True 188 return
182 189
183 txt = "".join(self.__source) 190 txt = "".join(self.__source)
184 try: 191 try:
185 Utilities.writeEncodedFile(self.__filename, txt, encoding) 192 if sys.version_info[0] == 3:
186 except (IOError, Utilities.CodingError, UnicodeError) as err: 193 txt = txt.encode(encoding)
187 E5MessageBox.critical( 194 if encoding == 'utf-8-bom':
188 self, 195 txt = codecs.BOM_UTF8 + txt
189 self.trUtf8("Fix Code Style Issues"), 196
190 self.trUtf8( 197 with open(self.__filename, "wb") as fp:
191 """<p>Could not save the file <b>{0}</b>.""" 198 fp.write(txt)
192 """ Skipping it.</p><p>Reason: {1}</p>""") 199 except (IOError, UnicodeError) as err:
193 .format(self.__filename, str(err)) 200 # Could not save the file! Skipping it. Reason: {0}
194 ) 201 return ("FWRITE_ERROR", (str(err),))
195 return False 202 return
196
197 return True
198 203
199 def __codeMatch(self, code): 204 def __codeMatch(self, code):
200 """ 205 """
201 Private method to check, if the code should be fixed. 206 Private method to check, if the code should be fixed.
202 207
235 @param message message text (string) 240 @param message message text (string)
236 @return value indicating an applied/deferred fix (-1, 0, 1), 241 @return value indicating an applied/deferred fix (-1, 0, 1),
237 a message for the fix (string) and an ID for a deferred 242 a message for the fix (string) and an ID for a deferred
238 fix (integer) 243 fix (integer)
239 """ 244 """
240 code = message.split(None, 1)[0].strip() 245 if isinstance(message, (tuple, list)):
246 code = message[0].strip()
247 else:
248 code = message.split(None, 1)[0].strip()
241 249
242 if line <= len(self.__source) and \ 250 if line <= len(self.__source) and \
243 self.__codeMatch(code) and \ 251 self.__codeMatch(code) and \
244 code in self.__fixes: 252 code in self.__fixes:
245 res = self.__fixes[code](code, line, pos) 253 res = self.__fixes[code](code, line, pos)
284 @return ID for a deferred fix (integer) 292 @return ID for a deferred fix (integer)
285 """ 293 """
286 self.__lastID += 1 294 self.__lastID += 1
287 return self.__lastID 295 return self.__lastID
288 296
289 def __getEol(self):
290 """
291 Private method to get the applicable eol string.
292
293 @return eol string (string)
294 """
295 if not self.__eol:
296 if self.__origName:
297 fn = self.__origName
298 else:
299 fn = self.__filename
300
301 if self.__project.isOpen() and self.__project.isProjectFile(fn):
302 self.__eol = self.__project.getEolString()
303 else:
304 self.__eol = Utilities.linesep()
305 return self.__eol
306
307 def __findLogical(self): 297 def __findLogical(self):
308 """ 298 """
309 Private method to extract the index of all the starts and ends of 299 Private method to extract the index of all the starts and ends of
310 lines. 300 lines.
311 301
313 of lines 303 of lines
314 """ 304 """
315 logical_start = [] 305 logical_start = []
316 logical_end = [] 306 logical_end = []
317 last_newline = True 307 last_newline = True
318 sio = io.StringIO("".join(self.__source)) 308 sio = StringIO("".join(self.__source))
319 parens = 0 309 parens = 0
320 for t in tokenize.generate_tokens(sio.readline): 310 for t in tokenize.generate_tokens(sio.readline):
321 if t[0] in [tokenize.COMMENT, tokenize.DEDENT, 311 if t[0] in [tokenize.COMMENT, tokenize.DEDENT,
322 tokenize.INDENT, tokenize.NL, 312 tokenize.INDENT, tokenize.NL,
323 tokenize.ENDMARKER]: 313 tokenize.ENDMARKER]:
372 """ 362 """
373 Private method to determine the indentation type. 363 Private method to determine the indentation type.
374 364
375 @return string to be used for an indentation (string) 365 @return string to be used for an indentation (string)
376 """ 366 """
377 sio = io.StringIO("".join(self.__source)) 367 sio = StringIO("".join(self.__source))
378 indentWord = " " # default in case of failure 368 indentWord = " " # default in case of failure
379 try: 369 try:
380 for token in tokenize.generate_tokens(sio.readline): 370 for token in tokenize.generate_tokens(sio.readline):
381 if token[0] == tokenize.INDENT: 371 if token[0] == tokenize.INDENT:
382 indentWord = token[1] 372 indentWord = token[1]
403 string and a set of line numbers belonging to a multi line 393 string and a set of line numbers belonging to a multi line
404 documentation string (tuple of two set of integer) 394 documentation string (tuple of two set of integer)
405 """ 395 """
406 if self.__multiLineNumbers is None: 396 if self.__multiLineNumbers is None:
407 source = "".join(self.__source) 397 source = "".join(self.__source)
408 sio = io.StringIO(source) 398 sio = StringIO(source)
409 self.__multiLineNumbers = set() 399 self.__multiLineNumbers = set()
410 self.__docLineNumbers = set() 400 self.__docLineNumbers = set()
411 previousTokenType = '' 401 previousTokenType = ''
412 try: 402 try:
413 for t in tokenize.generate_tokens(sio.readline): 403 for t in tokenize.generate_tokens(sio.readline):
509 left, right = self.__source[line].rsplit("'''", 1) 499 left, right = self.__source[line].rsplit("'''", 1)
510 self.__source[line] = left + '"""' + right 500 self.__source[line] = left + '"""' + right
511 break 501 break
512 line += 1 502 line += 1
513 503
514 return ( 504 # Triple single quotes converted to triple double quotes.
515 1, 505 return (1, "FD111", 0)
516 self.trUtf8(
517 "Triple single quotes converted to triple double quotes."),
518 0)
519 506
520 def __fixD112(self, code, line, pos): 507 def __fixD112(self, code, line, pos):
521 """ 508 """
522 Private method to fix docstring 'r' or 'u' in leading quotes. 509 Private method to fix docstring 'r' or 'u' in leading quotes.
523 510
539 return (0, "", 0) 526 return (0, "", 0)
540 527
541 newText = self.__getIndent(self.__source[line]) + \ 528 newText = self.__getIndent(self.__source[line]) + \
542 insertChar + self.__source[line].lstrip() 529 insertChar + self.__source[line].lstrip()
543 self.__source[line] = newText 530 self.__source[line] = newText
544 return ( 531 # Introductory quotes corrected to be {0}"""
545 1, 532 return (1, ('FD112', (insertChar,)), 0)
546 self.trUtf8('Introductory quotes corrected to be {0}"""')
547 .format(insertChar),
548 0)
549 533
550 def __fixD121(self, code, line, pos, apply=False): 534 def __fixD121(self, code, line, pos, apply=False):
551 """ 535 """
552 Private method to fix a single line docstring on multiple lines. 536 Private method to fix a single line docstring on multiple lines.
553 537
570 return (0, "", 0) 554 return (0, "", 0)
571 555
572 docstring = self.__source[line].rstrip() + \ 556 docstring = self.__source[line].rstrip() + \
573 self.__source[line + 1].strip() 557 self.__source[line + 1].strip()
574 if docstring.endswith('"""'): 558 if docstring.endswith('"""'):
575 docstring += self.__getEol() 559 docstring += self.__eol
576 else: 560 else:
577 docstring += self.__source[line + 2].lstrip() 561 docstring += self.__source[line + 2].lstrip()
578 self.__source[line + 2] = "" 562 self.__source[line + 2] = ""
579 563
580 self.__source[line] = docstring 564 self.__source[line] = docstring
581 self.__source[line + 1] = "" 565 self.__source[line + 1] = ""
582 return ( 566 # Single line docstring put on one line.
583 1, 567 return (1, "FD121", 0)
584 self.trUtf8("Single line docstring put on one line."),
585 0)
586 else: 568 else:
587 id = self.__getID() 569 id = self.__getID()
588 self.__stack.append((id, code, line, pos)) 570 self.__stack.append((id, code, line, pos))
589 return (-1, "", id) 571 return (-1, "", id)
590 572
606 newText = "" 588 newText = ""
607 if self.__source[line].rstrip().endswith(('"""', "'''")) and \ 589 if self.__source[line].rstrip().endswith(('"""', "'''")) and \
608 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')): 590 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')):
609 # it is a one-liner 591 # it is a one-liner
610 newText = self.__source[line].rstrip()[:-3].rstrip() + "." + \ 592 newText = self.__source[line].rstrip()[:-3].rstrip() + "." + \
611 self.__source[line].rstrip()[-3:] + self.__getEol() 593 self.__source[line].rstrip()[-3:] + self.__eol
612 else: 594 else:
613 if line < len(self.__source) - 1 and \ 595 if line < len(self.__source) - 1 and \
614 (not self.__source[line + 1].strip() or 596 (not self.__source[line + 1].strip() or
615 self.__source[line + 1].lstrip().startswith("@") or 597 self.__source[line + 1].lstrip().startswith("@") or
616 (self.__source[line + 1].strip() in ('"""', "'''") and 598 (self.__source[line + 1].strip() in ('"""', "'''") and
617 not self.__source[line].lstrip().startswith("@"))): 599 not self.__source[line].lstrip().startswith("@"))):
618 newText = self.__source[line].rstrip() + "." + self.__getEol() 600 newText = self.__source[line].rstrip() + "." + self.__eol
619 601
620 if newText: 602 if newText:
621 self.__source[line] = newText 603 self.__source[line] = newText
622 return (1, self.trUtf8("Period added to summary line."), 0) 604 # Period added to summary line.
605 return (1, "FD131", 0)
623 else: 606 else:
624 return (0, "", 0) 607 return (0, "", 0)
625 608
626 def __fixD141(self, code, line, pos, apply=False): 609 def __fixD141(self, code, line, pos, apply=False):
627 """ 610 """
640 fix (integer) 623 fix (integer)
641 """ 624 """
642 if apply: 625 if apply:
643 line = line - 1 626 line = line - 1
644 self.__source[line - 1] = "" 627 self.__source[line - 1] = ""
645 return ( 628 # Blank line before function/method docstring removed.
646 1, 629 return (1, "FD141", 0)
647 self.trUtf8(
648 "Blank line before function/method docstring removed."),
649 0)
650 else: 630 else:
651 id = self.__getID() 631 id = self.__getID()
652 self.__stack.append((id, code, line, pos)) 632 self.__stack.append((id, code, line, pos))
653 return (-1, "", id) 633 return (-1, "", id)
654 634
668 a message for the fix (string) and an ID for a deferred 648 a message for the fix (string) and an ID for a deferred
669 fix (integer) 649 fix (integer)
670 """ 650 """
671 if apply: 651 if apply:
672 line = line - 1 652 line = line - 1
673 self.__source[line] = self.__getEol() + self.__source[line] 653 self.__source[line] = self.__eol + self.__source[line]
674 return ( 654 # Blank line inserted before class docstring.
675 1, 655 return (1, "FD142", 0)
676 self.trUtf8("Blank line inserted before class docstring."),
677 0)
678 else: 656 else:
679 id = self.__getID() 657 id = self.__getID()
680 self.__stack.append((id, code, line, pos)) 658 self.__stack.append((id, code, line, pos))
681 return (-1, "", id) 659 return (-1, "", id)
682 660
696 a message for the fix (string) and an ID for a deferred 674 a message for the fix (string) and an ID for a deferred
697 fix (integer) 675 fix (integer)
698 """ 676 """
699 if apply: 677 if apply:
700 line = line - 1 678 line = line - 1
701 self.__source[line] += self.__getEol() 679 self.__source[line] += self.__eol
702 return ( 680 # Blank line inserted after class docstring.
703 1, 681 return (1, "FD143", 0)
704 self.trUtf8("Blank line inserted after class docstring."),
705 0)
706 else: 682 else:
707 id = self.__getID() 683 id = self.__getID()
708 self.__stack.append((id, code, line, pos)) 684 self.__stack.append((id, code, line, pos))
709 return (-1, "", id) 685 return (-1, "", id)
710 686
728 line = line - 1 704 line = line - 1
729 if not self.__source[line].rstrip().endswith("."): 705 if not self.__source[line].rstrip().endswith("."):
730 # only correct summary lines can be fixed here 706 # only correct summary lines can be fixed here
731 return (0, "", 0) 707 return (0, "", 0)
732 708
733 self.__source[line] += self.__getEol() 709 self.__source[line] += self.__eol
734 return ( 710 # Blank line inserted after docstring summary.
735 1, 711 return (1, "FD144", 0)
736 self.trUtf8("Blank line inserted after docstring summary."),
737 0)
738 else: 712 else:
739 id = self.__getID() 713 id = self.__getID()
740 self.__stack.append((id, code, line, pos)) 714 self.__stack.append((id, code, line, pos))
741 return (-1, "", id) 715 return (-1, "", id)
742 716
756 a message for the fix (string) and an ID for a deferred 730 a message for the fix (string) and an ID for a deferred
757 fix (integer) 731 fix (integer)
758 """ 732 """
759 if apply: 733 if apply:
760 line = line - 1 734 line = line - 1
761 self.__source[line] = self.__getEol() + self.__source[line] 735 self.__source[line] = self.__eol + self.__source[line]
762 return ( 736 # Blank line inserted after last paragraph of docstring.
763 1, 737 return (1, "FD145", 0)
764 self.trUtf8("Blank line inserted after last paragraph"
765 " of docstring."),
766 0)
767 else: 738 else:
768 id = self.__getID() 739 id = self.__getID()
769 self.__stack.append((id, code, line, pos)) 740 self.__stack.append((id, code, line, pos))
770 return (-1, "", id) 741 return (-1, "", id)
771 742
796 else: 767 else:
797 first, second = source[:3], source[3:].strip() 768 first, second = source[:3], source[3:].strip()
798 else: 769 else:
799 # trailing 770 # trailing
800 first, second = source[:-3].strip(), source[-3:] 771 first, second = source[:-3].strip(), source[-3:]
801 newText = indent + first + self.__getEol() + \ 772 newText = indent + first + self.__eol + \
802 indent + second + self.__getEol() 773 indent + second + self.__eol
803 self.__source[line] = newText 774 self.__source[line] = newText
804 if code == "D221": 775 if code == "D221":
805 msg = self.trUtf8("Leading quotes put on separate line.") 776 # Leading quotes put on separate line.
777 msg = "FD221"
806 else: 778 else:
807 msg = self.trUtf8("Trailing quotes put on separate line.") 779 # Trailing quotes put on separate line.
780 msg = "FD222"
808 return (1, msg, 0) 781 return (1, msg, 0)
809 else: 782 else:
810 id = self.__getID() 783 id = self.__getID()
811 self.__stack.append((id, code, line, pos)) 784 self.__stack.append((id, code, line, pos))
812 return (-1, "", id) 785 return (-1, "", id)
829 """ 802 """
830 if apply: 803 if apply:
831 line = line - 1 804 line = line - 1
832 self.__source[line - 1] = "" 805 self.__source[line - 1] = ""
833 if code == "D242": 806 if code == "D242":
834 msg = self.trUtf8("Blank line before class docstring removed.") 807 # Blank line before class docstring removed.
808 msg = "FD242"
835 else: 809 else:
836 msg = self.trUtf8( 810 # Blank line before function/method docstring removed.
837 "Blank line before function/method docstring removed.") 811 msg = "FD244"
838 return (1, msg, 0) 812 return (1, msg, 0)
839 else: 813 else:
840 id = self.__getID() 814 id = self.__getID()
841 self.__stack.append((id, code, line, pos)) 815 self.__stack.append((id, code, line, pos))
842 return (-1, "", id) 816 return (-1, "", id)
859 """ 833 """
860 if apply: 834 if apply:
861 line = line - 1 835 line = line - 1
862 self.__source[line + 1] = "" 836 self.__source[line + 1] = ""
863 if code == "D243": 837 if code == "D243":
864 msg = self.trUtf8("Blank line after class docstring removed.") 838 # Blank line after class docstring removed.
839 msg = "FD243"
865 else: 840 else:
866 msg = self.trUtf8( 841 # Blank line after function/method docstring removed.
867 "Blank line after function/method docstring removed.") 842 msg = "FD245"
868 return (1, msg, 0) 843 return (1, msg, 0)
869 else: 844 else:
870 id = self.__getID() 845 id = self.__getID()
871 self.__stack.append((id, code, line, pos)) 846 self.__stack.append((id, code, line, pos))
872 return (-1, "", id) 847 return (-1, "", id)
888 fix (integer) 863 fix (integer)
889 """ 864 """
890 if apply: 865 if apply:
891 line = line - 1 866 line = line - 1
892 self.__source[line - 1] = "" 867 self.__source[line - 1] = ""
893 return ( 868 # Blank line after last paragraph removed.
894 1, 869 return (1, "FD247", 0)
895 self.trUtf8("Blank line after last paragraph removed."),
896 0)
897 else: 870 else:
898 id = self.__getID() 871 id = self.__getID()
899 self.__stack.append((id, code, line, pos)) 872 self.__stack.append((id, code, line, pos))
900 return (-1, "", id) 873 return (-1, "", id)
901 874
917 self.__reindenter.run() 890 self.__reindenter.run()
918 fixedLine = self.__reindenter.fixedLine(line - 1) 891 fixedLine = self.__reindenter.fixedLine(line - 1)
919 if fixedLine is not None and fixedLine != self.__source[line - 1]: 892 if fixedLine is not None and fixedLine != self.__source[line - 1]:
920 self.__source[line - 1] = fixedLine 893 self.__source[line - 1] = fixedLine
921 if code in ["E101", "W191"]: 894 if code in ["E101", "W191"]:
922 msg = self.trUtf8("Tab converted to 4 spaces.") 895 # Tab converted to 4 spaces.
896 msg = "FE101"
923 else: 897 else:
924 msg = self.trUtf8( 898 # Indentation adjusted to be a multiple of four.
925 "Indentation adjusted to be a multiple of four.") 899 msg = "FE111"
926 return (1, msg, 0) 900 return (1, msg, 0)
927 else: 901 else:
928 return (0, "", 0) 902 return (0, "", 0)
929 903
930 def __fixE121(self, code, line, pos, apply=False): 904 def __fixE121(self, code, line, pos, apply=False):
948 if logical: 922 if logical:
949 # Fix by adjusting initial indent level. 923 # Fix by adjusting initial indent level.
950 changed = self.__fixReindent(line, pos, logical) 924 changed = self.__fixReindent(line, pos, logical)
951 if changed: 925 if changed:
952 if code == "E121": 926 if code == "E121":
953 msg = self.trUtf8( 927 # Indentation of continuation line corrected.
954 "Indentation of continuation line corrected.") 928 msg = "FE121"
955 elif code == "E124": 929 elif code == "E124":
956 msg = self.trUtf8( 930 # Indentation of closing bracket corrected.
957 "Indentation of closing bracket corrected.") 931 msg = "FE124"
958 return (1, msg, 0) 932 return (1, msg, 0)
959 return (0, "", 0) 933 return (0, "", 0)
960 else: 934 else:
961 id = self.__getID() 935 id = self.__getID()
962 self.__stackLogical.append((id, code, line, pos)) 936 self.__stackLogical.append((id, code, line, pos))
987 line = line - 1 961 line = line - 1
988 text = self.__source[line] 962 text = self.__source[line]
989 indentation = self.__getIndent(text) 963 indentation = self.__getIndent(text)
990 self.__source[line] = indentation + \ 964 self.__source[line] = indentation + \
991 self.__indentWord + text.lstrip() 965 self.__indentWord + text.lstrip()
992 return ( 966 # Missing indentation of continuation line corrected.
993 1, 967 return (1, "FE122", 0)
994 self.trUtf8(
995 "Missing indentation of continuation line corrected."),
996 0)
997 return (0, "", 0) 968 return (0, "", 0)
998 else: 969 else:
999 id = self.__getID() 970 id = self.__getID()
1000 self.__stackLogical.append((id, code, line, pos)) 971 self.__stackLogical.append((id, code, line, pos))
1001 return (-1, "", id) 972 return (-1, "", id)
1028 changed = self.__fixReindent(line, pos, logical) 999 changed = self.__fixReindent(line, pos, logical)
1029 else: 1000 else:
1030 self.__source[row] = newText 1001 self.__source[row] = newText
1031 changed = True 1002 changed = True
1032 if changed: 1003 if changed:
1033 return (1, self.trUtf8( 1004 # Closing bracket aligned to opening bracket.
1034 "Closing bracket aligned to opening bracket."), 1005 return (1, "FE123", 0)
1035 0)
1036 return (0, "", 0) 1006 return (0, "", 0)
1037 else: 1007 else:
1038 id = self.__getID() 1008 id = self.__getID()
1039 self.__stackLogical.append((id, code, line, pos)) 1009 self.__stackLogical.append((id, code, line, pos))
1040 return (-1, "", id) 1010 return (-1, "", id)
1063 if not modified: 1033 if not modified:
1064 row = line - 1 1034 row = line - 1
1065 text = self.__source[row] 1035 text = self.__source[row]
1066 self.__source[row] = self.__getIndent(text) + \ 1036 self.__source[row] = self.__getIndent(text) + \
1067 self.__indentWord + text.lstrip() 1037 self.__indentWord + text.lstrip()
1068 return (1, self.trUtf8("Indentation level changed."), 0) 1038 # Indentation level changed.
1039 return (1, "FE125", 0)
1069 return (0, "", 0) 1040 return (0, "", 0)
1070 else: 1041 else:
1071 id = self.__getID() 1042 id = self.__getID()
1072 self.__stackLogical.append((id, code, line, pos)) 1043 self.__stackLogical.append((id, code, line, pos))
1073 return (-1, "", id) 1044 return (-1, "", id)
1102 changed = self.__fixReindent(line, pos, logical) 1073 changed = self.__fixReindent(line, pos, logical)
1103 else: 1074 else:
1104 self.__source[row] = newText 1075 self.__source[row] = newText
1105 changed = True 1076 changed = True
1106 if changed: 1077 if changed:
1107 return (1, self.trUtf8( 1078 # Indentation level of hanging indentation changed.
1108 "Indentation level of hanging indentation changed."), 1079 return (1, "FE126", 0)
1109 0)
1110 return (0, "", 0) 1080 return (0, "", 0)
1111 else: 1081 else:
1112 id = self.__getID() 1082 id = self.__getID()
1113 self.__stackLogical.append((id, code, line, pos)) 1083 self.__stackLogical.append((id, code, line, pos))
1114 return (-1, "", id) 1084 return (-1, "", id)
1158 changed = self.__fixReindent(line, pos, logical) 1128 changed = self.__fixReindent(line, pos, logical)
1159 else: 1129 else:
1160 self.__source[row] = newText 1130 self.__source[row] = newText
1161 changed = True 1131 changed = True
1162 if changed: 1132 if changed:
1163 return (1, self.trUtf8("Visual indentation corrected."), 0) 1133 # Visual indentation corrected.
1134 return (1, "FE127", 0)
1164 return (0, "", 0) 1135 return (0, "", 0)
1165 else: 1136 else:
1166 id = self.__getID() 1137 id = self.__getID()
1167 self.__stackLogical.append((id, code, line, pos)) 1138 self.__stackLogical.append((id, code, line, pos))
1168 return (-1, "", id) 1139 return (-1, "", id)
1189 newText = self.__fixWhitespace(text, pos, '') 1160 newText = self.__fixWhitespace(text, pos, '')
1190 if newText == text: 1161 if newText == text:
1191 return (0, "", 0) 1162 return (0, "", 0)
1192 1163
1193 self.__source[line] = newText 1164 self.__source[line] = newText
1194 return (1, self.trUtf8("Extraneous whitespace removed."), 0) 1165 # Extraneous whitespace removed.
1166 return (1, "FE201", 0)
1195 1167
1196 def __fixE221(self, code, line, pos): 1168 def __fixE221(self, code, line, pos):
1197 """ 1169 """
1198 Private method to fix extraneous whitespace around operator or 1170 Private method to fix extraneous whitespace around operator or
1199 keyword. 1171 keyword.
1218 if newText == text: 1190 if newText == text:
1219 return (0, "", 0) 1191 return (0, "", 0)
1220 1192
1221 self.__source[line] = newText 1193 self.__source[line] = newText
1222 if code in ["E225", "E226", "E227", "E228"]: 1194 if code in ["E225", "E226", "E227", "E228"]:
1223 return (1, self.trUtf8("Missing whitespace added."), 0) 1195 # Missing whitespace added.
1224 else: 1196 return (1, "", 0)
1225 return (1, self.trUtf8("Extraneous whitespace removed."), 0) 1197 else:
1198 # Extraneous whitespace removed.
1199 return (1, "", 0)
1226 1200
1227 def __fixE231(self, code, line, pos): 1201 def __fixE231(self, code, line, pos):
1228 """ 1202 """
1229 Private method to fix missing whitespace after ',;:'. 1203 Private method to fix missing whitespace after ',;:'.
1230 1204
1239 """ 1213 """
1240 line = line - 1 1214 line = line - 1
1241 pos = pos + 1 1215 pos = pos + 1
1242 self.__source[line] = self.__source[line][:pos] + \ 1216 self.__source[line] = self.__source[line][:pos] + \
1243 " " + self.__source[line][pos:] 1217 " " + self.__source[line][pos:]
1244 return (1, self.trUtf8("Missing whitespace added."), 0) 1218 # Missing whitespace added.
1219 return (1, "FE231", 0)
1245 1220
1246 def __fixE251(self, code, line, pos): 1221 def __fixE251(self, code, line, pos):
1247 """ 1222 """
1248 Private method to fix extraneous whitespace around keyword and 1223 Private method to fix extraneous whitespace around keyword and
1249 default parameter equals. 1224 default parameter equals.
1276 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')): 1251 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')):
1277 self.__source[line] = newText.rstrip("\n\r \t\\") 1252 self.__source[line] = newText.rstrip("\n\r \t\\")
1278 self.__source[line + 1] = self.__source[line + 1].lstrip() 1253 self.__source[line + 1] = self.__source[line + 1].lstrip()
1279 else: 1254 else:
1280 self.__source[line] = newText 1255 self.__source[line] = newText
1281 return (1, self.trUtf8("Extraneous whitespace removed."), 0) 1256 # Extraneous whitespace removed.
1257 return (1, "FE251", 0)
1282 1258
1283 def __fixE261(self, code, line, pos): 1259 def __fixE261(self, code, line, pos):
1284 """ 1260 """
1285 Private method to fix whitespace before or after inline comment. 1261 Private method to fix whitespace before or after inline comment.
1286 1262
1297 text = self.__source[line] 1273 text = self.__source[line]
1298 left = text[:pos].rstrip(' \t#') 1274 left = text[:pos].rstrip(' \t#')
1299 right = text[pos:].lstrip(' \t#') 1275 right = text[pos:].lstrip(' \t#')
1300 newText = left + (" # " + right if right.strip() else right) 1276 newText = left + (" # " + right if right.strip() else right)
1301 self.__source[line] = newText 1277 self.__source[line] = newText
1302 return (1, self.trUtf8("Whitespace around comment sign corrected."), 0) 1278 # Whitespace around comment sign corrected.
1279 return (1, "FE261", 0)
1303 1280
1304 def __fixE301(self, code, line, pos, apply=False): 1281 def __fixE301(self, code, line, pos, apply=False):
1305 """ 1282 """
1306 Private method to fix the need for one blank line. 1283 Private method to fix the need for one blank line.
1307 1284
1315 @return value indicating an applied/deferred fix (-1, 0, 1), 1292 @return value indicating an applied/deferred fix (-1, 0, 1),
1316 a message for the fix (string) and an ID for a deferred 1293 a message for the fix (string) and an ID for a deferred
1317 fix (integer) 1294 fix (integer)
1318 """ 1295 """
1319 if apply: 1296 if apply:
1320 self.__source.insert(line - 1, self.__getEol()) 1297 self.__source.insert(line - 1, self.__eol)
1321 return (1, self.trUtf8("One blank line inserted."), 0) 1298 # One blank line inserted.
1299 return (1, "FE301", 0)
1322 else: 1300 else:
1323 id = self.__getID() 1301 id = self.__getID()
1324 self.__stack.append((id, code, line, pos)) 1302 self.__stack.append((id, code, line, pos))
1325 return (-1, "", id) 1303 return (-1, "", id)
1326 1304
1353 1331
1354 line -= 1 1332 line -= 1
1355 if delta < 0: 1333 if delta < 0:
1356 # insert blank lines (one or two) 1334 # insert blank lines (one or two)
1357 while delta < 0: 1335 while delta < 0:
1358 self.__source.insert(line, self.__getEol()) 1336 self.__source.insert(line, self.__eol)
1359 delta += 1 1337 delta += 1
1360 changed = True 1338 # %n blank line(s) inserted.
1339 return (1, ("FE302+", 2 - blanks), 0)
1361 elif delta > 0: 1340 elif delta > 0:
1362 # delete superfluous blank lines 1341 # delete superfluous blank lines
1363 while delta > 0: 1342 while delta > 0:
1364 del self.__source[line - 1] 1343 del self.__source[line - 1]
1365 line -= 1 1344 line -= 1
1366 delta -= 1 1345 delta -= 1
1367 changed = True 1346 # %n superfluous line(s) removed.
1347 return (1, ("FE302-", blanks - 2), 0)
1368 else: 1348 else:
1369 changed = False 1349 return (0, "", 0)
1370
1371 if changed:
1372 if delta < 0:
1373 msg = self.trUtf8(
1374 "%n blank line(s) inserted.", "", -delta)
1375 elif delta > 0:
1376 msg = self.trUtf8(
1377 "%n superfluous lines removed", "", delta)
1378 else:
1379 msg = ""
1380 return (1, msg, 0)
1381 return (0, "", 0)
1382 else: 1350 else:
1383 id = self.__getID() 1351 id = self.__getID()
1384 self.__stack.append((id, code, line, pos)) 1352 self.__stack.append((id, code, line, pos))
1385 return (-1, "", id) 1353 return (-1, "", id)
1386 1354
1405 if self.__source[index].strip() == "": 1373 if self.__source[index].strip() == "":
1406 del self.__source[index] 1374 del self.__source[index]
1407 index -= 1 1375 index -= 1
1408 else: 1376 else:
1409 break 1377 break
1410 return (1, self.trUtf8("Superfluous blank lines removed."), 0) 1378 # Superfluous blank lines removed.
1379 return (1, "FE303", 0)
1411 else: 1380 else:
1412 id = self.__getID() 1381 id = self.__getID()
1413 self.__stack.append((id, code, line, pos)) 1382 self.__stack.append((id, code, line, pos))
1414 return (-1, "", id) 1383 return (-1, "", id)
1415 1384
1435 if self.__source[index].strip() == "": 1404 if self.__source[index].strip() == "":
1436 del self.__source[index] 1405 del self.__source[index]
1437 index -= 1 1406 index -= 1
1438 else: 1407 else:
1439 break 1408 break
1440 return (1, self.trUtf8( 1409 # Superfluous blank lines after function decorator removed.
1441 "Superfluous blank lines after function decorator removed."), 1410 return (1, "FE304", 0)
1442 0)
1443 else: 1411 else:
1444 id = self.__getID() 1412 id = self.__getID()
1445 self.__stack.append((id, code, line, pos)) 1413 self.__stack.append((id, code, line, pos))
1446 return (-1, "", id) 1414 return (-1, "", id)
1447 1415
1470 # statement followed by a semicolon and some unrelated 1438 # statement followed by a semicolon and some unrelated
1471 # statement with commas in it. 1439 # statement with commas in it.
1472 if ';' in text: 1440 if ';' in text:
1473 return (0, "", 0) 1441 return (0, "", 0)
1474 1442
1475 newText = text[:pos].rstrip("\t ,") + self.__getEol() + \ 1443 newText = text[:pos].rstrip("\t ,") + self.__eol + \
1476 self.__getIndent(text) + "import " + text[pos:].lstrip("\t ,") 1444 self.__getIndent(text) + "import " + text[pos:].lstrip("\t ,")
1477 self.__source[line] = newText 1445 self.__source[line] = newText
1478 return (1, self.trUtf8("Imports were put on separate lines."), 0) 1446 # Imports were put on separate lines.
1447 return (1, "FE401", 0)
1479 else: 1448 else:
1480 id = self.__getID() 1449 id = self.__getID()
1481 self.__stack.append((id, code, line, pos)) 1450 self.__stack.append((id, code, line, pos))
1482 return (-1, "", id) 1451 return (-1, "", id)
1483 1452
1510 nextText = self.__source[line + 1] 1479 nextText = self.__source[line + 1]
1511 else: 1480 else:
1512 nextText = "" 1481 nextText = ""
1513 shortener = LineShortener( 1482 shortener = LineShortener(
1514 text, prevText, nextText, 1483 text, prevText, nextText,
1515 maxLength=self.__maxLineLength, eol=self.__getEol(), 1484 maxLength=self.__maxLineLength, eol=self.__eol,
1516 indentWord=self.__indentWord, isDocString=isDocString) 1485 indentWord=self.__indentWord, isDocString=isDocString)
1517 changed, newText, newNextText = shortener.shorten() 1486 changed, newText, newNextText = shortener.shorten()
1518 if changed: 1487 if changed:
1519 if newText != text: 1488 if newText != text:
1520 self.__source[line] = newText 1489 self.__source[line] = newText
1521 if newNextText and newNextText != nextText: 1490 if newNextText and newNextText != nextText:
1522 if newNextText == " ": 1491 if newNextText == " ":
1523 newNextText = "" 1492 newNextText = ""
1524 self.__source[line + 1] = newNextText 1493 self.__source[line + 1] = newNextText
1525 return (1, self.trUtf8("Long lines have been shortened."), 0) 1494 # Long lines have been shortened.
1495 return (1, "FE501", 0)
1526 else: 1496 else:
1527 return (0, "", 0) 1497 return (0, "", 0)
1528 else: 1498 else:
1529 id = self.__getID() 1499 id = self.__getID()
1530 self.__stack.append((id, code, line, pos)) 1500 self.__stack.append((id, code, line, pos))
1542 @return value indicating an applied/deferred fix (-1, 0, 1), 1512 @return value indicating an applied/deferred fix (-1, 0, 1),
1543 a message for the fix (string) and an ID for a deferred 1513 a message for the fix (string) and an ID for a deferred
1544 fix (integer) 1514 fix (integer)
1545 """ 1515 """
1546 self.__source[line - 1] = \ 1516 self.__source[line - 1] = \
1547 self.__source[line - 1].rstrip("\n\r \t\\") + self.__getEol() 1517 self.__source[line - 1].rstrip("\n\r \t\\") + self.__eol
1548 return (1, self.trUtf8("Redundant backslash in brackets removed."), 0) 1518 # Redundant backslash in brackets removed.
1519 return (1, "FE502", 0)
1549 1520
1550 def __fixE701(self, code, line, pos, apply=False): 1521 def __fixE701(self, code, line, pos, apply=False):
1551 """ 1522 """
1552 Private method to fix colon-separated compound statements. 1523 Private method to fix colon-separated compound statements.
1553 1524
1565 if apply: 1536 if apply:
1566 line = line - 1 1537 line = line - 1
1567 text = self.__source[line] 1538 text = self.__source[line]
1568 pos = pos + 1 1539 pos = pos + 1
1569 1540
1570 newText = text[:pos] + self.__getEol() + self.__getIndent(text) + \ 1541 newText = text[:pos] + self.__eol + self.__getIndent(text) + \
1571 self.__indentWord + text[pos:].lstrip("\n\r \t\\") + \ 1542 self.__indentWord + text[pos:].lstrip("\n\r \t\\") + \
1572 self.__getEol() 1543 self.__eol
1573 self.__source[line] = newText 1544 self.__source[line] = newText
1574 return (1, self.trUtf8("Compound statement corrected."), 0) 1545 # Compound statement corrected.
1546 return (1, "FE701", 0)
1575 else: 1547 else:
1576 id = self.__getID() 1548 id = self.__getID()
1577 self.__stack.append((id, code, line, pos)) 1549 self.__stack.append((id, code, line, pos))
1578 return (-1, "", id) 1550 return (-1, "", id)
1579 1551
1599 if text.rstrip().endswith("\\"): 1571 if text.rstrip().endswith("\\"):
1600 # normalize '1; \\\n2' into '1; 2' 1572 # normalize '1; \\\n2' into '1; 2'
1601 self.__source[line] = text.rstrip("\n\r \t\\") 1573 self.__source[line] = text.rstrip("\n\r \t\\")
1602 self.__source[line + 1] = self.__source[line + 1].lstrip() 1574 self.__source[line + 1] = self.__source[line + 1].lstrip()
1603 elif text.rstrip().endswith(";"): 1575 elif text.rstrip().endswith(";"):
1604 self.__source[line] = text.rstrip("\n\r \t;") + self.__getEol() 1576 self.__source[line] = text.rstrip("\n\r \t;") + self.__eol
1605 else: 1577 else:
1606 first = text[:pos].rstrip("\n\r \t;") + self.__getEol() 1578 first = text[:pos].rstrip("\n\r \t;") + self.__eol
1607 second = text[pos:].lstrip("\n\r \t;") 1579 second = text[pos:].lstrip("\n\r \t;")
1608 self.__source[line] = first + self.__getIndent(text) + second 1580 self.__source[line] = first + self.__getIndent(text) + second
1609 return (1, self.trUtf8("Compound statement corrected."), 0) 1581 # Compound statement corrected.
1582 return (1, "FE702", 0)
1610 else: 1583 else:
1611 id = self.__getID() 1584 id = self.__getID()
1612 self.__stack.append((id, code, line, pos)) 1585 self.__stack.append((id, code, line, pos))
1613 return (-1, "", id) 1586 return (-1, "", id)
1614 1587
1645 center = "is not" 1618 center = "is not"
1646 else: 1619 else:
1647 return (0, "", 0) 1620 return (0, "", 0)
1648 1621
1649 self.__source[line] = " ".join([left, center, right]) 1622 self.__source[line] = " ".join([left, center, right])
1650 return (1, self.trUtf8("Comparison to None/True/False corrected."), 0) 1623 # Comparison to None/True/False corrected.
1624 return (1, "FE711", 0)
1651 1625
1652 def __fixN804(self, code, line, pos, apply=False): 1626 def __fixN804(self, code, line, pos, apply=False):
1653 """ 1627 """
1654 Private method to fix a wrong first argument of normal and 1628 Private method to fix a wrong first argument of normal and
1655 class methods. 1629 class methods.
1673 else: 1647 else:
1674 arg = "self" 1648 arg = "self"
1675 1649
1676 if text.rstrip().endswith("("): 1650 if text.rstrip().endswith("("):
1677 newText = text + self.__getIndent(text) + \ 1651 newText = text + self.__getIndent(text) + \
1678 self.__indentWord + arg + "," + self.__getEol() 1652 self.__indentWord + arg + "," + self.__eol
1679 else: 1653 else:
1680 index = text.find("(") + 1 1654 index = text.find("(") + 1
1681 left = text[:index] 1655 left = text[:index]
1682 right = text[index:] 1656 right = text[index:]
1683 if right.startswith(")"): 1657 if right.startswith(")"):
1684 center = arg 1658 center = arg
1685 else: 1659 else:
1686 center = arg + ", " 1660 center = arg + ", "
1687 newText = left + center + right 1661 newText = left + center + right
1688 self.__source[line] = newText 1662 self.__source[line] = newText
1689 return (1, self.trUtf8("'{0}' argument added.").format(arg), 0) 1663 # '{0}' argument added.
1664 return (1, ("FN804", (arg,)), 0)
1690 else: 1665 else:
1691 id = self.__getID() 1666 id = self.__getID()
1692 self.__stack.append((id, code, line, pos)) 1667 self.__stack.append((id, code, line, pos))
1693 return (-1, "", id) 1668 return (-1, "", id)
1694 1669
1744 self.__source[line - 1].rstrip() + right 1719 self.__source[line - 1].rstrip() + right
1745 self.__source[line] = "" 1720 self.__source[line] = ""
1746 else: 1721 else:
1747 self.__source[line] = indent + right 1722 self.__source[line] = indent + right
1748 1723
1749 return (1, self.trUtf8("'{0}' argument removed.").format(arg), 0) 1724 # '{0}' argument removed.
1725 return (1, ("FN806", arg), 0)
1750 else: 1726 else:
1751 id = self.__getID() 1727 id = self.__getID()
1752 self.__stack.append((id, code, line, pos)) 1728 self.__stack.append((id, code, line, pos))
1753 return (-1, "", id) 1729 return (-1, "", id)
1754 1730
1765 a message for the fix (string) and an ID for a deferred 1741 a message for the fix (string) and an ID for a deferred
1766 fix (integer) 1742 fix (integer)
1767 """ 1743 """
1768 self.__source[line - 1] = re.sub(r'[\t ]+(\r?)$', r"\1", 1744 self.__source[line - 1] = re.sub(r'[\t ]+(\r?)$', r"\1",
1769 self.__source[line - 1]) 1745 self.__source[line - 1])
1770 return (1, self.trUtf8("Whitespace stripped from end of line."), 0) 1746 # Whitespace stripped from end of line.
1747 return (1, "FW291", 0)
1771 1748
1772 def __fixW292(self, code, line, pos): 1749 def __fixW292(self, code, line, pos):
1773 """ 1750 """
1774 Private method to fix a missing newline at the end of file. 1751 Private method to fix a missing newline at the end of file.
1775 1752
1780 @param pos position inside line (integer) 1757 @param pos position inside line (integer)
1781 @return value indicating an applied/deferred fix (-1, 0, 1), 1758 @return value indicating an applied/deferred fix (-1, 0, 1),
1782 a message for the fix (string) and an ID for a deferred 1759 a message for the fix (string) and an ID for a deferred
1783 fix (integer) 1760 fix (integer)
1784 """ 1761 """
1785 self.__source[line - 1] += self.__getEol() 1762 self.__source[line - 1] += self.__eol
1786 return (1, self.trUtf8("newline added to end of file."), 0) 1763 # newline added to end of file.
1764 return (1, "FW292", 0)
1787 1765
1788 def __fixW391(self, code, line, pos): 1766 def __fixW391(self, code, line, pos):
1789 """ 1767 """
1790 Private method to fix trailing blank lines. 1768 Private method to fix trailing blank lines.
1791 1769
1803 if self.__source[index].strip() == "": 1781 if self.__source[index].strip() == "":
1804 del self.__source[index] 1782 del self.__source[index]
1805 index -= 1 1783 index -= 1
1806 else: 1784 else:
1807 break 1785 break
1808 return (1, self.trUtf8( 1786 # Superfluous trailing blank lines removed from end of file.
1809 "Superfluous trailing blank lines removed from end of file."), 0) 1787 return (1, "FW391", 0)
1810 1788
1811 def __fixW603(self, code, line, pos): 1789 def __fixW603(self, code, line, pos):
1812 """ 1790 """
1813 Private method to fix the not equal notation. 1791 Private method to fix the not equal notation.
1814 1792
1820 @return value indicating an applied/deferred fix (-1, 0, 1), 1798 @return value indicating an applied/deferred fix (-1, 0, 1),
1821 a message for the fix (string) and an ID for a deferred 1799 a message for the fix (string) and an ID for a deferred
1822 fix (integer) 1800 fix (integer)
1823 """ 1801 """
1824 self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=") 1802 self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=")
1825 return (1, self.trUtf8("'<>' replaced by '!='."), 0) 1803 # '<>' replaced by '!='.
1804 return (1, "FW603", 0)
1826 1805
1827 1806
1828 class Reindenter(object): 1807 class Reindenter(object):
1829 """ 1808 """
1830 Class to reindent badly-indented code to uniformly use four-space 1809 Class to reindent badly-indented code to uniformly use four-space
2041 (list of strings) 2020 (list of strings)
2042 """ 2021 """
2043 self.lines = physical_lines 2022 self.lines = physical_lines
2044 self.tokens = [] 2023 self.tokens = []
2045 self.rel_indent = None 2024 self.rel_indent = None
2046 sio = io.StringIO(''.join(physical_lines)) 2025 sio = StringIO(''.join(physical_lines))
2047 for t in tokenize.generate_tokens(sio.readline): 2026 for t in tokenize.generate_tokens(sio.readline):
2048 if not len(self.tokens) and t[0] in self.SKIP_TOKENS: 2027 if not len(self.tokens) and t[0] in self.SKIP_TOKENS:
2049 continue 2028 continue
2050 if t[0] != tokenize.ENDMARKER: 2029 if t[0] != tokenize.ENDMARKER:
2051 self.tokens.append(t) 2030 self.tokens.append(t)
2336 return True, newText, newNext 2315 return True, newText, newNext
2337 2316
2338 indent = self.__getIndent(self.__text) 2317 indent = self.__getIndent(self.__text)
2339 source = self.__text[len(indent):] 2318 source = self.__text[len(indent):]
2340 assert source.lstrip() == source 2319 assert source.lstrip() == source
2341 sio = io.StringIO(source) 2320 sio = StringIO(source)
2342 2321
2343 # Check for multi line string. 2322 # Check for multi line string.
2344 try: 2323 try:
2345 tokens = list(tokenize.generate_tokens(sio.readline)) 2324 tokens = list(tokenize.generate_tokens(sio.readline))
2346 except (SyntaxError, tokenize.TokenError): 2325 except (SyntaxError, tokenize.TokenError):

eric ide

mercurial