blob: c17bdc51f6f353f49140609897defef1f7fe7236 [file] [log] [blame] [view]
Garret Kelly9eebde02019-10-22 15:36:49 -04001---
2title: "Python Coding Style Guide"
3---
lowRISC Contributors802543a2019-08-31 12:12:56 +01004
5## Basics
6
7### Summary
8
9Python3 is the main language used for simple tools.
10
11Python can be written in vastly different styles, which can lead to code conflicts and code review latency.
12This style guide aims to promote Python readability across groups.
13To quote the C++ style guide: "Creating common, required idioms and patterns makes code much easier to understand."
14
15This guide defines the lowRISC style for Python version 3.
16The goals are to:
17
18* promote consistency across hardware development projects
19* promote best practices
20* increase code sharing and re-use
21
lowRISC Contributors802543a2019-08-31 12:12:56 +010022
23### Terminology Conventions
24
25Unless otherwise noted, the following terminology conventions apply to this style guide:
26
27* The word ***must*** indicates a mandatory requirement.
28 Similarly, ***do not*** indicates a prohibition.
29 Imperative and declarative statements correspond to ***must***.
30* The word ***recommended*** indicates that a certain course of action is preferred or is most suitable.
31 Similarly, ***not recommended*** indicates that a course of action is unsuitable, but not prohibited.
32 There may be reasons to use other options, but the implications and reasons for doing so must be fully understood.
33* The word ***may*** indicates a course of action is permitted and optional.
34* The word ***can*** indicates a course of action is possible given material, physical, or causal constraints.
35
36### Style Guide Exceptions
37
38***Justify exceptions with a comment.***
39
40No style guide is perfect.
41There 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.
42It 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.
43
44A common case where you may wish to disable tool-enforced reformatting is for large manually formatted data literals.
45In this case, no explanatory comment is required and yapf can be disabled for that literal [with a single pragma](https://github.com/google/yapf#why-does-yapf-destroy-my-awesome-formatting).
46
47## Python Conventions
48
49### Summary
50
51The lowRISC style matches [PEP8](https://www.python.org/dev/peps/pep-0008/) with the following options:
52* Bitwise operators should be placed before a line split
53* Logical operators should be placed before a line split
54
55To avoid doubt, the interpretation of PEP8 is done by [yapf](https://github.com/google/yapf) and the style guide is set using a `.style.yapf` file in the top level directory of the repository.
56This just sets the base style to pep8 and overrides with the exceptions given above.
57
58In addition to the basic style, imports must be ordered alphabetically within sections:
59* Future
60* Python Standard Library
61* Third Party
62* Current Python Project
63
64The import ordering matches that enforced by [isort](https://github.com/timothycrosley/isort).
65Currently the `isort` defaults are used.
66If this changes a `.isort.cfg` file will be placed in the top level directory of the repository.
67
68### Lint tool
69
Philipp Wagner14a3fee2019-11-21 10:07:02 +000070The `lintpy.py` utility in `util` can be used to check Python code.
71It checks all Python (`.py`) files that are modified in the local repository and will report problems.
lowRISC Contributors802543a2019-08-31 12:12:56 +010072Both `yapf` and `isort` checks are run.
73
74Basic lintpy usage is just to run from the util directory.
75If everything is fine the command produces no output, otherwise it will report the problems.
76Additional information will be printed if the `--verbose` or `-v` flag is given.
77
78```console
79$ cd $REPO_TOP/util
80$ ./lintpy.py
81$ ./lintpy.py -v
82```
83
84Checking can be done on an explicit list of files using the `--file` or `-f` flag.
85In this case the tool will not derive the list from git, so any file can be checked even if it has not been modified.
86
87```console
88$ cd $REPO_TOP/util
89$ ./lintpy.py -f a.py subdir/*.py
90```
91
92Errors 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).
Philipp Wagner14a3fee2019-11-21 10:07:02 +000093This uses the same set of files as are being checked, so unless the`--file` or `-f` flag is used this will only affect files that have already been modifed (or staged for commit if `-c`is used) and will not fix errors in Python files that have not been touched.
lowRISC Contributors802543a2019-08-31 12:12:56 +010094
95```console
96$ cd $REPO_TOP/util
97$ ./lintpy.py --fix
98```
99
100lintpy.py can be installed as a git pre-commit hook which will prevent commits if there are any lint errors.
101This 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).
102Since git hooks are not automatically installed the symlink hook can be installed if required using the tool:
103
104```console
105$ cd $REPO_TOP/util
106$ ./lintpy.py --hook
107```
108
109
110Fixing style errors for a single file can also be done with `yapf` directly:
111```console
112$ yapf -i file.py
113```
114
115Fixing import ordering errors for a single file can be done with `isort`:
116```console
117$ isort file.py
118```
119
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000120Yapf and isort are Python packages and should be installed with pip:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100121
122```console
123$ pip3 install --user yapt
124$ pip3 install --user isort
125```
126
127### File Extensions
128
129***Use the `.py` extension for Python files***
130
131### General File Appearance
132
133#### Characters
134
135***Use only UTF-8 characters with UNIX-style line endings(`"\n"`).***
136
137Follows PEP8.
138
139#### POSIX File Endings
140
141***All lines on non-empty files must end with a newline (`"\n"`).***
142
143#### Line Length
144
145***Wrap the code at 79 characters per line.***
146
147The maximum line length follows PEP8.
148
149Exceptions:
150
151- Any place where line wraps are impossible (for example, an include path might extend past 79 characters).
152
153#### No Tabs
154
155***Do not use tabs anywhere.***
156
157Use spaces to indent or align text.
158
159To convert tabs to spaces on any file, you can use the [UNIX `expand`](http://linux.die.net/man/1/expand) utility.
160
161#### No Trailing Spaces
162
163***Delete trailing whitespace at the end of lines.***
164
165### Indentation
166
167***Indentation is four spaces per level.***
168
169Follows PEP8.
170Use spaces for indentation.
171Do not use tabs.
172You should set your editor to emit spaces when you hit the tab key.
173
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000174### Executable Python tools
lowRISC Contributors802543a2019-08-31 12:12:56 +0100175
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000176Tools that can be executed should use `env` to avoid making assumptions about the location of the Python interpreter.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100177Thus they should begin with the line:
178
179```console
180#!/usr/bin/env python3
181```
182
183This should be followed by a comment with the license information and the doc string describing the command.
184
185#### Argument Parsing
186
187***Use argparse to parse command line arguments.***
188
189In command line tools use the [argparse library](https://docs.python.org/3/library/argparse.html) to parse arguments.
190This will provide support for `--help` and `-h` to get usage information.
191
192Every command line program should provide `--version` to provide standard version information.
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000193This lists the git repositary information for the tool and the version numbers of any Python packages that are used.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100194The `show_and_exit` routine in `reggen/version.py` can be used to do this.