Introduction
I have been spent the last few weeks building a Django flashcard app and playing around with python. Now that my project is almost complete, I wanted to improve my Django code by using pre-commit.
Pre-commit is a powerful tool that can greatly enhance your development workflow by automating code quality checks. It acts as a pre-flight checklist for your codebase, ensuring that certain checks and validations are performed before you commit your changes.
Think of pre-commit as a gatekeeper that rigorously examines your code for potential issues and enforces best practices. It helps maintain consistency and readability across your codebase by applying a set of predefined checks, often referred to as “hooks.” These hooks can include linting, style enforcement, formatting, and more.
One of the popular checks enforced by pre-commit is adherence to the PEP8 style guidelines. PEP8 provides a set of recommendations on how to structure and format your Python code to improve its readability. Pre-commit can automatically verify that your code complies with these guidelines and notify you of any violations.
Sounds cool, right? Here is how I added pre-commit to my Django project.
Installation
1.Install pre-commit using pip:
$ pip3 install pre-commit
2. Verify pre-commit is installed by checking the version:
$ pre-commit --version
pre-commit 3.3.2
3. Install the git hook scripts:
pre-commit install
pre-commit installed at .git/hooks/pre-commit
4. Create a pre-commit configuration file in the root of your repository:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
This file defines the pre-commit hooks that you want to run.
5. Run against all files:
pre-commit run --all-files
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/psf/black.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/psf/black.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
check yaml...........................................(no files to check)Skipped
fix end of files.........................................................Failed
- hook id: end-of-file-fixer
- exit code: 1
- files were modified by this hook
Fixing templates/home.html
Fixing flashcards/templates/flashcards/create_card_set.html
Fixing README.md
Fixing flashcards/forms.py
Fixing flashcards/templates/flashcards/flashcards.html
Fixing templates/base.html
Fixing flashcards/templates/flashcards/add_edit_cards.html
Fixing flashcards/templates/flashcards/view_cards.html
trim trailing whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing flashcards/urls.py
Fixing flashcards/admin.py
Fixing flashcard_project/urls.py
Fixing templates/home.html
Fixing .gitignore
Fixing flashcards/models.py
Fixing flashcards/templates/flashcards/create_card_set.html
Fixing README.md
Fixing flashcards/forms.py
Fixing flashcard_project/settings.py
Fixing flashcards/templates/flashcards/flashcards.html
Fixing templates/base.html
Fixing flashcards/views.py
Fixing flashcard_project/views.py
Fixing flashcards/templates/flashcards/add_edit_cards.html
Fixing flashcards/templates/flashcards/view_cards.html
black....................................................................Failed
- hook id: black
- files were modified by this hook
reformatted flashcard_project/asgi.py
reformatted flashcard_project/wsgi.py
reformatted flashcard_project/views.py
reformatted flashcards/apps.py
reformatted flashcard_project/urls.py
reformatted flashcards/forms.py
reformatted flashcards/urls.py
reformatted flashcards/admin.py
reformatted manage.py
reformatted flashcard_project/settings.py
reformatted flashcards/models.py
reformatted flashcards/migrations/0001_initial.py
reformatted flashcards/views.py
All done! ✨ 🍰 ✨
13 files reformatted, 4 files left unchanged.
You can see that pre-commit checked all the files in my project repo and “fixed” them based on the the hooks I have set up.
Black is a Python code formatter and it will check all the files that you commit for any inconsistencies and bad styling, based on the PEP8 standard. The hook will automatically fix any issues it encounters.
6. If you want to exclude certain files from being reformatted by pre-commit, you can add them to the top of your .pre-commit-config.yaml file:
exclude: .*migrations\/.*
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
...
7. Flake8 is another great tool for style guide enforcement. You can add it to your pre-commit-config.yaml file as follows:
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
8. You can create a .flake8 file at the root of your repository and set any custom configuration as need. For example, to set the max-line-length to something other than the default of 79, add the following to your .flake8 file:
[flake8]
max-line-length=120
Note – values set at the command line have highest priority, followed by those in the configuration file (.flake8 in our example), and finally the defaults.
9. Now if you run pre-commit again, you will see the issues that flake8 found and the files and lines where the issue occurs. You will need to go through and fix these issues one by one, as they are not fixed automatically.
$ pre-commit run --all-files
[INFO] Initializing environment for https://github.com/pycqa/flake8.
[INFO] Installing environment for https://github.com/pycqa/flake8.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
check yaml...........................................(no files to check)Skipped
fix end of files.........................................................Failed
- hook id: end-of-file-fixer
- exit code: 1
- files were modified by this hook
Fixing flashcards/templates/flashcards/flashcards.html
trim trailing whitespace.................................................Passed
black....................................................................Passed
flake8...................................................................Failed
- hook id: flake8
- exit code: 1
flashcard_project/settings.py:13:1: F401 'pathlib.Path' imported but unused
flashcard_project/settings.py:19:1: E265 block comment should start with '# '
flashcard_project/settings.py:47:5: E265 block comment should start with '# '
flashcard_project/urls.py:23:121: E501 line too long (126 > 120 characters)
flashcard_project/views.py:2:1: F401 'django.shortcuts.HttpResponseRedirect' imported but unused
flashcards/admin.py:24:1: E302 expected 2 blank lines, found 1
flashcards/admin.py:26:121: E501 line too long (132 > 120 characters)
flashcards/forms.py:2:1: F401 'django.forms' imported but unused
flashcards/models.py:5:1: E302 expected 2 blank lines, found 1
flashcards/models.py:24:5: E301 expected 1 blank line, found 0
flashcards/tests.py:1:1: F401 'django.test.TestCase' imported but unused
flashcards/urls.py:2:1: F401 'django.urls.include' imported but unused
flashcards/views.py:8:1: E302 expected 2 blank lines, found 1
10. After you have fixed all the issue, run pre-commit again to verify all issues are fixed:
$ pre-commit run --all-files
check yaml...........................................(no files to check)Skipped
fix end of files.........................................................Passed
trim trailing whitespace.................................................Passed
black....................................................................Passed
flake8...................................................................Passed
Great! It looks like we are all set now! Now every time you commit changes from your repository, pre-commit will be run and notify you of any issues.
Conclusion
We went through the steps of installing and setting up pre-commit for a project and added several pre-commit hooks. By integrating pre-commit into your development process, you can catch issues early on and ensure that code quality remains high. It not only saves time by automating checks but also reduces the chances of introducing bugs or inconsistencies into your codebase. Also, who doesn’t like seeing all of the “Passed” statuses?!