Let me take you on a journey. It's the journey everyone goes through when they first hear about pylint.
Step 1: Install it
$ pip install pylint
Step 2: Run it
$ pylint No config file found, using default configuration Usage: pylint [options] module_or_package ... reams of help output ...
Step 3: It probably needs a path then
$ pylint . No config file found, using default configuration ************* Module my_project F: 1, 0: error while code parsing: Unable to load file '__init__.py' ([Errno 2] No such file or directory: '__init__.py') (parse-error)
Step 4: Ok, so it needs a package. But my project has many packages... ok then.
$ pylint my_project/package1 my_project/package2 my_project/package3
At this point, Pylint runs, and you sit there aghast as 1,000,000 errors stream past you faster than you can read them. From what you spot, you see that a lot are 'line too long' errors, because pylint uses 80 characters by default. You also see a lot of 'not documented' warnings, because let's be honest, who needs to document every function?
It's quite easy to give up at this point, as it seems like the output will be useless to you.
$ pip uninstall pylint
Stop! Pylint is Great
Pylint is a fantastic tool which has been going for centuries and has several dedicated maintainers who are also really lovely people - at EuroPython 2014, I was able to meet them at the 'static analysis dinner'. The logilab blog shows just how much work goes on.
To get the best out of Pylint, however, you do need to spend the time tweaking it. It's like a new puppy, very eager to impress by showing you all the things it can do, but what you actually want is usually a subset of that.
$ pip install prospector $ prospector ... lots of useful stuff ...
Chances are, you will consider most of the warnings that come from tools like
pyflakes to be a bit picky. There are warnings about line length, there are warnings about whitespace on empty lines, there are warnings about how much space there is between methods on your class. What you probably want, however, is a list of actual problems in your code.
For that reason, Prospector has a series of settings and default behaviours to supress the more picky warnings and only provide things that are important. This is the 'strictness' of Prospector and can be configured:
$ prospector --strictness high
A strictness of
veryhigh is basically all output of all tools, but the defaut of
medium is designed to hide the pernickety in favour of the important. Ideally, the real errors are not lost in a swathe of stylistic errors.
Changing Behaviour Based on Dependencies
If you run pylint on a Django project with its default settings, it will warn you:
Class 'MyModel' has no 'objects' member
It will also inspect all of the
south migrations that you have, and various other things that are... unwelcome. Django creates lots of things at runtime via meta-programming, so it's hard for static analysis tools to get a complete picture of what's actually going to happen without running the code.
For Django specifically, I wrote a pylint plugin called pylint-django to aid it in understanding Django code. There's also one for celery although it is very basic at the moment. I hope to add more plugins for more libraries and frameworks in the future.
Prospector will do its best to detect what your project uses as libraries and will automatically adjust the output of the tools it runs depending on what you use. For example, it will detect Django and include the
pylint-django plugin. This will give you many useful messages that are specific to Django code.
Should you wish to delve further into the configuration of prospector, you can use profiles. These are YAML files with directives about which tools and messages to disable or enable.
If you have a project using django, you may have configuration to reflect that. If all you can have is one single configuration file, then you can't reuse configuration in a project which uses django and also celery. Profiles in prospector are able to inherit from each other - so you could create one specific to how you want to use django, and one specific to how you want to use celery, and if you use both in the same project, simply inherit from both.
When I first described Landscape to a friend of mine, he liked the idea of creating your own 'coding style guides' and letting people inspect and share the guides of others. Profiles were designed with this in mind; it may be a space-fairy-unicorn kind of idea but I'd like to see that in the future.
All tools have their own way of outputting messages, their own way of formatting their message, and even their own idea of what exit codes to use if messages are found. This can make it tricky to parse the output of more than one tool. With Prospector, since all tools are sub-commands, and the output is handled and reorganised into a consistent whole. There are several output formats available, including human readable and machine readable.
As Prospector runs six different tools by default, there is naturally some overlap. The same error can be pointed out by several of the tools a the same time. Prospector therefore has the 'blender', which merges messages together when they are warning about the same thing, so that you only get a single message.
One of the benefits of pylint is that there are several plugins and tools designed to use it already out there. For example, there's a Jenkins plugin. By using the
pylint output format, it should be possible to slot prospector in where pylint once was.
$ prospector --output-format pylint
This feature is somewhat untested in the wild, so if you find that it doesn't work in your case, please add an issue and I'll see what I can do to help!
Static Analysis For Humans
The whole purpose of this project is to get people using static analysis. I think they're an excellent resource for projects and can help you find problems in your code and even learn new things. I even gave a rather rambly talk about it at EuroPython, because I honestly believe that software gets better by using automatic checks. At the very least, it won't get worse.
I hope that prospector becomes the 'gateway drug' for static analysis. It's likely that if you want complete control over the analysis of your project, prospector won't be quite configurable enough. However, if you want that level of control, you're probably already using static analysis tools. The goal of prospector therefore is to get people kickstarted, to give projects a sensible base to start from, and the hope is that they will get a lot of benefit, and perhaps even branch out into configuring the tools directly.