406

I would like to get some feedback on these tools on:

  • features;
  • adaptability;
  • ease of use and learning curve.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bite code
  • 578,959
  • 113
  • 301
  • 329
  • 1
    Shouldn't the title be edited to include pep8 as an option? At first, I thought you guys were talking about the proposition, not an actual PyPI package. – Ehtesh Choudhury Jul 17 '11 at 20:35
  • I suggest you start with something very strict, make it less strict at first for obviously painful cases, use it for a while, then get stricter later on by adding back rules (not all at the same time). Do it slowly but do it. – Christophe Roussy Jul 19 '16 at 10:14
  • Just mentioning `prospector` ;) – Dunatotatos Jun 20 '18 at 10:46
  • I'd just like to raise an objection to the closure of this question, as this is an unfortunate tendency in SO to continually anticipate opinion based answers, even before any answers have been submitted. It's kind of sad to have to say it, but of course answers to questions like this can be submitted based on technical pros and cons that are inherent in the feature sets of the software under investigation. How else are folks going to get answers on which packages experienced and knowledgeable devs are using for particular purposes? E.g. why not use Pylint? Maybe it breaks code sometimes? – NeilG Oct 01 '22 at 08:04

2 Answers2

292

Well, I am a bit curious, so I just tested the three myself right after asking the question ;-)

Ok, this is not a very serious review, but here is what I can say:

