# Use python linters!

**URL:** <https://www.rubin.community/t/use-python-linters/328>\
**Category:** Data Management\
**Tags:** dm-dev\
**Created:** [October 22, 2015, 3:59pm UTC](https://www.rubin.community/t/use-python-linters/328 "2015-10-22T15:59:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![rowen](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rowen/32/52_2.png) [@rowen](https://www.rubin.community/u/rowen)\
**Post date:** [October 22, 2015, 3:59pm UTC](https://www.rubin.community/t/use-python-linters/328/1 "2015-10-22T15:59:22Z")

</div>

Please run a linter on your Python code before checking it into the stack. Unlike C++, many Python errors will not show up until a particular branch of code is executed. Running a linter can catch many errors that might otherwise be missed.

The two most common linters are `pyflakes` and `flake8`. The latter adds `PEP-8` style checking, which can be useful once you configure it to eliminate false warnings. `pyflakes` catches important errors such as trying to use a variable that has never been defined. It also warns you of unused imports and setting variables that are never used, and rightly complains about `from foo import *`

Many editors support automatic live linting of Python code, including `Emacs`, `Sublime Text` and `Atom`. I strongly using automatic linting if your editor supports it, the linting is more likely to occur and you will catch errors earlier.

---

<div class="post-metadata">

**Author:** ![rowen](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rowen/32/52_2.png) [@rowen](https://www.rubin.community/u/rowen)\
**Post date:** [October 22, 2015, 4:07pm UTC](https://www.rubin.community/t/use-python-linters/328/2 "2015-10-22T16:07:43Z")

</div>

**Sublime Text** details: install packages `SublimeLinter` and `SublimeLinter-plyflakes`. Then configure `SublimeLinter` as follows (until we switch to Python 3, presumably with `future` for backwards compatibility):

```
    "@python": 2,

```

I also recommend that you bring up a dialog with errors on save, though this can drive you nuts if you are editing code that includes warnings you want to leave for some reason (that will abate as we start insisting that our code passes pyflakes:

```
    "show_errors_on_save": true,
```

---

<div class="post-metadata">

**Author:** ![jsick](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/jsick/32/672_2.png) [@jsick](https://www.rubin.community/u/jsick)\
**Post date:** [October 22, 2015, 4:08pm UTC](https://www.rubin.community/t/use-python-linters/328/3 "2015-10-22T16:08:11Z")

</div>

For **vim,** I use and advocate the [syntastic](https://github.com/scrooloose/syntastic) plugin. It requires you to install `flake8` separately. The README has details on how to customize the error codes that `flake8` cares about (e.g., exceptions to PEP8).

For lines of code that you _want_ to be exceptions to `flake8` rules, you can append a

```auto
# NOQA

```

comment to that line of code. Then Flake8 will ignore errors on that line.

I often find this useful in ` __init__.py` files where I import modules to setup a namespace, but of course do not _use_ those modules in the ` __init__ ` module itself. (Pyflakes catches unused imports, among other things)

---

<div class="post-metadata">

**Author:** ![rowen](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rowen/32/52_2.png) [@rowen](https://www.rubin.community/u/rowen)\
**Post date:** [October 22, 2015, 4:16pm UTC](https://www.rubin.community/t/use-python-linters/328/4 "2015-10-22T16:16:28Z")

</div>

**Atom** details: install package `linter` and `linter-flake8`. (Note that there is a `linter-pyflakes` but last I checked it was broken with no sign of development.)

You will probably want to configure `linter-flake8` to reduce spurious warnings. I have `Max Line Length` set to 110 and `Ignore Error Codes` set as follows (which may be too aggressive, but you will at least want a subset):

```
C901, E112, E113, E121, E122, E123, E124, E125, E126, E127, E128, E129, E131, E133, E201, E202, E203, E211, E221, E222, E225, E226, E227, E228, E231, E241, E251, E261, E262, E265, E271, E272, E301, E302, E303, E502, W292, W293, W391
```

---

<div class="post-metadata">

**Author:** ![jsick](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/jsick/32/672_2.png) [@jsick](https://www.rubin.community/u/jsick)\
**Post date:** [October 22, 2015, 4:16pm UTC](https://www.rubin.community/t/use-python-linters/328/5 "2015-10-22T16:16:31Z")

</div>

**Emacs** users should speak for their own setups, but [https://github.com/flycheck/flycheck](https://github.com/flycheck/flycheck) seems to be the way to use Flake8 from Emacs. [Search this page of the docs](http://www.flycheck.org/manual/0.24/Supported-languages.html#Supported-languages) for “Python”.

---

<div class="post-metadata">

**Author:** ![jsick](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/jsick/32/672_2.png) [@jsick](https://www.rubin.community/u/jsick)\
**Post date:** [October 22, 2015, 4:17pm UTC](https://www.rubin.community/t/use-python-linters/328/6 "2015-10-22T16:17:27Z")

</div>

**Atom** users also have another Flake8 plugin: [https://atom.io/packages/flake8](https://atom.io/packages/flake8)

… but linter-flake8 that @rowen mentions above seem more comprehensive at first glance: [https://github.com/AtomLinter/linter-flake8](https://github.com/AtomLinter/linter-flake8)

---

<div class="post-metadata">

**Author:** ![parejkoj](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/parejkoj/32/138_2.png) [@parejkoj](https://www.rubin.community/u/parejkoj)\
**Post date:** [October 22, 2015, 7:39pm UTC](https://www.rubin.community/t/use-python-linters/328/7 "2015-10-22T19:39:38Z")

</div>

Yes, linters are amazing. SublimeLinter also supports pylint, which is slightly different from pyflakes in a way that I don’t quite understand.

This does bring up a good point, though: we’ve likely got plenty of `from foo import *` scattered around. I would be of the opinion that such things should go away, since the make certain linting checks impossible and it generally makes code less clear. But we should specify where (outside of \__init_\_.py, if anywhere) it’s allowed to import \* in our standards.

---

<div class="post-metadata">

**Author:** ![rowen](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rowen/32/52_2.png) [@rowen](https://www.rubin.community/u/rowen)\
**Post date:** [October 22, 2015, 7:51pm UTC](https://www.rubin.community/t/use-python-linters/328/8 "2015-10-22T19:51:50Z")

</div>

We already disallow `from foo import *` except in ` __init__.py` files.  
[https://confluence.lsstcorp.org/display/LDMDG/Python+Coding+Standard](https://confluence.lsstcorp.org/display/LDMDG/Python+Coding+Standard)  
see Consistency with the DM C++ Coding Guide namespaces SHOULD be followed
