4812N/AA Beginner's Guide to Code Standards in Python - Pylint Tutorial
4812N/A****************************************************************
4812N/ABeginner to coding standards? Pylint can be your guide to reveal
4812N/Awhat's really going on behind the scenes and help you to become a more
4812N/ASharing code is a rewarding endeavor. Putting your code 'out there'
4812N/Acan be either an act of philanthropy, 'coming of age', or a basic
4812N/Aextension of belief in open source. Whatever the motivation, your
4812N/Agood intentions may not have the desired outcome if people find your
4812N/Acode hard to use or understand. The Python community has formalized
4812N/Asome recommended programming styles to help everyone write code in a
4812N/Acommon, agreed-upon style that makes the most sense for shared code.
4812N/AThis style is captured in PEP-8. Pylint can be a quick and easy way
4812N/Aof seeing if your code has captured the essence of PEP-8 and is
4812N/Atherefore 'friendly' to other potential users.
4812N/APerhaps you're not ready to share your code but you'd like to learn a
4812N/Abit more about writing better code and don't know where to start.
4812N/APylint can tell you where you may have run astray and point you in the
4812N/Adirection to figure out what you have done and how to do better.
4812N/AThis tutorial is all about approaching coding standards with little or
4812N/Ano knowledge of in-depth programming or the code standards themselves.
4812N/AIt's the equivalent of skipping the manual and jumping right in.
4812N/AMy command line prompt for these examples is:
4812N/ARunning Pylint with no arguments will invoke the help dialogue and
4812N/Agive you a idea of the arguments available to you. Do that now,
i.e.:
4812N/AA couple of the options that we'll focus on here are:
4812N/AAlso pay attention to the last bit of help output. This gives you a
4812N/Ahint of what Pylint is going to 'pick on':
4812N/A Using the default text output, the message format is :
4812N/A MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE
4812N/A There are 5 kind of message types :
4812N/A * (C) convention, for programming standard violation
4812N/A * (R) refactor, for bad code smell
4812N/A * (W) warning, for python specific problems
4812N/A * (E) error, for much probably bugs in the code
4812N/A * (F) fatal, if an error occurred which prevented pylint from doing
4812N/AWhen Pylint is first run on a fresh piece of code, a common complaint
4812N/Ais that it is too 'noisy'. The current default configuration is set
4812N/Ato enforce all possible warnings. We'll use some of the options I
4812N/Anoted above to make it suit your preferences a bit better (and thus
4812N/Amake it 'scream only when needed').
4812N/AWe'll use a basic python script as fodder for our tutorial. I
4812N/Aborrowed extensively from the code here:
4812N/A 6 choice = raw_input("would you like to encode or decode?")
4812N/A 7 word = (raw_input("Please enter text"))
4812N/A 16 encoded=encoded + letters[x]
4812N/A 23 encoded = encoded + letters[x]
4812N/A No config file found, using default configuration
4812N/A ************* Module simplecaeser
4812N/A C: 1, 0: Missing module docstring (missing-docstring)
4812N/A W: 3, 0: Uses of a deprecated module 'string' (deprecated-module)
4812N/A C: 5, 0: Invalid constant name "shift" (invalid-name)
4812N/A C: 6, 0: Invalid constant name "choice" (invalid-name)
4812N/A C: 7, 0: Invalid constant name "word" (invalid-name)
4812N/A C: 8, 0: Invalid constant name "letters" (invalid-name)
4812N/A C: 9, 0: Invalid constant name "encoded" (invalid-name)
4812N/A C: 16,12: Operator not preceded by a space
4812N/A encoded=encoded + letters[x]
4812N/A ^ (no-space-before-operator)
4812N/A +-------------------------+------+---------+-----------+
4812N/A | |now |previous |difference |
4812N/A +=========================+======+=========+===========+
4812N/A |nb duplicated lines |0 |0 |= |
4812N/A +-------------------------+------+---------+-----------+
4812N/A |percent duplicated lines |0.000 |0.000 |= |
4812N/A +-------------------------+------+---------+-----------+
4812N/A +----------+-------+------+---------+-----------+
4812N/A |type |number |% |previous |difference |
4812N/A +==========+=======+======+=========+===========+
4812N/A +----------+-------+------+---------+-----------+
4812N/A |docstring |0 |0.00 |0 |= |
4812N/A +----------+-------+------+---------+-----------+
4812N/A +----------+-------+------+---------+-----------+
4812N/A +----------+-------+------+---------+-----------+
4812N/A +---------+-------+-----------+-----------+------------+---------+
4812N/A |type |number |old number |difference |%documented |%badname |
4812N/A +=========+=======+===========+===========+============+=========+
4812N/A |module |1 |1 |= |0.00 |0.00 |
4812N/A +---------+-------+-----------+-----------+------------+---------+
4812N/A |class |0 |0 |= |0.00 |0.00 |
4812N/A +---------+-------+-----------+-----------+------------+---------+
4812N/A |method |0 |0 |= |0.00 |0.00 |
4812N/A +---------+-------+-----------+-----------+------------+---------+
4812N/A |function |0 |0 |= |0.00 |0.00 |
4812N/A +---------+-------+-----------+-----------+------------+---------+
4812N/A +-----------+-------+---------+-----------+
4812N/A |type |number |previous |difference |
4812N/A +===========+=======+=========+===========+
4812N/A +-----------+-------+---------+-----------+
4812N/A +-----------+-------+---------+-----------+
4812N/A +-----------+-------+---------+-----------+
4812N/A +-----------+-------+---------+-----------+
4812N/A +-------------------------+------------+
4812N/A +=========================+============+
4812N/A +-------------------------+------------+
4812N/A |no-space-before-operator |1 |
4812N/A +-------------------------+------------+
4812N/A +-------------------------+------------+
4812N/A +-------------------------+------------+
4812N/A Your code has been rated at 5.79/10
4812N/AWow. That's a lot of stuff. The first part is the 'messages' section
4812N/Awhile the second part is the 'report' section. There are two points I
4812N/AFirst point is that all the tables of statistics (
i.e. the report) are
4812N/Aa bit overwhelming so I want to silence them. To do that, I will use
4812N/ATip: Many of Pylint's commonly used command line options have
4812N/A shortcuts. for example, "--reports=n" can be abbreviated to "-rn".
4812N/A Pylint's man page lists all these shortcuts.
4812N/ASecond, previous experience taught me that the default output for the
4812N/Amessages needed a bit more info. We can see the first line is:
4812N/A "C: 1: Missing docstring (missing-docstring)"
4812N/AThis basically means that line 1 violates a convention 'C'. It's
4812N/Atelling me I really should have a docstring. I agree, but what if I
4812N/Adidn't fully understand what rule I violated. Knowing only that I
4812N/Aviolated a convention isn't much help if I'm a newbie. Another
4812N/Ainformation there is the message symbol between parens, *missing-
4812N/AIf I want to read up a bit more about that, I can go back to the
4812N/A robertk01 Desktop$ pylint --help-msg=missing-docstring
4812N/A No config file found, using default configuration
4812N/A :missing-docstring (C0111): *Missing docstring*
4812N/A Used when a module, function, class or method has no docstring. Some special
4812N/A methods like __init__ doesn't necessary require a docstring. This message
4812N/A belongs to the basic checker.
4812N/AYeah, ok. That one was a bit of a no-brainer but I have run into error
4812N/Amessages that left me with no clue about what went wrong, simply
4812N/Abecause I was unfamiliar with the underlying mechanism of code theory.
4812N/AOne error that puzzled my newbie mind was:
4812N/A :too-many-instance-attributes (R0902): *Too many instance attributes (%s/%s)*
4812N/AI get it now thanks to Pylint pointing it out to me. If you don't get
4812N/Athat one, pour a fresh cup of coffee and look into it - let your
4812N/ANow that we got some configuration stuff out of the way, let's see
4812N/Awhat we can do with the remaining warnings.
4812N/AIf we add a docstring to describe what the code is meant to do that
4812N/Awill help. I'm also going to be a bit cowboy and ignore the
4812N/A*deprecated-module* message because I like to take risks in life. A
4812N/Adeprecation warning means that future versions of Python may not
4812N/Asupport that code so my code may break in the future. There are 5
4812N/A*invalid-name* messages that we will get to later. Lastly, I violated
4812N/Athe convention of using spaces around an operator such as "=" so I'll
4812N/Afix that too. To sum up, I'll add a docstring to line 2, put spaces
4812N/Aaround the = sign on line 16 and use the *--disable=deprecated-module*
4812N/Ato ignore the deprecation warning.
4812N/A 2 """This script prompts a user to enter a message to encode or decode
4812N/A 3 using a classic Caeser shift substitution (3 letter shift)"""
4812N/A 8 choice = raw_input("would you like to encode or decode?")
4812N/A 9 word = (raw_input("Please enter text"))
4812N/A 18 encoded = encoded + letters[x]
4812N/A 25 encoded = encoded + letters[x]
4812N/AAnd here is what happens when we run it with our *--disable
4812N/A No config file found, using default configuration
4812N/A ************* Module simplecaeser
4812N/A C: 7, 0: Invalid constant name "shift" (invalid-name)
4812N/A C: 8, 0: Invalid constant name "choice" (invalid-name)
4812N/A C: 9, 0: Invalid constant name "word" (invalid-name)
4812N/A C: 10, 0: Invalid constant name "letters" (invalid-name)
4812N/A C: 11, 0: Invalid constant name "encoded" (invalid-name)
4812N/ANice! We're down to just the *invalid-name* messages.
4812N/AThere are fairly well defined conventions around naming things like
4812N/Ainstance variables, functions, classes, etc. The conventions focus on
4812N/Athe use of UPPERCASE and lowercase as well as the characters that
4812N/Aseparate multiple words in the name. This lends itself well to
4812N/Achecking via a regular expression, thus the "should match
4812N/A(([A-Z_][A-Z1-9_]*)|(__.*__))$".
4812N/AIn this case Pylint is telling me that those variables appear to be
4812N/Aconstants and should be all UPPERCASE. This rule is in fact a naming
4812N/Aconvention that is specific to the folks at Logilab who created
4812N/APylint. That is the way they have chosen to name those variables.
4812N/AYou too can create your own in-house naming conventions but for the
4812N/Apurpose of this tutorial, we want to stick to the PEP-8 standard. In
4812N/Athis case, the variables I declared should follow the convention of
4812N/Aall lowercase. The appropriate rule would be something like: "should
4812N/Amatch [a-z_][a-z0-9_]{2,30}$". Notice the lowercase letters in the
4812N/Aregular expression (a-z versus A-Z).
4812N/AIf we run that rule using a *--const-rgx='[a-z_][a-z0-9_]{2,30}$'*
4812N/Aoption, it will now be quite quiet:
4812N/A robertk01 Desktop$ pylint --reports=n --disable=deprecated-module --const-rgx='[a-z_][a-z0-9_]{2,30}$'
simplecaeser.py 4812N/A No config file found, using default configuration
4812N/ARegular expressions can be quite a beast so take my word on this
4812N/Aparticular example but go ahead and read up on them if you want.
4812N/ATip: It would really be a pain in the butt to have to use all these
4812N/A options on the command line all the time. That's what the rc file
4812N/A is for. We can configure our Pylint to store our options for us so
4812N/A we don't have to declare them on the command line. Using the rc
4812N/A file is a nice way of formalizing your rules and quickly sharing
4812N/A them with others. Invoking "pylint --generate-rcfile" will create a
4812N/A sample rcfile with all the options set and explained in comments.
4812N/AThat's it for the basic intro. More tutorials will follow.