eric7/DataViews/PyCoverageDialog.py

branch
unittest
changeset 9070
eab09a1ab8ce
parent 8943
23f9c7b9e18e
child 9078
44d1d68096b6
equal deleted inserted replaced
9069:938039ea15ca 9070:eab09a1ab8ce
9 9
10 import contextlib 10 import contextlib
11 import os 11 import os
12 import time 12 import time
13 13
14 from PyQt6.QtCore import pyqtSlot, Qt 14 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt
15 from PyQt6.QtWidgets import ( 15 from PyQt6.QtWidgets import (
16 QDialog, QDialogButtonBox, QMenu, QHeaderView, QTreeWidgetItem, 16 QDialog, QDialogButtonBox, QMenu, QHeaderView, QTreeWidgetItem,
17 QApplication 17 QApplication
18 ) 18 )
19 19
29 29
30 30
31 class PyCoverageDialog(QDialog, Ui_PyCoverageDialog): 31 class PyCoverageDialog(QDialog, Ui_PyCoverageDialog):
32 """ 32 """
33 Class implementing a dialog to display the collected code coverage data. 33 Class implementing a dialog to display the collected code coverage data.
34
35 @signal openFile(str) emitted to open the given file in an editor
34 """ 36 """
37 openFile = pyqtSignal(str)
38
35 def __init__(self, parent=None): 39 def __init__(self, parent=None):
36 """ 40 """
37 Constructor 41 Constructor
38 42
39 @param parent parent widget (QWidget) 43 @param parent parent widget
44 @type QWidget
40 """ 45 """
41 super().__init__(parent) 46 super().__init__(parent)
42 self.setupUi(self) 47 self.setupUi(self)
43 self.setWindowFlags(Qt.WindowType.Window) 48 self.setWindowFlags(Qt.WindowType.Window)
44 49
78 """ 83 """
79 Private method to format a list of integers into string by coalescing 84 Private method to format a list of integers into string by coalescing
80 groups. 85 groups.
81 86
82 @param lines list of integers 87 @param lines list of integers
88 @type list of int
83 @return string representing the list 89 @return string representing the list
90 @rtype str
84 """ 91 """
85 pairs = [] 92 pairs = []
86 lines.sort() 93 lines.sort()
87 maxValue = lines[-1] 94 maxValue = lines[-1]
88 start = None 95 start = None
108 """ 115 """
109 Private helper function to generate a string representation of a 116 Private helper function to generate a string representation of a
110 pair. 117 pair.
111 118
112 @param pair pair of integers 119 @param pair pair of integers
120 @type tuple of (int, int
121 @return representation of the pair
122 @rtype str
113 """ 123 """
114 start, end = pair 124 start, end = pair
115 if start == end: 125 if start == end:
116 return "{0:d}".format(start) 126 return "{0:d}".format(start)
117 else: 127 else:
122 def __createResultItem(self, file, statements, executed, coverage, 132 def __createResultItem(self, file, statements, executed, coverage,
123 excluded, missing): 133 excluded, missing):
124 """ 134 """
125 Private method to create an entry in the result list. 135 Private method to create an entry in the result list.
126 136
127 @param file filename of file (string) 137 @param file filename of file
128 @param statements amount of statements (integer) 138 @type str
129 @param executed amount of executed statements (integer) 139 @param statements number of statements
130 @param coverage percent of coverage (integer) 140 @type int
131 @param excluded list of excluded lines (string) 141 @param executed number of executed statements
132 @param missing list of lines without coverage (string) 142 @type int
143 @param coverage percent of coverage
144 @type int
145 @param excluded list of excluded lines
146 @type str
147 @param missing list of lines without coverage
148 @type str
133 """ 149 """
134 itm = QTreeWidgetItem(self.resultList, [ 150 itm = QTreeWidgetItem(self.resultList, [
135 file, 151 file,
136 str(statements), 152 str(statements),
137 str(executed), 153 str(executed),
144 if statements != executed: 160 if statements != executed:
145 font = itm.font(0) 161 font = itm.font(0)
146 font.setBold(True) 162 font.setBold(True)
147 for col in range(itm.columnCount()): 163 for col in range(itm.columnCount()):
148 itm.setFont(col, font) 164 itm.setFont(col, font)
149 165
150 def start(self, cfn, fn): 166 def start(self, cfn, fn):
151 """ 167 """
152 Public slot to start the coverage data evaluation. 168 Public slot to start the coverage data evaluation.
153 169
154 @param cfn basename of the coverage file (string) 170 @param cfn basename of the coverage file
171 @type str
155 @param fn file or list of files or directory to be checked 172 @param fn file or list of files or directory to be checked
156 (string or list of strings) 173 @type str or list of str
157 """ 174 """
158 self.__cfn = cfn 175 self.__cfn = cfn
159 self.__fn = fn 176 self.__fn = fn
160 177
161 self.basename = os.path.splitext(cfn)[0] 178 self.basename = os.path.splitext(cfn)[0]
249 self.tr("""%n file(s) could not be parsed. Coverage""" 266 self.tr("""%n file(s) could not be parsed. Coverage"""
250 """ info for these is not available.""", "", 267 """ info for these is not available.""", "",
251 total_exceptions)) 268 total_exceptions))
252 269
253 self.__finish() 270 self.__finish()
254 271
255 def __finish(self): 272 def __finish(self):
256 """ 273 """
257 Private slot called when the action finished or the user pressed the 274 Private slot called when the action finished or the user pressed the
258 button. 275 button.
259 """ 276 """
269 QHeaderView.ResizeMode.ResizeToContents) 286 QHeaderView.ResizeMode.ResizeToContents)
270 self.resultList.header().setStretchLastSection(True) 287 self.resultList.header().setStretchLastSection(True)
271 self.summaryList.header().resizeSections( 288 self.summaryList.header().resizeSections(
272 QHeaderView.ResizeMode.ResizeToContents) 289 QHeaderView.ResizeMode.ResizeToContents)
273 self.summaryList.header().setStretchLastSection(True) 290 self.summaryList.header().setStretchLastSection(True)
274 291
275 def on_buttonBox_clicked(self, button): 292 def on_buttonBox_clicked(self, button):
276 """ 293 """
277 Private slot called by a button of the button box clicked. 294 Private slot called by a button of the button box clicked.
278 295
279 @param button button that was clicked (QAbstractButton) 296 @param button button that was clicked
297 @type QAbstractButton
280 """ 298 """
281 if button == self.buttonBox.button( 299 if button == self.buttonBox.button(
282 QDialogButtonBox.StandardButton.Close 300 QDialogButtonBox.StandardButton.Close
283 ): 301 ):
284 self.close() 302 self.close()
285 elif button == self.buttonBox.button( 303 elif button == self.buttonBox.button(
286 QDialogButtonBox.StandardButton.Cancel 304 QDialogButtonBox.StandardButton.Cancel
287 ): 305 ):
288 self.__finish() 306 self.__finish()
289 307
290 def __showContextMenu(self, coord): 308 def __showContextMenu(self, coord):
291 """ 309 """
292 Private slot to show the context menu of the listview. 310 Private slot to show the context menu of the listview.
293 311
294 @param coord the position of the mouse pointer (QPoint) 312 @param coord position of the mouse pointer
313 @type QPoint
295 """ 314 """
296 itm = self.resultList.itemAt(coord) 315 itm = self.resultList.itemAt(coord)
297 if itm: 316 if itm:
298 self.annotate.setEnabled(True) 317 self.annotate.setEnabled(True)
299 self.openAct.setEnabled(True) 318 self.openAct.setEnabled(True)
300 else: 319 else:
301 self.annotate.setEnabled(False) 320 self.annotate.setEnabled(False)
302 self.openAct.setEnabled(False) 321 self.openAct.setEnabled(False)
303 self.__menu.popup(self.mapToGlobal(coord)) 322 self.__menu.popup(self.mapToGlobal(coord))
304 323
305 def __openFile(self, itm=None): 324 def __openFile(self, itm=None):
306 """ 325 """
307 Private slot to open the selected file. 326 Private slot to open the selected file.
308 327
309 @param itm reference to the item to be opened (QTreeWidgetItem) 328 @param itm reference to the item to be opened
329 @type QTreeWidgetItem
310 """ 330 """
311 if itm is None: 331 if itm is None:
312 itm = self.resultList.currentItem() 332 itm = self.resultList.currentItem()
313 fn = itm.text(0) 333 fn = itm.text(0)
314 334
315 vm = ericApp().getObject("ViewManager") 335 try:
316 vm.openSourceFile(fn) 336 vm = ericApp().getObject("ViewManager")
317 editor = vm.getOpenEditor(fn) 337 vm.openSourceFile(fn)
318 editor.codeCoverageShowAnnotations() 338 editor = vm.getOpenEditor(fn)
319 339 editor.codeCoverageShowAnnotations(coverageFile=self.cfn)
340 except KeyError:
341 self.openFile.emit(fn)
342
343 # TODO: Coverage.annotate is deprecated
320 def __annotate(self): 344 def __annotate(self):
321 """ 345 """
322 Private slot to handle the annotate context menu action. 346 Private slot to handle the annotate context menu action.
323 347
324 This method produce an annotated coverage file of the 348 This method produces an annotated coverage file of the
325 selected file. 349 selected file.
326 """ 350 """
327 itm = self.resultList.currentItem() 351 itm = self.resultList.currentItem()
328 fn = itm.text(0) 352 fn = itm.text(0)
329 353
330 cover = Coverage(data_file=self.cfn) 354 cover = Coverage(data_file=self.cfn)
331 cover.exclude(self.excludeList[0]) 355 cover.exclude(self.excludeList[0])
332 cover.load() 356 cover.load()
333 cover.annotate([fn], None, True) 357 cover.annotate([fn], None, True)
334 358
359 # TODO: Coverage.annotate is deprecated
335 def __annotateAll(self): 360 def __annotateAll(self):
336 """ 361 """
337 Private slot to handle the annotate all context menu action. 362 Private slot to handle the annotate all context menu action.
338 363
339 This method produce an annotated coverage file of every 364 This method produce an annotated coverage file of every
365 if progress.wasCanceled(): 390 if progress.wasCanceled():
366 break 391 break
367 cover.annotate([file], None) # , True) 392 cover.annotate([file], None) # , True)
368 393
369 progress.setValue(len(files)) 394 progress.setValue(len(files))
370 395
371 def __erase(self): 396 def __erase(self):
372 """ 397 """
373 Private slot to handle the erase context menu action. 398 Private slot to handle the erase context menu action.
374 399
375 This method erases the collected coverage data that is 400 This method erases the collected coverage data that is
380 cover.erase() 405 cover.erase()
381 406
382 self.reloadButton.setEnabled(False) 407 self.reloadButton.setEnabled(False)
383 self.resultList.clear() 408 self.resultList.clear()
384 self.summaryList.clear() 409 self.summaryList.clear()
385 410
386 def __deleteAnnotated(self): 411 def __deleteAnnotated(self):
387 """ 412 """
388 Private slot to handle the delete annotated context menu action. 413 Private slot to handle the delete annotated context menu action.
389 414
390 This method deletes all annotated files. These are files 415 This method deletes all annotated files. These are files
392 """ 417 """
393 files = Utilities.direntries(self.path, True, '*,cover', False) 418 files = Utilities.direntries(self.path, True, '*,cover', False)
394 for file in files: 419 for file in files:
395 with contextlib.suppress(OSError): 420 with contextlib.suppress(OSError):
396 os.remove(file) 421 os.remove(file)
397 422
398 @pyqtSlot() 423 @pyqtSlot()
399 def on_reloadButton_clicked(self): 424 def on_reloadButton_clicked(self):
400 """ 425 """
401 Private slot to reload the coverage info. 426 Private slot to reload the coverage info.
402 """ 427 """

eric ide

mercurial