PluginMetricsRadon.py

changeset 12
32a3c9d62e90
parent 11
de8cadbd6a41
child 13
22bc345844e7
equal deleted inserted replaced
11:de8cadbd6a41 12:32a3c9d62e90
14 from PyQt5.QtCore import pyqtSignal, QObject, QTranslator 14 from PyQt5.QtCore import pyqtSignal, QObject, QTranslator
15 from PyQt5.QtWidgets import QAction 15 from PyQt5.QtWidgets import QAction
16 16
17 from E5Gui.E5Application import e5App 17 from E5Gui.E5Application import e5App
18 from E5Gui.E5Action import E5Action 18 from E5Gui.E5Action import E5Action
19 from E5Gui import E5MessageBox
19 20
20 from Project.ProjectBrowserModel import ProjectBrowserFileItem 21 from Project.ProjectBrowserModel import ProjectBrowserFileItem
21 22
22 import Preferences 23 import Preferences
23 from Utilities import determinePythonVersion 24 from Utilities import determinePythonVersion
258 259
259 def __initialize(self): 260 def __initialize(self):
260 """ 261 """
261 Private slot to (re)initialize the plugin. 262 Private slot to (re)initialize the plugin.
262 """ 263 """
263 self.__projectRawMetricsAct = None
264 self.__projectRawMetricsDialog = None 264 self.__projectRawMetricsDialog = None
265 self.__projectMIAct = None
266 self.__projectMIDialog = None 265 self.__projectMIDialog = None
266 self.__projectMetricsActs = []
267 self.__projectSeparatorActs = [] 267 self.__projectSeparatorActs = []
268 268
269 self.__projectBrowserRawMetricsDialog = None
270 self.__projectBrowserMIDialog = None
269 self.__projectBrowserMenu = None 271 self.__projectBrowserMenu = None
270 self.__projectBrowserRawMetricsAct = None 272 self.__projectBrowserMetricsActs = []
271 self.__projectBrowserRawMetricsDialog = None
272 self.__projectBrowserMIAct = None
273 self.__projectBrowserMIDialog = None
274 self.__projectBrowserSeparatorActs = [] 273 self.__projectBrowserSeparatorActs = []
275 274
276 self.__editors = [] 275 self.__editors = []
277 self.__editorRawMetricsAct = None
278 self.__editorRawMetricsDialog = None 276 self.__editorRawMetricsDialog = None
279 self.__editorMIAct = None
280 self.__editorMIDialog = None 277 self.__editorMIDialog = None
278 self.__editorMetricsActs = []
281 self.__editorSeparatorActs = [] 279 self.__editorSeparatorActs = []
282 280
283 def rawMetrics(self, lang, filename, source): 281 def rawMetrics(self, lang, filename, source):
284 """ 282 """
285 Public method to prepare raw code metrics calculation on one Python 283 Public method to prepare raw code metrics calculation on one Python
400 @rtype (None, bool) 398 @rtype (None, bool)
401 """ 399 """
402 global error 400 global error
403 error = "" # clear previous error 401 error = "" # clear previous error
404 402
403 # Project menu actions
405 menu = e5App().getObject("Project").getMenu("Show") 404 menu = e5App().getObject("Project").getMenu("Show")
406 if menu: 405 if menu:
407 if not menu.isEmpty(): 406 if not menu.isEmpty():
408 act = menu.addSeparator() 407 act = menu.addSeparator()
409 # TODO: change this to a 'header' action with bold text
410 act.setText(self.tr("Radon"))
411 self.__projectSeparatorActs.append(act) 408 self.__projectSeparatorActs.append(act)
412 409
413 self.__projectRawMetricsAct = E5Action( 410 # header action
411 act = QAction(self.tr("Radon"), self)
412 font = act.font()
413 font.setBold(True)
414 act.setFont(font)
415 act.triggered.connect(self.__showRadonVersion)
416 menu.addAction(act)
417 self.__projectMetricsActs.append(act)
418
419 act = E5Action(
414 self.tr('Code Metrics'), 420 self.tr('Code Metrics'),
415 self.tr('Code &Metrics...'), 0, 0, 421 self.tr('Code &Metrics...'), 0, 0,
416 self, 'project_show_radon_raw') 422 self, 'project_show_radon_raw')
417 self.__projectRawMetricsAct.setStatusTip( 423 act.setStatusTip(
418 self.tr('Show raw code metrics.')) 424 self.tr('Show raw code metrics.'))
419 self.__projectRawMetricsAct.setWhatsThis(self.tr( 425 act.setWhatsThis(self.tr(
420 """<b>Code Metrics...</b>""" 426 """<b>Code Metrics...</b>"""
421 """<p>This calculates raw code metrics of Python files""" 427 """<p>This calculates raw code metrics of Python files"""
422 """ and shows the amount of lines of code, logical lines""" 428 """ and shows the amount of lines of code, logical lines"""
423 """ of code, source lines of code, comment lines,""" 429 """ of code, source lines of code, comment lines,"""
424 """ multi-line strings and blank lines.</p>""" 430 """ multi-line strings and blank lines.</p>"""
425 )) 431 ))
426 self.__projectRawMetricsAct.triggered.connect( 432 act.triggered.connect(self.__projectRawMetrics)
427 self.__projectRawMetrics) 433 menu.addAction(act)
428 menu.addAction(self.__projectRawMetricsAct) 434 self.__projectMetricsActs.append(act)
429 435
430 self.__projectMIAct = E5Action( 436 act = E5Action(
431 self.tr('Maintainability Index'), 437 self.tr('Maintainability Index'),
432 self.tr('Maintainability &Index...'), 0, 0, 438 self.tr('Maintainability &Index...'), 0, 0,
433 self, 'project_show_radon_mi') 439 self, 'project_show_radon_mi')
434 self.__projectMIAct.setStatusTip( 440 act.setStatusTip(
435 self.tr('Show the maintainability index for Python files.')) 441 self.tr('Show the maintainability index for Python files.'))
436 self.__projectMIAct.setWhatsThis(self.tr( 442 act.setWhatsThis(self.tr(
437 """<b>Maintainability Index...</b>""" 443 """<b>Maintainability Index...</b>"""
438 """<p>This calculates the maintainability index of Python""" 444 """<p>This calculates the maintainability index of Python"""
439 """ files and shows it together with a ranking.</p>""" 445 """ files and shows it together with a ranking.</p>"""
440 )) 446 ))
441 self.__projectMIAct.triggered.connect( 447 act.triggered.connect(self.__projectMaintainabilityIndex)
442 self.__projectMaintainabilityIndex) 448 menu.addAction(act)
443 menu.addAction(self.__projectMIAct) 449 self.__projectMetricsActs.append(act)
444 450
445 act = menu.addSeparator() 451 act = menu.addSeparator()
446 self.__projectSeparatorActs.append(act) 452 self.__projectSeparatorActs.append(act)
447 453
448 e5App().getObject("Project").addE5Actions([ 454 e5App().getObject("Project").addE5Actions(
449 self.__projectRawMetricsAct, 455 self.__projectMetricsActs[1:])
450 self.__projectMIAct 456
451 ]) 457 # Editor menu actions
452 458 act = QAction(self)
453 act = QAction("Radon", self)
454 act.setSeparator(True) 459 act.setSeparator(True)
455 self.__editorSeparatorActs.append(act) 460 self.__editorSeparatorActs.append(act)
456 act = QAction(self) 461 act = QAction(self)
457 act.setSeparator(True) 462 act.setSeparator(True)
458 self.__editorSeparatorActs.append(act) 463 self.__editorSeparatorActs.append(act)
459 464
460 self.__editorRawMetricsAct = E5Action( 465 # header action
466 act = QAction(self.tr("Radon"), self)
467 font = act.font()
468 font.setBold(True)
469 act.setFont(font)
470 act.triggered.connect(self.__showRadonVersion)
471 menu.addAction(act)
472 self.__editorMetricsActs.append(act)
473
474 act = E5Action(
461 self.tr('Code Metrics'), 475 self.tr('Code Metrics'),
462 self.tr('Code &Metrics...'), 0, 0, 476 self.tr('Code &Metrics...'), 0, 0,
463 self, "") 477 self, "")
464 self.__editorRawMetricsAct.setWhatsThis(self.tr( 478 act.setStatusTip(
479 self.tr('Show raw code metrics.'))
480 act.setWhatsThis(self.tr(
465 """<b>Code Metrics...</b>""" 481 """<b>Code Metrics...</b>"""
466 """<p>This calculates raw code metrics of Python files""" 482 """<p>This calculates raw code metrics of Python files"""
467 """ and shows the amount of lines of code, logical lines""" 483 """ and shows the amount of lines of code, logical lines"""
468 """ of code, source lines of code, comment lines,""" 484 """ of code, source lines of code, comment lines,"""
469 """ multi-line strings and blank lines.</p>""" 485 """ multi-line strings and blank lines.</p>"""
470 )) 486 ))
471 self.__editorRawMetricsAct.triggered.connect(self.__editorRawMetrics) 487 act.triggered.connect(self.__editorRawMetrics)
472 488 self.__editorMetricsActs.append(act)
473 self.__editorMIAct = E5Action( 489
490 act = E5Action(
474 self.tr('Maintainability Index'), 491 self.tr('Maintainability Index'),
475 self.tr('Maintainability &Index...'), 0, 0, 492 self.tr('Maintainability &Index...'), 0, 0,
476 self, "") 493 self, "")
477 self.__editorMIAct.setStatusTip( 494 act.setStatusTip(
478 self.tr('Show the maintainability index for Python files.')) 495 self.tr('Show the maintainability index for Python files.'))
479 self.__projectMIAct.setWhatsThis(self.tr( 496 act.setWhatsThis(self.tr(
480 """<b>Maintainability Index...</b>""" 497 """<b>Maintainability Index...</b>"""
481 """<p>This calculates the maintainability index of Python""" 498 """<p>This calculates the maintainability index of Python"""
482 """ files and shows it together with a ranking.</p>""" 499 """ files and shows it together with a ranking.</p>"""
483 )) 500 ))
484 self.__editorMIAct.triggered.connect( 501 act.triggered.connect(self.__editorMaintainabilityIndex)
485 self.__editorMaintainabilityIndex) 502 self.__editorMetricsActs.append(act)
486 503
487 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu) 504 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu)
488 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\ 505 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\
489 .showMenu.connect(self.__projectBrowserShowMenu) 506 .showMenu.connect(self.__projectBrowserShowMenu)
490 e5App().getObject("ViewManager").editorOpenedEd.connect( 507 e5App().getObject("ViewManager").editorOpenedEd.connect(
512 529
513 menu = e5App().getObject("Project").getMenu("Show") 530 menu = e5App().getObject("Project").getMenu("Show")
514 if menu: 531 if menu:
515 for sep in self.__projectSeparatorActs: 532 for sep in self.__projectSeparatorActs:
516 menu.removeAction(sep) 533 menu.removeAction(sep)
517 menu.removeAction(self.__projectRawMetricsAct) 534 for act in self.__projectMetricsActs:
518 menu.removeAction(self.__projectMIAct) 535 menu.removeAction(act)
519 e5App().getObject("Project").removeE5Actions([ 536 e5App().getObject("Project").removeE5Actions(
520 self.__projectRawMetricsAct, 537 self.__projectMetricsActs[1:])
521 self.__projectMIAct
522 ])
523 538
524 if self.__projectBrowserMenu: 539 if self.__projectBrowserMenu:
525 for sep in self.__projectBrowserSeparatorActs: 540 for sep in self.__projectBrowserSeparatorActs:
526 self.__projectBrowserMenu.removeAction(sep) 541 self.__projectBrowserMenu.removeAction(sep)
527 if self.__projectBrowserRawMetricsAct: 542 for act in self.__projectBrowserMetricsActs:
528 self.__projectBrowserMenu.removeAction( 543 self.__projectBrowserMenu.removeAction(act)
529 self.__projectBrowserRawMetricsAct)
530 if self.__projectBrowserMIAct:
531 self.__projectBrowserMenu.removeAction(
532 self.__projectBrowserMIAct)
533 544
534 for editor in self.__editors: 545 for editor in self.__editors:
535 editor.showMenu.disconnect(self.__editorShowMenu) 546 editor.showMenu.disconnect(self.__editorShowMenu)
536 menu = editor.getMenu("Show") 547 menu = editor.getMenu("Show")
537 if menu is not None: 548 if menu is not None:
538 for sep in self.__editorSeparatorActs: 549 for sep in self.__editorSeparatorActs:
539 menu.removeAction(sep) 550 menu.removeAction(sep)
540 menu.removeAction(self.__editorRawMetricsAct) 551 for act in self.__editorMetricsActs:
541 menu.removeAction(self.__editorMIAct) 552 menu.removeAction(act)
542 553
543 self.__initialize() 554 self.__initialize()
544 555
545 def __loadTranslator(self): 556 def __loadTranslator(self):
546 """ 557 """
571 @type str 582 @type str
572 @param menu reference to the menu 583 @param menu reference to the menu
573 @type QMenu 584 @type QMenu
574 """ 585 """
575 if menuName == "Show": 586 if menuName == "Show":
576 for act in [self.__projectRawMetricsAct, self.__projectMIAct]: 587 for act in self.__projectMetricsActs[1:]:
577 if act is not None: 588 act.setEnabled(
578 act.setEnabled( 589 e5App().getObject("Project").getProjectLanguage() in
579 e5App().getObject("Project").getProjectLanguage() in 590 ["Python3", "Python2", "Python"])
580 ["Python3", "Python2", "Python"])
581 591
582 def __projectBrowserShowMenu(self, menuName, menu): 592 def __projectBrowserShowMenu(self, menuName, menu):
583 """ 593 """
584 Private slot called, when the the project browser context menu or a 594 Private slot called, when the the project browser context menu or a
585 submenu is about to be shown. 595 submenu is about to be shown.
590 if menuName == "Show" and \ 600 if menuName == "Show" and \
591 e5App().getObject("Project").getProjectLanguage() in \ 601 e5App().getObject("Project").getProjectLanguage() in \
592 ["Python3", "Python2", "Python"]: 602 ["Python3", "Python2", "Python"]:
593 if self.__projectBrowserMenu is None: 603 if self.__projectBrowserMenu is None:
594 self.__projectBrowserMenu = menu 604 self.__projectBrowserMenu = menu
605
595 act = menu.addSeparator() 606 act = menu.addSeparator()
596 act.setText(self.tr("Radon"))
597 self.__projectBrowserSeparatorActs.append(act) 607 self.__projectBrowserSeparatorActs.append(act)
598 608
599 self.__projectBrowserRawMetricsAct = E5Action( 609 # header action
610 act = QAction(self.tr("Radon"), self)
611 font = act.font()
612 font.setBold(True)
613 act.setFont(font)
614 act.triggered.connect(self.__showRadonVersion)
615 menu.addAction(act)
616 self.__projectBrowserMetricsActs.append(act)
617
618 act = E5Action(
600 self.tr('Code Metrics'), 619 self.tr('Code Metrics'),
601 self.tr('Code &Metrics...'), 0, 0, 620 self.tr('Code &Metrics...'), 0, 0,
602 self, '') 621 self, '')
603 self.__projectBrowserRawMetricsAct.setStatusTip( 622 act.setStatusTip(
604 self.tr('Show raw code metrics.')) 623 self.tr('Show raw code metrics.'))
605 self.__projectBrowserRawMetricsAct.setWhatsThis(self.tr( 624 act.setWhatsThis(self.tr(
606 """<b>Code Metrics...</b>""" 625 """<b>Code Metrics...</b>"""
607 """<p>This calculates raw code metrics of Python files""" 626 """<p>This calculates raw code metrics of Python files"""
608 """ and shows the amount of lines of code, logical lines""" 627 """ and shows the amount of lines of code, logical lines"""
609 """ of code, source lines of code, comment lines,""" 628 """ of code, source lines of code, comment lines,"""
610 """ multi-line strings and blank lines.</p>""" 629 """ multi-line strings and blank lines.</p>"""
611 )) 630 ))
612 self.__projectBrowserRawMetricsAct.triggered.connect( 631 act.triggered.connect(self.__projectBrowserRawMetrics)
613 self.__projectBrowserRawMetrics) 632 menu.addAction(act)
614 menu.addAction(self.__projectBrowserRawMetricsAct) 633 self.__projectBrowserMetricsActs.append(act)
615 634
616 self.__projectBrowserMIAct = E5Action( 635 act = E5Action(
617 self.tr('Maintainability Index'), 636 self.tr('Maintainability Index'),
618 self.tr('Maintainability &Index...'), 0, 0, 637 self.tr('Maintainability &Index...'), 0, 0,
619 self, 'project_show_radon_mi') 638 self, 'project_show_radon_mi')
620 self.__projectBrowserMIAct.setStatusTip( 639 act.setStatusTip(
621 self.tr('Show the maintainability index for Python' 640 self.tr('Show the maintainability index for Python'
622 ' files.')) 641 ' files.'))
623 self.__projectBrowserMIAct.setWhatsThis(self.tr( 642 act.setWhatsThis(self.tr(
624 """<b>Maintainability Index...</b>""" 643 """<b>Maintainability Index...</b>"""
625 """<p>This calculates the maintainability index of""" 644 """<p>This calculates the maintainability index of"""
626 """ Python files and shows it together with a ranking.""" 645 """ Python files and shows it together with a ranking."""
627 """</p>""" 646 """</p>"""
628 )) 647 ))
629 self.__projectBrowserMIAct.triggered.connect( 648 act.triggered.connect(
630 self.__projectBrowserMaintainabilityIndex) 649 self.__projectBrowserMaintainabilityIndex)
631 menu.addAction(self.__projectBrowserMIAct) 650 menu.addAction(act)
651 self.__projectBrowserMetricsActs.append(act)
652
653 act = menu.addSeparator()
654 self.__projectBrowserSeparatorActs.append(act)
632 655
633 def __editorOpened(self, editor): 656 def __editorOpened(self, editor):
634 """ 657 """
635 Private slot called, when a new editor was opened. 658 Private slot called, when a new editor was opened.
636 659
638 @type QScintilla.Editor 661 @type QScintilla.Editor
639 """ 662 """
640 menu = editor.getMenu("Show") 663 menu = editor.getMenu("Show")
641 if menu is not None: 664 if menu is not None:
642 menu.addAction(self.__editorSeparatorActs[0]) 665 menu.addAction(self.__editorSeparatorActs[0])
643 menu.addAction(self.__editorRawMetricsAct) 666 menu.addActions(self.__editorMetricsActs)
644 menu.addAction(self.__editorMIAct)
645 menu.addAction(self.__editorSeparatorActs[1]) 667 menu.addAction(self.__editorSeparatorActs[1])
646 editor.showMenu.connect(self.__editorShowMenu) 668 editor.showMenu.connect(self.__editorShowMenu)
647 self.__editors.append(editor) 669 self.__editors.append(editor)
648 670
649 def __editorClosed(self, editor): 671 def __editorClosed(self, editor):
666 @param menu reference to the menu (QMenu) 688 @param menu reference to the menu (QMenu)
667 @param editor reference to the editor 689 @param editor reference to the editor
668 """ 690 """
669 if menuName == "Show": 691 if menuName == "Show":
670 enable = editor.isPyFile() 692 enable = editor.isPyFile()
671 self.__editorRawMetricsAct.setEnabled(enable) 693 for act in self.__editorMetricsActs:
672 self.__editorMIAct.setEnabled(enable) 694 act.setEnabled(enable)
673 695
674 ################################################################## 696 ##################################################################
675 ## Raw code metrics calculations 697 ## Raw code metrics calculations
676 ################################################################## 698 ##################################################################
677 699
788 from RadonMetrics.MaintainabilityIndexDialog import \ 810 from RadonMetrics.MaintainabilityIndexDialog import \
789 MaintainabilityIndexDialog 811 MaintainabilityIndexDialog
790 self.__editorMIDialog = MaintainabilityIndexDialog(self) 812 self.__editorMIDialog = MaintainabilityIndexDialog(self)
791 self.__editorMIDialog.show() 813 self.__editorMIDialog.show()
792 self.__editorMIDialog.start(editor.getFileName()) 814 self.__editorMIDialog.start(editor.getFileName())
815
816 def __showRadonVersion(self):
817 """
818 Private slot to show the version number of the used radon library.
819 """
820 from RadonMetrics.radon import __version__
821 E5MessageBox.information(
822 None,
823 self.tr("Radon"),
824 self.tr(
825 """<p><b>Radon Version {0}</b></p>"""
826 """<p>Radon is a Python tool that computes various metrics"""
827 """ from the source code. Radon can compute:"""
828 """<ul>"""
829 """<li><b>Raw</b> metrics (these include SLOC, comment"""
830 """ lines, blank lines, multi line strings, ...)</li>"""
831 """<li><b>Maintainability Index</b> (the one used in Visual"""
832 """ Studio)</li>"""
833 """<li><b>McCabe's complexity</b>, i.e. cyclomatic"""
834 """ complexity</li>"""
835 """</ul></p>"""
836 ).format(__version__))
837

eric ide

mercurial