--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyLint/PyLintConfigDialog.py Fri Jul 29 19:03:10 2011 +0200 @@ -0,0 +1,338 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2005 - 2011 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to configure the PyLint process +""" + +import os +import copy + +from PyQt4.QtCore import pyqtSlot, QProcess, SIGNAL +from PyQt4.QtGui import QDialog, QFileDialog + +from E5Gui.E5Application import e5App +from E5Gui import E5FileDialog, E5MessageBox +from E5Gui.E5Completers import E5FileCompleter + +from .Ui_PyLintConfigDialog import Ui_PyLintConfigDialog + +import Preferences +import Utilities + + +class PyLintConfigDialog(QDialog, Ui_PyLintConfigDialog): + """ + Class implementing a dialog to configure the PyLint process + """ + def __init__(self, ppath, exe, parms=None, parent=None): + """ + Constructor + + @param ppath project path (string or QString) + Used to set the default path for the rcfile selection dialog + @param exe name of the pylint executable (string) + @param parms parameters to set in the dialog + @param parent reference to the parent widget (QWidget) + """ + super().__init__(parent) + self.setupUi(self) + + self.pylintProc = None + self.lint = exe + + self.__initializeDefaults() + + # get a copy of the defaults to store the user settings + self.parameters = copy.deepcopy(self.defaults) + + # combine it with the values of parms + if parms is not None: + for key, value in parms.items(): + self.parameters[key] = parms[key] + + self.configfileCompleter = E5FileCompleter(self.configfileEdit) + self.reportfileCompleter = E5FileCompleter(self.reportfileEdit) + + # initialize general tab + self.configfileEdit.setText(self.parameters['configFile']) + self.txtOutputButton.setChecked(self.parameters['txtReport']) + self.htmlOutputButton.setChecked(self.parameters['htmlReport']) + self.dialogOutputButton.setChecked(self.parameters['dialogReport']) + self.reportfileEdit.setText(self.parameters['reportFile']) + + # initialize checkers tab + self.basicCheckBox.setChecked(self.parameters['enableBasic']) + self.classesCheckBox.setChecked(self.parameters['enableClasses']) + self.designCheckBox.setChecked(self.parameters['enableDesign']) + self.exceptionsCheckBox.setChecked(self.parameters['enableExceptions']) + self.formatCheckBox.setChecked(self.parameters['enableFormat']) + self.importsCheckBox.setChecked(self.parameters['enableImports']) + self.metricsCheckBox.setChecked(self.parameters['enableMetrics']) + self.miscellaneousCheckBox.setChecked(self.parameters['enableMiscellaneous']) + self.newstyleCheckBox.setChecked(self.parameters['enableNewstyle']) + self.similaritiesCheckBox.setChecked(self.parameters['enableSimilarities']) + self.typecheckCheckBox.setChecked(self.parameters['enableTypecheck']) + self.variablesCheckBox.setChecked(self.parameters['enableVariables']) + self.rpythonCheckBox.setChecked(self.parameters['enableRPython']) + + self.ppath = ppath + + def __initializeDefaults(self): + """ + Private method to set the default values. + + These are needed later on to generate the commandline + parameters. + """ + self.defaults = { + # general options + 'configFile': '', + 'reportFile': '', + 'txtReport': False, + 'htmlReport': True, + 'dialogReport': False, + + # enabled checkers + 'enableBasic': False, + 'enableClasses': False, + 'enableDesign': False, + 'enableExceptions': False, + 'enableFormat': False, + 'enableImports': False, + 'enableMetrics': True, + 'enableMiscellaneous': False, + 'enableNewstyle': False, + 'enableSimilarities': False, + 'enableTypecheck': False, + 'enableVariables': False, + 'enableRPython': False, + } + + def generateParameters(self): + """ + Public method that generates the commandline parameters. + + It generates a QStringList to be used + to set the QProcess arguments for the pylint call and + a list containing the non default parameters. The second + list can be passed back upon object generation to overwrite + the default settings. + + <b>Note</b>: The arguments list contains the name of the pylint executable as + the first parameter. + + @return a tuple of the commandline parameters and non default parameters + (list of strings, dictionary) + """ + parms = {} + args = [] + + # 1. the program name + args.append(self.lint) + + # 2. the commandline options + # 2.1 general options + if self.parameters['configFile'] != self.defaults['configFile']: + parms['configFile'] = self.parameters['configFile'] + args.append('--rcfile={0}'.format(self.parameters['configFile'])) + parms['txtReport'] = self.parameters['txtReport'] + parms['htmlReport'] = self.parameters['htmlReport'] + parms['dialogReport'] = self.parameters['dialogReport'] + if self.parameters['htmlReport']: + args.append('--output-format=html') + elif self.parameters['dialogReport']: + args.append('--output-format=parseable') + args.append('--report=n') + else: + args.append('--output-format=text') + if self.parameters['reportFile'] != self.defaults['reportFile']: + parms['reportFile'] = self.parameters['reportFile'] + + # 2.2 checkers options + parms['enableBasic'] = self.parameters['enableBasic'] + parms['enableClasses'] = self.parameters['enableClasses'] + parms['enableDesign'] = self.parameters['enableDesign'] + parms['enableExceptions'] = self.parameters['enableExceptions'] + parms['enableFormat'] = self.parameters['enableFormat'] + parms['enableImports'] = self.parameters['enableImports'] + parms['enableMetrics'] = self.parameters['enableMetrics'] + parms['enableMiscellaneous'] = self.parameters['enableMiscellaneous'] + parms['enableNewstyle'] = self.parameters['enableNewstyle'] + parms['enableSimilarities'] = self.parameters['enableSimilarities'] + parms['enableTypecheck'] = self.parameters['enableTypecheck'] + parms['enableVariables'] = self.parameters['enableVariables'] + parms['enableRPython'] = self.parameters['enableRPython'] + + checkers = [] + if self.parameters['enableBasic']: + checkers.append('basic') + if self.parameters['enableClasses']: + checkers.append('classes') + if self.parameters['enableDesign']: + checkers.append('design') + if self.parameters['enableExceptions']: + checkers.append('exceptions') + if self.parameters['enableFormat']: + checkers.append('format') + if self.parameters['enableImports']: + checkers.append('imports') + if self.parameters['enableMetrics']: + checkers.append('metrics') + if self.parameters['enableMiscellaneous']: + checkers.append('miscellaneous') + if self.parameters['enableNewstyle']: + checkers.append('newstyle') + if self.parameters['enableSimilarities']: + checkers.append('similarities') + if self.parameters['enableTypecheck']: + checkers.append('typecheck') + if self.parameters['enableVariables']: + checkers.append('variables') + if self.parameters['enableRPython']: + checkers.append('rpython') + args.append('--enable={0}'.format(','.join(checkers))) + + return (args, parms) + + @pyqtSlot() + def on_configfileButton_clicked(self): + """ + Private slot to select the configuration file. + + It displays a file selection dialog to select the configuration file. + """ + startWith = self.configfileEdit.text() + if startWith == "": + startWith = self.ppath + config = E5FileDialog.getOpenFileName( + self, + self.trUtf8("Select configuration file"), + startWith, + self.trUtf8("Configuration Files (*.cfg *.cnf *.rc);;All Files (*)")) + if config: + self.configfileEdit.setText(Utilities.toNativeSeparators(config)) + + @pyqtSlot() + def on_reportfileButton_clicked(self): + """ + Private slot to select the report file. + + It displays a file selection dialog to select the report file. + """ + report = E5FileDialog.getSaveFileName( + self, + self.trUtf8("Select report file"), + self.reportfileEdit.text(), + None, + None, + QFileDialog.Options(QFileDialog.DontConfirmOverwrite)) + + if report: + self.reportfileEdit.setText(Utilities.toNativeSeparators(report)) + + def accept(self): + """ + Protected slot called by the Ok button. + + It saves the values in the parameters dictionary. + """ + # get data of general tab + self.parameters['configFile'] = self.configfileEdit.text() + self.parameters['txtReport'] = self.txtOutputButton.isChecked() + self.parameters['htmlReport'] = self.htmlOutputButton.isChecked() + self.parameters['dialogReport'] = self.dialogOutputButton.isChecked() + self.parameters['reportFile'] = self.reportfileEdit.text() + + # get data of checkers tab + self.parameters['enableBasic'] = self.basicCheckBox.isChecked() + self.parameters['enableClasses'] = self.classesCheckBox.isChecked() + self.parameters['enableDesign'] = self.designCheckBox.isChecked() + self.parameters['enableExceptions'] = self.exceptionsCheckBox.isChecked() + self.parameters['enableFormat'] = self.formatCheckBox.isChecked() + self.parameters['enableImports'] = self.importsCheckBox.isChecked() + self.parameters['enableMetrics'] = self.metricsCheckBox.isChecked() + self.parameters['enableMiscellaneous'] = self.miscellaneousCheckBox.isChecked() + self.parameters['enableNewstyle'] = self.newstyleCheckBox.isChecked() + self.parameters['enableSimilarities'] = self.similaritiesCheckBox.isChecked() + self.parameters['enableTypecheck'] = self.typecheckCheckBox.isChecked() + self.parameters['enableVariables'] = self.variablesCheckBox.isChecked() + self.parameters['enableRPython'] = self.rpythonCheckBox.isChecked() + + # call the accept slot of the base class + super().accept() + + ############################################################################ + ## Methods below are needed to generate a configuration file template + ############################################################################ + + @pyqtSlot() + def on_configButton_clicked(self): + """ + Public slot to handle the generation of a sample configuration. + """ + self.buf = "" + self.pylintProc = QProcess() + args = [] + + self.__ioEncoding = Preferences.getSystem("IOEncoding") + + args.append('--generate-rcfile') + + self.pylintProc.readyReadStandardOutput.connect(self.__readStdout) + self.pylintProc.readyReadStandardError.connect(self.__readStderr) + self.pylintProc.finished.connect(self.__createConfigDone) + + self.pylintProc.start(self.lint, args) + procStarted = self.pylintProc.waitForStarted() + if procStarted: + e5App().getObject("ViewManager").enableEditorsCheckFocusIn(False) + else: + E5MessageBox.critical(self, + self.trUtf8('Process Generation Error'), + self.trUtf8( + 'Could not start {0}.<br>' + 'Ensure that it is in the search path.' + ).format(self.lint)) + + def __createConfigDone(self, exitCode, exitStatus): + """ + Private slot to handle the the finished signal of the pylint process. + + @param exitCode exit code of the process (integer) + @param exitStatus exit status of the process (QProcess.ExitStatus) + """ + vm = e5App().getObject("ViewManager") + vm.enableEditorsCheckFocusIn(True) + if exitStatus == QProcess.NormalExit and exitCode == 0: + vm.newEditor() + aw = vm.activeWindow() + aw.insertAt(self.buf, 0, 0) + aw.setLanguage('dummy.rc') + self.reject() + + def __readStdout(self): + """ + Private slot to handle the readyReadStandardOutput signal of the pylint process. + """ + if self.pylintProc is None: + return + self.pylintProc.setReadChannel(QProcess.StandardOutput) + + while self.pylintProc and self.pylintProc.canReadLine(): + line = str(self.pylintProc.readLine(), self.__ioEncoding, "replace").rstrip() + self.buf += line + os.linesep + + def __readStderr(self): + """ + Private slot to handle the readyReadStandardError signal of the pylint process. + """ + if self.pylintProc is None: + return + self.pylintProc.setReadChannel(QProcess.StandardError) + while self.pylintProc and self.pylintProc.canReadLine(): + s = 'pylint: ' + str( + self.pylintProc.readLine(), self.__ioEncoding, "replace") + e5App().getObject("UserInterface").emit(SIGNAL('appendStderr'), s)