RadonMetrics/CyclomaticComplexityCalculator.py

branch
eric7
changeset 94
725eaca7bc4b
parent 90
1405e41edc0b
child 104
6eac83394939
equal deleted inserted replaced
93:1ae73306422a 94:725eaca7bc4b
12 12
13 13
14 def initService(): 14 def initService():
15 """ 15 """
16 Initialize the service and return the entry point. 16 Initialize the service and return the entry point.
17 17
18 @return the entry point for the background client (function) 18 @return the entry point for the background client (function)
19 """ 19 """
20 return cyclomaticComplexity 20 return cyclomaticComplexity
21 21
22 22
23 def initBatchService(): 23 def initBatchService():
24 """ 24 """
25 Initialize the batch service and return the entry point. 25 Initialize the batch service and return the entry point.
26 26
27 @return the entry point for the background client (function) 27 @return the entry point for the background client (function)
28 """ 28 """
29 return batchCyclomaticComplexity 29 return batchCyclomaticComplexity
30 30
31 31
32 def cyclomaticComplexity(file, text=""): 32 def cyclomaticComplexity(file, text=""):
33 """ 33 """
34 Private function to calculate the cyclomatic complexity of one file. 34 Private function to calculate the cyclomatic complexity of one file.
35 35
36 @param file source filename 36 @param file source filename
37 @type str 37 @type str
38 @param text source text 38 @param text source text
39 @type str 39 @type str
40 @return tuple containing the result dictionary 40 @return tuple containing the result dictionary
41 @rtype (tuple of dict) 41 @rtype (tuple of dict)
42 """ 42 """
43 return __cyclomaticComplexity(file, text) 43 return __cyclomaticComplexity(file, text)
44 44
45 45
46 def batchCyclomaticComplexity(argumentsList, send, fx, cancelled, 46 def batchCyclomaticComplexity(argumentsList, send, fx, cancelled, maxProcesses=0):
47 maxProcesses=0):
48 """ 47 """
49 Module function to calculate the cyclomatic complexity for a batch of 48 Module function to calculate the cyclomatic complexity for a batch of
50 files. 49 files.
51 50
52 @param argumentsList list of arguments tuples as given for 51 @param argumentsList list of arguments tuples as given for
53 cyclomaticComplexity 52 cyclomaticComplexity
54 @type list 53 @type list
55 @param send reference to send function 54 @param send reference to send function
56 @type function 55 @type function
81 for task in argumentsList[:initialTasks]: 80 for task in argumentsList[:initialTasks]:
82 taskQueue.put(task) 81 taskQueue.put(task)
83 82
84 # Start worker processes 83 # Start worker processes
85 workers = [ 84 workers = [
86 multiprocessing.Process( 85 multiprocessing.Process(target=workerTask, args=(taskQueue, doneQueue))
87 target=workerTask, args=(taskQueue, doneQueue) 86 for _ in range(NumberOfProcesses)
88 ) for _ in range(NumberOfProcesses)
89 ] 87 ]
90 for worker in workers: 88 for worker in workers:
91 worker.start() 89 worker.start()
92 90
93 # Get and send results 91 # Get and send results
94 endIndex = len(argumentsList) - initialTasks 92 endIndex = len(argumentsList) - initialTasks
95 for i in range(len(argumentsList)): 93 for i in range(len(argumentsList)):
96 resultSent = False 94 resultSent = False
97 wasCancelled = False 95 wasCancelled = False
98 96
99 while not resultSent: 97 while not resultSent:
100 try: 98 try:
101 # get result (waiting max. 3 seconds and send it to frontend 99 # get result (waiting max. 3 seconds and send it to frontend
102 filename, result = doneQueue.get() 100 filename, result = doneQueue.get()
103 send(fx, filename, result) 101 send(fx, filename, result)
105 except queue.Empty: 103 except queue.Empty:
106 # ignore empty queue, just carry on 104 # ignore empty queue, just carry on
107 if cancelled(): 105 if cancelled():
108 wasCancelled = True 106 wasCancelled = True
109 break 107 break
110 108
111 if wasCancelled or cancelled(): 109 if wasCancelled or cancelled():
112 # just exit the loop ignoring the results of queued tasks 110 # just exit the loop ignoring the results of queued tasks
113 break 111 break
114 112
115 if i < endIndex: 113 if i < endIndex:
116 taskQueue.put(argumentsList[i + initialTasks]) 114 taskQueue.put(argumentsList[i + initialTasks])
117 115
118 # Tell child processes to stop 116 # Tell child processes to stop
119 for _ in range(NumberOfProcesses): 117 for _ in range(NumberOfProcesses):
120 taskQueue.put('STOP') 118 taskQueue.put("STOP")
121 119
122 for worker in workers: 120 for worker in workers:
123 worker.join() 121 worker.join()
124 worker.close() 122 worker.close()
125 123
126 124
127 def workerTask(inputQueue, outputQueue): 125 def workerTask(inputQueue, outputQueue):
128 """ 126 """
129 Module function acting as the parallel worker for the cyclomatic 127 Module function acting as the parallel worker for the cyclomatic
130 complexity calculation. 128 complexity calculation.
131 129
132 @param inputQueue input queue 130 @param inputQueue input queue
133 @type multiprocessing.Queue 131 @type multiprocessing.Queue
134 @param outputQueue output queue 132 @param outputQueue output queue
135 @type multiprocessing.Queue 133 @type multiprocessing.Queue
136 """ 134 """
137 for filename, source in iter(inputQueue.get, 'STOP'): 135 for filename, source in iter(inputQueue.get, "STOP"):
138 result = __cyclomaticComplexity(filename, source) 136 result = __cyclomaticComplexity(filename, source)
139 outputQueue.put((filename, result)) 137 outputQueue.put((filename, result))
140 138
141 139
142 def __cyclomaticComplexity(file, text=""): 140 def __cyclomaticComplexity(file, text=""):
143 """ 141 """
144 Private function to calculate the cyclomatic complexity for one Python 142 Private function to calculate the cyclomatic complexity for one Python
145 file. 143 file.
146 144
147 @param file source filename 145 @param file source filename
148 @type str 146 @type str
149 @param text source text 147 @param text source text
150 @type str 148 @type str
151 @return tuple containing the result dictionary 149 @return tuple containing the result dictionary
152 @rtype (tuple of dict) 150 @rtype (tuple of dict)
153 """ 151 """
154 from radon.complexity import cc_visit, cc_rank 152 from radon.complexity import cc_visit, cc_rank
155 153
156 try: 154 try:
157 cc = cc_visit(text) 155 cc = cc_visit(text)
158 res = {"result": [v for v in map(__cc2Dict, cc) 156 res = {"result": [v for v in map(__cc2Dict, cc) if v["type"] != "method"]}
159 if v["type"] != "method"]}
160 totalCC = 0 157 totalCC = 0
161 rankSummary = { 158 rankSummary = {
162 "A": 0, 159 "A": 0,
163 "B": 0, 160 "B": 0,
164 "C": 0, 161 "C": 0,
172 res["total_cc"] = totalCC 169 res["total_cc"] = totalCC
173 res["count"] = len(cc) 170 res["count"] = len(cc)
174 res["summary"] = rankSummary 171 res["summary"] = rankSummary
175 except Exception as err: 172 except Exception as err:
176 res = {"error": str(err)} 173 res = {"error": str(err)}
177 return (res, ) 174 return (res,)
178 175
179 176
180 def __cc2Dict(obj): 177 def __cc2Dict(obj):
181 """ 178 """
182 Private function to convert an object holding cyclomatic complexity results 179 Private function to convert an object holding cyclomatic complexity results
183 into a dictionary. 180 into a dictionary.
184 181
185 @param obj object as returned from cc_visit() 182 @param obj object as returned from cc_visit()
186 @type radon.visitors.Function 183 @type radon.visitors.Function
187 @return conversion result 184 @return conversion result
188 @rtype dict 185 @rtype dict
189 """ 186 """
190 from radon.complexity import cc_rank 187 from radon.complexity import cc_rank
191 from radon.visitors import Function 188 from radon.visitors import Function
192 189
193 result = { 190 result = {
194 'type': __getType(obj), 191 "type": __getType(obj),
195 'rank': cc_rank(obj.complexity), 192 "rank": cc_rank(obj.complexity),
196 } 193 }
197 attrs = set(Function._fields) - {'is_method', 'closures'} 194 attrs = set(Function._fields) - {"is_method", "closures"}
198 attrs.add("fullname") 195 attrs.add("fullname")
199 for attr in attrs: 196 for attr in attrs:
200 v = getattr(obj, attr, None) 197 v = getattr(obj, attr, None)
201 if v is not None: 198 if v is not None:
202 result[attr] = v 199 result[attr] = v
203 for key in ('methods', 'closures'): 200 for key in ("methods", "closures"):
204 if hasattr(obj, key): 201 if hasattr(obj, key):
205 result[key] = list(map(__cc2Dict, getattr(obj, key))) 202 result[key] = list(map(__cc2Dict, getattr(obj, key)))
206 return result 203 return result
207 204
208 205
209 def __getType(obj): 206 def __getType(obj):
210 """ 207 """
211 Private function to get the type of an object as a string. 208 Private function to get the type of an object as a string.
212 209
213 @param obj object to be analyzed 210 @param obj object to be analyzed
214 @type radon.visitors.Function or radon.visitors.Class 211 @type radon.visitors.Function or radon.visitors.Class
215 @return type string for the object 212 @return type string for the object
216 @rtype str, one of ["method", "function", "class"] 213 @rtype str, one of ["method", "function", "class"]
217 """ 214 """
218 from radon.visitors import Function 215 from radon.visitors import Function
219 216
220 if isinstance(obj, Function): 217 if isinstance(obj, Function):
221 if obj.is_method: 218 if obj.is_method:
222 return 'method' 219 return "method"
223 else: 220 else:
224 return 'function' 221 return "function"
225 else: 222 else:
226 return 'class' 223 return "class"

eric ide

mercurial