Prasad Muley bio photo

Prasad Muley

24, Python Programmer, Photographer, Portraitist and Pro-Biker.

Email Twitter Instagram Github

We understood the difference between pep8 and linters in previous post. We’ll see various linters available in python with sample example.

Sample program:

I’ve written a error-prone program. It contains some unused imported modules, variables and arguments. It also overriddes one function. I’ve intentionally not followed pep8’s guidelines. Let’s see output of each linter.

#!/usr/bin/env python
# encoding: utf-8

#unused modules
import os
import sys
import argparse


#unused global constant variable
user_name = 'rootpy'



def setUserName(self, name):
    fname = 'Prasad'
    u_name = name
    return u_name



class User(object):

    def __init__(self, str, int):
        self.name = None
        self.password = None
        return

    def getUserPassword(self, password):
        self.password = password
        return

    def changeUserName(self, email):
        return
        print "How can I reach here?"

    def getUserPassword(self, password):
        return self.password == password

###PyChecker * It imports each module and compiles the each function, class and method for possible errors. * It determines the imported modules, classes and functions and creates a tree based on it. * It can’t process the module if there is an import error. * It compiles and executes the imported module so your code get executed. * For example: If you’ve SQL queries in python program then it executes every time which is bad (IMO) * Let’s pass the sample_program.py and analyze the output.

prasad@Rootpy: master ⚡
$ pychecker sample_program.py
Processing module test_program_rootpy (test_program_rootpy.py)...

Warnings...

sample_program.py:5: Imported module (os) not used
sample_program.py:6: Imported module (sys) not used
sample_program.py:7: Imported module (argparse) not used
sample_program.py:15: self is argument in function
sample_program.py:16: Local variable (fname) not used
sample_program.py:23: Parameter (int) not used
sample_program.py:23: Parameter (str) not used
sample_program.py:32: Redefining attribute (getUserPassword) original line (28)
FAIL: 1


prasad@Rootpy: master ⚡
$

Here,

  • It detects following errors:
    • unused imported module, local variable and arguments errors.
    • self is argument in function
  • But it doesn’t detect following errors:
    • unused global variable user_name.
    • pep8 related errors (some linters detect it).
  • It becomes slower than other linters because it imports all the modules and execute it one by one.
  • You can create configure it by creating configuration file (.pycheckerr)
  • Check here for more information

###PyFlake * It is a static code analyzer as It identifies errors without executing python code. * It is faster than PyChecker because it doesn’t import any module and execute it. * Let’s see output for sample_program.py

prasad@Rootpy: master ⚡
$ pyflakes sample_program.py
sample_program.py:5: 'os' imported but unused
sample_program.py:6: 'sys' imported but unused
sample_program.py:7: 'argparse' imported but unused
sample_program.py:16: local variable 'fname' is assigned to but never used
sample_program.py:32: redefinition of unused 'getUserPassword' from line 28

FAIL: 1

prasad@Rootpy: master ⚡
$

Here,

  • It detects unused imported module, local variable and arguments related errors.
  • It doesn’t detect following errors:
    • Unused global variable user_name.
    • pep8 style guide related error.
    • Self is used as argument in function
    • Redefining parameters like int, str which are built-in data type in python
  • It examines the syntax tree of each file individually So it is faster.
  • Check on github or docs for more information.

###Flake8 * It is a static code analyzer. Actually it is combination of pep8 and PyFlake. * It identifies programming errors as well as pep8 style-guide errors. * Let’s check what it gives on sample_program.py

prasad@Rootpy: master ⚡
$ flake8 sample_program.py

sample_program.py:5:1: F401 'os' imported but unused
sample_program.py:6:1: F401 'sys' imported but unused
sample_program.py:7:1: F401 'argparse' imported but unused
sample_program.py:15:1: E303 too many blank lines (3)
sample_program.py:16:5: F841 local variable 'fname' is assigned to but never used
sample_program.py:32:5: F811 redefinition of unused 'getUserPassword' from line 28
sample_program.py:39:1: W391 blank line at end of file
FAIL: 1

