eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleFixer.py

changeset 7256
4ef3b78ebb4e
parent 7249
0bf517e60f54
child 7360
9190402e4505
equal deleted inserted replaced
7255:d595f6f9cbf8 7256:4ef3b78ebb4e
286 if isinstance(message, (tuple, list)): 286 if isinstance(message, (tuple, list)):
287 code = message[0].strip() 287 code = message[0].strip()
288 else: 288 else:
289 code = message.split(None, 1)[0].strip() 289 code = message.split(None, 1)[0].strip()
290 290
291 if line <= len(self.__source) and \ 291 if (
292 self.__codeMatch(code) and \ 292 line <= len(self.__source) and
293 code in self.__fixes: 293 self.__codeMatch(code) and
294 code in self.__fixes
295 ):
294 res = self.__fixes[code](code, line, pos) 296 res = self.__fixes[code](code, line, pos)
295 if res[0] == 1: 297 if res[0] == 1:
296 self.__modified = True 298 self.__modified = True
297 self.fixed += 1 299 self.fixed += 1
298 else: 300 else:
566 elif code == "D113": 568 elif code == "D113":
567 insertChar = "u" 569 insertChar = "u"
568 else: 570 else:
569 return (0, "", 0) 571 return (0, "", 0)
570 572
571 newText = self.__getIndent(self.__source[line]) + \ 573 newText = (
572 insertChar + self.__source[line].lstrip() 574 self.__getIndent(self.__source[line]) +
575 insertChar +
576 self.__source[line].lstrip()
577 )
573 self.__source[line] = newText 578 self.__source[line] = newText
574 # Introductory quotes corrected to be {0}""" 579 # Introductory quotes corrected to be {0}"""
575 return (1, ('FD112', (insertChar,)), 0) 580 return (1, ('FD112', (insertChar,)), 0)
576 581
577 def __fixD121(self, code, line, pos, apply=False): 582 def __fixD121(self, code, line, pos, apply=False):
594 if not self.__source[line].lstrip().startswith( 599 if not self.__source[line].lstrip().startswith(
595 ('"""', 'r"""', 'u"""')): 600 ('"""', 'r"""', 'u"""')):
596 # only correctly formatted docstrings will be fixed 601 # only correctly formatted docstrings will be fixed
597 return (0, "", 0) 602 return (0, "", 0)
598 603
599 docstring = self.__source[line].rstrip() + \ 604 docstring = (
605 self.__source[line].rstrip() +
600 self.__source[line + 1].strip() 606 self.__source[line + 1].strip()
607 )
601 if docstring.endswith('"""'): 608 if docstring.endswith('"""'):
602 docstring += self.__eol 609 docstring += self.__eol
603 else: 610 else:
604 docstring += self.__source[line + 2].lstrip() 611 docstring += self.__source[line + 2].lstrip()
605 self.__source[line + 2] = "" 612 self.__source[line + 2] = ""
627 a message for the fix (string) and an ID for a deferred 634 a message for the fix (string) and an ID for a deferred
628 fix (integer) 635 fix (integer)
629 """ 636 """
630 line = line - 1 637 line = line - 1
631 newText = "" 638 newText = ""
632 if self.__source[line].rstrip().endswith(('"""', "'''")) and \ 639 if (
633 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')): 640 self.__source[line].rstrip().endswith(('"""', "'''")) and
641 self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""'))
642 ):
634 # it is a one-liner 643 # it is a one-liner
635 newText = self.__source[line].rstrip()[:-3].rstrip() + "." + \ 644 newText = (
636 self.__source[line].rstrip()[-3:] + self.__eol 645 self.__source[line].rstrip()[:-3].rstrip() +
637 else: 646 "." +
638 if line < len(self.__source) - 1 and \ 647 self.__source[line].rstrip()[-3:] +
648 self.__eol
649 )
650 else:
651 if (
652 line < len(self.__source) - 1 and
639 (not self.__source[line + 1].strip() or 653 (not self.__source[line + 1].strip() or
640 self.__source[line + 1].lstrip().startswith("@") or 654 self.__source[line + 1].lstrip().startswith("@") or
641 (self.__source[line + 1].strip() in ('"""', "'''") and 655 (self.__source[line + 1].strip() in ('"""', "'''") and
642 not self.__source[line].lstrip().startswith("@"))): 656 not self.__source[line].lstrip().startswith("@")))
657 ):
643 newText = self.__source[line].rstrip() + "." + self.__eol 658 newText = self.__source[line].rstrip() + "." + self.__eol
644 659
645 if newText: 660 if newText:
646 self.__source[line] = newText 661 self.__source[line] = newText
647 # Period added to summary line. 662 # Period added to summary line.
810 else: 825 else:
811 first, second = source[:3], source[3:].strip() 826 first, second = source[:3], source[3:].strip()
812 else: 827 else:
813 # trailing 828 # trailing
814 first, second = source[:-3].strip(), source[-3:] 829 first, second = source[:-3].strip(), source[-3:]
815 newText = indent + first + self.__eol + \ 830 newText = (
816 indent + second + self.__eol 831 indent +
832 first +
833 self.__eol +
834 indent +
835 second +
836 self.__eol
837 )
817 self.__source[line] = newText 838 self.__source[line] = newText
818 if code == "D221": 839 if code == "D221":
819 # Leading quotes put on separate line. 840 # Leading quotes put on separate line.
820 msg = "FD221" 841 msg = "FD221"
821 else: 842 else:
1002 if not modified: 1023 if not modified:
1003 # fall back to simple method 1024 # fall back to simple method
1004 line = line - 1 1025 line = line - 1
1005 text = self.__source[line] 1026 text = self.__source[line]
1006 indentation = self.__getIndent(text) 1027 indentation = self.__getIndent(text)
1007 self.__source[line] = indentation + \ 1028 self.__source[line] = (
1029 indentation +
1008 self.__indentWord + text.lstrip() 1030 self.__indentWord + text.lstrip()
1031 )
1009 # Missing indentation of continuation line corrected. 1032 # Missing indentation of continuation line corrected.
1010 return (1, "FE122", 0) 1033 return (1, "FE122", 0)
1011 return (0, "", 0) 1034 return (0, "", 0)
1012 else: 1035 else:
1013 fixId = self.__getID() 1036 fixId = self.__getID()
1074 # Fix by adjusting initial indent level. 1097 # Fix by adjusting initial indent level.
1075 modified = self.__fixReindent(line, pos, logical) 1098 modified = self.__fixReindent(line, pos, logical)
1076 if not modified: 1099 if not modified:
1077 row = line - 1 1100 row = line - 1
1078 text = self.__source[row] 1101 text = self.__source[row]
1079 self.__source[row] = self.__getIndent(text) + \ 1102 self.__source[row] = (
1103 self.__getIndent(text) +
1080 self.__indentWord + text.lstrip() 1104 self.__indentWord + text.lstrip()
1105 )
1081 # Indentation level changed. 1106 # Indentation level changed.
1082 return (1, "FE125", 0) 1107 return (1, "FE125", 0)
1083 return (0, "", 0) 1108 return (0, "", 0)
1084 else: 1109 else:
1085 fixId = self.__getID() 1110 fixId = self.__getID()
1107 if logical: 1132 if logical:
1108 # Fix by deleting whitespace to the left. 1133 # Fix by deleting whitespace to the left.
1109 logicalLines = logical[2] 1134 logicalLines = logical[2]
1110 row = line - 1 1135 row = line - 1
1111 text = self.__source[row] 1136 text = self.__source[row]
1112 newText = self.__getIndent(logicalLines[0]) + \ 1137 newText = (
1138 self.__getIndent(logicalLines[0]) +
1113 self.__indentWord + text.lstrip() 1139 self.__indentWord + text.lstrip()
1140 )
1114 if newText == text: 1141 if newText == text:
1115 # fall back to slower method 1142 # fall back to slower method
1116 changed = self.__fixReindent(line, pos, logical) 1143 changed = self.__fixReindent(line, pos, logical)
1117 else: 1144 else:
1118 self.__source[row] = newText 1145 self.__source[row] = newText
1149 row = line - 1 1176 row = line - 1
1150 text = self.__source[row] 1177 text = self.__source[row]
1151 newText = text 1178 newText = text
1152 1179
1153 if logicalLines[0].rstrip().endswith('\\'): 1180 if logicalLines[0].rstrip().endswith('\\'):
1154 newText = self.__getIndent(logicalLines[0]) + \ 1181 newText = (
1155 self.__indentWord + text.lstrip() 1182 self.__getIndent(logicalLines[0]) +
1183 self.__indentWord +
1184 text.lstrip()
1185 )
1156 else: 1186 else:
1157 startIndex = None 1187 startIndex = None
1158 for symbol in '([{': 1188 for symbol in '([{':
1159 if symbol in logicalLines[0]: 1189 if symbol in logicalLines[0]:
1160 foundIndex = logicalLines[0].find(symbol) + 1 1190 foundIndex = logicalLines[0].find(symbol) + 1
1289 a message for the fix (string) and an ID for a deferred 1319 a message for the fix (string) and an ID for a deferred
1290 fix (integer) 1320 fix (integer)
1291 """ 1321 """
1292 line = line - 1 1322 line = line - 1
1293 pos = pos + 1 1323 pos = pos + 1
1294 self.__source[line] = self.__source[line][:pos] + \ 1324 self.__source[line] = (
1295 " " + self.__source[line][pos:] 1325 self.__source[line][:pos] +
1326 " " +
1327 self.__source[line][pos:]
1328 )
1296 # Missing whitespace added. 1329 # Missing whitespace added.
1297 return (1, "FE231", 0) 1330 return (1, "FE231", 0)
1298 1331
1299 def __fixE251(self, code, line, pos): 1332 def __fixE251(self, code, line, pos):
1300 """ 1333 """
1321 newText = text 1354 newText = text
1322 else: 1355 else:
1323 newText = text[:col].rstrip() + text[col:].lstrip() 1356 newText = text[:col].rstrip() + text[col:].lstrip()
1324 1357
1325 # There could be an escaped newline 1358 # There could be an escaped newline
1326 # like 'def foo(a=\
1327 # 1)'
1328 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')): 1359 if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')):
1329 self.__source[line] = newText.rstrip("\n\r \t\\") 1360 self.__source[line] = newText.rstrip("\n\r \t\\")
1330 self.__source[line + 1] = self.__source[line + 1].lstrip() 1361 self.__source[line + 1] = self.__source[line + 1].lstrip()
1331 else: 1362 else:
1332 self.__source[line] = newText 1363 self.__source[line] = newText
1469 # statement followed by a semicolon and some unrelated 1500 # statement followed by a semicolon and some unrelated
1470 # statement with commas in it. 1501 # statement with commas in it.
1471 if ';' in text: 1502 if ';' in text:
1472 return (0, "", 0) 1503 return (0, "", 0)
1473 1504
1474 newText = text[:pos].rstrip("\t ,") + self.__eol + \ 1505 newText = (
1475 self.__getIndent(text) + "import " + text[pos:].lstrip("\t ,") 1506 text[:pos].rstrip("\t ,") +
1507 self.__eol +
1508 self.__getIndent(text) +
1509 "import " +
1510 text[pos:].lstrip("\t ,")
1511 )
1476 self.__source[line] = newText 1512 self.__source[line] = newText
1477 # Imports were put on separate lines. 1513 # Imports were put on separate lines.
1478 return (1, "FE401", 0) 1514 return (1, "FE401", 0)
1479 else: 1515 else:
1480 fixId = self.__getID() 1516 fixId = self.__getID()
1495 @return value indicating an applied/deferred fix (-1, 0, 1), 1531 @return value indicating an applied/deferred fix (-1, 0, 1),
1496 a message for the fix (string) and an ID for a deferred 1532 a message for the fix (string) and an ID for a deferred
1497 fix (integer) 1533 fix (integer)
1498 """ 1534 """
1499 if apply: 1535 if apply:
1500 multilineStringLines, docStringLines = \ 1536 multilineStringLines, docStringLines = (
1501 self.__multilineStringLines() 1537 self.__multilineStringLines()
1538 )
1502 isDocString = line in docStringLines 1539 isDocString = line in docStringLines
1503 line = line - 1 1540 line = line - 1
1504 text = self.__source[line] 1541 text = self.__source[line]
1505 if line > 0: 1542 if line > 0:
1506 prevText = self.__source[line - 1] 1543 prevText = self.__source[line - 1]
1542 @param pos position inside line (integer) 1579 @param pos position inside line (integer)
1543 @return value indicating an applied/deferred fix (-1, 0, 1), 1580 @return value indicating an applied/deferred fix (-1, 0, 1),
1544 a message for the fix (string) and an ID for a deferred 1581 a message for the fix (string) and an ID for a deferred
1545 fix (integer) 1582 fix (integer)
1546 """ 1583 """
1547 self.__source[line - 1] = \ 1584 self.__source[line - 1] = (
1548 self.__source[line - 1].rstrip("\n\r \t\\") + self.__eol 1585 self.__source[line - 1].rstrip("\n\r \t\\") +
1586 self.__eol
1587 )
1549 # Redundant backslash in brackets removed. 1588 # Redundant backslash in brackets removed.
1550 return (1, "FE502", 0) 1589 return (1, "FE502", 0)
1551 1590
1552 def __fixE701(self, code, line, pos, apply=False): 1591 def __fixE701(self, code, line, pos, apply=False):
1553 """ 1592 """
1567 if apply: 1606 if apply:
1568 line = line - 1 1607 line = line - 1
1569 text = self.__source[line] 1608 text = self.__source[line]
1570 pos = pos + 1 1609 pos = pos + 1
1571 1610
1572 newText = text[:pos] + self.__eol + self.__getIndent(text) + \ 1611 newText = (
1573 self.__indentWord + text[pos:].lstrip("\n\r \t\\") + \ 1612 text[:pos] +
1613 self.__eol +
1614 self.__getIndent(text) +
1615 self.__indentWord +
1616 text[pos:].lstrip("\n\r \t\\") +
1574 self.__eol 1617 self.__eol
1618 )
1575 self.__source[line] = newText 1619 self.__source[line] = newText
1576 # Compound statement corrected. 1620 # Compound statement corrected.
1577 return (1, "FE701", 0) 1621 return (1, "FE701", 0)
1578 else: 1622 else:
1579 fixId = self.__getID() 1623 fixId = self.__getID()
1677 arg = "cls" 1721 arg = "cls"
1678 else: 1722 else:
1679 arg = "self" 1723 arg = "self"
1680 1724
1681 if text.rstrip().endswith("("): 1725 if text.rstrip().endswith("("):
1682 newText = text + self.__getIndent(text) + \ 1726 newText = (
1683 self.__indentWord + arg + "," + self.__eol 1727 text +
1728 self.__getIndent(text) +
1729 self.__indentWord +
1730 arg +
1731 "," +
1732 self.__eol
1733 )
1684 else: 1734 else:
1685 index = text.find("(") + 1 1735 index = text.find("(") + 1
1686 left = text[:index] 1736 left = text[:index]
1687 right = text[index:] 1737 right = text[index:]
1688 if right.startswith(")"): 1738 if right.startswith(")"):
1744 right = right[4:] 1794 right = right[4:]
1745 arg = "self" 1795 arg = "self"
1746 right = right.lstrip(", ") 1796 right = right.lstrip(", ")
1747 if right.startswith("):"): 1797 if right.startswith("):"):
1748 # merge with previous line 1798 # merge with previous line
1749 self.__source[line - 1] = \ 1799 self.__source[line - 1] = (
1750 self.__source[line - 1].rstrip() + right 1800 self.__source[line - 1].rstrip() + right
1801 )
1751 self.__source[line] = "" 1802 self.__source[line] = ""
1752 else: 1803 else:
1753 self.__source[line] = indent + right 1804 self.__source[line] = indent + right
1754 1805
1755 # '{0}' argument removed. 1806 # '{0}' argument removed.
1916 # in which case we should shift it like its base 1967 # in which case we should shift it like its base
1917 # line got shifted. 1968 # line got shifted.
1918 for j in range(i - 1, -1, -1): 1969 for j in range(i - 1, -1, -1):
1919 jline, jlevel = stats[j] 1970 jline, jlevel = stats[j]
1920 if jlevel >= 0: 1971 if jlevel >= 0:
1921 want = \ 1972 want = (
1922 have + \ 1973 have +
1923 self.__getlspace(after[jline - 1]) - \ 1974 self.__getlspace(after[jline - 1]) -
1924 self.__getlspace(lines[jline]) 1975 self.__getlspace(lines[jline])
1976 )
1925 break 1977 break
1926 if want < 0: 1978 if want < 0:
1927 # Still no luck -- leave it alone. 1979 # Still no luck -- leave it alone.
1928 want = have 1980 want = have
1929 else: 1981 else:
2210 2262
2211 # Returning to original continuation_line_indentation() from 2263 # Returning to original continuation_line_indentation() from
2212 # pycodestyle. 2264 # pycodestyle.
2213 visual_indent = indent_chances.get(start[1]) 2265 visual_indent = indent_chances.get(start[1])
2214 last_indent = start 2266 last_indent = start
2215 rel_indent[row] = \ 2267 rel_indent[row] = (
2216 pycodestyle.expand_indent(line) - indent_level 2268 pycodestyle.expand_indent(line) - indent_level
2269 )
2217 hang = rel_indent[row] - rel_indent[open_row] 2270 hang = rel_indent[row] - rel_indent[open_row]
2218 2271
2219 if token_type == tokenize.OP and text in ']})': 2272 if token_type == tokenize.OP and text in ']})':
2220 pass 2273 pass
2221 elif visual_indent is True: 2274 elif visual_indent is True:
2307 return False, "", "" 2360 return False, "", ""
2308 else: 2361 else:
2309 return True, newText, "" 2362 return True, newText, ""
2310 elif '#' in self.__text: 2363 elif '#' in self.__text:
2311 pos = self.__text.rfind("#") 2364 pos = self.__text.rfind("#")
2312 newText = self.__text[:pos].rstrip() + self.__eol + \ 2365 newText = (
2313 self.__getIndent(self.__text) + self.__text[pos:] 2366 self.__text[:pos].rstrip() +
2367 self.__eol +
2368 self.__getIndent(self.__text) +
2369 self.__text[pos:]
2370 )
2314 if newText == self.__text: 2371 if newText == self.__text:
2315 return False, "", "" 2372 return False, "", ""
2316 else: 2373 else:
2317 return True, newText, "" 2374 return True, newText, ""
2318 2375
2330 second = self.__text[blank:].lstrip() 2387 second = self.__text[blank:].lstrip()
2331 if self.__nextText.strip(): 2388 if self.__nextText.strip():
2332 if self.__nextText.lstrip().startswith("@"): 2389 if self.__nextText.lstrip().startswith("@"):
2333 # eric doc comment 2390 # eric doc comment
2334 # create a new line and indent it 2391 # create a new line and indent it
2335 newText = first + self.__eol + \ 2392 newText = (
2336 self.__getIndent(first) + self.__indentWord + \ 2393 first +
2394 self.__eol +
2395 self.__getIndent(first) +
2396 self.__indentWord +
2337 second 2397 second
2398 )
2338 newNext = "" 2399 newNext = ""
2339 else: 2400 else:
2340 newText = first + self.__eol 2401 newText = first + self.__eol
2341 newNext = self.__getIndent(self.__nextText) + \ 2402 newNext = (
2342 second.rstrip() + " " + self.__nextText.lstrip() 2403 self.__getIndent(self.__nextText) +
2404 second.rstrip() +
2405 " " +
2406 self.__nextText.lstrip()
2407 )
2343 else: 2408 else:
2344 # empty line, add a new line 2409 # empty line, add a new line
2345 newText = first + self.__eol + self.__getIndent(first) + \ 2410 newText = (
2411 first +
2412 self.__eol +
2413 self.__getIndent(first) +
2346 second 2414 second
2415 )
2347 newNext = "" 2416 newNext = ""
2348 return True, newText, newNext 2417 return True, newText, newNext
2349 2418
2350 indent = self.__getIndent(self.__text) 2419 indent = self.__getIndent(self.__text)
2351 source = self.__text[len(indent):] 2420 source = self.__text[len(indent):]
2357 tokens = list(tokenize.generate_tokens(sio.readline)) 2426 tokens = list(tokenize.generate_tokens(sio.readline))
2358 except (SyntaxError, tokenize.TokenError): 2427 except (SyntaxError, tokenize.TokenError):
2359 if source.rstrip().endswith("\\"): 2428 if source.rstrip().endswith("\\"):
2360 # just join the continuation line and let the next run 2429 # just join the continuation line and let the next run
2361 # handle it once it tokenizes ok 2430 # handle it once it tokenizes ok
2362 newText = indent + source.rstrip()[:-1].rstrip() + " " + \ 2431 newText = (
2432 indent +
2433 source.rstrip()[:-1].rstrip() +
2434 " " +
2363 self.__nextText.lstrip() 2435 self.__nextText.lstrip()
2436 )
2364 if indent: 2437 if indent:
2365 newNext = indent 2438 newNext = indent
2366 else: 2439 else:
2367 newNext = " " 2440 newNext = " "
2368 return True, newText, newNext 2441 return True, newText, newNext
2440 indentation = self.__getIndent(newText) + '# ' 2513 indentation = self.__getIndent(newText) + '# '
2441 maxLength = min(self.__maxLength, 2514 maxLength = min(self.__maxLength,
2442 len(indentation) + 72) 2515 len(indentation) + 72)
2443 2516
2444 MIN_CHARACTER_REPEAT = 5 2517 MIN_CHARACTER_REPEAT = 5
2445 if len(newText) - len(newText.rstrip(newText[-1])) >= \ 2518 if (
2446 MIN_CHARACTER_REPEAT and \ 2519 len(newText) - len(newText.rstrip(newText[-1])) >=
2447 not newText[-1].isalnum(): 2520 MIN_CHARACTER_REPEAT and
2521 not newText[-1].isalnum()
2522 ):
2448 # Trim comments that end with things like --------- 2523 # Trim comments that end with things like ---------
2449 return newText[:maxLength] + self.__eol 2524 return newText[:maxLength] + self.__eol
2450 elif isLast and re.match(r"\s*#+\s*\w+", newText): 2525 elif isLast and re.match(r"\s*#+\s*\w+", newText):
2451 import textwrap 2526 import textwrap
2452 splitLines = textwrap.wrap(newText.lstrip(" \t#"), 2527 splitLines = textwrap.wrap(newText.lstrip(" \t#"),
2502 if second.endswith(")"): 2577 if second.endswith(")"):
2503 # don't merge with next line 2578 # don't merge with next line
2504 newText += self.__getIndent(newText) + second + self.__eol 2579 newText += self.__getIndent(newText) + second + self.__eol
2505 newNext = "" 2580 newNext = ""
2506 else: 2581 else:
2507 newNext = self.__getIndent(newNext) + \ 2582 newNext = (
2508 second + " " + newNext.lstrip() 2583 self.__getIndent(newNext) +
2584 second +
2585 " " +
2586 newNext.lstrip()
2587 )
2509 else: 2588 else:
2510 # empty line, add a new line 2589 # empty line, add a new line
2511 newText = first + self.__eol 2590 newText = first + self.__eol
2512 newNext = self.__getIndent(newNext) + \ 2591 newNext = (
2513 second + self.__eol + newNext.lstrip() 2592 self.__getIndent(newNext) +
2593 second +
2594 self.__eol +
2595 newNext.lstrip()
2596 )
2514 return newText, newNext 2597 return newText, newNext
2515 else: 2598 else:
2516 return None 2599 return None
2517 2600
2518 def __isProbablyInsideStringOrComment(self, line, index): 2601 def __isProbablyInsideStringOrComment(self, line, index):
2670 if currentLine.startswith(badStart): 2753 if currentLine.startswith(badStart):
2671 rank += 100 2754 rank += 100
2672 2755
2673 for ending in '([{': 2756 for ending in '([{':
2674 # Avoid lonely opening. They result in longer lines. 2757 # Avoid lonely opening. They result in longer lines.
2675 if currentLine.endswith(ending) and \ 2758 if (
2676 len(currentLine.strip()) <= len(self.__indentWord): 2759 currentLine.endswith(ending) and
2760 len(currentLine.strip()) <= len(self.__indentWord)
2761 ):
2677 rank += 100 2762 rank += 100
2678 2763
2679 if currentLine.endswith('%'): 2764 if currentLine.endswith('%'):
2680 rank -= 20 2765 rank -= 20
2681 2766

eric ide

mercurial