How to Easily Extend Pylint With Plugins | by Eldad Uzman | Apr, 2022

picture by Paulius Andriekus on unsplash

Static code evaluation and linting are foundational for software program improvement’s success. Some of the generally used static code analyzers for python is pylint

On this article, I’ll present you the way straightforward it’s to increase Pylint utilizing it’s built-in plugins structure.

Static code evaluation is an automatic try to judge code high quality with out working it, versus dynamic code evaluation which is an automatic try to research code high quality at runtime.

So the enter of a static code analyzing software is both the supply code itself or its byte code illustration (if exists), whereas its output is determined by the aim we’re aiming to attain.

Linters are a subtype of static code analyzer that aimed to detect potential bugs, errors, malpractices, and stylistic points.

So like all static code analyzers, linters take the supply code as enter and as output, it offers an inventory of suspicious code statements that builders are ought to enhance.

Pylint is arguably the preferred linter for python programming language.

Since python is an interpreted language, it has no compilation time.
Due to that, there’s no built-in error detection mechanism.
Linting is the one means for a python developer to validate their code earlier than execution.

Along with that, pylint performs type checks to ensure the code is pep8 compliant.

Let’s check out a brief code instance:

This can be a quite simple instance, it opens somefile.txt with write privileges, it writes “howdy world” to the file.

Let’s run this code:

python instance.py

And we get a file with “howdy world” written in it.

Lets lint this code with pylint, first now we have to put in pylint from PyPI warehouse:

pip set up pylint

Now let’s run pylint on our code:

pylint instance.py

Output:

************* Module instance
instance.py:1:0: C0114: Lacking module docstring (missing-module-docstring)
instance.py:1:7: W1514: Utilizing open with out explicitly specifying an encoding (unspecified-encoding)
instance.py:1:7: R1732: Think about using 'with' for resource-allocating operations (consider-using-with)
------------------------------------------------------------------
Your code has been rated at 0.00/10 (earlier run: 0.00/10, +0.00)

We’ve acquired 3 hints:

1 — There’s no module docstring.
That is “simply” a conference trace and it has no impact on runtime, however it is extremely essential to make use of docstrings to ensure your code is communicative and readable.

2 — opening a file with out explicitly specifying encoding.
The default encoding is utf-8, however failing to specify an encoding explicitly could possibly be problematic.

3 — a refactoring suggestion to make use of a with assertion when opening the file, that is truly essential refactor!
On this code, I used the open assertion with out closing the file, I’m in danger of leaking resources!

Along with these errors, my code acquired a rating of 0 out of 10 — yeah it’s that unhealthy!

So lets shortly refactor the code to unravel these 3 issues

Now lets lint this code:

pylint instance.py

Result’s:

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (earlier run: 10.00/10, +0.00)

Nice! there aren’t any errors within the code and the rating is 10/10!

Pylint has a plugin structure that means that you can lengthen it’s performance simply.

To display the usage of such a plugin, let’s write a brief code:

it is a quite simple scripts that has 3 unused imports, which I are not looking for pylint to verify (therefore the trace to disregard unused imports error to pylint)

However as you possibly can see, I’ve 2 import statements from the sys module that may be merged into simply 1.

Lets lint this file with pylint:

pylint ./app/__main__.py

Output:

-------------------------------------------------------------------
Your code has been rated at 10.00/10 (earlier run: 8.57/10, +1.43)

No errors.

It’s because pylint has no checkers for duplicated import.

So lets create considered one of our personal 🙂

First, we have to create a plugin module:

I’ve determined to put in writing this within the __init__.py file so this code runs when the module is loaded.
The register operate is acknowledged by pylints’ plugins supervisor and it used to register a checker to pylints checkers listing.

Now let’s create our checker that checks if there are duplicated from imports:

Pylint checker has a number of parts:

  1. msgs — a dictionary the place the hot button is a regular pylint trace index.
    The trace index begins with both a c (conference), r (refactor), w (warning), e (error), f (deadly), after which 4 digits that don’t battle with some other pylint quantity.
    The worth of the dictionary is a tuple of three components, the message to be displayed, the message lookup title, and a suggestion.
  2. __init__ methodology whereby we instantiate a set.
  3. And the astroid protocol strategies.

Astroid is a visitor that has designated hook strategies for each node sort.
The 2 strategies for every node sort are both go to or go away, and the strategies are acknowledged by the codecs: visit_<node_type> or leave_<node_type> .

As anticipated, the go to methodology is known as when pylints parser visits a node and the go away methodology is known as when it leaves the node.

In our instance, we’ve acquired 2 such strategies:

  1. leave_module — each time after we go away a module we wish to clear the set, in order that it received’t cross aggregated content material from one module to a different.
  2. visit_importfrom — that is the place the validation occurs, after we’ve reached an import from assertion, we wish to verify if now we have already encountered an import from a press release with the identical module title and suggest the developer to merge the 2 import statements into 1.
    We’ll first verify if the module title is within the set member of the category, if is, then we’ll ship a message of the kind duplication-module-imports
    In any other case will add the module title to the set and proceed.
    That is the rationale why we’ve chosen a set as a result of it doesn’t enable for duplications and it has a relentless [O(1)] time complexity for lookup.

Now we have to run pylint with our plugin utilizing pylints load-plugin choices.

set PYTHONPATH=.pylint --load-plugins pylint_plugins.duplicated_imports_plugin app__main__.py

End result:

************* Module __main__
app__main__.py:6:0: W8801: Import from 'sys' module is duplicated (duplication-module-imports)
-------------------------------------------------------------------
Your code has been rated at 8.57/10 (earlier run: 10.00/10, -1.43)

Cool! pylint used the principles offered by the plugin and detected the error we wished it to detect!

Now let’s refactor our code and merge the duplicated import statements.

Lint once more:

set PYTHONPATH=.pylint --load-plugins pylint_plugins.duplicated_imports_plugin app__main__.py

And the result’s:

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (earlier run: 10.00/10, +0.00)

Superior!

More Posts