9 minutes read

Good and clear code is critical. It not only works but is easy to read and understand. "Code is read more often than it is written" is a famous phrase by Guido van Rossum, the founder of Python. You should keep in mind that other people are going to read your code to inspect and contribute to it. It's up to you to make this task easy!

We have the PEP 8 style guide that tells us how to name variables, how many blank lines to use, and so on. It makes the code explicit and consistent, but there are so many conventions! As a beginner, you will certainly have a hard time trying to stick to them. Fortunately, we have linters. A linter is a tool that analyzes your code and reports all the bugs, logical and stylistic errors. In this topic, we'll learn the most popular Python linters: pycodestyle, pylint, and flake8. We'll also have a look at some other tools. Let's start!

You can use pip install modulename to install all the modules mentioned in this topic.

Getting started

Before we start, we need a piece of code to test our linters. Here's what we have:

#a comment
import math, os


def Function1(a, b):
    return a + b

def function2():
    string="This is just a very, very, very, very, very, very long string, it's really way too long"
    return strng

As you can see, there are plenty of mistakes here:

  • no whitespace after # in a comment;

  • two imports on one line;

  • the imported modules aren't used in the code;

  • the function name starts with a capital letter;

  • a string longer than 79 characters;

  • no whitespaces around =;

  • a typo in the second return statement, there's no variable named strng.

Will the linters detect all our mistakes? Let's try and see!

Pycodestyle

We start with pycodestyle – a tool previously called pep8. It checks if your code is compliant with the PEP 8 style guide. That means it doesn't catch logical mistakes, only stylistic ones.

First, we save our code as file.py and then run pycodestyle file.py in the command line. Here's the output:

file.py:1:1: E265 block comment should start with '# '
file.py:2:12: E401 multiple imports on one line
file.py:8:1: E302 expected 2 blank lines, found 1
file.py:9:11: E225 missing whitespace around operator
file.py:9:80: E501 line too long (100 > 79 characters)

So, what do we see here? Each line is formatted like this:

file name: line number: number of character: error code and a description

pycodestyle informs us about missing whitespaces, blank lines, and long lines. The main errors are there. However, it ignores Function1 – a function name starting with a capital letter. Unnecessary imports and a non-existing strng variable are also ignored. Which makes sense – as you remember, pycodestyle doesn't catch logical errors.

There are more features you can use. For example, --show-source will display the lines of code with errors. pycodestyle --show-source file.py will output error messages like this one:

file.py:1:1: E265 block comment should start with '# '
#a comment
^

The --show-pep8 argument will print out the conventions of PEP 8 that are not followed by your code, often with examples and detailed explanations. Pycodestyle --show-pep8 file.py prints an error message like this:

file.py:9:80: E501 line too long (100 > 79 characters)
    Limit all lines to a maximum of 79 characters.

    There are still many devices around that are limited to 80 character
    lines; plus, limiting windows to 80 characters makes it possible to
    have several windows side-by-side.  The default wrapping on such
    devices looks ugly.  Therefore, please limit all lines to a maximum
    of 79 characters. For flowing long blocks of text (docstrings or
    comments), limiting the length to 72 characters is recommended.

    Reports error E501.

These options can be used together if you want to see both the code line and the PEP 8 text. Just use pycodestyle --show-source --show-pep8 file.py.

There are other useful keywords like --statistics that shows how many times each error was found; --ignore=error code allows you to ignore certain errors. Run pycodestyle -h in your command line to see all the options available. You can also read about them in the official documentation.

Autopep8

We've mentioned two tools: linters and helpers. What is a helper? It's a tool that automatically edits your code. One such tool is autopep8 – an automated version of pycodestyle. Let's see how it works.

The standard way of using autopep8 is autopep8 file name. This will only display the corrected version in the console. We want to modify our file, too, so we need autopep8 --in-place file.py. There's no output in the console, but the file now looks like this:

# a comment
import math
import os


def Function1(a, b):
    return a + b


def function2():
    string = "This is just a very, very, very, very, very, very long string, it's really way too long"
    return strng

As you see, many of the mistakes are corrected: import statements are now on separate lines, there are enough blank lines and there are spaces around # and =. However, the long string is unchanged. The logical errors are left out as well since autopep8 only corrects what is detected by pycodestyle.

We strongly recommend you to learn the style conventions and use them yourself instead of referring to helpers. However, sometimes a tool like this may be useful.

Flake8

Now, let's have a look at flake8 – another tool based on pycodestyle. This time it's not a helper, but another linter. Its main advantage over pycodestyle is that it detects logical mistakes as well. Let's check it out!

We call flake8 the same way as other tools: flake8 file.py. Here's the output:

