PluginMetricsRadon.py

changeset 6
13e9698a9981
parent 4
9ac53bf21182
child 9
7f6e04213998
equal deleted inserted replaced
5:db25d1d5cc3a 6:13e9698a9981
171 """ 171 """
172 Private slot to (re)initialize the plugin. 172 Private slot to (re)initialize the plugin.
173 """ 173 """
174 self.__projectRawMetricsAct = None 174 self.__projectRawMetricsAct = None
175 self.__projectRawMetricsDialog = None 175 self.__projectRawMetricsDialog = None
176 self.__projectMIAct = None
177 self.__projectMIDialog = None
176 self.__projectSeparatorActs = [] 178 self.__projectSeparatorActs = []
177 179
178 self.__projectBrowserMenu = None 180 self.__projectBrowserMenu = None
179 self.__projectBrowserRawMetricsAct = None 181 self.__projectBrowserRawMetricsAct = None
180 self.__projectBrowserRawMetricsDialog = None 182 self.__projectBrowserRawMetricsDialog = None
183 self.__projectBrowserMIAct = None
184 self.__projectBrowserMIDialog = None
181 self.__projectBrowserSeparatorActs = [] 185 self.__projectBrowserSeparatorActs = []
182 186
183 self.__editors = [] 187 self.__editors = []
184 self.__editorRawMetricsAct = None 188 self.__editorRawMetricsAct = None
185 self.__editorRawMetricsDialog = None 189 self.__editorRawMetricsDialog = None
190 self.__editorMIAct = None
191 self.__editorMIDialog = None
186 self.__editorSeparatorActs = [] 192 self.__editorSeparatorActs = []
187 193
188 def rawMetrics(self, lang, filename, source): 194 def rawMetrics(self, lang, filename, source):
189 """ 195 """
190 Public method to prepare raw code metrics calculation on one Python 196 Public method to prepare raw code metrics calculation on one Python
238 """ 244 """
239 Public method to cancel all batch jobs. 245 Public method to cancel all batch jobs.
240 """ 246 """
241 for lang in ['Python2', 'Python3']: 247 for lang in ['Python2', 'Python3']:
242 self.backgroundService.requestCancel('batch_radon', lang) 248 self.backgroundService.requestCancel('batch_radon', lang)
249
250 def maintainabilityIndex(self, lang, filename, source):
251 """
252 Public method to prepare maintainability index calculation on one
253 Python source file.
254
255 @param lang language of the file or None to determine by internal
256 algorithm
257 @type str or None
258 @param filename source filename
259 @type str
260 @param source string containing the code
261 @type str
262 """
263 if lang is None:
264 lang = 'Python{0}'.format(determinePythonVersion(filename, source))
265 if lang not in ['Python2', 'Python3']:
266 return
267
268 self.backgroundService.enqueueRequest(
269 'radon', lang, filename, [source, 'mi'])
270
271 def maintainabilityIndexBatch(self, argumentsList):
272 """
273 Public method to prepare maintainability index calculation on multiple
274 Python source files.
275
276 @param argumentsList list of arguments tuples with each tuple
277 containing filename and source
278 @type (str, str)
279 """
280 data = {
281 "Python2": [],
282 "Python3": [],
283 }
284 for filename, source in argumentsList:
285 lang = 'Python{0}'.format(determinePythonVersion(filename, source))
286 if lang not in ['Python2', 'Python3']:
287 continue
288 else:
289 data[lang].append((filename, source, 'mi'))
290
291 self.queuedBatches = []
292 for lang in ['Python2', 'Python3']:
293 if data[lang]:
294 self.queuedBatches.append(lang)
295 self.backgroundService.enqueueRequest('batch_radon', lang, "",
296 data[lang])
297 self.batchesFinished = False
298
299 def cancelMaintainabilityIndexBatch(self):
300 """
301 Public method to cancel all batch jobs.
302 """
303 for lang in ['Python2', 'Python3']:
304 self.backgroundService.requestCancel('batch_radon', lang)
243 305
244 def activate(self): 306 def activate(self):
245 """ 307 """
246 Public method to activate this plug-in. 308 Public method to activate this plug-in.
247 309
255 if menu: 317 if menu:
256 if not menu.isEmpty(): 318 if not menu.isEmpty():
257 act = menu.addSeparator() 319 act = menu.addSeparator()
258 act.setText(self.tr("Radon")) 320 act.setText(self.tr("Radon"))
259 self.__projectSeparatorActs.append(act) 321 self.__projectSeparatorActs.append(act)
322
260 self.__projectRawMetricsAct = E5Action( 323 self.__projectRawMetricsAct = E5Action(
261 self.tr('Code Metrics'), 324 self.tr('Code Metrics'),
262 self.tr('Code &Metrics...'), 0, 0, 325 self.tr('Code &Metrics...'), 0, 0,
263 self, 'project_show_radon_raw') 326 self, 'project_show_radon_raw')
264 self.__projectRawMetricsAct.setStatusTip( 327 self.__projectRawMetricsAct.setStatusTip(
271 """ multi-line strings and blank lines.</p>""" 334 """ multi-line strings and blank lines.</p>"""
272 )) 335 ))
273 self.__projectRawMetricsAct.triggered.connect( 336 self.__projectRawMetricsAct.triggered.connect(
274 self.__projectRawMetrics) 337 self.__projectRawMetrics)
275 menu.addAction(self.__projectRawMetricsAct) 338 menu.addAction(self.__projectRawMetricsAct)
339
340 self.__projectMIAct = E5Action(
341 self.tr('Maintainability Index'),
342 self.tr('Maintainability &Index...'), 0, 0,
343 self, 'project_show_radon_mi')
344 self.__projectMIAct.setStatusTip(
345 self.tr('Show the maintainability index for Python files.'))
346 self.__projectMIAct.setWhatsThis(self.tr(
347 """<b>Maintainability Index...</b>"""
348 """<p>This calculates the maintainability index of Python"""
349 """ files and shows it together with a ranking.</p>"""
350 ))
351 self.__projectMIAct.triggered.connect(
352 self.__projectMaintainabilityIndex)
353 menu.addAction(self.__projectMIAct)
354
276 act = menu.addSeparator() 355 act = menu.addSeparator()
277 self.__projectSeparatorActs.append(act) 356 self.__projectSeparatorActs.append(act)
278 357
279 e5App().getObject("Project").addE5Actions([ 358 e5App().getObject("Project").addE5Actions([
280 self.__projectRawMetricsAct, 359 self.__projectRawMetricsAct,
360 self.__projectMIAct
281 ]) 361 ])
282 362
283 act = QAction("Radon", self) 363 act = QAction("Radon", self)
284 act.setSeparator(True) 364 act.setSeparator(True)
285 self.__editorSeparatorActs.append(act) 365 self.__editorSeparatorActs.append(act)
298 """ of code, source lines of code, comment lines,""" 378 """ of code, source lines of code, comment lines,"""
299 """ multi-line strings and blank lines.</p>""" 379 """ multi-line strings and blank lines.</p>"""
300 )) 380 ))
301 self.__editorRawMetricsAct.triggered.connect(self.__editorRawMetrics) 381 self.__editorRawMetricsAct.triggered.connect(self.__editorRawMetrics)
302 382
383 self.__editorMIAct = E5Action(
384 self.tr('Maintainability Index'),
385 self.tr('Maintainability &Index...'), 0, 0,
386 self, "")
387 self.__editorMIAct.setStatusTip(
388 self.tr('Show the maintainability index for Python files.'))
389 self.__projectMIAct.setWhatsThis(self.tr(
390 """<b>Maintainability Index...</b>"""
391 """<p>This calculates the maintainability index of Python"""
392 """ files and shows it together with a ranking.</p>"""
393 ))
394 self.__editorMIAct.triggered.connect(
395 self.__editorMaintainabilityIndex)
396
303 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu) 397 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu)
304 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\ 398 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\
305 .showMenu.connect(self.__projectBrowserShowMenu) 399 .showMenu.connect(self.__projectBrowserShowMenu)
306 e5App().getObject("ViewManager").editorOpenedEd.connect( 400 e5App().getObject("ViewManager").editorOpenedEd.connect(
307 self.__editorOpened) 401 self.__editorOpened)
329 menu = e5App().getObject("Project").getMenu("Show") 423 menu = e5App().getObject("Project").getMenu("Show")
330 if menu: 424 if menu:
331 for sep in self.__projectSeparatorActs: 425 for sep in self.__projectSeparatorActs:
332 menu.removeAction(sep) 426 menu.removeAction(sep)
333 menu.removeAction(self.__projectRawMetricsAct) 427 menu.removeAction(self.__projectRawMetricsAct)
334 e5App().getObject("Project").removeE5Actions( 428 menu.removeAction(self.__projectMIAct)
335 [self.__projectRawMetricsAct]) 429 e5App().getObject("Project").removeE5Actions([
430 self.__projectRawMetricsAct,
431 self.__projectMIAct
432 ])
336 433
337 if self.__projectBrowserMenu: 434 if self.__projectBrowserMenu:
338 for sep in self.__projectBrowserSeparatorActs: 435 for sep in self.__projectBrowserSeparatorActs:
339 self.__projectBrowserMenu.removeAction(sep) 436 self.__projectBrowserMenu.removeAction(sep)
340 if self.__projectBrowserRawMetricsAct: 437 if self.__projectBrowserRawMetricsAct:
341 self.__projectBrowserMenu.removeAction( 438 self.__projectBrowserMenu.removeAction(
342 self.__projectBrowserRawMetricsAct) 439 self.__projectBrowserRawMetricsAct)
440 if self.__projectBrowserMIAct:
441 self.__projectBrowserMenu.removeAction(
442 self.__projectBrowserMIAct)
343 443
344 for editor in self.__editors: 444 for editor in self.__editors:
345 editor.showMenu.disconnect(self.__editorShowMenu) 445 editor.showMenu.disconnect(self.__editorShowMenu)
346 menu = editor.getMenu("Show") 446 menu = editor.getMenu("Show")
347 if menu is not None: 447 if menu is not None:
348 for sep in self.__editorSeparatorActs: 448 for sep in self.__editorSeparatorActs:
349 menu.removeAction(sep) 449 menu.removeAction(sep)
350 menu.removeAction(self.__editorRawMetricsAct) 450 menu.removeAction(self.__editorRawMetricsAct)
451 menu.removeAction(self.__editorMIAct)
351 452
352 self.__initialize() 453 self.__initialize()
353 454
354 def __loadTranslator(self): 455 def __loadTranslator(self):
355 """ 456 """
380 @type str 481 @type str
381 @param menu reference to the menu 482 @param menu reference to the menu
382 @type QMenu 483 @type QMenu
383 """ 484 """
384 if menuName == "Show": 485 if menuName == "Show":
385 for act in [self.__projectRawMetricsAct]: 486 for act in [self.__projectRawMetricsAct, self.__projectMIAct]:
386 if act is not None: 487 if act is not None:
387 act.setEnabled( 488 act.setEnabled(
388 e5App().getObject("Project").getProjectLanguage() in 489 e5App().getObject("Project").getProjectLanguage() in
389 ["Python3", "Python2", "Python"]) 490 ["Python3", "Python2", "Python"])
390 491
419 """ multi-line strings and blank lines.</p>""" 520 """ multi-line strings and blank lines.</p>"""
420 )) 521 ))
421 self.__projectBrowserRawMetricsAct.triggered.connect( 522 self.__projectBrowserRawMetricsAct.triggered.connect(
422 self.__projectBrowserRawMetrics) 523 self.__projectBrowserRawMetrics)
423 menu.addAction(self.__projectBrowserRawMetricsAct) 524 menu.addAction(self.__projectBrowserRawMetricsAct)
525
526 self.__projectBrowserMIAct = E5Action(
527 self.tr('Maintainability Index'),
528 self.tr('Maintainability &Index...'), 0, 0,
529 self, 'project_show_radon_mi')
530 self.__projectBrowserMIAct.setStatusTip(
531 self.tr('Show the maintainability index for Python'
532 ' files.'))
533 self.__projectBrowserMIAct.setWhatsThis(self.tr(
534 """<b>Maintainability Index...</b>"""
535 """<p>This calculates the maintainability index of"""
536 """ Python files and shows it together with a ranking."""
537 """</p>"""
538 ))
539 self.__projectBrowserMIAct.triggered.connect(
540 self.__projectBrowserMaintainabilityIndex)
541 menu.addAction(self.__projectBrowserMIAct)
542
543 def __editorOpened(self, editor):
544 """
545 Private slot called, when a new editor was opened.
546
547 @param editor reference to the new editor
548 @type QScintilla.Editor
549 """
550 menu = editor.getMenu("Show")
551 if menu is not None:
552 menu.addAction(self.__editorSeparatorActs[0])
553 menu.addAction(self.__editorRawMetricsAct)
554 menu.addAction(self.__editorMIAct)
555 menu.addAction(self.__editorSeparatorActs[1])
556 editor.showMenu.connect(self.__editorShowMenu)
557 self.__editors.append(editor)
558
559 def __editorClosed(self, editor):
560 """
561 Private slot called, when an editor was closed.
562
563 @param editor reference to the editor (QScintilla.Editor)
564 """
565 try:
566 self.__editors.remove(editor)
567 except ValueError:
568 pass
569
570 def __editorShowMenu(self, menuName, menu, editor):
571 """
572 Private slot called, when the the editor context menu or a submenu is
573 about to be shown.
574
575 @param menuName name of the menu to be shown (string)
576 @param menu reference to the menu (QMenu)
577 @param editor reference to the editor
578 """
579 if menuName == "Show":
580 enable = editor.isPyFile()
581 self.__editorRawMetricsAct.setEnabled(enable)
582 self.__editorMIAct.setEnabled(enable)
583
584 ##################################################################
585 ## Raw code metrics calculations
586 ##################################################################
424 587
425 def __projectRawMetrics(self): 588 def __projectRawMetrics(self):
426 """ 589 """
427 Private slot used to calculate raw code metrics for the project. 590 Private slot used to calculate raw code metrics for the project.
428 """ 591 """
440 self.__projectRawMetricsDialog.show() 603 self.__projectRawMetricsDialog.show()
441 self.__projectRawMetricsDialog.prepare(files, project) 604 self.__projectRawMetricsDialog.prepare(files, project)
442 605
443 def __projectBrowserRawMetrics(self): 606 def __projectBrowserRawMetrics(self):
444 """ 607 """
445 Private method to handle the tabnanny context menu action of the 608 Private method to handle the code metrics context menu action of the
446 project sources browser. 609 project sources browser.
447 """ 610 """
448 browser = e5App().getObject("ProjectBrowser").getProjectBrowser( 611 browser = e5App().getObject("ProjectBrowser").getProjectBrowser(
449 "sources") 612 "sources")
450 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1: 613 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1:
461 from RadonMetrics.RawMetricsDialog import RawMetricsDialog 624 from RadonMetrics.RawMetricsDialog import RawMetricsDialog
462 self.__projectBrowserRawMetricsDialog = RawMetricsDialog(self) 625 self.__projectBrowserRawMetricsDialog = RawMetricsDialog(self)
463 self.__projectBrowserRawMetricsDialog.show() 626 self.__projectBrowserRawMetricsDialog.show()
464 self.__projectBrowserRawMetricsDialog.start(fn) 627 self.__projectBrowserRawMetricsDialog.start(fn)
465 628
466 def __editorOpened(self, editor):
467 """
468 Private slot called, when a new editor was opened.
469
470 @param editor reference to the new editor
471 @type QScintilla.Editor
472 """
473 menu = editor.getMenu("Show")
474 if menu is not None:
475 menu.addAction(self.__editorSeparatorActs[0])
476 menu.addAction(self.__editorRawMetricsAct)
477 menu.addAction(self.__editorSeparatorActs[1])
478 editor.showMenu.connect(self.__editorShowMenu)
479 self.__editors.append(editor)
480
481 def __editorClosed(self, editor):
482 """
483 Private slot called, when an editor was closed.
484
485 @param editor reference to the editor (QScintilla.Editor)
486 """
487 try:
488 self.__editors.remove(editor)
489 except ValueError:
490 pass
491
492 def __editorShowMenu(self, menuName, menu, editor):
493 """
494 Private slot called, when the the editor context menu or a submenu is
495 about to be shown.
496
497 @param menuName name of the menu to be shown (string)
498 @param menu reference to the menu (QMenu)
499 @param editor reference to the editor
500 """
501 if menuName == "Show":
502 self.__editorRawMetricsAct.setEnabled(editor.isPyFile())
503
504 def __editorRawMetrics(self): 629 def __editorRawMetrics(self):
505 """ 630 """
506 Private slot to handle the raw code metrics action of the editor show 631 Private slot to handle the raw code metrics action of the editor show
507 menu. 632 menu.
508 """ 633 """
511 if editor.checkDirty() and editor.getFileName() is not None: 636 if editor.checkDirty() and editor.getFileName() is not None:
512 from RadonMetrics.RawMetricsDialog import RawMetricsDialog 637 from RadonMetrics.RawMetricsDialog import RawMetricsDialog
513 self.__editorRawMetricsDialog = RawMetricsDialog(self) 638 self.__editorRawMetricsDialog = RawMetricsDialog(self)
514 self.__editorRawMetricsDialog.show() 639 self.__editorRawMetricsDialog.show()
515 self.__editorRawMetricsDialog.start(editor.getFileName()) 640 self.__editorRawMetricsDialog.start(editor.getFileName())
641
642 ##################################################################
643 ## Maintainability index calculations
644 ##################################################################
645
646 def __projectMaintainabilityIndex(self):
647 """
648 Private slot used to calculate the maintainability indexes for the
649 project.
650 """
651 project = e5App().getObject("Project")
652 project.saveAllScripts()
653 ppath = project.getProjectPath()
654 files = [os.path.join(ppath, file)
655 for file in project.pdata["SOURCES"]
656 if file.endswith(
657 tuple(Preferences.getPython("Python3Extensions")) +
658 tuple(Preferences.getPython("PythonExtensions")))]
659
660 from RadonMetrics.MaintainabilityIndexDialog import \
661 MaintainabilityIndexDialog
662 self.__projectMIDialog = MaintainabilityIndexDialog(self)
663 self.__projectMIDialog.show()
664 self.__projectMIDialog.prepare(files, project)
665
666 def __projectBrowserMaintainabilityIndex(self):
667 """
668 Private method to handle the maintainability index context menu action
669 of the project sources browser.
670 """
671 browser = e5App().getObject("ProjectBrowser").getProjectBrowser(
672 "sources")
673 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1:
674 fn = []
675 for itm in browser.getSelectedItems([ProjectBrowserFileItem]):
676 fn.append(itm.fileName())
677 else:
678 itm = browser.model().item(browser.currentIndex())
679 try:
680 fn = itm.fileName()
681 except AttributeError:
682 fn = itm.dirName()
683
684 from RadonMetrics.MaintainabilityIndexDialog import \
685 MaintainabilityIndexDialog
686 self.__projectBrowserMIDialog = MaintainabilityIndexDialog(self)
687 self.__projectBrowserMIDialog.show()
688 self.__projectBrowserMIDialog.start(fn)
689
690 def __editorMaintainabilityIndex(self):
691 """
692 Private slot to handle the maintainability index action of the editor
693 show menu.
694 """
695 editor = e5App().getObject("ViewManager").activeWindow()
696 if editor is not None:
697 if editor.checkDirty() and editor.getFileName() is not None:
698 from RadonMetrics.MaintainabilityIndexDialog import \
699 MaintainabilityIndexDialog
700 self.__editorMIDialog = MaintainabilityIndexDialog(self)
701 self.__editorMIDialog.show()
702 self.__editorMIDialog.start(editor.getFileName())

eric ide

mercurial