eric7/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyChecker.py

branch
eric7
changeset 8312
800c432b34c8
parent 8225
811b7fa1b8a9
child 8881
54e42bc2437a
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the checker for simplifying Python code.
8 """
9
10 import ast
11 import copy
12
13 from .SimplifyNodeVisitor import SimplifyNodeVisitor
14
15
16 class SimplifyChecker:
17 """
18 Class implementing a checker for to help simplifying Python code.
19 """
20 Codes = [
21 # Python-specifics
22 "Y101", "Y102", "Y103", "Y104", "Y105", "Y106", "Y107", "Y108",
23 "Y109", "Y110", "Y111", "Y112", "Y113", "Y114", "Y115", "Y116",
24 "Y117", "Y118", "Y119", "Y120", "Y121", "Y122",
25
26 # Python-specifics not part of flake8-simplify
27 "Y181", "Y182",
28
29 # Comparations
30 "Y201", "Y202", "Y203", "Y204", "Y205", "Y206", "Y207", "Y208",
31 "Y211", "Y212", "Y213",
32 "Y221", "Y222", "Y223", "Y224",
33
34 # Opinionated
35 "Y301",
36
37 # General Code Style
38 "Y401", "Y402",
39 ]
40
41 def __init__(self, source, filename, tree, selected, ignored, expected,
42 repeat):
43 """
44 Constructor
45
46 @param source source code to be checked
47 @type list of str
48 @param filename name of the source file
49 @type str
50 @param tree AST tree of the source code
51 @type ast.Module
52 @param selected list of selected codes
53 @type list of str
54 @param ignored list of codes to be ignored
55 @type list of str
56 @param expected list of expected codes
57 @type list of str
58 @param repeat flag indicating to report each occurrence of a code
59 @type bool
60 """
61 self.__select = tuple(selected)
62 self.__ignore = ('',) if selected else tuple(ignored)
63 self.__expected = expected[:]
64 self.__repeat = repeat
65 self.__filename = filename
66 self.__source = source[:]
67 self.__tree = copy.deepcopy(tree)
68
69 # statistics counters
70 self.counters = {}
71
72 # collection of detected errors
73 self.errors = []
74
75 self.__checkCodes = (code for code in self.Codes
76 if not self.__ignoreCode(code))
77
78 def __ignoreCode(self, code):
79 """
80 Private method to check if the message code should be ignored.
81
82 @param code message code to check for
83 @type str
84 @return flag indicating to ignore the given code
85 @rtype bool
86 """
87 return (code.startswith(self.__ignore) and
88 not code.startswith(self.__select))
89
90 def __error(self, lineNumber, offset, code, *args):
91 """
92 Private method to record an issue.
93
94 @param lineNumber line number of the issue
95 @type int
96 @param offset position within line of the issue
97 @type int
98 @param code message code
99 @type str
100 @param args arguments for the message
101 @type list
102 """
103 if self.__ignoreCode(code):
104 return
105
106 # record the issue with one based line number
107 errorInfo = {
108 "file": self.__filename,
109 "line": lineNumber + 1,
110 "offset": offset,
111 "code": code,
112 "args": args,
113 }
114
115 if errorInfo not in self.errors:
116 # this issue was not seen before
117 if code in self.counters:
118 self.counters[code] += 1
119 else:
120 self.counters[code] = 1
121
122 # Don't care about expected codes
123 if code in self.__expected:
124 return
125
126 if code and (self.counters[code] == 1 or self.__repeat):
127 self.errors.append(errorInfo)
128
129 def run(self):
130 """
131 Public method to check the given source against functions
132 to be replaced by 'pathlib' equivalents.
133 """
134 if not self.__filename:
135 # don't do anything, if essential data is missing
136 return
137
138 if not self.__checkCodes:
139 # don't do anything, if no codes were selected
140 return
141
142 # Add parent information
143 for node in ast.walk(self.__tree):
144 for child in ast.iter_child_nodes(node):
145 child.parent = node # type: ignore
146
147 visitor = SimplifyNodeVisitor(self.__error)
148 visitor.visit(self.__tree)

eric ide

mercurial