Wagtail Tutorial Series:
To learn more about Wagtail CMS, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Modern Frontend Techs for Wagtail
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Create Stylish Wagtail Pages with Tailwind CSS
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add Pagination Component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Online Demo http://wagtail-blog.accordbox.com/
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics:
Introduction
In this Wagtail tutorial, I will teach you how to have clean coding style for your Wagtail/Django project. After reading this article, you will get:
- How to check if your Wagtail project follows the PEP8 guidelines.
- How to auto fix your Wagtail project to make it follow PEP8 using
autopep8
- How to organize your Wagtail project import statements using
isort
- How to format Python code with
Black
- What is
pre-commit
and how to use it.
PEP8
PEP8 is a document that provides guidelines and best practices on how to write Python code.
If your Python code is following the guidelines of PEP8, then your Python code would be easy to read and maintain.
Here we use pycodestyle
(formerly called pep8) to let it helps us check our Python code.
pycodestyle is a tool to check your Python code against some of the style conventions in PEP 8.
Let's first create a test python file test.py
, as you can see, this file has bad coding style and not easy to read.
import math, sys;
def example1():
####This is a long comment. This should be wrapped to fit within 72 characters.
some_tuple=( 1,2, 3,'a' );
some_variable={'long':'Long code lines should be wrapped within 79 characters.',
'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'],
'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1,
20,300,40000,500000000,60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key(''));
class Example3( object ):
def __init__ ( self, bar ):
#Comments should have a space after the hash.
if bar : bar+=1; bar=bar* bar ; return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
Now we use pycodestyle
to check the above file.
$ pip install pycodestyle
$ pycodestyle test.py
test.py:1:12: E401 multiple imports on one line
test.py:1:17: E703 statement ends with a semicolon
test.py:3:1: E302 expected 2 blank lines, found 1
test.py:4:5: E265 block comment should start with '# '
test.py:4:80: E501 line too long (83 > 79 characters)
test.py:5:15: E225 missing whitespace around operator
test.py:5:17: E201 whitespace after '('
...
pycodestyle
give us some output and we can fix the Python file based on the output.
There are some other tools which can do similar jobs and here I recommend you to try flake8
flake8
Flake8 is a wrapper of
pycodestyle
and it also add some more useful features.
$ pip install flake8
$ flake8 fabfile.py
test.py:1:12: E401 multiple imports on one line
test.py:1:17: E703 statement ends with a semicolon
test.py:3:1: E302 expected 2 blank lines, found 1
test.py:4:5: E265 block comment should start with '# '
test.py:5:15: E225 missing whitespace around operator
test.py:5:17: E201 whitespace after '('
test.py:5:21: E231 missing whitespace after ','
...
Here you might see flake8
and pycodestyle
print the similar output, but I recommend you to use flake8
because it provides more features compared with pycodestyle
How to config flake8 check rule
By default, the max-line of Python file is 80, If you want to change the max-line length to 120 instead of 80. You can create setup.cfg
in the root of your project. setup.cfg
can contain many config sections for different tools, we can put them in one single file.
Below is a sample config file.
[flake8]
ignore=E501,C901,F401
exclude = */migrations/*,node_modules,*/settings/*,
max-line-length = 120
The exclude
would tell flake8 to ignore some directory and ignore
would tell it to ignore some errors. For example, if you have imported some module but did not use it in your code, you will see something like this. F401, module imported but unused
. Then you can add F401
to your setup.cfg to let it pass.
If you want pyflake8 to ignore some lines in python file, you can append # noqa
just like this.
from .base import * # noqa
# noqa
tells pyflake8
to not check this line, this is commonly used in Wagtail settings file.
Now you can try run flake8
for your Django/Wagtail project.
# cd to the root of the project
$ flake8 django_app
Autopep8
If you are new to Python world, you might see long output after you run flake8
command, is there something that can help you solve this?
autopep8
can save you!
$ pip install autopep8
$ autopep8 test.py --in-place --aggressive --aggressive
Now you can see the test.py has been reformatted
with clean style.
import math
import sys
def example1():
# This is a long comment. This should be wrapped to fit within 72
# characters.
some_tuple = (1, 2, 3, 'a')
some_variable = {
'long': 'Long code lines should be wrapped within 79 characters.',
'other': [
math.pi,
100,
200,
300,
9876543210,
'This is a long string that goes on'],
'more': {
'inner': 'This whole logical line should be wrapped.',
some_tuple: [
1,
20,
300,
40000,
500000000,
60000000000000000]}}
return (some_tuple, some_variable)
def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}
class Example3(object):
def __init__(self, bar):
# Comments should have a space after the hash.
if bar:
bar += 1
bar = bar * bar
return bar
else:
some_string = """
Indentation in multiline strings should not be touched.
Only actual code should be reindented.
"""
return (sys.path, some_string)
You can also let autopep8
to help you fix the whole directory
autopep8 project_dir --recursive --aggressive --in-place --verbose
Please make sure you have two --aggressive
in your command, the file would not be fixed if you only have one --aggressive
Black
Black is the uncompromising Python code formatter. By using it, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for more important matters.
You can see black as another tool which help you Python code has good coding style, which is more and more popular in Python community.
$ pip install black
$ black django_app
reformatted xxx.py
isort
When coding with Wagtail, most code are coming from django
, wagtail
, and some are coming from other 3-party packages. isort
can help us better manage the import statement
.
$ pip install isort
$ isort --recursive project_dir --skip django_app/wsgi.py --skip-glob "*/migrations/*" --skip-glob "*/node_modules/*"
Prettier
Now we already know how to make our Python code have good style using flake8
, black
and isort
But in Wagtail projects, sometimes we also need to write CSS, SCSS and JS code.
So we should use Prettier to help us.
pre-commit
pre-commit is a framework for managing and maintaining multi-language pre-commit hooks.
Let's create .pre-commit-config.yaml
at root directory
repos:
- repo: https://gitlab.com/pycqa/flake8
rev: 4.0.1 # you can change the version as you like
hooks:
- id: flake8
args: ['--config=setup.cfg']
- repo: https://github.com/PyCQA/isort
rev: 5.9.3
hooks:
- id: isort
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.1.2
hooks:
- id: prettier
types: [javascript]
$ pip install pre-commit
# install git hook
$ pre-commit install
$ pre-commit run --all-files
flake8...................................................................Passed
isort....................................................................Passed
prettier.................................................................Passed
- Everytime we run
git commit
,pre-commit
will run to check the commit files automatically. pre-commit
can works with any programming language (prettier
in this case)- Wagtail also use this solution https://github.com/wagtail/wagtail/blob/v2.15.1/.pre-commit-config.yaml
Check Python code style in CI job
With pre-commit
, we can run pre-commit run --all-files
in CI or use https://pre-commit.ci/ service.
Node.js
Another thing I want to say is pre-commit
has dependency nodeenv, which will create an isolated node.js env automatically.
So if you run pre-commit command in a pure python env, the prettier
can still work as expected.
Wagtail Tutorial Series:
To learn more about Wagtail CMS, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Modern Frontend Techs for Wagtail
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Create Stylish Wagtail Pages with Tailwind CSS
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add Pagination Component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Online Demo http://wagtail-blog.accordbox.com/
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics: