Invoking Pylint programmatically

Viewed 14893

I'd like to invoke the Pylint checker, limited to the error signalling part, as part of my unit testing. So I checked the Pylint executable script, got to the pylint.lint.Run helper class and there I got lost in a quite long __init__ function, ending with a call to sys.exit().

Anybody ever tried and managed to do so?

The dream-plan would be this:

if __name__ == '__main__':
  import pylint.lint
  pylint.lint.something(__file__, justerrors=True)
  # now continue with unit testing

Any hints? Other than "copy the __init__ method and skip the sys.exit()", I mean?

I don't need the tests to be run by Pylint, it might as well be pyflakes or other software: feel free to suggest alternatives.

8 Answers

Take a look at the pylint/epylint.py file which contains two different ways to start Pylint programmatically.

You can also simply call

from pylint.lint import Run
Run(['--errors-only', 'myfile.py'])

for instance.

I'm glad I came across this. I used some of the answers here and some initiative to come up with:

# a simple class with a write method
class WritableObject:
    def __init__(self):
        self.content = []
    def write(self, string):
        self.content.append(string)
pylint_output = WritableObject()

pylint = lint.Run(args, reporter=ParseableTextReporter(pylint_output), exit=False)

Args in the above is a list of strings eg. ["-r", "n", "myfile.py"]

Here is a wrapper I use to programmatically call pylint so I have a --fail-under arg to overwite the default pylint exit code (usefull for CI). This snippet was tested using pylint 2.3.1

""" Execute pylint and fail if score not reached. """
import argparse
import sys
from pylint import lint

desc = "PyLint wrapper that add the --fail-under option."\
       " All other arguments are passed to pylint."
parser = argparse.ArgumentParser(description=desc, allow_abbrev=False)
parser.add_argument('--fail-under', dest='threshold', type=float, default=8,
                    help='If the final score is more than THRESHOLD, exit with'
                    ' exitcode 0, and pylint\'s exitcode otherwise.')

args, remaining_args = parser.parse_known_args()

threshold = args.threshold

run = lint.Run(remaining_args, do_exit=False)
score = run.linter.stats['global_note']

if score < threshold:
    sys.exit(run.linter.msg_status)

As other answers here have mentioned, pylint.lint.Run is the way to go, however, there is not a good demonstration of Python 3 specific uses. Also, pylint gives a useful reporter class that should be used to capture the output of a pylint run. There are options for all different output types. In the following examples, I'll capture the Colorized output using the ColorizedTextReporter class.

As of pylint 2.12

from pylint import lint
from pylint.reporters import text

# list of pylint args to only enable warnings, errors, and fatals
args = ["my_file.py", "--enable=W,E,F"]

pylint_output = StringIO() # need a StringIO object where the output will be stored
reporter = text.ColorizedTextReporter(pylint_output)

run = lint.Run(args, reporter=reporter, exit=False) # exit=False means don't exit when the run is over

score = run.lint.stats.global_note # pylint score out of 10

# also available are stats.error, stats.warnings, etc...

Before pylint 2.12

The only difference is that the stats object of Run().lint is a dictionary. So you'd get the score by run.lint.stats.get("global_note")

Related