8 """ |
8 """ |
9 |
9 |
10 import os |
10 import os |
11 import re |
11 import re |
12 import tokenize |
12 import tokenize |
|
13 import contextlib |
13 from io import StringIO |
14 from io import StringIO |
14 |
15 |
15 # CodeStyleCheckerDialog tries to import FixableCodeStyleIssues which fails |
16 # CodeStyleCheckerDialog tries to import FixableCodeStyleIssues which fails |
16 # under Python3. So ignore it. |
17 # under Python3. So ignore it. |
17 try: |
18 with contextlib.suppress(ImportError): |
18 import pycodestyle |
19 import pycodestyle |
19 except ImportError: |
|
20 pass |
|
21 |
20 |
22 FixableCodeStyleIssues = [ |
21 FixableCodeStyleIssues = [ |
23 "D111", "D112", "D121", "D131", "D141", "D142", |
22 "D111", "D112", "D121", "D131", "D141", "D142", |
24 "D143", "D144", "D145", |
23 "D143", "D144", "D145", |
25 "D221", "D222", "D231", "D242", "D243", "D244", |
24 "D221", "D222", "D231", "D242", "D243", "D244", |
36 "N804", "N805", "N806", |
35 "N804", "N805", "N806", |
37 "W191", "W291", "W292", "W293", "W391", "W603", |
36 "W191", "W291", "W292", "W293", "W391", "W603", |
38 ] |
37 ] |
39 |
38 |
40 |
39 |
41 class CodeStyleFixer(object): |
40 class CodeStyleFixer: |
42 """ |
41 """ |
43 Class implementing a fixer for certain code style issues. |
42 Class implementing a fixer for certain code style issues. |
44 """ |
43 """ |
45 def __init__(self, filename, sourceLines, fixCodes, noFixCodes, |
44 def __init__(self, filename, sourceLines, fixCodes, noFixCodes, |
46 maxLineLength, blankLines, inPlace, eol, backup=False): |
45 maxLineLength, blankLines, inPlace, eol, backup=False): |
69 @type str |
68 @type str |
70 @param backup flag indicating to create a backup before fixing |
69 @param backup flag indicating to create a backup before fixing |
71 anything |
70 anything |
72 @type bool |
71 @type bool |
73 """ |
72 """ |
74 super(CodeStyleFixer, self).__init__() |
73 super().__init__() |
75 |
74 |
76 self.__filename = filename |
75 self.__filename = filename |
77 self.__origName = "" |
76 self.__origName = "" |
78 self.__source = sourceLines[:] # save a copy |
77 self.__source = sourceLines[:] # save a copy |
79 self.__fixCodes = [c.strip() for c in fixCodes.split(",") if c.strip()] |
78 self.__fixCodes = [c.strip() for c in fixCodes.split(",") if c.strip()] |
207 # create a backup file before writing any changes |
206 # create a backup file before writing any changes |
208 if os.path.islink(self.__filename): |
207 if os.path.islink(self.__filename): |
209 bfn = '{0}~'.format(os.path.realpath(self.__filename)) |
208 bfn = '{0}~'.format(os.path.realpath(self.__filename)) |
210 else: |
209 else: |
211 bfn = '{0}~'.format(self.__filename) |
210 bfn = '{0}~'.format(self.__filename) |
212 try: |
211 with contextlib.suppress(OSError): |
213 os.remove(bfn) |
212 os.remove(bfn) |
214 except OSError: |
213 with contextlib.suppress(OSError): |
215 # if there was an error, ignore it |
|
216 pass |
|
217 try: |
|
218 os.rename(self.__filename, bfn) |
214 os.rename(self.__filename, bfn) |
219 except OSError: |
|
220 # if there was an error, ignore it |
|
221 pass |
|
222 |
215 |
223 txt = "".join(self.__source) |
216 txt = "".join(self.__source) |
224 try: |
217 try: |
225 enc = 'utf-8' if encoding == 'utf-8-bom' else encoding |
218 enc = 'utf-8' if encoding == 'utf-8-bom' else encoding |
226 txt = txt.encode(enc) |
219 txt = txt.encode(enc) |
250 @return flag indicating that one string starts with the other |
243 @return flag indicating that one string starts with the other |
251 (boolean) |
244 (boolean) |
252 """ |
245 """ |
253 return b.startswith(a) or a.startswith(b) |
246 return b.startswith(a) or a.startswith(b) |
254 |
247 |
255 if self.__noFixCodes: |
248 if ( |
256 for noFixCode in [c.strip() for c in self.__noFixCodes]: |
249 self.__noFixCodes and |
257 if mutualStartswith(code.lower(), noFixCode.lower()): |
250 any(mutualStartswith(code.lower(), noFixCode.lower()) |
258 return False |
251 for noFixCode in [c.strip() for c in self.__noFixCodes]) |
|
252 ): |
|
253 return False |
259 |
254 |
260 if self.__fixCodes: |
255 if self.__fixCodes: |
261 for fixCode in [c.strip() for c in self.__fixCodes]: |
256 return any(mutualStartswith(code.lower(), fixCode.lower()) |
262 if mutualStartswith(code.lower(), fixCode.lower()): |
257 for fixCode in [c.strip() for c in self.__fixCodes]) |
263 return True |
|
264 return False |
|
265 |
258 |
266 return True |
259 return True |
267 |
260 |
268 def fixIssue(self, line, pos, code): |
261 def fixIssue(self, line, pos, code): |
269 """ |
262 """ |
376 try: |
369 try: |
377 (logical_start, logical_end) = self.__findLogical() |
370 (logical_start, logical_end) = self.__findLogical() |
378 except (SyntaxError, tokenize.TokenError): |
371 except (SyntaxError, tokenize.TokenError): |
379 return None |
372 return None |
380 |
373 |
381 line = line - 1 |
374 line -= 1 |
382 ls = None |
375 ls = None |
383 le = None |
376 le = None |
384 for i in range(0, len(logical_start)): |
377 for i in range(0, len(logical_start)): |
385 x = logical_end[i] |
378 x = logical_end[i] |
386 if x[0] > line or (x[0] == line and x[1] > pos): |
379 if x[0] > line or (x[0] == line and x[1] > pos): |
399 |
392 |
400 @return string to be used for an indentation (string) |
393 @return string to be used for an indentation (string) |
401 """ |
394 """ |
402 sio = StringIO("".join(self.__source)) |
395 sio = StringIO("".join(self.__source)) |
403 indentWord = " " # default in case of failure |
396 indentWord = " " # default in case of failure |
404 try: |
397 with contextlib.suppress(SyntaxError, tokenize.TokenError): |
405 for token in tokenize.generate_tokens(sio.readline): |
398 for token in tokenize.generate_tokens(sio.readline): |
406 if token[0] == tokenize.INDENT: |
399 if token[0] == tokenize.INDENT: |
407 indentWord = token[1] |
400 indentWord = token[1] |
408 break |
401 break |
409 except (SyntaxError, tokenize.TokenError): |
|
410 pass |
|
411 return indentWord |
402 return indentWord |
412 |
403 |
413 def __getIndent(self, line): |
404 def __getIndent(self, line): |
414 """ |
405 """ |
415 Private method to get the indentation string. |
406 Private method to get the indentation string. |
432 source = "".join(self.__source) |
423 source = "".join(self.__source) |
433 sio = StringIO(source) |
424 sio = StringIO(source) |
434 self.__multiLineNumbers = set() |
425 self.__multiLineNumbers = set() |
435 self.__docLineNumbers = set() |
426 self.__docLineNumbers = set() |
436 previousTokenType = '' |
427 previousTokenType = '' |
437 try: |
428 with contextlib.suppress(SyntaxError, tokenize.TokenError): |
438 for t in tokenize.generate_tokens(sio.readline): |
429 for t in tokenize.generate_tokens(sio.readline): |
439 tokenType = t[0] |
430 tokenType = t[0] |
440 startRow = t[2][0] |
431 startRow = t[2][0] |
441 endRow = t[3][0] |
432 endRow = t[3][0] |
442 |
433 |
447 else: |
438 else: |
448 self.__docLineNumbers |= set( |
439 self.__docLineNumbers |= set( |
449 range(startRow, 1 + endRow)) |
440 range(startRow, 1 + endRow)) |
450 |
441 |
451 previousTokenType = tokenType |
442 previousTokenType = tokenType |
452 except (SyntaxError, tokenize.TokenError): |
|
453 pass |
|
454 |
443 |
455 return self.__multiLineNumbers, self.__docLineNumbers |
444 return self.__multiLineNumbers, self.__docLineNumbers |
456 |
445 |
457 def __fixReindent(self, line, pos, logical): |
446 def __fixReindent(self, line, pos, logical): |
458 """ |
447 """ |
531 @return value indicating an applied/deferred fix (-1, 0, 1), |
520 @return value indicating an applied/deferred fix (-1, 0, 1), |
532 a message code for the fix, a list of arguments for the |
521 a message code for the fix, a list of arguments for the |
533 message and an ID for a deferred fix |
522 message and an ID for a deferred fix |
534 @rtype tuple of (int, str, list or int, int) |
523 @rtype tuple of (int, str, list or int, int) |
535 """ |
524 """ |
536 line = line - 1 |
525 line -= 1 |
537 quotes = re.match(r"""\s*[ru]?('''|'|\")""", |
526 quotes = re.match(r"""\s*[ru]?('''|'|\")""", |
538 self.__source[line]).group(1) |
527 self.__source[line]).group(1) |
539 left, right = self.__source[line].split(quotes, 1) |
528 left, right = self.__source[line].split(quotes, 1) |
540 self.__source[line] = left + '"""' + right |
529 self.__source[line] = left + '"""' + right |
541 while line < len(self.__source): |
530 while line < len(self.__source): |
563 @return value indicating an applied/deferred fix (-1, 0, 1), |
552 @return value indicating an applied/deferred fix (-1, 0, 1), |
564 a message code for the fix, a list of arguments for the |
553 a message code for the fix, a list of arguments for the |
565 message and an ID for a deferred fix |
554 message and an ID for a deferred fix |
566 @rtype tuple of (int, str, list or int, int) |
555 @rtype tuple of (int, str, list or int, int) |
567 """ |
556 """ |
568 line = line - 1 |
557 line -= 1 |
569 if code == "D112": |
558 if code == "D112": |
570 insertChar = "r" |
559 insertChar = "r" |
571 else: |
560 else: |
572 return (0, "", 0) |
561 return (0, "", 0) |
573 |
562 |
598 a message code for the fix, a list of arguments for the |
587 a message code for the fix, a list of arguments for the |
599 message and an ID for a deferred fix |
588 message and an ID for a deferred fix |
600 @rtype tuple of (int, str, list or int, int) |
589 @rtype tuple of (int, str, list or int, int) |
601 """ |
590 """ |
602 if apply: |
591 if apply: |
603 line = line - 1 |
592 line -= 1 |
604 if not self.__source[line].lstrip().startswith( |
593 if not self.__source[line].lstrip().startswith( |
605 ('"""', 'r"""', 'u"""')): |
594 ('"""', 'r"""', 'u"""')): |
606 # only correctly formatted docstrings will be fixed |
595 # only correctly formatted docstrings will be fixed |
607 return (0, "", [], 0) |
596 return (0, "", [], 0) |
608 |
597 |
641 @return value indicating an applied/deferred fix (-1, 0, 1), |
630 @return value indicating an applied/deferred fix (-1, 0, 1), |
642 a message code for the fix, a list of arguments for the |
631 a message code for the fix, a list of arguments for the |
643 message and an ID for a deferred fix |
632 message and an ID for a deferred fix |
644 @rtype tuple of (int, str, list or int, int) |
633 @rtype tuple of (int, str, list or int, int) |
645 """ |
634 """ |
646 line = line - 1 |
635 line -= 1 |
647 newText = "" |
636 newText = "" |
648 if ( |
637 if ( |
649 self.__source[line].rstrip().endswith(('"""', "'''")) and |
638 self.__source[line].rstrip().endswith(('"""', "'''")) and |
650 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')) |
639 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')) |
651 ): |
640 ): |
692 a message code for the fix, a list of arguments for the |
681 a message code for the fix, a list of arguments for the |
693 message and an ID for a deferred fix |
682 message and an ID for a deferred fix |
694 @rtype tuple of (int, str, list or int, int) |
683 @rtype tuple of (int, str, list or int, int) |
695 """ |
684 """ |
696 if apply: |
685 if apply: |
697 line = line - 1 |
686 line -= 1 |
698 self.__source[line - 1] = "" |
687 self.__source[line - 1] = "" |
699 # Blank line before function/method docstring removed. |
688 # Blank line before function/method docstring removed. |
700 return (1, "FIXD141", [], 0) |
689 return (1, "FIXD141", [], 0) |
701 else: |
690 else: |
702 fixId = self.__getID() |
691 fixId = self.__getID() |
722 a message code for the fix, a list of arguments for the |
711 a message code for the fix, a list of arguments for the |
723 message and an ID for a deferred fix |
712 message and an ID for a deferred fix |
724 @rtype tuple of (int, str, list or int, int) |
713 @rtype tuple of (int, str, list or int, int) |
725 """ |
714 """ |
726 if apply: |
715 if apply: |
727 line = line - 1 |
716 line -= 1 |
728 self.__source[line] = self.__eol + self.__source[line] |
717 self.__source[line] = self.__eol + self.__source[line] |
729 # Blank line inserted before class docstring. |
718 # Blank line inserted before class docstring. |
730 return (1, "FIXD142", [], 0) |
719 return (1, "FIXD142", [], 0) |
731 else: |
720 else: |
732 fixId = self.__getID() |
721 fixId = self.__getID() |
752 a message code for the fix, a list of arguments for the |
741 a message code for the fix, a list of arguments for the |
753 message and an ID for a deferred fix |
742 message and an ID for a deferred fix |
754 @rtype tuple of (int, str, list or int, int) |
743 @rtype tuple of (int, str, list or int, int) |
755 """ |
744 """ |
756 if apply: |
745 if apply: |
757 line = line - 1 |
746 line -= 1 |
758 self.__source[line] += self.__eol |
747 self.__source[line] += self.__eol |
759 # Blank line inserted after class docstring. |
748 # Blank line inserted after class docstring. |
760 return (1, "FIXD143", [], 0) |
749 return (1, "FIXD143", [], 0) |
761 else: |
750 else: |
762 fixId = self.__getID() |
751 fixId = self.__getID() |
782 a message code for the fix, a list of arguments for the |
771 a message code for the fix, a list of arguments for the |
783 message and an ID for a deferred fix |
772 message and an ID for a deferred fix |
784 @rtype tuple of (int, str, list or int, int) |
773 @rtype tuple of (int, str, list or int, int) |
785 """ |
774 """ |
786 if apply: |
775 if apply: |
787 line = line - 1 |
776 line -= 1 |
788 if not self.__source[line].rstrip().endswith("."): |
777 if not self.__source[line].rstrip().endswith("."): |
789 # only correct summary lines can be fixed here |
778 # only correct summary lines can be fixed here |
790 return (0, "", 0) |
779 return (0, "", 0) |
791 |
780 |
792 self.__source[line] += self.__eol |
781 self.__source[line] += self.__eol |
816 a message code for the fix, a list of arguments for the |
805 a message code for the fix, a list of arguments for the |
817 message and an ID for a deferred fix |
806 message and an ID for a deferred fix |
818 @rtype tuple of (int, str, list or int, int) |
807 @rtype tuple of (int, str, list or int, int) |
819 """ |
808 """ |
820 if apply: |
809 if apply: |
821 line = line - 1 |
810 line -= 1 |
822 self.__source[line] = self.__eol + self.__source[line] |
811 self.__source[line] = self.__eol + self.__source[line] |
823 # Blank line inserted after last paragraph of docstring. |
812 # Blank line inserted after last paragraph of docstring. |
824 return (1, "FIXD145", [], 0) |
813 return (1, "FIXD145", [], 0) |
825 else: |
814 else: |
826 fixId = self.__getID() |
815 fixId = self.__getID() |
846 a message code for the fix, a list of arguments for the |
835 a message code for the fix, a list of arguments for the |
847 message and an ID for a deferred fix |
836 message and an ID for a deferred fix |
848 @rtype tuple of (int, str, list or int, int) |
837 @rtype tuple of (int, str, list or int, int) |
849 """ |
838 """ |
850 if apply: |
839 if apply: |
851 line = line - 1 |
840 line -= 1 |
852 indent = self.__getIndent(self.__source[line]) |
841 indent = self.__getIndent(self.__source[line]) |
853 source = self.__source[line].strip() |
842 source = self.__source[line].strip() |
854 if code == "D221": |
843 if code == "D221": |
855 # leading |
844 # leading |
856 if source.startswith(("r", "u")): |
845 if source.startswith(("r", "u")): |
900 a message code for the fix, a list of arguments for the |
889 a message code for the fix, a list of arguments for the |
901 message and an ID for a deferred fix |
890 message and an ID for a deferred fix |
902 @rtype tuple of (int, str, list or int, int) |
891 @rtype tuple of (int, str, list or int, int) |
903 """ |
892 """ |
904 if apply: |
893 if apply: |
905 line = line - 1 |
894 line -= 1 |
906 self.__source[line - 1] = "" |
895 self.__source[line - 1] = "" |
907 if code == "D242": |
896 if code == "D242": |
908 # Blank line before class docstring removed. |
897 # Blank line before class docstring removed. |
909 msg = "FIXD242" |
898 msg = "FIXD242" |
910 else: |
899 else: |
935 a message code for the fix, a list of arguments for the |
924 a message code for the fix, a list of arguments for the |
936 message and an ID for a deferred fix |
925 message and an ID for a deferred fix |
937 @rtype tuple of (int, str, list or int, int) |
926 @rtype tuple of (int, str, list or int, int) |
938 """ |
927 """ |
939 if apply: |
928 if apply: |
940 line = line - 1 |
929 line -= 1 |
941 self.__source[line + 1] = "" |
930 self.__source[line + 1] = "" |
942 if code == "D243": |
931 if code == "D243": |
943 # Blank line after class docstring removed. |
932 # Blank line after class docstring removed. |
944 msg = "FIXD243" |
933 msg = "FIXD243" |
945 else: |
934 else: |
970 a message code for the fix, a list of arguments for the |
959 a message code for the fix, a list of arguments for the |
971 message and an ID for a deferred fix |
960 message and an ID for a deferred fix |
972 @rtype tuple of (int, str, list or int, int) |
961 @rtype tuple of (int, str, list or int, int) |
973 """ |
962 """ |
974 if apply: |
963 if apply: |
975 line = line - 1 |
964 line -= 1 |
976 self.__source[line - 1] = "" |
965 self.__source[line - 1] = "" |
977 # Blank line after last paragraph removed. |
966 # Blank line after last paragraph removed. |
978 return (1, "FIXD247", [], 0) |
967 return (1, "FIXD247", [], 0) |
979 else: |
968 else: |
980 fixId = self.__getID() |
969 fixId = self.__getID() |
1077 if logical: |
1066 if logical: |
1078 # Fix by adding an initial indent. |
1067 # Fix by adding an initial indent. |
1079 modified = self.__fixReindent(line, pos, logical) |
1068 modified = self.__fixReindent(line, pos, logical) |
1080 if not modified: |
1069 if not modified: |
1081 # fall back to simple method |
1070 # fall back to simple method |
1082 line = line - 1 |
1071 line -= 1 |
1083 text = self.__source[line] |
1072 text = self.__source[line] |
1084 indentation = self.__getIndent(text) |
1073 indentation = self.__getIndent(text) |
1085 self.__source[line] = ( |
1074 self.__source[line] = ( |
1086 indentation + |
1075 indentation + |
1087 self.__indentWord + text.lstrip() |
1076 self.__indentWord + text.lstrip() |
1299 @return value indicating an applied/deferred fix (-1, 0, 1), |
1288 @return value indicating an applied/deferred fix (-1, 0, 1), |
1300 a message code for the fix, a list of arguments for the |
1289 a message code for the fix, a list of arguments for the |
1301 message and an ID for a deferred fix |
1290 message and an ID for a deferred fix |
1302 @rtype tuple of (int, str, list or int, int) |
1291 @rtype tuple of (int, str, list or int, int) |
1303 """ |
1292 """ |
1304 line = line - 1 |
1293 line -= 1 |
1305 text = self.__source[line] |
1294 text = self.__source[line] |
1306 |
1295 |
1307 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1296 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1308 return (0, "", [], 0) |
1297 return (0, "", [], 0) |
1309 |
1298 |
1331 @return value indicating an applied/deferred fix (-1, 0, 1), |
1320 @return value indicating an applied/deferred fix (-1, 0, 1), |
1332 a message code for the fix, a list of arguments for the |
1321 a message code for the fix, a list of arguments for the |
1333 message and an ID for a deferred fix |
1322 message and an ID for a deferred fix |
1334 @rtype tuple of (int, str, list or int, int) |
1323 @rtype tuple of (int, str, list or int, int) |
1335 """ |
1324 """ |
1336 line = line - 1 |
1325 line -= 1 |
1337 text = self.__source[line] |
1326 text = self.__source[line] |
1338 |
1327 |
1339 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1328 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1340 return (0, "", [], 0) |
1329 return (0, "", [], 0) |
1341 |
1330 |
1361 @return value indicating an applied/deferred fix (-1, 0, 1), |
1350 @return value indicating an applied/deferred fix (-1, 0, 1), |
1362 a message code for the fix, a list of arguments for the |
1351 a message code for the fix, a list of arguments for the |
1363 message and an ID for a deferred fix |
1352 message and an ID for a deferred fix |
1364 @rtype tuple of (int, str, list or int, int) |
1353 @rtype tuple of (int, str, list or int, int) |
1365 """ |
1354 """ |
1366 line = line - 1 |
1355 line -= 1 |
1367 text = self.__source[line] |
1356 text = self.__source[line] |
1368 |
1357 |
1369 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1358 if '"""' in text or "'''" in text or text.rstrip().endswith('\\'): |
1370 return (0, "", [], 0) |
1359 return (0, "", [], 0) |
1371 |
1360 |
1406 @return value indicating an applied/deferred fix (-1, 0, 1), |
1395 @return value indicating an applied/deferred fix (-1, 0, 1), |
1407 a message code for the fix, a list of arguments for the |
1396 a message code for the fix, a list of arguments for the |
1408 message and an ID for a deferred fix |
1397 message and an ID for a deferred fix |
1409 @rtype tuple of (int, str, list or int, int) |
1398 @rtype tuple of (int, str, list or int, int) |
1410 """ |
1399 """ |
1411 line = line - 1 |
1400 line -= 1 |
1412 pos = pos + 1 |
1401 pos += 1 |
1413 self.__source[line] = ( |
1402 self.__source[line] = ( |
1414 self.__source[line][:pos] + |
1403 self.__source[line][:pos] + |
1415 " " + |
1404 " " + |
1416 self.__source[line][pos:] |
1405 self.__source[line][pos:] |
1417 ) |
1406 ) |
1434 @return value indicating an applied/deferred fix (-1, 0, 1), |
1423 @return value indicating an applied/deferred fix (-1, 0, 1), |
1435 a message code for the fix, a list of arguments for the |
1424 a message code for the fix, a list of arguments for the |
1436 message and an ID for a deferred fix |
1425 message and an ID for a deferred fix |
1437 @rtype tuple of (int, str, list or int, int) |
1426 @rtype tuple of (int, str, list or int, int) |
1438 """ |
1427 """ |
1439 line = line - 1 |
1428 line -= 1 |
1440 text = self.__source[line] |
1429 text = self.__source[line] |
1441 |
1430 |
1442 # This is necessary since pycodestyle sometimes reports columns that |
1431 # This is necessary since pycodestyle sometimes reports columns that |
1443 # goes past the end of the physical line. This happens in cases like, |
1432 # goes past the end of the physical line. This happens in cases like, |
1444 # foo(bar\n=None) |
1433 # foo(bar\n=None) |
1445 col = min(pos, len(text) - 1) |
1434 col = min(pos, len(text) - 1) |
1446 if text[col].strip(): |
1435 newText = ( |
1447 newText = text |
1436 text |
1448 else: |
1437 if text[col].strip() else |
1449 newText = text[:col].rstrip() + text[col:].lstrip() |
1438 text[:col].rstrip() + text[col:].lstrip() |
|
1439 ) |
1450 |
1440 |
1451 # There could be an escaped newline |
1441 # There could be an escaped newline |
1452 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')): |
1442 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')): |
1453 self.__source[line] = newText.rstrip("\n\r \t\\") |
1443 self.__source[line] = newText.rstrip("\n\r \t\\") |
1454 self.__source[line + 1] = self.__source[line + 1].lstrip() |
1444 self.__source[line + 1] = self.__source[line + 1].lstrip() |
1472 @return value indicating an applied/deferred fix (-1, 0, 1), |
1462 @return value indicating an applied/deferred fix (-1, 0, 1), |
1473 a message code for the fix, a list of arguments for the |
1463 a message code for the fix, a list of arguments for the |
1474 message and an ID for a deferred fix |
1464 message and an ID for a deferred fix |
1475 @rtype tuple of (int, str, list or int, int) |
1465 @rtype tuple of (int, str, list or int, int) |
1476 """ |
1466 """ |
1477 line = line - 1 |
1467 line -= 1 |
1478 text = self.__source[line] |
1468 text = self.__source[line] |
1479 left = text[:pos].rstrip(' \t#') |
1469 left = text[:pos].rstrip(' \t#') |
1480 right = text[pos:].lstrip(' \t#') |
1470 right = text[pos:].lstrip(' \t#') |
1481 newText = left + (" # " + right if right.strip() else right) |
1471 newText = left + (" # " + right if right.strip() else right) |
1482 self.__source[line] = newText |
1472 self.__source[line] = newText |
1598 a message code for the fix, a list of arguments for the |
1588 a message code for the fix, a list of arguments for the |
1599 message and an ID for a deferred fix |
1589 message and an ID for a deferred fix |
1600 @rtype tuple of (int, str, list or int, int) |
1590 @rtype tuple of (int, str, list or int, int) |
1601 """ |
1591 """ |
1602 if apply: |
1592 if apply: |
1603 line = line - 1 |
1593 line -= 1 |
1604 text = self.__source[line] |
1594 text = self.__source[line] |
1605 if not text.lstrip().startswith("import"): |
1595 if not text.lstrip().startswith("import"): |
1606 return (0, "", [], 0) |
1596 return (0, "", [], 0) |
1607 |
1597 |
1608 # pycodestyle (1.3.1) reports false positive if there is an import |
1598 # pycodestyle (1.3.1) reports false positive if there is an import |
1648 if apply: |
1638 if apply: |
1649 multilineStringLines, docStringLines = ( |
1639 multilineStringLines, docStringLines = ( |
1650 self.__multilineStringLines() |
1640 self.__multilineStringLines() |
1651 ) |
1641 ) |
1652 isDocString = line in docStringLines |
1642 isDocString = line in docStringLines |
1653 line = line - 1 |
1643 line -= 1 |
1654 text = self.__source[line] |
1644 text = self.__source[line] |
1655 if line > 0: |
1645 if line > 0: |
1656 prevText = self.__source[line - 1] |
1646 prevText = self.__source[line - 1] |
1657 else: |
1647 else: |
1658 prevText = "" |
1648 prevText = "" |
1723 a message code for the fix, a list of arguments for the |
1713 a message code for the fix, a list of arguments for the |
1724 message and an ID for a deferred fix |
1714 message and an ID for a deferred fix |
1725 @rtype tuple of (int, str, list or int, int) |
1715 @rtype tuple of (int, str, list or int, int) |
1726 """ |
1716 """ |
1727 if apply: |
1717 if apply: |
1728 line = line - 1 |
1718 line -= 1 |
1729 text = self.__source[line] |
1719 text = self.__source[line] |
1730 pos = pos + 1 |
1720 pos += 1 |
1731 |
1721 |
1732 newText = ( |
1722 newText = ( |
1733 text[:pos] + |
1723 text[:pos] + |
1734 self.__eol + |
1724 self.__eol + |
1735 self.__getIndent(text) + |
1725 self.__getIndent(text) + |
1763 a message code for the fix, a list of arguments for the |
1753 a message code for the fix, a list of arguments for the |
1764 message and an ID for a deferred fix |
1754 message and an ID for a deferred fix |
1765 @rtype tuple of (int, str, list or int, int) |
1755 @rtype tuple of (int, str, list or int, int) |
1766 """ |
1756 """ |
1767 if apply: |
1757 if apply: |
1768 line = line - 1 |
1758 line -= 1 |
1769 text = self.__source[line] |
1759 text = self.__source[line] |
1770 |
1760 |
1771 if text.rstrip().endswith("\\"): |
1761 if text.rstrip().endswith("\\"): |
1772 # normalize '1; \\\n2' into '1; 2' |
1762 # normalize '1; \\\n2' into '1; 2' |
1773 self.__source[line] = text.rstrip("\n\r \t\\") |
1763 self.__source[line] = text.rstrip("\n\r \t\\") |
1800 @return value indicating an applied/deferred fix (-1, 0, 1), |
1790 @return value indicating an applied/deferred fix (-1, 0, 1), |
1801 a message code for the fix, a list of arguments for the |
1791 a message code for the fix, a list of arguments for the |
1802 message and an ID for a deferred fix |
1792 message and an ID for a deferred fix |
1803 @rtype tuple of (int, str, list or int, int) |
1793 @rtype tuple of (int, str, list or int, int) |
1804 """ |
1794 """ |
1805 line = line - 1 |
1795 line -= 1 |
1806 text = self.__source[line] |
1796 text = self.__source[line] |
1807 |
1797 |
1808 rightPos = pos + 2 |
1798 rightPos = pos + 2 |
1809 if rightPos >= len(text): |
1799 if rightPos >= len(text): |
1810 return (0, "", 0) |
1800 return (0, "", 0) |
1846 a message code for the fix, a list of arguments for the |
1836 a message code for the fix, a list of arguments for the |
1847 message and an ID for a deferred fix |
1837 message and an ID for a deferred fix |
1848 @rtype tuple of (int, str, list or int, int) |
1838 @rtype tuple of (int, str, list or int, int) |
1849 """ |
1839 """ |
1850 if apply: |
1840 if apply: |
1851 line = line - 1 |
1841 line -= 1 |
1852 text = self.__source[line] |
1842 text = self.__source[line] |
1853 if code == "N804": |
1843 if code == "N804": |
1854 arg = "cls" |
1844 arg = "cls" |
1855 else: |
1845 else: |
1856 arg = "self" |
1846 arg = "self" |
1899 a message code for the fix, a list of arguments for the |
1889 a message code for the fix, a list of arguments for the |
1900 message and an ID for a deferred fix |
1890 message and an ID for a deferred fix |
1901 @rtype tuple of (int, str, list or int, int) |
1891 @rtype tuple of (int, str, list or int, int) |
1902 """ |
1892 """ |
1903 if apply: |
1893 if apply: |
1904 line = line - 1 |
1894 line -= 1 |
1905 text = self.__source[line] |
1895 text = self.__source[line] |
1906 index = text.find("(") + 1 |
1896 index = text.find("(") + 1 |
1907 left = text[:index] |
1897 left = text[:index] |
1908 right = text[index:] |
1898 right = text[index:] |
1909 |
1899 |
1918 right = right.lstrip(", ") |
1908 right = right.lstrip(", ") |
1919 newText = left + right |
1909 newText = left + right |
1920 self.__source[line] = newText |
1910 self.__source[line] = newText |
1921 else: |
1911 else: |
1922 # they are on the next line |
1912 # they are on the next line |
1923 line = line + 1 |
1913 line += 1 |
1924 text = self.__source[line] |
1914 text = self.__source[line] |
1925 indent = self.__getIndent(text) |
1915 indent = self.__getIndent(text) |
1926 right = text.lstrip() |
1916 right = text.lstrip() |
1927 if right.startswith("cls"): |
1917 if right.startswith("cls"): |
1928 right = right[3:] |
1918 right = right[3:] |
2037 self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=") |
2027 self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=") |
2038 # '<>' replaced by '!='. |
2028 # '<>' replaced by '!='. |
2039 return (1, "FIXW603", [], 0) |
2029 return (1, "FIXW603", [], 0) |
2040 |
2030 |
2041 |
2031 |
2042 class Reindenter(object): |
2032 class Reindenter: |
2043 """ |
2033 """ |
2044 Class to reindent badly-indented code to uniformly use four-space |
2034 Class to reindent badly-indented code to uniformly use four-space |
2045 indentation. |
2035 indentation. |
2046 |
2036 |
2047 Released to the public domain, by Tim Peters, 03 October 2000. |
2037 Released to the public domain, by Tim Peters, 03 October 2000. |
2419 ) |
2409 ) |
2420 hang = rel_indent[row] - rel_indent[open_row] |
2410 hang = rel_indent[row] - rel_indent[open_row] |
2421 |
2411 |
2422 if token_type == tokenize.OP and text in ']})': |
2412 if token_type == tokenize.OP and text in ']})': |
2423 pass |
2413 pass |
2424 elif visual_indent is True: |
2414 elif visual_indent is True and not indent[depth]: |
2425 if not indent[depth]: |
2415 indent[depth] = start[1] |
2426 indent[depth] = start[1] |
|
2427 |
2416 |
2428 # line altered: comments shouldn't define a visual indent |
2417 # line altered: comments shouldn't define a visual indent |
2429 if parens[row] and not indent[depth] and token_type not in ( |
2418 if parens[row] and not indent[depth] and token_type not in ( |
2430 tokenize.NL, tokenize.COMMENT |
2419 tokenize.NL, tokenize.COMMENT |
2431 ): |
2420 ): |
2462 last_token_multiline = (start[0] != end[0]) |
2451 last_token_multiline = (start[0] != end[0]) |
2463 |
2452 |
2464 return valid_indents |
2453 return valid_indents |
2465 |
2454 |
2466 |
2455 |
2467 class LineShortener(object): |
2456 class LineShortener: |
2468 """ |
2457 """ |
2469 Class used to shorten lines to a given maximum of characters. |
2458 Class used to shorten lines to a given maximum of characters. |
2470 """ |
2459 """ |
2471 def __init__(self, curLine, prevLine, nextLine, maxLength=79, eol="\n", |
2460 def __init__(self, curLine, prevLine, nextLine, maxLength=79, eol="\n", |
2472 indentWord=" ", isDocString=False): |
2461 indentWord=" ", isDocString=False): |
2882 badStartingSymbol = { |
2871 badStartingSymbol = { |
2883 '(': ')', |
2872 '(': ')', |
2884 '[': ']', |
2873 '[': ']', |
2885 '{': '}'}.get(lines[0][-1], None) |
2874 '{': '}'}.get(lines[0][-1], None) |
2886 |
2875 |
2887 if len(lines) > 1: |
2876 if ( |
2888 if (badStartingSymbol and |
2877 len(lines) > 1 and |
2889 lines[1].lstrip().startswith(badStartingSymbol)): |
2878 badStartingSymbol and |
2890 rank += 20 |
2879 lines[1].lstrip().startswith(badStartingSymbol) |
|
2880 ): |
|
2881 rank += 20 |
2891 |
2882 |
2892 if re.match(r".*[+\-\*/] \($", lines[0]): |
2883 if re.match(r".*[+\-\*/] \($", lines[0]): |
2893 # "1 * (\n" is ugly as hell. |
2884 # "1 * (\n" is ugly as hell. |
2894 rank += 100 |
2885 rank += 100 |
2895 |
2886 |