23 QTreeWidgetItem, |
23 QTreeWidgetItem, |
24 ) |
24 ) |
25 |
25 |
26 from eric7.EricWidgets import EricMessageBox |
26 from eric7.EricWidgets import EricMessageBox |
27 from eric7.EricWidgets.EricApplication import ericApp |
27 from eric7.EricWidgets.EricApplication import ericApp |
|
28 from eric7.RemoteServerInterface.EricServerCoverageInterface import ( |
|
29 EricServerCoverageError, |
|
30 ) |
28 from eric7.SystemUtilities import FileSystemUtilities |
31 from eric7.SystemUtilities import FileSystemUtilities |
29 |
32 |
30 from .Ui_PyCoverageDialog import Ui_PyCoverageDialog |
33 from .Ui_PyCoverageDialog import Ui_PyCoverageDialog |
31 |
34 |
32 |
35 |
55 |
58 |
56 self.summaryList.headerItem().setText(self.summaryList.columnCount(), "") |
59 self.summaryList.headerItem().setText(self.summaryList.columnCount(), "") |
57 self.resultList.headerItem().setText(self.resultList.columnCount(), "") |
60 self.resultList.headerItem().setText(self.resultList.columnCount(), "") |
58 |
61 |
59 self.cancelled = False |
62 self.cancelled = False |
60 self.path = "." |
|
61 self.reload = False |
63 self.reload = False |
62 |
64 |
63 self.excludeList = ["# *pragma[: ]*[nN][oO] *[cC][oO][vV][eE][rR]"] |
65 self.excludeList = ["# *pragma[: ]*[nN][oO] *[cC][oO][vV][eE][rR]"] |
64 |
66 |
65 self.__reportsMenu = QMenu(self.tr("Create Report"), self) |
67 self.__reportsMenu = QMenu(self.tr("Create Report"), self) |
75 self.__menu.addMenu(self.__reportsMenu) |
77 self.__menu.addMenu(self.__reportsMenu) |
76 self.__menu.addSeparator() |
78 self.__menu.addSeparator() |
77 self.__menu.addAction(self.tr("Erase Coverage Info"), self.__erase) |
79 self.__menu.addAction(self.tr("Erase Coverage Info"), self.__erase) |
78 self.resultList.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) |
80 self.resultList.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) |
79 self.resultList.customContextMenuRequested.connect(self.__showContextMenu) |
81 self.resultList.customContextMenuRequested.connect(self.__showContextMenu) |
|
82 |
|
83 # eric-ide server interface |
|
84 self.__serverCoverageInterface = ericApp().getObject( |
|
85 "EricServer" |
|
86 ).getServiceInterface("Coverage") |
80 |
87 |
81 def __format_lines(self, lines): |
88 def __format_lines(self, lines): |
82 """ |
89 """ |
83 Private method to format a list of integers into string by coalescing |
90 Private method to format a list of integers into string by coalescing |
84 groups. |
91 groups. |
141 @param executed number of executed statements |
148 @param executed number of executed statements |
142 @type int |
149 @type int |
143 @param coverage percent of coverage |
150 @param coverage percent of coverage |
144 @type int |
151 @type int |
145 @param excluded list of excluded lines |
152 @param excluded list of excluded lines |
146 @type str |
153 @type list of int |
147 @param missing list of lines without coverage |
154 @param missing list of lines without coverage |
148 @type str |
155 @type str |
149 """ |
156 """ |
150 itm = QTreeWidgetItem( |
157 itm = QTreeWidgetItem( |
151 self.resultList, |
158 self.resultList, |
152 [ |
159 [ |
153 file, |
160 file, |
154 str(statements), |
161 str(statements), |
155 str(executed), |
162 str(executed), |
156 "{0:.0f}%".format(coverage), |
163 "{0:.0f}%".format(coverage), |
157 excluded, |
164 excluded and self.__format_lines(excluded) or "", |
158 missing, |
165 missing, |
159 ], |
166 ], |
160 ) |
167 ) |
161 for col in range(1, 4): |
168 for col in range(1, 4): |
162 itm.setTextAlignment(col, Qt.AlignmentFlag.AlignRight) |
169 itm.setTextAlignment(col, Qt.AlignmentFlag.AlignRight) |
190 cfn |
197 cfn |
191 if cfn.endswith(".coverage") |
198 if cfn.endswith(".coverage") |
192 else "{0}.coverage".format(os.path.splitext(cfn)[0]) |
199 else "{0}.coverage".format(os.path.splitext(cfn)[0]) |
193 ) |
200 ) |
194 |
201 |
|
202 # TODO: adapt this to remote server |
195 if isinstance(fn, list): |
203 if isinstance(fn, list): |
196 files = fn |
204 files = fn |
197 self.path = os.path.dirname(cfn) |
205 elif os.path.isdir(fn) and not FileSystemUtilities.isRemoteFileName(self.cfn): |
198 elif os.path.isdir(fn): |
206 # This case is not yet supported |
199 files = FileSystemUtilities.direntries(fn, True, "*.py", False) |
207 files = FileSystemUtilities.direntries(fn, True, "*.py", False) |
200 self.path = fn |
|
201 else: |
208 else: |
202 files = [fn] |
209 files = [fn] |
203 self.path = os.path.dirname(cfn) |
|
204 files.sort() |
210 files.sort() |
205 |
|
206 cover = Coverage(data_file=self.cfn) |
|
207 cover.load() |
|
208 |
211 |
209 # set the exclude pattern |
212 # set the exclude pattern |
210 self.excludeCombo.clear() |
213 self.excludeCombo.clear() |
211 self.excludeCombo.addItems(self.excludeList) |
214 self.excludeCombo.addItems(self.excludeList) |
212 |
215 |
215 |
218 |
216 total_statements = 0 |
219 total_statements = 0 |
217 total_executed = 0 |
220 total_executed = 0 |
218 total_exceptions = 0 |
221 total_exceptions = 0 |
219 |
222 |
220 cover.exclude(self.excludeList[0]) |
223 if FileSystemUtilities.isRemoteFileName(self.cfn): |
|
224 ok, error = self.__serverCoverageInterface.loadCoverageData( |
|
225 self.cfn, self.excludeList[0] |
|
226 ) |
|
227 if not ok: |
|
228 EricMessageBox.critical( |
|
229 self, |
|
230 self.tr("Load Coverage Data"), |
|
231 self.tr( |
|
232 "<p>The coverage data could not be loaded from file" |
|
233 " <b>{0}</b>.</p><p>Reason: {1}</p>" |
|
234 ).format(self.cfn, error), |
|
235 ) |
|
236 else: |
|
237 cover = Coverage(data_file=self.cfn) |
|
238 cover.load() |
|
239 cover.exclude(self.excludeList[0]) |
221 |
240 |
222 try: |
241 try: |
223 # disable updates of the list for speed |
242 # disable updates of the list for speed |
224 self.resultList.setUpdatesEnabled(False) |
243 self.resultList.setUpdatesEnabled(False) |
225 self.resultList.setSortingEnabled(False) |
244 self.resultList.setSortingEnabled(False) |
229 for progress, file in enumerate(files, start=1): |
248 for progress, file in enumerate(files, start=1): |
230 if self.cancelled: |
249 if self.cancelled: |
231 return |
250 return |
232 |
251 |
233 try: |
252 try: |
234 statements, excluded, missing, readable = cover.analysis2(file)[1:] |
253 if FileSystemUtilities.isRemoteFileName(self.cfn): |
235 readableEx = excluded and self.__format_lines(excluded) or "" |
254 file, statements, excluded, missing, readable = ( |
|
255 self.__serverCoverageInterface.analyzeFile(file) |
|
256 ) |
|
257 else: |
|
258 statements, excluded, missing, readable = ( |
|
259 cover.analysis2(file)[1:] |
|
260 ) |
236 n = len(statements) |
261 n = len(statements) |
237 m = n - len(missing) |
262 m = n - len(missing) |
238 pc = 100.0 * m / n if n > 0 else 100.0 |
263 pc = 100.0 * m / n if n > 0 else 100.0 |
239 self.__createResultItem( |
264 self.__createResultItem( |
240 file, str(n), str(m), pc, readableEx, readable |
265 file, str(n), str(m), pc, excluded, readable |
241 ) |
266 ) |
242 |
267 |
243 total_statements += n |
268 total_statements += n |
244 total_executed += m |
269 total_executed += m |
245 except CoverageException: |
270 except (CoverageException, EricServerCoverageError): |
246 total_exceptions += 1 |
271 total_exceptions += 1 |
247 |
272 |
248 self.checkProgress.setValue(progress) |
273 self.checkProgress.setValue(progress) |
249 if time.monotonic() - now > 0.01: |
274 if time.monotonic() - now > 0.01: |
250 QApplication.processEvents() |
275 QApplication.processEvents() |