Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit edddb20

Browse files
authored
Merge pull request #99 from mobify/python-tools-revisited
Update Python Coding Style Guide
2 parents afb199d + 8312f5e commit edddb20

File tree

2 files changed

+114
-138
lines changed

2 files changed

+114
-138
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
*.sw[a-z]
12
.idea/

python/README.md

Lines changed: 113 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,146 @@
1-
# Coding Style
1+
# Python Coding Style 🐍
22

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/):
44

5-
We have an additional standard for import order:
5+
**Sublime Text**
66

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).
1011

11-
# Third party modules.
12-
import requests
12+
## [PEP8](https://www.python.org/dev/peps/pep-0008/)
1313

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:
1616

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
1821

19-
**Checking from the command line**
22+
# Second, third-party libraries.
23+
import requests
2024

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+
```
2228

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
2830

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:
3033

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
3336

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+
```
3940

40-
Probably the best solution is *autopep8*:
41+
### PEP8 in Editors
4142

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).
5647

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 🛠
6649

50+
Use [`autopep8`](https://pypi.python.org/pypi/autopep8):
6751

68-
# Code Inspection
52+
```bash
53+
pip install autopep8
6954

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
7358

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+
```
7562

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:
7965

80-
## PyLint
66+
```bash
67+
pip install pep8radius
8168

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+
```
8471

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.
9274

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 🕵
9976

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!
10179

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
156130

157131
Pyflakes is another pip-installable code analysis tool that focuses on
158132
identifying coding issues (and less on code layout and formatting). _"Pyflakes
159133
makes a simple promise: it will never complain about style, and it will try
160134
very, very hard to never emit false positives."_
161135

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+
```
167142

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

Comments
 (0)