I tried the tools with the default settings (it's important because you can pretty much choose your check rules) on the following script:

#!/usr/local/bin/python
# by Daniel Rosengren modified by e-satis

import sys, time
stdout = sys.stdout

BAILOUT = 16
MAX_ITERATIONS = 1000

class Iterator(object) :

    def __init__(self):

        print 'Rendering...'
        for y in xrange(-39, 39):
            stdout.write('\n')
            for x in xrange(-39, 39):
                if self.mandelbrot(x/40.0, y/40.0) :
                    stdout.write(' ')
                else:
                    stdout.write('*')


    def mandelbrot(self, x, y):
        cr = y - 0.5
        ci = x
        zi = 0.0
        zr = 0.0

        for i in xrange(MAX_ITERATIONS) :
            temp = zr * zi
            zr2 = zr * zr
            zi2 = zi * zi
            zr = zr2 - zi2 + cr
            zi = temp + temp + ci

            if zi2 + zr2 > BAILOUT:
                return i

        return 0

t = time.time()
Iterator()
print '\nPython Elapsed %.02f' % (time.time() - t)

As a result:

  • PyChecker is troublesome because it compiles the module to analyze it. If you don't want your code to run (e.g, it performs a SQL query), that's bad.
  • PyFlakes is supposed to be light. Indeed, it decided that the code was perfect. I am looking for something quite severe so I don't think I'll go for it.
  • PyLint has been very talkative and rated the code 3/10 (OMG, I'm a dirty coder !).

Strong points of PyLint:

  • Very descriptive and accurate report.
  • Detect some code smells. Here it told me to drop my class to write something with functions because the OO approach was useless in this specific case. Something I knew, but never expected a computer to tell me :-p
  • The fully corrected code run faster (no class, no reference binding...).
  • Made by a French team. OK, it's not a plus for everybody, but I like it ;-)

Cons of Pylint:

  • Some rules are really strict. I know that you can change it and that the default is to match PEP8, but is it such a crime to write 'for x in seq'? Apparently yes because you can't write a variable name with less than 3 letters. I will change that.
  • Very very talkative. Be ready to use your eyes.

Corrected script (with lazy doc strings and variable names):

#!/usr/local/bin/python
# by Daniel Rosengren, modified by e-satis
"""
Module doctring
"""


import time
from sys import stdout

BAILOUT = 16
MAX_ITERATIONS = 1000

def mandelbrot(dim_1, dim_2):
    """
    function doc string
    """
    cr1 = dim_1 - 0.5
    ci1 = dim_2
    zi1 = 0.0
    zr1 = 0.0

    for i in xrange(MAX_ITERATIONS) :
        temp = zr1 * zi1
        zr2 = zr1 * zr1
        zi2 = zi1 * zi1
        zr1 = zr2 - zi2 + cr1
        zi1 = temp + temp + ci1

        if zi2 + zr2 > BAILOUT:
            return i

    return 0

def execute() :
    """
    func doc string
    """
    print 'Rendering...'
    for dim_1 in xrange(-39, 39):
        stdout.write('\n')
        for dim_2 in xrange(-39, 39):
            if mandelbrot(dim_1/40.0, dim_2/40.0) :
                stdout.write(' ')
            else:
                stdout.write('*')


START_TIME = time.time()
execute()
print '\nPython Elapsed %.02f' % (time.time() - START_TIME)

Thanks to Rudiger Wolf, I discovered pep8 that does exactly what its name suggests: matching PEP8. It has found several syntax no-nos that Pylint did not. But Pylint found stuff that was not specifically linked to PEP8 but interesting. Both tools are interesting and complementary.

Eventually I will use both since there are really easy to install (via packages or setuptools) and the output text is so easy to chain.

To give you a little idea of their output:

pep8:

./python_mandelbrot.py:4:11: E401 multiple imports on one line
./python_mandelbrot.py:10:1: E302 expected 2 blank lines, found 1
./python_mandelbrot.py:10:23: E203 whitespace before ':'
./python_mandelbrot.py:15:80: E501 line too long (108 characters)
./python_mandelbrot.py:23:1: W291 trailing whitespace
./python_mandelbrot.py:41:5: E301 expected 1 blank line, found 3

Pylint:

************* Module python_mandelbrot
C: 15: Line too long (108/80)
C: 61: Line too long (85/80)
C:  1: Missing docstring
C:  5: Invalid name "stdout" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
C: 10:Iterator: Missing docstring
C: 15:Iterator.__init__: Invalid name "y" (should match [a-z_][a-z0-9_]{2,30}$)
C: 17:Iterator.__init__: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)

[...] and a very long report with useful stats like :

Duplication
-----------

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |0        |=          |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |0.000    |=          |
+-------------------------+------+---------+-----------+
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bite code
  • 578,959
  • 113
  • 301
  • 329
  • 18
    The purpose of pyflakes is to statically analyze your code to make sure there will be no name errors or unused variables/imports. – culebrón Jun 14 '11 at 18:42
  • 4
    Am I getting this wrong or is there no strong/weak point for PyChecker nor PyFlakes? – Wernight Mar 29 '12 at 22:13
  • 1
    Strong/weak points for PyChecker and PyFlakes is given here: http://stackoverflow.com/a/44996/452885 – GuruM Jul 19 '12 at 10:59
  • also try pyhint if you’ve since found that pylint is a pain in the ass and ovely finnicky ;) – flying sheep Sep 12 '12 at 19:01
  • 17
    "Strongs points : Very descriptive and accurate report." Which report? Is this section about all the tools or just one? – ijk Jan 22 '13 at 01:43
  • 3
    I wonder. I abviously wrote the whole pro/con only about PyLint. I have no idea why I wrote in this stupid way. Hangover maybe ? Sorry guys. – Bite code Jan 22 '13 at 13:25
  • 16
    [flake8](https://flake8.readthedocs.org/en/2.0/) covers both `pyflakes` and `pep8`. Strongly suggest it over just using one or the other. – Ehtesh Choudhury Feb 14 '14 at 20:38
  • 1
    “PyChecker is troublesome because it compiles the module to analyze it. If you don't want your code to run […] that's bad.”: you know, an `if __name__ == '__main__':` doesn't cost much ;-) . – Hibou57 Sep 02 '14 at 09:40
  • 3
    @Hibou57 It may not cost much, but that's a bizarre comment to make about a tool whose very purpose is to _check for mistakes_. – alexh Feb 22 '15 at 01:02
  • FYI For pylint you could use: pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" to get the same unix style output message – moylop260 Aug 11 '16 at 19:09
  • FYI For pylint you could use: `pylint -rn` to avoid the report output – moylop260 Aug 11 '16 at 19:10
  • 1
    pylint is talkative but it really do its jobs. Some rules are quite trick, like variable name cannot be shorter than 3 characters or import must be before any code even sys.path.append() – PT Huynh Oct 20 '16 at 00:10
  • Exactery. Why isn't `flake8` in the mix here? – NeilG Jul 31 '23 at 03:51
95

pep8 was recently added to PyPi.

  • pep8 - Python style guide checker
  • pep8 is a tool to check your Python code against some of the style conventions in PEP 8.

It is now super easy to check your code against pep8.

See http://pypi.python.org/pypi/pep8

Rudiger Wolf
  • 1,760
  • 12
  • 15
  • 59
    There is IMO better package. [`flake8`](http://pypi.python.org/pypi/flake8), it combines the two and adds conditional complexity, works on directories and is generally good. – DinGODzilla Oct 09 '12 at 21:19
  • 1
    Running `flake8` for the first time taught me that I jumped right into a project without learning that Python strongly prefers spaces for some reason. I had to use `--ignore W191` to make the output useful. – cjm Jan 15 '17 at 07:14
  • 4
    Note that recent versions of `pep8` are now called `pycodestyle`; see https://pypi.org/project/pycodestyle @cjm : python strongly prefers spaces because that is what's specified by the style guidelines. Spaces aren't necessarily superior, but consistency across the community is a great advantage, and the community has decided on spaces, so do that. – Chris L. Barnes Sep 01 '18 at 23:21
  • How do I best configure my editor (either BBEdit or vim) to use spaces for Python and tabs for absolutely everything else? It seems that (at least for BBEdit) it’s a global setting. – cjm Sep 05 '18 at 01:41
  • 1
    @cjm In vim, you can do `:set et` (short for `expandtabs`) and then `:retab` to convert all tabs in the current buffer into spaces. It may also be useful to set `ts=4 sts=4 sw=4` (`tabstop`, `softtabstop`, `shiftwidth`) first. As far as a general approach, I prefer using https://editorconfig.org/ and its plugins to set the right settings in a repo, so you don't have to worry about reconfiguring your editor for different codebases. – codermonkeyfuel Apr 24 '19 at 19:04