79 |
80 |
80 def __getProgramVersion(exe): |
81 def __getProgramVersion(exe): |
81 """ |
82 """ |
82 Private method to generate a program entry. |
83 Private method to generate a program entry. |
83 |
84 |
84 @param exe name of the executable program (string) |
85 @param exe name of the executable program |
85 @return version string of detected version (string) |
86 @type str |
|
87 @return version string of detected version |
|
88 @rtype str |
86 """ |
89 """ |
87 proc = QProcess() |
90 proc = QProcess() |
88 proc.setProcessChannelMode(QProcess.MergedChannels) |
91 proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) |
89 proc.start(exe, ['--version']) |
92 proc.start(exe, ['--version']) |
90 finished = proc.waitForFinished(10000) |
93 finished = proc.waitForFinished(10000) |
91 if finished: |
94 if finished: |
92 output = str(proc.readAllStandardOutput(), |
95 output = str(proc.readAllStandardOutput(), |
93 Preferences.getSystem("IOEncoding"), |
96 Preferences.getSystem("IOEncoding"), |
302 |
305 |
303 def activate(self): |
306 def activate(self): |
304 """ |
307 """ |
305 Public method to activate this plugin. |
308 Public method to activate this plugin. |
306 |
309 |
307 @return tuple of None and activation status (boolean) |
310 @return tuple of None and activation status |
|
311 @rtype tuple of (None, bool) |
308 """ |
312 """ |
309 global error |
313 global error |
310 |
314 |
311 # There is already an error, don't activate |
315 # There is already an error, don't activate |
312 if error: |
316 if error: |
313 return None, False |
317 return None, False |
314 # pylint is only activated if it is available |
318 # pylint is only activated if it is available |
315 if not _checkProgram(): |
319 if not _checkProgram(): |
316 return None, False |
320 return None, False |
317 |
321 |
318 menu = e5App().getObject("Project").getMenu("Checks") |
322 menu = ericApp().getObject("Project").getMenu("Checks") |
319 if menu: |
323 if menu: |
320 self.__projectAct = E5Action( |
324 self.__projectAct = EricAction( |
321 self.tr('Run PyLint'), |
325 self.tr('Run PyLint'), |
322 self.tr('Run &PyLint...'), 0, 0, |
326 self.tr('Run &PyLint...'), 0, 0, |
323 self, 'project_check_pylint') |
327 self, 'project_check_pylint') |
324 self.__projectAct.setStatusTip( |
328 self.__projectAct.setStatusTip( |
325 self.tr('Check project, packages or modules with pylint.')) |
329 self.tr('Check project, packages or modules with pylint.')) |
327 """<b>Run PyLint...</b>""" |
331 """<b>Run PyLint...</b>""" |
328 """<p>This checks the project, packages or modules using""" |
332 """<p>This checks the project, packages or modules using""" |
329 """ pylint.</p>""" |
333 """ pylint.</p>""" |
330 )) |
334 )) |
331 self.__projectAct.triggered.connect(self.__projectPylint) |
335 self.__projectAct.triggered.connect(self.__projectPylint) |
332 e5App().getObject("Project").addE5Actions([self.__projectAct]) |
336 ericApp().getObject("Project").addEricActions([self.__projectAct]) |
333 menu.addAction(self.__projectAct) |
337 menu.addAction(self.__projectAct) |
334 |
338 |
335 self.__projectShowAct = E5Action( |
339 self.__projectShowAct = EricAction( |
336 self.tr('Show PyLint Dialog'), |
340 self.tr('Show PyLint Dialog'), |
337 self.tr('Show Py&Lint Dialog...'), 0, 0, |
341 self.tr('Show Py&Lint Dialog...'), 0, 0, |
338 self, 'project_check_pylintshow') |
342 self, 'project_check_pylintshow') |
339 self.__projectShowAct.setStatusTip(self.tr( |
343 self.__projectShowAct.setStatusTip(self.tr( |
340 'Show the PyLint dialog with the results of the last run.')) |
344 'Show the PyLint dialog with the results of the last run.')) |
343 """<p>This shows the PyLint dialog with the results""" |
347 """<p>This shows the PyLint dialog with the results""" |
344 """ of the last run.</p>""" |
348 """ of the last run.</p>""" |
345 )) |
349 )) |
346 self.__projectShowAct.triggered.connect( |
350 self.__projectShowAct.triggered.connect( |
347 self.__projectPylintShow) |
351 self.__projectPylintShow) |
348 e5App().getObject("Project").addE5Actions([self.__projectShowAct]) |
352 ericApp().getObject("Project").addEricActions( |
|
353 [self.__projectShowAct]) |
349 menu.addAction(self.__projectShowAct) |
354 menu.addAction(self.__projectShowAct) |
350 |
355 |
351 self.__editorAct = E5Action( |
356 self.__editorAct = EricAction( |
352 self.tr('Run PyLint'), |
357 self.tr('Run PyLint'), |
353 self.tr('Run &PyLint...'), 0, 0, |
358 self.tr('Run &PyLint...'), 0, 0, |
354 self, "") |
359 self, "") |
355 self.__editorAct.setWhatsThis(self.tr( |
360 self.__editorAct.setWhatsThis(self.tr( |
356 """<b>Run PyLint...</b>""" |
361 """<b>Run PyLint...</b>""" |
357 """<p>This checks the loaded module using pylint.</p>""" |
362 """<p>This checks the loaded module using pylint.</p>""" |
358 )) |
363 )) |
359 self.__editorAct.triggered.connect(self.__editorPylint) |
364 self.__editorAct.triggered.connect(self.__editorPylint) |
360 |
365 |
361 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu) |
366 ericApp().getObject("Project").showMenu.connect(self.__projectShowMenu) |
362 e5App().getObject("ProjectBrowser").getProjectBrowser( |
367 ericApp().getObject("ProjectBrowser").getProjectBrowser( |
363 "sources").showMenu.connect(self.__projectBrowserShowMenu) |
368 "sources").showMenu.connect(self.__projectBrowserShowMenu) |
364 e5App().getObject("ViewManager").editorOpenedEd.connect( |
369 ericApp().getObject("ViewManager").editorOpenedEd.connect( |
365 self.__editorOpened) |
370 self.__editorOpened) |
366 e5App().getObject("ViewManager").editorClosedEd.connect( |
371 ericApp().getObject("ViewManager").editorClosedEd.connect( |
367 self.__editorClosed) |
372 self.__editorClosed) |
368 |
373 |
369 for editor in e5App().getObject("ViewManager").getOpenEditors(): |
374 for editor in ericApp().getObject("ViewManager").getOpenEditors(): |
370 self.__editorOpened(editor) |
375 self.__editorOpened(editor) |
371 |
376 |
372 error = "" |
377 error = "" |
373 return None, True |
378 return None, True |
374 |
379 |
375 def deactivate(self): |
380 def deactivate(self): |
376 """ |
381 """ |
377 Public method to deactivate this plugin. |
382 Public method to deactivate this plugin. |
378 """ |
383 """ |
379 e5App().getObject("Project").showMenu.disconnect( |
384 ericApp().getObject("Project").showMenu.disconnect( |
380 self.__projectShowMenu) |
385 self.__projectShowMenu) |
381 e5App().getObject("ProjectBrowser").getProjectBrowser( |
386 ericApp().getObject("ProjectBrowser").getProjectBrowser( |
382 "sources").showMenu.disconnect(self.__projectBrowserShowMenu) |
387 "sources").showMenu.disconnect(self.__projectBrowserShowMenu) |
383 e5App().getObject("ViewManager").editorOpenedEd.disconnect( |
388 ericApp().getObject("ViewManager").editorOpenedEd.disconnect( |
384 self.__editorOpened) |
389 self.__editorOpened) |
385 e5App().getObject("ViewManager").editorClosedEd.disconnect( |
390 ericApp().getObject("ViewManager").editorClosedEd.disconnect( |
386 self.__editorClosed) |
391 self.__editorClosed) |
387 |
392 |
388 menu = e5App().getObject("Project").getMenu("Checks") |
393 menu = ericApp().getObject("Project").getMenu("Checks") |
389 if menu: |
394 if menu: |
390 if self.__projectAct: |
395 if self.__projectAct: |
391 menu.removeAction(self.__projectAct) |
396 menu.removeAction(self.__projectAct) |
392 e5App().getObject("Project").removeE5Actions( |
397 ericApp().getObject("Project").removeEricActions( |
393 [self.__projectAct]) |
398 [self.__projectAct]) |
394 if self.__projectShowAct: |
399 if self.__projectShowAct: |
395 menu.removeAction(self.__projectShowAct) |
400 menu.removeAction(self.__projectShowAct) |
396 e5App().getObject("Project").removeE5Actions( |
401 ericApp().getObject("Project").removeEricActions( |
397 [self.__projectShowAct]) |
402 [self.__projectShowAct]) |
398 |
403 |
399 if self.__projectBrowserMenu: |
404 if self.__projectBrowserMenu: |
400 if self.__projectBrowserAct: |
405 if self.__projectBrowserAct: |
401 self.__projectBrowserMenu.removeAction( |
406 self.__projectBrowserMenu.removeAction( |
424 translation = "pylint_{0}".format(loc) |
429 translation = "pylint_{0}".format(loc) |
425 translator = QTranslator(None) |
430 translator = QTranslator(None) |
426 loaded = translator.load(translation, locale_dir) |
431 loaded = translator.load(translation, locale_dir) |
427 if loaded: |
432 if loaded: |
428 self.__translator = translator |
433 self.__translator = translator |
429 e5App().installTranslator(self.__translator) |
434 ericApp().installTranslator(self.__translator) |
430 else: |
435 else: |
431 print("Warning: translation file '{0}' could not be" |
436 print("Warning: translation file '{0}' could not be" |
432 " loaded.".format(translation)) |
437 " loaded.".format(translation)) |
433 print("Using default.") |
438 print("Using default.") |
434 |
439 |
435 def __projectShowMenu(self, menuName, menu): |
440 def __projectShowMenu(self, menuName, menu): |
436 """ |
441 """ |
437 Private slot called, when the the project menu or a submenu is |
442 Private slot called, when the the project menu or a submenu is |
438 about to be shown. |
443 about to be shown. |
439 |
444 |
440 @param menuName name of the menu to be shown (string) |
445 @param menuName name of the menu to be shown |
441 @param menu reference to the menu (QMenu) |
446 @type str |
|
447 @param menu reference to the menu |
|
448 @type QMenu |
442 """ |
449 """ |
443 if menuName == "Checks": |
450 if menuName == "Checks": |
444 lang = e5App().getObject("Project").getProjectLanguage() |
451 lang = ericApp().getObject("Project").getProjectLanguage() |
445 if self.__projectAct is not None: |
452 if self.__projectAct is not None: |
446 self.__projectAct.setEnabled(lang.startswith("Python")) |
453 self.__projectAct.setEnabled(lang.startswith("Python")) |
447 if self.__projectShowAct is not None: |
454 if self.__projectShowAct is not None: |
448 self.__projectShowAct.setEnabled(lang.startswith("Python")) |
455 self.__projectShowAct.setEnabled(lang.startswith("Python")) |
449 self.__projectShowAct.setEnabled(self.__pylintPDialog is not None) |
456 self.__projectShowAct.setEnabled(self.__pylintPDialog is not None) |
451 def __projectBrowserShowMenu(self, menuName, menu): |
458 def __projectBrowserShowMenu(self, menuName, menu): |
452 """ |
459 """ |
453 Private slot called, when the the project browser menu or a submenu is |
460 Private slot called, when the the project browser menu or a submenu is |
454 about to be shown. |
461 about to be shown. |
455 |
462 |
456 @param menuName name of the menu to be shown (string) |
463 @param menuName name of the menu to be shown |
457 @param menu reference to the menu (QMenu) |
464 @type str |
|
465 @param menu reference to the menu |
|
466 @type QMenu |
458 """ |
467 """ |
459 if ( |
468 if ( |
460 menuName == "Checks" and |
469 menuName == "Checks" and |
461 e5App().getObject("Project").getProjectLanguage() |
470 ericApp().getObject("Project").getProjectLanguage() |
462 .startswith("Python") |
471 .startswith("Python") |
463 ): |
472 ): |
464 self.__projectBrowserMenu = menu |
473 self.__projectBrowserMenu = menu |
465 if self.__projectBrowserAct is None: |
474 if self.__projectBrowserAct is None: |
466 self.__projectBrowserAct = E5Action( |
475 self.__projectBrowserAct = EricAction( |
467 self.tr('Run PyLint'), |
476 self.tr('Run PyLint'), |
468 self.tr('Run &PyLint...'), 0, 0, |
477 self.tr('Run &PyLint...'), 0, 0, |
469 self, '') |
478 self, '') |
470 self.__projectBrowserAct.setWhatsThis(self.tr( |
479 self.__projectBrowserAct.setWhatsThis(self.tr( |
471 """<b>Run PyLint...</b>""" |
480 """<b>Run PyLint...</b>""" |
474 )) |
483 )) |
475 self.__projectBrowserAct.triggered.connect( |
484 self.__projectBrowserAct.triggered.connect( |
476 self.__projectBrowserPylint) |
485 self.__projectBrowserPylint) |
477 |
486 |
478 if self.__projectBrowserShowAct is None: |
487 if self.__projectBrowserShowAct is None: |
479 self.__projectBrowserShowAct = E5Action( |
488 self.__projectBrowserShowAct = EricAction( |
480 self.tr('Show PyLint Dialog'), |
489 self.tr('Show PyLint Dialog'), |
481 self.tr('Show Py&Lint Dialog...'), 0, 0, |
490 self.tr('Show Py&Lint Dialog...'), 0, 0, |
482 self, '') |
491 self, '') |
483 self.__projectBrowserShowAct.setWhatsThis(self.tr( |
492 self.__projectBrowserShowAct.setWhatsThis(self.tr( |
484 """<b>Show PyLint Dialog...</b>""" |
493 """<b>Show PyLint Dialog...</b>""" |
492 menu.addAction(self.__projectBrowserAct) |
501 menu.addAction(self.__projectBrowserAct) |
493 if self.__projectBrowserShowAct not in menu.actions(): |
502 if self.__projectBrowserShowAct not in menu.actions(): |
494 menu.addAction(self.__projectBrowserShowAct) |
503 menu.addAction(self.__projectBrowserShowAct) |
495 |
504 |
496 enable = ( |
505 enable = ( |
497 e5App().getObject("ProjectBrowser") |
506 ericApp().getObject("ProjectBrowser") |
498 .getProjectBrowser("sources") |
507 .getProjectBrowser("sources") |
499 .getSelectedItemsCount([ProjectBrowserFileItem]) == 1) |
508 .getSelectedItemsCount([ProjectBrowserFileItem]) == 1) |
500 self.__projectBrowserAct.setEnabled(enable) |
509 self.__projectBrowserAct.setEnabled(enable) |
501 self.__projectBrowserShowAct.setEnabled( |
510 self.__projectBrowserShowAct.setEnabled( |
502 enable and self.__pylintPsbDialog is not None) |
511 enable and self.__pylintPsbDialog is not None) |
504 def __pyLint(self, project, mpName, forProject, forEditor=False): |
513 def __pyLint(self, project, mpName, forProject, forEditor=False): |
505 """ |
514 """ |
506 Private method used to perform a PyLint run. |
515 Private method used to perform a PyLint run. |
507 |
516 |
508 @param project reference to the Project object |
517 @param project reference to the Project object |
509 @param mpName name of module or package to be checked (string) |
518 @type Project |
510 @param forProject flag indicating a run for the project (boolean) |
519 @param mpName name of module or package to be checked |
511 @param forEditor flag indicating a run for an editor (boolean) |
520 @type str |
|
521 @param forProject flag indicating a run for the project |
|
522 @type bool |
|
523 @param forEditor flag indicating a run for an editor |
|
524 @type bool |
512 """ |
525 """ |
513 if forEditor: |
526 if forEditor: |
514 parms = copy.deepcopy(self.__editorParms) |
527 parms = copy.deepcopy(self.__editorParms) |
515 editor = e5App().getObject("ViewManager").getOpenEditor(mpName) |
528 editor = ericApp().getObject("ViewManager").getOpenEditor(mpName) |
516 majorVersionStr = editor.getLanguage() |
529 majorVersionStr = editor.getLanguage() |
517 else: |
530 else: |
518 parms = project.getData('CHECKERSPARMS', "PYLINT") |
531 parms = project.getData('CHECKERSPARMS', "PYLINT") |
519 majorVersionStr = project.getProjectLanguage() |
532 majorVersionStr = project.getProjectLanguage() |
520 exe, version = {"Python3": exePy3}.get(majorVersionStr) |
533 exe, version = {"Python3": exePy3}.get(majorVersionStr) |
521 if exe == '': |
534 if exe == '': |
522 E5MessageBox.critical( |
535 EricMessageBox.critical( |
523 None, |
536 None, |
524 self.tr("pylint"), |
537 self.tr("pylint"), |
525 self.tr("""The pylint executable could not be found.""")) |
538 self.tr("""The pylint executable could not be found.""")) |
526 return |
539 return |
527 elif version < '0.23.0': |
540 |
528 E5MessageBox.critical( |
541 from PyLintInterface.PyLintConfigDialog import PyLintConfigDialog |
529 None, |
|
530 self.tr("pylint"), |
|
531 self.tr("PyLint version < 0.23.0.")) |
|
532 return |
|
533 |
|
534 from PyLint.PyLintConfigDialog import PyLintConfigDialog |
|
535 dlg = PyLintConfigDialog(project.getProjectPath(), exe, parms, version) |
542 dlg = PyLintConfigDialog(project.getProjectPath(), exe, parms, version) |
536 if dlg.exec() == QDialog.Accepted: |
543 if dlg.exec() == QDialog.DialogCode.Accepted: |
537 args, parms = dlg.generateParameters() |
544 args, parms = dlg.generateParameters() |
538 self.__editorParms = copy.deepcopy(parms) |
545 self.__editorParms = copy.deepcopy(parms) |
539 if not forEditor: |
546 if not forEditor: |
540 project.setData('CHECKERSPARMS', "PYLINT", parms) |
547 project.setData('CHECKERSPARMS', "PYLINT", parms) |
541 |
548 |
542 # now do the call |
549 # now do the call |
543 from PyLint.PyLintExecDialog import PyLintExecDialog |
550 from PyLintInterface.PyLintExecDialog import PyLintExecDialog |
544 dlg2 = PyLintExecDialog() |
551 dlg2 = PyLintExecDialog() |
545 reportFile = parms.get('reportFile', None) |
552 reportFile = parms.get('reportFile', None) |
546 res = dlg2.start(args, mpName, reportFile, |
553 res = dlg2.start(args, mpName, reportFile, |
547 project.getProjectPath()) |
554 project.getProjectPath()) |
548 if res: |
555 if res: |
608 |
616 |
609 def __editorClosed(self, editor): |
617 def __editorClosed(self, editor): |
610 """ |
618 """ |
611 Private slot called, when an editor was closed. |
619 Private slot called, when an editor was closed. |
612 |
620 |
613 @param editor reference to the editor (QScintilla.Editor) |
621 @param editor reference to the editor |
|
622 @type Editor |
614 """ |
623 """ |
615 with contextlib.suppress(ValueError): |
624 with contextlib.suppress(ValueError): |
616 self.__editors.remove(editor) |
625 self.__editors.remove(editor) |
617 |
626 |
618 def __editorShowMenu(self, menuName, menu, editor): |
627 def __editorShowMenu(self, menuName, menu, editor): |
619 """ |
628 """ |
620 Private slot called, when the the editor context menu or a submenu is |
629 Private slot called, when the the editor context menu or a submenu is |
621 about to be shown. |
630 about to be shown. |
622 |
631 |
623 @param menuName name of the menu to be shown (string) |
632 @param menuName name of the menu to be shown |
624 @param menu reference to the menu (QMenu) |
633 @type str |
625 @param editor reference to the editor (QScintilla.Editor) |
634 @param menu reference to the menu |
|
635 @type QMenu |
|
636 @param editor reference to the editor |
|
637 @type Editor |
626 """ |
638 """ |
627 if menuName == "Checks": |
639 if menuName == "Checks": |
628 if self.__editorAct not in menu.actions(): |
640 if self.__editorAct not in menu.actions(): |
629 menu.addAction(self.__editorAct) |
641 menu.addAction(self.__editorAct) |
630 self.__editorAct.setEnabled(editor.isPyFile()) |
642 self.__editorAct.setEnabled(editor.isPyFile()) |
631 |
643 |
632 def __editorPylint(self): |
644 def __editorPylint(self): |
633 """ |
645 """ |
634 Private slot to handle the Pylint context menu action of the editors. |
646 Private slot to handle the Pylint context menu action of the editors. |
635 """ |
647 """ |
636 editor = e5App().getObject("ViewManager").activeWindow() |
648 editor = ericApp().getObject("ViewManager").activeWindow() |
637 if ( |
649 if ( |
638 editor is not None and |
650 editor is not None and |
639 not editor.checkDirty() |
651 not editor.checkDirty() |
640 ): |
652 ): |
641 return |
653 return |
642 |
654 |
643 fn = editor.getFileName() |
655 fn = editor.getFileName() |
644 project = e5App().getObject("Project") |
656 project = ericApp().getObject("Project") |
645 self.__pyLint(project, fn, False, True) |
657 self.__pyLint(project, fn, False, True) |
|
658 |
|
659 |
|
660 def installDependencies(pipInstall): |
|
661 """ |
|
662 Function to install dependencies of this plug-in. |
|
663 |
|
664 @param pipInstall function to be called with a list of package names. |
|
665 @type function |
|
666 """ |
|
667 try: |
|
668 import pylint # __IGNORE_WARNING__ |
|
669 except ImportError: |
|
670 pipInstall(["pylint"]) |
646 |
671 |
647 # |
672 # |
648 # eflag: noqa = M801 |
673 # eflag: noqa = M801 |