prasad@Rootpy: master ⚡
$

Here,

  • It detects following errors:
    • unused imported module, local variable, arguments error.
    • pep8 related errors like blank line, too many blank line etc.
  • It doesn’t detect following errors:
    • unused global variable user_name.
    • Self is used as argument in function
    • Parameters like int, str which are built-in data type in python
  • Check flake8’s docs for more information.

###PyLint * It is a static code analyzer which checks errors in python code. * It looks for bad codes and tries to enforce a coding standard. * It displays statistics about the number of warnings and errors found in different files. * It also gives overall mark, based on numbers of warnings and errors. Some key features as below: * Refactoring: * It also detects duplicates codes. * Fully Customizable: * You can create your own .pylintrc and modify which errors are important for you. * UML Diagram: * It creates UML diagrams for python code using Pyreverse * Editor and IDE integration: * Editor Integration are available for various editors like emacs, vim and eclipse * IDE integration are also available for various IDEs like spyder, editra and TextMate * Check list of supported editors and IDEs * It gives very descriptive output. The output is divided into two categories message and reports. * message contains warnings, errors, coding standard convention, Refactoring and Fatal errors. * error messages type: * [R]efactor for a “good practice” metric violation * [C]onvention for coding standard violation * [W]arning for stylistic problems, or minor programming issues * [E]rror for important programming issues (i.e. most probably bug) * [F]atal for errors which prevented further processing. * Reports contains statistics information for by type, raw metrics, duplication, message by category etc. * Let’s run pylint on sample_program.py and check the output.

prasad@Rootpy: master ⚡
$ pylint sample_program.py                                          

************* Module sample_program
C:  1, 0: Missing module docstring (missing-docstring)
C: 11, 0: Invalid constant name "user_name" (invalid-name)
C: 15, 0: Invalid function name "setUserName" (invalid-name)
C: 15, 0: Missing function docstring (missing-docstring)
W: 15,16: Unused argument 'self' (unused-argument)
W: 16, 4: Unused variable 'fname' (unused-variable)
C: 21, 0: Missing class docstring (missing-docstring)
W: 23,28: Redefining built-in 'int' (redefined-builtin)
W: 23,23: Redefining built-in 'str' (redefined-builtin)
W: 23,28: Unused argument 'int' (unused-argument)
W: 23,23: Unused argument 'str' (unused-argument)
C: 28, 4: Invalid method name "getUserPassword" (invalid-name)
C: 28, 4: Missing method docstring (missing-docstring)
E: 32, 4: method already defined line 28 (function-redefined)
C: 32, 4: Invalid method name "getUserPassword" (invalid-name)
C: 32, 4: Missing method docstring (missing-docstring)
C: 35, 4: Invalid method name "changeUserName" (invalid-name)
C: 35, 4: Missing method docstring (missing-docstring)
W: 37, 8: Unreachable code (unreachable)
W: 35,29: Unused argument 'email' (unused-argument)
R: 35, 4: Method could be a function (no-self-use)
W:  5, 0: Unused import os (unused-import)
W:  6, 0: Unused import sys (unused-import)
W:  7, 0: Unused import argparse (unused-import)


Report
======
22 statements analysed.

Statistics by type
------------------

+---------+-------+-----------+-----------+------------+---------+
|type     |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module   |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|class    |1      |NC         |NC         |0.00        |0.00     |
+---------+-------+-----------+-----------+------------+---------+
|method   |4      |NC         |NC         |25.00       |75.00    |
+---------+-------+-----------+-----------+------------+---------+
|function |1      |NC         |NC         |0.00        |100.00   |
+---------+-------+-----------+-----------+------------+---------+



Raw metrics
-----------

