Linting Your Python Code

One class of productivity tools that can be used to support the development of code that conforms to a particular style guide or coding convention such as PEP8 are known as code linters.

These tools provide offline, static analysis of code and can generate reports that describe where code diverges from the style guide.

Some tools may also automatically correct code style, although from a learning perspective it can often be more useful to be warned when you diverge from the code style guidelines so that you can fix the code (and learn how to write it correctly) rather than having the code style automatically corrected for you.

Installation

The pycodestyle_magic extension provides some IPython magic for automatically running the flake8 PEP8 linter against code cells each time you run them.

If your code diverges from PEP8 style guidelines, a warning will be issued.

Install the package by running the following command, which also installs some additional linting rules, such as rules covering function name styling and docstrings.

In [ ]:
%%capture
!pip install --user flake8 pycodestyle pycodestyle_magic

#Install additional style convention rules
!pip install --user pep8-naming flake8-bugbear flake8-docstrings flake8-builtins

# Provide additional conventions for pandas code: https://github.com/deppen8/pandas-vet
!pip install --user pandas-vet

To disable rules associated with a particular flake8 extension package, uninstall it and then restart the notebook kernel. For example:

!pip uninstall -y flake8-bugbear

Other flake8 extensions can be found in this awesome list of flake8 extensions.

Loading the Magic

Each time you want to run the linter, you need to load the magic into a notebook using the command:

In [ ]:
%load_ext pycodestyle_magic

Alternatively, you can modify the startup file that is loaded in to each notebook to automatically load the magic into every notebook. Run the following cell to update the startup file:

In [ ]:
!echo "\n%load_ext pycodestyle_magic\n" >> /home/oustudent/.ipython/profile_default/startup/tm351_start.ipy

Enabling the Magic

The linter can be enabled within a particular notebook by running the magic command:

In [ ]:
%flake8_on

With the linter enabled, each time you run a code cell the code within it will be passed through the linter, and any deviations from the flake installed style conventions will be reported on.

If you want the automatic linter to be enabled automatically for each notebook, add the flake8_on command to the notebook startup file:

In [ ]:
echo "\nflake8_on\n" >> /home/oustudent/.ipython/profile_default/startup/tm351_start.ipy

Automatic running of the linter within a notebook can be disabled by using the command: %flake8_off

Note that if you have turned flake8_on several times in the same notebook, you need to run %flake8_off the same number of times to disable it.

Note that the linter is run against the complete contents of every code cell, so if you include IPython command line directives (lines prefixed with a ! that execute code on the command line), these lines are likely to raise warnings.

In [ ]:
! echo "hello"

As the linter is applied to the complete contents of a code cell, to prevent the linter being applied to a particular cell, you need to run %flake8_off in the cell before it, and then enable %flake8_on again at the end of the cell you want to run without linting.

In [ ]:
%flake8_off
In [ ]:
! echo "hello"
%flake8_on

Example Reports

The following code cells contain examples code that will generate style guide warnings.

Note that the doctring warning D100 will be raised in each code cell because the code cell it treated as a Python module and the style guide requires it to be prefixed with docstring. Hopefully, a way of disabling certain warnings will be provided in a future version of the magic.

In [ ]:
a=1
b = [1,2,3]
map = None

Correctly formatted code should have whitespace around the operator and after each , in the list. Any variable names that clash with Python reserved words are warned against.

In [ ]:
a = 1
b = [1, 2, 3]
my_map = None

Several style conventions are associate with function definitions, including function naming and the requirement for a correctly styled docstring:

In [ ]:
def myFunction(txt):
    a=1
    print(txt)
    return

Note that unused arguments are identified and warned about.

A well formatted function takes the following form:

In [ ]:
def my_function(txt):
    """Print a simple annotated message and return a number."""
    a = 1
    print(txt)
    return a

Automatically Repairing Incorrectly Styled Code

Several tools are available that can be used to repair unstyled code, where possible:

  • within a single cell,
  • across all cells,
  • automatically whenever a code cell is run.

One such tool is provided by the Python autopep8 package. An autopep8 extension is provided as part of the jupyter_contrib_nbextensions package but it requires the installation of the autopep8 dependency to work:

In [ ]:
%%capture
!pip install --user autopep8

#Enable the extension
!jupyter nbextension enable code_prettify/autopep8

The autopep8 extension configurator can be found here: code_prettify/autopep8.

Reload the notebook to see the enabled toolbar button (a hammer).

When a code cell such as the following code cell is selected, clicking the toolbar button will repair the code styling insofar as such repairs are possible.

In [ ]:
def myFunction(txt):
    a=1
    print(txt)
    return

Additional tools, including ones that run automatically, will be described in another document.

Whilst automatic code styling support tools are undoubtedly useful, when learning good practice it can often be more useful — if not also slightly more annoying! — to receive a warning each time you do make a stylistic error.