Python Coding Style Guide
Python3 is the main language used for simple tools. As tools grow in complexity, or the requirements on them develop, they serve as valuable prototypes to re-implement tools or their behaviors more maintainably.
Python can be written in vastly different styles, which can lead to code conflicts and code review latency. This style guide aims to promote Python readability across groups. To quote the C++ style guide: “Creating common, required idioms and patterns makes code much easier to understand.”
This guide defines the lowRISC style for Python version 3. The goals are to:
- promote consistency across hardware development projects
- promote best practices
- increase code sharing and re-use
Unless otherwise noted, the following terminology conventions apply to this style guide:
- The word must indicates a mandatory requirement. Similarly, do not indicates a prohibition. Imperative and declarative statements correspond to must.
- The word recommended indicates that a certain course of action is preferred or is most suitable. Similarly, not recommended indicates that a course of action is unsuitable, but not prohibited. There may be reasons to use other options, but the implications and reasons for doing so must be fully understood.
- The word may indicates a course of action is permitted and optional.
- The word can indicates a course of action is possible given material, physical, or causal constraints.
Style Guide Exceptions
Justify exceptions with a comment.
No style guide is perfect. There are times when the best path to a working design, or for working around a tool issue, is to simply cut the Gordian Knot and create code that is at variance with this style guide. It is always okay to deviate from the style guide by necessity, as long as that necessity is clearly justified by a brief comment, as well as a lint waiver pragma where appropriate.
A common case where you may wish to disable tool-enforced reformatting is for large manually formatted data literals. In this case, no explanatory comment is required and yapf can be disabled for that literal with a single pragma.
The lowRISC style matches PEP8 with the following options:
- Bitwise operators should be placed before a line split
- Logical operators should be placed before a line split
To avoid doubt, the interpretation of PEP8 is done by yapf and the style guide is set using a
.style.yapf file in the top level directory of the repository.
This just sets the base style to pep8 and overrides with the exceptions given above.
In addition to the basic style, imports must be ordered alphabetically within sections:
- Python Standard Library
- Third Party
- Current Python Project
The import ordering matches that enforced by isort.
isort defaults are used.
If this changes a
.isort.cfg file will be placed in the top level directory of the repository.
lintpy.py utility in
util can be used to check Python code.
It checks all Python (
.py) files that are modified in the local repository and will report problems.
isort checks are run.
Basic lintpy usage is just to run from the util directory.
If everything is fine the command produces no output, otherwise it will report the problems.
Additional information will be printed if the
-v flag is given.
$ cd $REPO_TOP/util $ ./lintpy.py $ ./lintpy.py -v
Checking can be done on an explicit list of files using the
In this case the tool will not derive the list from git, so any file can be checked even if it has not been modified.
$ cd $REPO_TOP/util $ ./lintpy.py -f a.py subdir/*.py
Errors may be fixed using the same tool to edit the problem file(s) in-place (you may need to refresh the file(s) in your editor after doing this).
This uses the same set of files as are being checked, so unless the
-f flag is used this will only affect files that have already been modified (or staged for commit if
-cis used) and will not fix errors in Python files that have not been touched.
$ cd $REPO_TOP/util $ ./lintpy.py --fix
lintpy.py can be installed as a git pre-commit hook which will prevent commits if there are any lint errors.
This will normally be a symlink to the tool in util so changes are automatically used (it also works if
lintpy.py is copied to
.git/hooks/pre-commit but in that case the hook must be reinstalled each time the tool changes).
Since git hooks are not automatically installed the symlink hook can be installed if required using the tool:
$ cd $REPO_TOP/util $ ./lintpy.py --hook
Fixing style errors for a single file can also be done with
$ yapf -i file.py
Fixing import ordering errors for a single file can be done with
$ isort file.py
Yapf and isort are Python packages and should be installed with pip:
$ pip3 install --user yapt $ pip3 install --user isort
.py extension for Python files
General File Appearance
Use only UTF-8 characters with UNIX-style line endings(
POSIX File Endings
All lines on non-empty files must end with a newline (
Wrap the code at 79 characters per line.
The maximum line length follows PEP8.
- Any place where line wraps are impossible (for example, an include path might extend past 79 characters).
Do not use tabs anywhere.
Use spaces to indent or align text.
To convert tabs to spaces on any file, you can use the UNIX
No Trailing Spaces
Delete trailing whitespace at the end of lines.
Indentation is four spaces per level.
Follows PEP8. Use spaces for indentation. Do not use tabs. You should set your editor to emit spaces when you hit the tab key.
Executable Python tools
Tools that can be executed should use
env to avoid making assumptions about the location of the Python interpreter.
Thus they should begin with the line:
This should be followed by a comment with the license information and the doc string describing the command.
Use argparse to parse command line arguments.
In command line tools use the argparse library to parse arguments.
This will provide support for
-h to get usage information.
Every command line program should provide
--version to provide standard version information.
This lists the git repository information for the tool and the version numbers of any Python packages that are used.
show_and_exit routine in
reggen/version.py can be used to do this.
Options that consume an arbitrary number of command line arguments with
nargs="+" should be avoided wherever possible.
Comma separated lists can be passed to form single arguments and can be split after arguments are parsed.
Args that allow for lists should mention that capability and the separator using the help keyword.
To display proper delimiting of lists, args that allow for lists may demonstrate the separator with the metavar keyword.