+----------+-------+------+---------+-----------+
|type      |number |%     |previous |difference |
+==========+=======+======+=========+===========+
|code      |19     |55.88 |NC       |NC         |
+----------+-------+------+---------+-----------+
|docstring |1      |2.94  |NC       |NC         |
+----------+-------+------+---------+-----------+
|comment   |4      |11.76 |NC       |NC         |
+----------+-------+------+---------+-----------+
|empty     |10     |29.41 |NC       |NC         |
+----------+-------+------+---------+-----------+



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

+-------------------------+------+---------+-----------+
|                         |now   |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines      |0     |NC       |NC         |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC       |NC         |
+-------------------------+------+---------+-----------+



Messages by category
--------------------

+-----------+-------+---------+-----------+
|type       |number |previous |difference |
+===========+=======+=========+===========+
|convention |11     |NC       |NC         |
+-----------+-------+---------+-----------+
|refactor   |1      |NC       |NC         |
+-----------+-------+---------+-----------+
|warning    |11     |NC       |NC         |
+-----------+-------+---------+-----------+
|error      |1      |NC       |NC         |
+-----------+-------+---------+-----------+



Messages
--------

+-------------------+------------+
|message id         |occurrences |
+===================+============+
|missing-docstring  |6           |
+-------------------+------------+
|invalid-name       |5           |
+-------------------+------------+
|unused-argument    |4           |
+-------------------+------------+
|unused-import      |3           |
+-------------------+------------+
|redefined-builtin  |2           |
+-------------------+------------+
|unused-variable    |1           |
+-------------------+------------+
|unreachable        |1           |
+-------------------+------------+
|no-self-use        |1           |
+-------------------+------------+
|function-redefined |1           |
+-------------------+------------+



Global evaluation
-----------------
Your code has been rated at -2.73/10

FAIL: 30

prasad@Rootpy: master ⚡
$  

Here,

  • It detects highest number of errors compared to other linters. Following errors which are detected by all other linters as well as PyLint:
    • unused variables, imported modules, arguments etc.
    • Invalid variable name, method name etc.
  • But there is a lot of differnece between Pylint’s output and other’s output. It detects following errors which other linters don’t detect.:
    • Unreachable code
    • Redefining built in int and str
    • unused global variable user_name which other linters are failed to detect.
    • missing doc strings.
  • Report contains various statistics information which is useful for programmer.
  • It’s awesome code rating. It has given -2.7 rating to sample program. (OMG)
  • Pylint has great documentation. Every thing is well explained.
  • You can configure pylint by creating configuration file i.e .pylintrc file.

###PyLama * It is a static code analyzer which combines power of other linters. * It wrapes following tools: * PEP8 * PEP257 * PyFlakes * Mccabe * PyLint * Let’s check it’s output

prasad@Rootpy: master ⚡
$ pylama sample_program.py
sample_program.py:4:1: E265 block comment should start with '# ' [pep8]
sample_program.py:5:1: W0611 'os' imported but unused [pyflakes]
sample_program.py:6:1: W0611 'sys' imported but unused [pyflakes]
sample_program.py:7:1: W0611 'argparse' imported but unused [pyflakes]
sample_program.py:10:1: E265 block comment should start with '# ' [pep8]
sample_program.py:15:1: E303 too many blank lines (3) [pep8]
sample_program.py:16:1: W0612 local variable 'fname' is assigned to but never used [pyflakes]
sample_program.py:32:1: W0404 redefinition of unused 'getUserPassword' from line 28 [pyflakes]
sample_program.py:39:1: W391 blank line at end of file [pep8]
FAIL: 1

prasad@Rootpy: master ⚡

Here,

  • It detects following errors:
    • unused variable, imported module and argument errors.
    • redefinition of function.
    • pep8 errors
  • It doesn’t detect following errors:
    • unreachable code
    • missing doc string
    • Self is used as argument in function
    • redefining built-in datatype like int, str etc.
    • invalid function name like getUserPassword etc.

Conclusion:

  • Most of these tools detect some of the errors in sample_program.py. We saw all tools output for sample_program.py
  • PyLint gives us very descriptive output as well as detects various errors.
  • So we can deduce that Pylint’s is a very powerful linters for python programming.