PyLint/PyLintConfigDialog.py

Thu, 24 Oct 2013 18:56:00 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 24 Oct 2013 18:56:00 +0200
changeset 28
1dae294006e8
parent 24
b01348dd84d5
child 30
de4b620a6e88
permissions
-rw-r--r--

Fixed some code style issues.

# -*- coding: utf-8 -*-

# Copyright (c) 2005 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to configure the PyLint process.
"""

from __future__ import unicode_literals     # __IGNORE_WARNING__
try:
    str = unicode                           # __IGNORE_WARNING__
except (NameError):
    pass

import os
import copy

from PyQt4.QtCore import pyqtSlot, QProcess, SIGNAL
from PyQt4.QtGui import QDialog

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, version):
        """
        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 version pylint version (string)
        """
        super(PyLintConfigDialog, self).__init__(None)
        self.setupUi(self)
        
        self.version = version
        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.loggingCheckBox.setChecked(self.parameters['enableLogging'])
        self.stringFormatCheckBox.setChecked(
            self.parameters['enableStringFormat'])
        
        # initialize messages tab
        self.enabledMessagesEdit.setText(self.parameters['enabledMessages'])
        self.disabledMessagesEdit.setText(self.parameters['disabledMessages'])
        
        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': True,
            'enableClasses': True,
            'enableDesign': True,
            'enableExceptions': True,
            'enableFormat': False,
            'enableImports': False,
            'enableLogging': True,
            'enableMetrics': True,
            'enableMiscellaneous': True,
            'enableNewstyle': True,
            'enableSimilarities': True,
            'enableStringFormat': True,
            'enableTypecheck': True,
            'enableVariables': True,
            
            # messages
            'enabledMessages': '',
            'disabledMessages': '',
        }

    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['enableLogging'] = self.parameters['enableLogging']
        parms['enableStringFormat'] = self.parameters['enableStringFormat']
        
        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['enableLogging']:
            checkers.append('logging')
        if self.parameters['enableStringFormat']:
            if self.version > '0.27.0':
                checkers.append('string')
            else:
                checkers.append('string_format')
            
        args.append('--disable=all')
        if checkers:
            args.append('--enable={0}'.format(','.join(checkers)))
        
        # 2.3 messages options
        parms['enabledMessages'] = self.parameters['enabledMessages']
        parms['disabledMessages'] = self.parameters['disabledMessages']
        if parms['enabledMessages']:
            args.append('--enable={0}'.format(parms['enabledMessages']))
        if parms['disabledMessages']:
            args.append('--disable={0}'.format(parms['disabledMessages']))
        
        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,
            E5FileDialog.Options(E5FileDialog.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['enableLogging'] = self.loggingCheckBox.isChecked()
        self.parameters['enableStringFormat'] = \
            self.stringFormatCheckBox.isChecked()
        
        # get data of messages tab
        self.parameters['enabledMessages'] = ','.join(
            [m.strip() for m in self.enabledMessagesEdit.text().split(',')])
        self.parameters['disabledMessages'] = ','.join(
            [m.strip() for m in self.disabledMessagesEdit.text().split(',')])
        
        # call the accept slot of the base class
        super(PyLintConfigDialog, self).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)

eric ide

mercurial