file.py:1:1: E265 block comment should start with '# '
file.py:2:1: F401 'math' imported but unused
file.py:2:1: F401 'os' imported but unused
file.py:2:12: E401 multiple imports on one line
file.py:8:1: E302 expected 2 blank lines, found 1
file.py:9:5: F841 local variable 'string' is assigned to but never used
file.py:9:11: E225 missing whitespace around operator
file.py:9:80: E501 line too long (100 > 79 characters)
file.py:10:12: F821 undefined name 'strng'

Flake8 highlights the same things as pycodestyle, but it also points out logical mistakes. It sees that we haven't used both of our modules; the string variable is also not used and the undefined strng name. That's an improvement!

This tool also has several keyword arguments. For example, --show-source, --statistics, and --ignore work the same way as in pycodestyle. Check out the documentation for the full list of available options (or use flake8 -h to see a help message in the console).

Pylint

The next tool we'd use is pylint. Its functionality is very close to flake8, though pylint generally produces longer, more detailed output. It's one of the most popular linters in Python, so let's have a look!

The design of this tool is similar to others; we run pylint file.py. Let's see what we get:

************* Module file
file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
file.py:2:0: C0410: Multiple imports on one line (math, os) (multiple-imports)
file.py:5:0: C0116: Missing function or method docstring (missing-function-docstring)
file.py:5:0: C0103: Function name "Function1" doesn't conform to snake_case naming style (invalid-name)
file.py:5:14: C0103: Argument name "a" doesn't conform to snake_case naming style (invalid-name)
file.py:5:17: C0103: Argument name "b" doesn't conform to snake_case naming style (invalid-name)
file.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
file.py:10:11: E0602: Undefined variable 'strng' (undefined-variable)
file.py:9:4: W0612: Unused variable 'string' (unused-variable)
file.py:2:0: W0611: Unused import math (unused-import)
file.py:2:0: W0611: Unused import os (unused-import)

------------------------------------------------------------------
Your code has been rated at 0.00/10 

That's longer than anything we've seen so far. It's also the first time all our mistakes are pointed out. Pycodestyle ignored logical issues, flake8 didn't notice a function name starting with a capital letter. Pylint sees it all!

Pylint also complains about missing docstrings and the naming of a and b variables. Why didn't any of the previous linters have a problem with that? The thing is that pycodestyle (and flake8 too, they are based on one another) only checks your code for consistency with PEP 8. However, pylint also has its recommendations, one of them is that variable names should be at least 3 characters long.

Now you see, why some people dislike pylint: not all of the error messages are equally useful. It's possible to customize this linter, telling it you're okay with short variable names, no docstrings, and other stuff, but it takes time. If you're willing to give it a go, you can learn more in the official documentation.

It's also the only linter that gives your code an overall rating. Ours was rated at 0 out of 10, which is... oh, well. However, it is not reasonable to reach for 10 out of 10, since pylint often complains about insignificant things.

IDE inspections

Saving your code to a file, running it through the command line, going back to correct it, then running again – that's weary. What if we could do it in real-time while writing the code? Many IDEs need plugins to do that, but PyCharm doesn't. PyCharm is a Python IDE developed by JetBrains, and in this section, we'll see how to use it for error detection.

PyCharm can detect almost all kinds of mistakes, but some warnings are disabled by default – to avoid bothering you with things you may not care about. However, to see how it works, go to Settings > Editor > Inspections and check all the boxes in the General section.

Now, let's paste our code in the PyCharm (no need to save it to a file this time). Then, click on an icon in the upper right corner that may look something like this:

Pycharm interface icons

It means PyCharm has one error (the red sign), one warning (the yellow sign), and six "notifications" (the beige sign) for us. Let's have a look at them:

PyCharm Project

As you see, it captured both stylistic and logical mistakes. They are ordered from the most severe to less severe ones: first errors, then warnings, then notifications. We also see the number of lines where problems occurred.

PyCharm provides you with a clear overview of all potential problems in your code. The output is easy to read and also easy to customize; while with pylint you'd have to write a whole script. No need to save your script into a file first. If you need more information on code inspections, visit the official PyCharm web page.

Conclusion

In this topic, you've learned about linters and helpers and why they're helpful. Now, you can check your code for mistakes with pycodestyle, flake8, pylint, or inspections in PyCharm. You also know how to correct the code automatically with autopep8. Let's quickly go through the main features of each tool:

  • Pycodestyle checks your code for compliance with PEP 8; it only sees stylistic mistakes;

  • Autopep8 is a helper that automatically corrects issues that pycodestyle finds;

  • Flake8 detects both logical and stylistic mistakes;

  • Pylint detects all kinds of mistakes too, but it uses its style recommendations as well as PEP 8, so the output is long and some error messages may be insignificant;

  • PyCharm catches all kinds of mistakes, allows you to check your code on the go (without saving it into a file and going to the command line), and allows for easy customization.

We hope that now it'd be easier for you to write beautiful, consistent code. Now let's practice!

89 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo