MENU

Enforcing Style in a Python Project

This article was first published on Python - datawookie , and kindly contributed to python-bloggers. (You can report issue about the content on this page here)
Want to share your content on python-bloggers? click here.

A linter and a styler can help you to write cleaner and more consistent code. In this post we’ll look at how to set up both for a Python project.

What are Pre-Commit Hooks?

Git has the ability to execute specific actions when certain events occur. The connections between the actions and the events are known as hooks. These hooks are configured via files in the

.git/hooks
.git/hooks folder.

Git hooks provide the perfect mechanism for insuring that the code committed to a repository is clean and consistent. We’ll be setting up pre-commit hooks that will run actions immediately before each commit to the Git repository. A commit will only succeed if all of the associated actions are succesful.

The Pre-Commit Framework

Despite the relative simplicity of their implementation, Git hooks can be somewhat fiddly. The pre-commit framework makes it easier to manage and maintain pre-commit hooks. It eliminates a lot of the fiddliness.

The way that the pre-commit framework replaces a collection of distinct hooks with a single hook (the pre-commit hook) and a configuration file. At commit time the pre-commit hook is triggered and it runs all of the actions specified in the configuration file.

Install

Installing the pre-commit framework is simple. You’ll probably want to do this in a virtual environment.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pip install pre-commit
pip install pre-commit
pip install pre-commit

At this point you should also add

pre-commit
pre-commit to your project
requirements.txt
requirements.txt.

Now add pre-commit as a hook.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pre-commit install
pre-commit install
pre-commit install

This will create a hook file at

.git/hooks/pre-commit
.git/hooks/pre-commit.

Configure

The actions run by pre-commit are configured via the

.pre-commit-config.yaml
.pre-commit-config.yaml file. Run the following to generate a simple default configuration.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pre-commit sample-config >.pre-commit-config.yaml
pre-commit sample-config >.pre-commit-config.yaml
pre-commit sample-config >.pre-commit-config.yaml

The contents of the configuration file should look something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.2.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
    -   id: check-yaml
    -   id: check-added-large-files

This configuration will run four distinct actions (

trailing-whitespace
trailing-whitespace,
end-of-file-fixer
end-of-file-fixer,
check-yaml
check-yaml and
check-added-large-files
check-added-large-files) against each file in the repository.

Test

You can test the configuration by manually running the hooks against all files.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pre-commit run --all-files
pre-commit run --all-files
pre-commit run --all-files

If you then run

git status
git status you’ll likely find that one or more of the files in your repository has been modified. In my case this generally involves adding empty lines at the end of various files. Take a look at the changes and if you are happy, stage and commit the changes.

Lint

The Flake8 linter is used to check for syntatic problems in Python code. To enable Flake8 add the following to the

.pre-commit-config.yaml
.pre-commit-config.yaml file.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
- repo: https://github.com/pycqa/flake8 rev: 5.0.4 hooks: - id: flake8
  - repo: https://github.com/pycqa/flake8
    rev: 5.0.4
    hooks:
      - id: flake8

You might want to check the Flake8 repository to see if there are more recent releases and update the

rev
rev field accordingly.

Configuration

You can tweak some Flake8 options by creating a

.flake8
.flake8 file. Its contents might look something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[flake8]
max-line-length = 120
exclude =
database/__init__.py
[flake8] max-line-length = 120 exclude = database/__init__.py
[flake8]
max-line-length = 120
exclude =
    database/__init__.py

A complete list of available options can be found here.

Ignoring Code

You can tell Flake8 to ignore a specific line of code by adding a

noqa
noqa hint as a comment at the end of the line.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from .database import * # noqa
from .database import * # noqa
from .database import * # noqa

You can be more specific by telling Flake8 which errors it should ignore.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from .database import * # noqa: F403
from .database import * # noqa: F401, F403
from .database import * # noqa: F403 from .database import * # noqa: F401, F403
from .database import * # noqa: F403
from .database import * # noqa: F401, F403

Style

The Black code formatter will enforce a consistent formatting style on Python code. Add the following to the

.pre-commit-config.yaml
.pre-commit-config.yaml file.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
- repo: https://github.com/psf/black
rev: 22.8.0
hooks:
- id: black
- repo: https://github.com/psf/black rev: 22.8.0 hooks: - id: black
  - repo: https://github.com/psf/black
    rev: 22.8.0
    hooks:
      - id: black

You might want to check the Black repository to see if there are more recent releases and update the

rev
rev field accordingly.

Prosper

With this setup in place your code will be checked every time you commit. Many issues will be automatically fixed. Others will be highlighted and you’ll have to manually intervene.

This works particularly well if you are part of a team because it means that everybody on the team will be committing and pushing code without any syntactic issues and with consistent formatting.

To leave a comment for the author, please follow the link and comment on their blog: Python - datawookie .

Want to share your content on python-bloggers? click here.