|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 from __future__ import unicode_literals |
|
7 |
|
8 try: |
|
9 str = unicode # __IGNORE_EXCEPTION __IGNORE_WARNING__ |
|
10 except NameError: |
|
11 pass |
|
12 |
|
13 import multiprocessing |
|
14 import sys |
|
15 |
|
16 |
|
17 def initService(): |
|
18 """ |
|
19 Initialize the service and return the entry point. |
|
20 |
|
21 @return the entry point for the background client (function) |
|
22 """ |
|
23 return maintainabilityIndex |
|
24 |
|
25 |
|
26 def initBatchService(): |
|
27 """ |
|
28 Initialize the batch service and return the entry point. |
|
29 |
|
30 @return the entry point for the background client (function) |
|
31 """ |
|
32 return batchMaintainabilityIndex |
|
33 |
|
34 |
|
35 def maintainabilityIndex(file, text=""): |
|
36 """ |
|
37 Private function to calculate the maintainability index of one file. |
|
38 |
|
39 @param file source filename |
|
40 @type str |
|
41 @param text source text |
|
42 @param str |
|
43 @return tuple containing the result dictionary |
|
44 @rtype (tuple of dict) |
|
45 """ |
|
46 return __maintainabilityIndex(file, text) |
|
47 |
|
48 |
|
49 def batchMaintainabilityIndex(argumentsList, send, fx, cancelled): |
|
50 """ |
|
51 Module function to calculate the maintainability index for a batch of |
|
52 files. |
|
53 |
|
54 @param argumentsList list of arguments tuples as given for check |
|
55 @type list |
|
56 @param send reference to send function |
|
57 @type function |
|
58 @param fx registered service name |
|
59 @type str |
|
60 @param cancelled reference to function checking for a cancellation |
|
61 @type function |
|
62 """ |
|
63 try: |
|
64 NumberOfProcesses = multiprocessing.cpu_count() |
|
65 if NumberOfProcesses >= 1: |
|
66 NumberOfProcesses -= 1 |
|
67 except NotImplementedError: |
|
68 NumberOfProcesses = 1 |
|
69 |
|
70 # Create queues |
|
71 taskQueue = multiprocessing.Queue() |
|
72 doneQueue = multiprocessing.Queue() |
|
73 |
|
74 # Submit tasks (initially two time number of processes |
|
75 initialTasks = 2 * NumberOfProcesses |
|
76 for task in argumentsList[:initialTasks]: |
|
77 taskQueue.put(task) |
|
78 |
|
79 # Start worker processes |
|
80 for i in range(NumberOfProcesses): |
|
81 multiprocessing.Process(target=worker, args=(taskQueue, doneQueue))\ |
|
82 .start() |
|
83 |
|
84 # Get and send results |
|
85 endIndex = len(argumentsList) - initialTasks |
|
86 for i in range(len(argumentsList)): |
|
87 filename, result = doneQueue.get() |
|
88 send(fx, filename, result) |
|
89 if cancelled(): |
|
90 # just exit the loop ignoring the results of queued tasks |
|
91 break |
|
92 if i < endIndex: |
|
93 taskQueue.put(argumentsList[i + initialTasks]) |
|
94 |
|
95 # Tell child processes to stop |
|
96 for i in range(NumberOfProcesses): |
|
97 taskQueue.put('STOP') |
|
98 |
|
99 |
|
100 def worker(input, output): |
|
101 """ |
|
102 Module function acting as the parallel worker for the style check. |
|
103 |
|
104 @param input input queue |
|
105 @type multiprocessing.Queue |
|
106 @param output output queue |
|
107 @type multiprocessing.Queue |
|
108 """ |
|
109 for filename, source in iter(input.get, 'STOP'): |
|
110 result = __maintainabilityIndex(filename, source) |
|
111 output.put((filename, result)) |
|
112 |
|
113 |
|
114 def __maintainabilityIndex(file, text=""): |
|
115 """ |
|
116 Private function to calculate the maintainability index for one Python |
|
117 file. |
|
118 |
|
119 @param file source filename |
|
120 @type str |
|
121 @param text source text |
|
122 @type str |
|
123 @return tuple containing the result dictionary |
|
124 @rtype (tuple of dict) |
|
125 """ |
|
126 from radon.metrics import mi_visit, mi_rank |
|
127 |
|
128 # Check type for py2: if not str it's unicode |
|
129 if sys.version_info[0] == 2: |
|
130 try: |
|
131 text = text.encode('utf-8') |
|
132 except UnicodeError: |
|
133 pass |
|
134 |
|
135 try: |
|
136 mi = mi_visit(text, True) |
|
137 rank = mi_rank(mi) |
|
138 res = {"mi": mi, "rank": rank} |
|
139 except Exception as err: |
|
140 res = {"error": str(err)} |
|
141 return (res, ) |