|
1 | | -# Coding Style |
| 1 | +# Python Coding Style 🐍 |
2 | 2 |
|
3 | | -Our Python coding style is [PEP8](http://www.python.org/dev/peps/pep-0008/). |
| 3 | +**TLDR**: Configure your text editor to use [`flake8`](https://flake8.readthedocs.org/en/latest/): |
4 | 4 |
|
5 | | -We have an additional standard for import order: |
| 5 | +**Sublime Text** |
6 | 6 |
|
7 | | - # Standard libs first in alpha order. |
8 | | - import abc |
9 | | - import urlparse |
| 7 | +Install [`flake8`](https://flake8.readthedocs.org/en/latest/#quickstart) then |
| 8 | +using [Package Control](https://packagecontrol.io/installation), |
| 9 | +install [SublimeLinter](http://www.sublimelinter.com/en/latest/installation.html) |
| 10 | +and [SublimeLinter-flake8](https://github.com/SublimeLinter/SublimeLinter-flake8). |
10 | 11 |
|
11 | | - # Third party modules. |
12 | | - import requests |
| 12 | +## [PEP8](https://www.python.org/dev/peps/pep-0008/) |
13 | 13 |
|
14 | | - # Project modules (using relative paths where necessary) |
15 | | - from . import mymodule |
| 14 | +We follow [PEP8](http://www.python.org/dev/peps/pep-0008/) with an additional |
| 15 | +standard for ordering imports: |
16 | 16 |
|
17 | | -It's easy to check your code for PEP8 compliance: |
| 17 | +```python |
| 18 | +# First, standard libraries ordered alphabetically. |
| 19 | +import abc |
| 20 | +import urlparse |
18 | 21 |
|
19 | | -**Checking from the command line** |
| 22 | +# Second, third-party libraries. |
| 23 | +import requests |
20 | 24 |
|
21 | | -Install the `pep8` package and run it on one or more directories or files: |
| 25 | +# Third, project libraries, using using relative paths where applicable. |
| 26 | +from . import mymodule |
| 27 | +``` |
22 | 28 |
|
23 | | - $ pip install pep8 |
24 | | - $ # check an individual file |
25 | | - $ pep8 portal/core/admin.py |
26 | | - $ # check a whole directory |
27 | | - $ pep8 portal/mailers |
| 29 | +### PEP8 on the Command Line |
28 | 30 |
|
29 | | -**Checking in IDEs/editors** |
| 31 | +Install the [`pycodestyle`](https://github.com/PyCQA/pycodestyle) package and |
| 32 | +run it on one or more directories or files: |
30 | 33 |
|
31 | | -1. In PyCharm, enable the `PEP8 Coding Style violation` and `PEP8 Naming |
32 | | -Convention violation` inspection rules to have all PEP8 problems marked. |
| 34 | +```bash |
| 35 | +pip install pycodestyle |
33 | 36 |
|
34 | | -2. In Sublime Text, install one of the PEP8 plugins, e.g. [PEP8 Autoformat] |
35 | | -(https://packagecontrol.io/packages/Python%20PEP8%20Autoformat) or [Sublime |
36 | | -Linter PEP8](https://packagecontrol.io/packages/SublimeLinter-pep8). |
37 | | - |
38 | | -**Automatically fixing PEP8 issues** |
| 37 | +pycodestyle portal/core/admin.py # Check a file |
| 38 | +pycodestyle portal/mailers # Check a folder |
| 39 | +``` |
39 | 40 |
|
40 | | -Probably the best solution is *autopep8*: |
| 41 | +### PEP8 in Editors |
41 | 42 |
|
42 | | - $ pip install autopep8 |
43 | | - $ # Spot PEP8 issues and generate a diff |
44 | | - $ autopep8 --diff portal/core/admin.py |
45 | | - $ # Fix PEP8 issues directly in a file |
46 | | - $ autopep8 --in-place portal/core/admin.py |
47 | | - $ # Fix all PEP8 issues in files in a directory |
48 | | - $ autopep8 -i portal/core/* |
49 | | - $ # Fix all PEP8 issues in all files in a directory tree, recursively |
50 | | - $ find portal/core -name '*.py' -print -exec autopep8 --in-place {} \; |
51 | | - |
52 | | -However, if fixing all the PEP8 issues in a file is scary, and all you did is |
53 | | -touch a few lines, you can use `pep8radius`. This will apply `autopep8` to |
54 | | -just the areas of any files that you have changed (it uses `git` to detect |
55 | | -the changes). |
| 43 | +* **PyCharm**: Enable `PEP8 Coding Style violation` and `PEP8 Naming Convention violation` |
| 44 | + inspection rules. |
| 45 | +* **Sublime Text**: Install a PEP8 plugins: [PEP8 Autoformat](https://packagecontrol.io/packages/Python%20PEP8%20Autoformat) or |
| 46 | + [Sublime Linter PEP8](https://packagecontrol.io/packages/SublimeLinter-pep8). |
56 | 47 |
|
57 | | - $ # Install pep8radius |
58 | | - $ # Make your edits.... get all tests running... |
59 | | - $ # Use pep8radius to fix issues in the code changed. The -vv |
60 | | - $ # sets verbose mode so that the output shows progress. |
61 | | - $ pep8radius -vv --in-place |
62 | | - $ # Now rerun tests, then commit |
63 | | - |
64 | | -Note that `pep8radius` will only look at files modified but not yet committed, |
65 | | -so your workflow should include it *before* commit. |
| 48 | +### Resolving PEP8 Errors 🛠 |
66 | 49 |
|
| 50 | +Use [`autopep8`](https://pypi.python.org/pypi/autopep8): |
67 | 51 |
|
68 | | -# Code Inspection |
| 52 | +```bash |
| 53 | +pip install autopep8 |
69 | 54 |
|
70 | | -There are a number of tools that can be used to check Python code for |
71 | | -potential errors. You should run these on code that's already been checked |
72 | | -for PEP8 compliance, so that PEP8 issues don't get flagged. |
| 55 | +autopep8 --diff portal/core/admin.py # Spot issues and generate a diff |
| 56 | +autopep8 --in-place portal/core/admin.py # Fix issues in a file |
| 57 | +autopep8 -i portal/core/* # Fix issues in a folder |
73 | 58 |
|
74 | | -## PyCharm |
| 59 | +# Fix issues in all files in a directory tree, recursively |
| 60 | +find portal/core -name '*.py' -print -exec autopep8 --in-place {} \; |
| 61 | +``` |
75 | 62 |
|
76 | | -The PyCharm IDE has built-in support for Python checking using the |
77 | | -*Inspect Code...* tool. The default set of inspections (all of them) |
78 | | -is suitable for use on our code. |
| 63 | +Use [`pep8radius`](https://pypi.python.org/pypi/pep8radius) limit fixes to areas |
| 64 | +that were modified: |
79 | 65 |
|
80 | | -## PyLint |
| 66 | +```bash |
| 67 | +pip install pep8radius |
81 | 68 |
|
82 | | -Like `pep8`, `pylint` is a pip-installable package providing a command |
83 | | -line tool that can be run on one or more files to check them. |
| 69 | +pep8radius -vv --in-place |
| 70 | +``` |
84 | 71 |
|
85 | | - $ pip install pylint |
86 | | - $ # Run on a single file |
87 | | - $ pylint portal/core/admin.py |
88 | | - $ # Run on a whole directory |
89 | | - $ pylint portal/core |
90 | | - |
91 | | -By default, pylint will dump output to stdout showing: |
| 72 | +`pep8radius` uses `git` to find changes in files that were modified but not |
| 73 | +commited. Use it *before* you commit. |
92 | 74 |
|
93 | | -* Errors found, with the numbers of the offending lines |
94 | | -* Statistics about the code |
95 | | -* A tree of external Python module dependencies |
96 | | -* A measure of duplications found (i.e., where the code could |
97 | | -be DRY'd up) |
98 | | -* A rating out of 10 for the code |
| 75 | +## Code Inspection 🕵 |
99 | 76 |
|
100 | | -You may find the HTML output more useful: |
| 77 | +There are a number of tools that can be used to check Python code for potential |
| 78 | +errors. Run these on code that passes PEP8! |
101 | 79 |
|
102 | | - $ pylint -f html portal/core/admin.py > pylint.html |
103 | | - |
104 | | -It gives more detailed output, including function or class+method names |
105 | | -to make it easier to locate the code that flagged an error. It's most useful |
106 | | -when running pylint over a whole set of files (or a whole directory). |
107 | | - |
108 | | -PyLint is very configurable, and a reference config file is included in |
109 | | -this repo (`pylint.rc`). You can save this in your project root, and pylint |
110 | | -will use it by default (when you run `pylint` from that directory). |
111 | | - |
112 | | - $ pylint --rcfile=pylint.rc mystuff/myapp/myfile.py |
113 | | - |
114 | | -...or save it to `~/.py |
115 | | - |
116 | | -### Fixing PyLint issues |
117 | | - |
118 | | -There are two ways to fix an issue that pylint flags (three if you include *ignore |
119 | | -it and hope someone else fixes it*). |
120 | | - |
121 | | -1. Modify the code to fix the issue. |
122 | | -2. Include a comment to flag to PyLint that it should suppress the check. These |
123 | | -comments take the form `# pylint: disable=<message-type-or-number>` and apply |
124 | | -to the block in which the comment occurs. For example: |
125 | | - |
126 | | - class Foo(object): |
127 | | - def unused_arg1(self, arg): |
128 | | - """This method is flagged because it has an unused argument""" |
129 | | - print self |
130 | | - |
131 | | - def unused_arg2(self, arg): |
132 | | - """ |
133 | | - This method is not flagged because we suppress the |
134 | | - check for unused argument. |
135 | | - """ |
136 | | - # pylint: disable=unused-argument |
137 | | - print self |
138 | | - |
139 | | -Checking this, we get: |
140 | | - |
141 | | - ************* Module a |
142 | | - a.py:line 1: : C0111:missing-docstring:Missing module docstring |
143 | | - a.py:line 1: Foo: C0111:missing-docstring:Missing class docstring |
144 | | - a.py:line 2: Foo.unused_arg1: W0613:unused-argument:Unused argument 'arg' |
145 | | - |
146 | | -...i.e., the unused-argument message is flagged only for method `unused_arg1` |
147 | | - |
148 | | -There's a full list of all the pylint message codes and names here: http://pylint-messages.wikidot.com/all-codes |
149 | | -and detailed documentation of what they mean here: http://docs.pylint.org/features.html |
150 | | - |
151 | | -Because the pylint disabling comments work for the whole block in which they |
152 | | -occur, you can include them at module level to suppress a warning across the |
153 | | -whole module. |
154 | | - |
155 | | -## Pyflakes |
| 80 | +### PyCharm |
| 81 | + |
| 82 | +The PyCharm IDE has built-in support for Python checking using the *Inspect |
| 83 | +Code...* tool. The default set of inspections is suitable for use on our code. |
| 84 | + |
| 85 | +### [PyLint](https://docs.pylint.org/) |
| 86 | + |
| 87 | +PyLint is a Python package for Python source code linting: |
| 88 | + |
| 89 | +```bash |
| 90 | +pip install pylint |
| 91 | + |
| 92 | + |
| 93 | +pylint portal/core/admin.py # Lint a file |
| 94 | +pylint portal/core # Lint a folder |
| 95 | + |
| 96 | +# Lint a file and output details to HTML |
| 97 | +pylint -f html portal/core/admin.py > pylint.html |
| 98 | +``` |
| 99 | + |
| 100 | +Linting is configured using a configuration file. Our reference config, |
| 101 | +[`pylintrc`](./pylintrc), is in this folder. Save it to a project's root folder |
| 102 | +and it will be used when `pylint` is run from there: |
| 103 | + |
| 104 | +```bash |
| 105 | +pylint --rcfile=pylint.rc mystuff/myapp/myfile.py |
| 106 | +``` |
| 107 | + |
| 108 | +#### Fixing PyLint Messages |
| 109 | + |
| 110 | +Fix the message or disable: |
| 111 | + |
| 112 | +```python |
| 113 | +class Foo(object): |
| 114 | + def unused_arg1(self, arg): |
| 115 | + """Messages about unused argument.""" |
| 116 | + print self |
| 117 | + |
| 118 | + def unused_arg2(self, arg): |
| 119 | + """No message because unused argument check is disabled.""" |
| 120 | + # pylint: disable=unused-argument |
| 121 | + print self |
| 122 | +``` |
| 123 | + |
| 124 | +Message codes can be found [here](http://pylint-messages.wikidot.com/all-codes). |
| 125 | + |
| 126 | +Disable works for the block in which they are found, so include it at the module |
| 127 | +level to disable a message for a module or file. |
| 128 | + |
| 129 | +### Pyflakes |
156 | 130 |
|
157 | 131 | Pyflakes is another pip-installable code analysis tool that focuses on |
158 | 132 | identifying coding issues (and less on code layout and formatting). _"Pyflakes |
159 | 133 | makes a simple promise: it will never complain about style, and it will try |
160 | 134 | very, very hard to never emit false positives."_ |
161 | 135 |
|
162 | | - $ pip install pyflakes |
163 | | - $ # Check one file |
164 | | - $ pyflakes portal/core/admin.py |
165 | | - $ # Check all the files in a tree |
166 | | - $ pyflakes portal/core |
| 136 | +```bash |
| 137 | +pip install pyflakes |
| 138 | + |
| 139 | +pyflakes portal/core/admin.py # Check one file |
| 140 | +pyflakes portal/core # Check all the files in a tree |
| 141 | +``` |
167 | 142 |
|
168 | | -Pyflakes has no configuration, and there is no way to suppress a warning |
169 | | -by adding comments. However, it spots a smaller set of issues than PyLint |
170 | | -(for example, it doesn't spot unused arguments). This does mean that anything |
171 | | -it spots is worth checking. |
| 143 | +Pyflakes has no configuration, and there is no way to suppress a warning by |
| 144 | +adding comments. However, it spots a smaller set of issues than PyLint (for |
| 145 | +example, it doesn't spot unused arguments). This does mean that anything it |
| 146 | +spots is worth checking. |
0 commit comments