diff options
author | Nicolas Chauvat <nicolas.chauvat@logilab.fr> | 2013-04-04 21:22:33 +0200 |
---|---|---|
committer | Nicolas Chauvat <nicolas.chauvat@logilab.fr> | 2013-04-04 21:22:33 +0200 |
commit | ebc9bc293c9166fefcd1a2e8a16dd94524af71dc (patch) | |
tree | b9bbba2eb1c2a5facbfabb20d72239842a1c8d41 /doc/tutorial.rst | |
parent | 2c32ee0a577d81fca4b6701871fb2444e1c3917b (diff) | |
download | pylint-ebc9bc293c9166fefcd1a2e8a16dd94524af71dc.tar.gz |
[doc] generate documentation with sphinx
Diffstat (limited to 'doc/tutorial.rst')
-rw-r--r-- | doc/tutorial.rst | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/doc/tutorial.rst b/doc/tutorial.rst new file mode 100644 index 0000000..0ffdeda --- /dev/null +++ b/doc/tutorial.rst @@ -0,0 +1,405 @@ +.. class:: article + +================================================================ +A Beginner's Guide to Code Standards in Python - Pylint Tutorial +================================================================ + +:Author: Robert Kirkpatrick + +For a detailed description of Pylint, see http://www.pylint.org + + +Intro +----- + +Beginner to coding standards? Pylint can be your guide to reveal what's really +going on behind the scenes and help you to become a more aware programmer. + +Sharing code is a rewarding endeavor. Putting your code 'out there' can be +either an act of philanthropy, 'coming of age', or a basic extension of belief +in open source. Whatever the motivation, your good intentions may not have the +desired outcome if people find your code hard to use or understand. The Python +community has formalized some recommended programming styles to help everyone +write code in a common, agreed-upon style that makes the most sense for shared +code. This style is captured in PEP-8_. Pylint can be a quick and easy way of +seeing if your code has captured the essence of PEP-8 and is therefore +'friendly' to other potential users. + +Perhaps you're not ready to share your code but you'd like to learn a bit more +about writing better code and don't know where to start. Pylint can tell you +where you may have run astray and point you in the direction to figure out what +you have done and how to do better. + +This tutorial is all about approaching coding standards with little or no +knowledge of in-depth programming or the code standards themselves. It's the +equivalent of skipping the manual and jumping right in. + +My command line prompt for these examples is: + +.. sourcecode:: bash + + robertk01 Desktop$ + +.. _PEP-8: http://www.python.org/dev/peps/pep-0008/ + +Getting Started +--------------- + +Running Pylint with no arguments will invoke the help dialogue and give you a +idea of the arguments available to you. Do that now, i.e.: + +.. sourcecode:: bash + + robertk01 Desktop$ pylint + ... + a bunch of stuff + ... + + +A couple of the options that we'll focus on here are: :: + + Master: + --generate-rcfile=<file> + Commands: + --help-msg=<msg-id> + Commands: + --help-msg=<msg-id> + Message control: + --disable=<msg-ids> + Reports: + --files-output=<y_or_n> + --reports=<y_or_n> + --include-ids=<y_or_n> + --output-format=<format> + +Also pay attention to the last bit of help output. This gives you a hint of what +Pylint is going to 'pick on': :: + + Output: + Using the default text output, the message format is : + MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE + There are 5 kind of message types : + * (C) convention, for programming standard violation + * (R) refactor, for bad code smell + * (W) warning, for python specific problems + * (E) error, for much probably bugs in the code + * (F) fatal, if an error occurred which prevented pylint from doing + further processing. + +When Pylint is first run on a fresh piece of code, a common complaint is that it +is too 'noisy'. The current default configuration is set to enforce all possible +warnings. We'll use some of the options I noted above to make it suit your +preferences a bit better (and thus make it 'scream only when needed'). + + +Your First Pylint'ing +--------------------- + +We'll use a basic python script as fodder for our tutorial. I borrowed +extensively from the code here: http://www.daniweb.com/code/snippet748.html +The starting code we will use is called simplecaeser.py and is here in its +entirety: + +.. sourcecode:: python + + 1 #!/usr/bin/env python + 2 + 3 import string + 4 + 5 shift = 3 + 6 choice = raw_input("would you like to encode or decode?") + 7 word = (raw_input("Please enter text")) + 8 letters = string.ascii_letters + string.punctuation + string.digits + 9 encoded = '' + 10 if choice == "encode": + 11 for letter in word: + 12 if letter == ' ': + 13 encoded = encoded + ' ' + 14 else: + 15 x = letters.index(letter) + shift + 16 encoded=encoded + letters[x] + 17 if choice == "decode": + 18 for letter in word: + 19 if letter == ' ': + 20 encoded = encoded + ' ' + 21 else: + 22 x = letters.index(letter) - shift + 23 encoded = encoded + letters[x] + 24 + 25 print encoded + + +Let's get started. + +If we run this: + +.. sourcecode:: bash + + robertk01 Desktop$ pylint simplecaeser.py + No config file found, using default configuration + ************* Module simplecaeser + C: 1: Missing docstring + W: 3: Uses of a deprecated module 'string' + C: 5: Invalid name "shift" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C: 6: Invalid name "choice" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C: 7: Invalid name "word" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C: 8: Invalid name "letters" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C: 9: Invalid name "encoded" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C: 16: Operator not preceded by a space + encoded=encoded + letters[x] + ^ + + + Report + ====== + 19 statements analysed. + + Duplication + ----------- + + +-------------------------+------+---------+-----------+ + | |now |previous |difference | + +=========================+======+=========+===========+ + |nb duplicated lines |0 |0 |= | + +-------------------------+------+---------+-----------+ + |percent duplicated lines |0.000 |0.000 |= | + +-------------------------+------+---------+-----------+ + + + + Raw metrics + ----------- + + +----------+-------+------+---------+-----------+ + |type |number |% |previous |difference | + +==========+=======+======+=========+===========+ + |code |21 |87.50 |21 |= | + +----------+-------+------+---------+-----------+ + |docstring |0 |0.00 |0 |= | + +----------+-------+------+---------+-----------+ + |comment |1 |4.17 |1 |= | + +----------+-------+------+---------+-----------+ + |empty |2 |8.33 |2 |= | + +----------+-------+------+---------+-----------+ + + + + Statistics by type + ------------------ + + +---------+-------+-----------+-----------+------------+---------+ + |type |number |old number |difference |%documented |%badname | + +=========+=======+===========+===========+============+=========+ + |module |1 |1 |= |0.00 |0.00 | + +---------+-------+-----------+-----------+------------+---------+ + |class |0 |0 |= |0.00 |0.00 | + +---------+-------+-----------+-----------+------------+---------+ + |method |0 |0 |= |0.00 |0.00 | + +---------+-------+-----------+-----------+------------+---------+ + |function |0 |0 |= |0.00 |0.00 | + +---------+-------+-----------+-----------+------------+---------+ + + + + Messages by category + -------------------- + + +-----------+-------+---------+-----------+ + |type |number |previous |difference | + +===========+=======+=========+===========+ + |convention |7 |7 |= | + +-----------+-------+---------+-----------+ + |refactor |0 |0 |= | + +-----------+-------+---------+-----------+ + |warning |1 |1 |= | + +-----------+-------+---------+-----------+ + |error |0 |0 |= | + +-----------+-------+---------+-----------+ + + + + Messages + -------- + + +-----------+-----------+ + |message id |occurrences | + +===========+===========+ + |C0103 |5 | + +-----------+-----------+ + |W0402 |1 | + +-----------+-----------+ + |C0322 |1 | + +-----------+-----------+ + |C0111 |1 | + +-----------+-----------+ + + + + Global evaluation + ----------------- + Your code has been rated at 5.79/10 + + +Wow. That's a lot of stuff. The first part is the 'messages' section while the +second part is the 'report' section. There are two points I want to tackle here. + +First point is that all the tables of statistics (i.e. the report) are a bit +overwhelming so I want to silence them. To do that, I will use the "--reports=n" option. + +Second, previous experience taught me that the default output for the messages +needed a bit more info. We can see the first line is: :: + + "C: 1: Missing docstring" + +This basically means that line 1 violates a convention 'C'. It's telling me I +really should have a docstring. I agree, but what if I didn't fully understand +what rule I violated. Knowing only that I violated a convention isn't much help +if I'm a newbie. So let's turn on a bit more info by using the option +"--include-ids=y". + +.. tip:: Many of Pylint's commonly used command line options have shortcuts. + for example, "--reports=n" can be abbreviated to "-r n", and "--include-ids=y" + can be abbreviated to "-i y". Pylint's man page lists all these shortcuts. + +Let's do it again! + +.. sourcecode:: bash + + robertk01 Desktop$ pylint --reports=n --include-ids=y simplecaeser.py + No config file found, using default configuration + ************* Module simplecaeser + C0111: 1: Missing docstring + W0402: 3: Uses of a deprecated module 'string' + C0103: 5: Invalid name "shift" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 6: Invalid name "choice" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 7: Invalid name "word" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 8: Invalid name "letters" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 9: Invalid name "encoded" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0322: 16: Operator not preceded by a space + encoded=encoded + letters[x] + +Oooh. I like that better. Now I know that I violated the convention number +C0111 and now I can read up a bit more about that. Let's go back to the +command line and try this: + +.. sourcecode:: bash + + robertk01 Desktop$ pylint --help-msg=C0111 + No config file found, using default configuration + :C0111: *Missing docstring* + Used when a module, function, class or method has no docstring. Some special + methods like __init__ doesn't necessary require a docstring. This message + belongs to the basic checker. + +Yeah, ok. That one was a bit of a no-brainer but I have run into error messages +that left me with no clue about what went wrong, simply because I was unfamiliar +with the underlying mechanism of code theory. One error that puzzled my newbie +mind was: :: + + :R0902: *Too many instance attributes (%s/%s)* + +I get it now thanks to Pylint pointing it out to me. If you don't get that one, +pour a fresh cup of coffee and look into it - let your programmer mind grow! + + +The Next Step +------------- + +Now that we got some configuration stuff out of the way, let's see what we can +do with the remaining warnings. + +If we add a docstring to describe what the code is meant to do that will help. +I'm also going to be a bit cowboy and ignore the W0402 message because I like to +take risks in life. A deprecation warning means that future versions of Python +may not support that code so my code may break in the future. There are 5 C0103 +messages that we will get to later. Lastly, I violated the convention of using +spaces around an operator such as "=" so I'll fix that too. To sum up, I'll add +a docstring to line 2, put spaces around the = sign on line 16 and use the +"--disable=W0402" to ignore the deprecation warning. + +Here is the updated code: + +.. sourcecode:: python + + 1 #!/usr/bin/env python + 2 """This script prompts a user to enter a message to encode or decode + 3 using a classic Caeser shift substitution (3 letter shift)""" + 4 + 5 import string + 6 + 7 shift = 3 + 8 choice = raw_input("would you like to encode or decode?") + 9 word = (raw_input("Please enter text")) + 10 letters = string.ascii_letters + string.punctuation + string.digits + 11 encoded = '' + 12 if choice == "encode": + 13 for letter in word: + 14 if letter == ' ': + 15 encoded = encoded + ' ' + 16 else: + 17 x = letters.index(letter) + shift + 18 encoded = encoded + letters[x] + 19 if choice == "decode": + 20 for letter in word: + 21 if letter == ' ': + 22 encoded = encoded + ' ' + 23 else: + 24 x = letters.index(letter) - shift + 25 encoded = encoded + letters[x] + 26 + 27 print encoded + +And here is what happens when we run it with our --disable=W0402 option: + +.. sourcecode:: python + + robertk01 Desktop$ pylint --reports=n --include-ids=y --disable=W0402 simplecaeser.py + No config file found, using default configuration + ************* Module simplecaeser + C0103: 7: Invalid name "shift" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 8: Invalid name "choice" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 9: Invalid name "word" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 10: Invalid name "letters" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + C0103: 11: Invalid name "encoded" (should match (([A-Z_][A-Z1-9_]*)|(__.*__))$) + +Nice! We're down to just the C0103 messages. + +There are fairly well defined conventions around naming things like instance +variables, functions, classes, etc. The conventions focus on the use of +UPPERCASE and lowercase as well as the characters that separate multiple words +in the name. This lends itself well to checking via a regular expression, thus +the "should match (([A-Z\_][A-Z1-9\_]*)|(__.*__))$". + +In this case Pylint is telling me that those variables appear to be constants +and should be all UPPERCASE. This rule is in fact a naming convention that is +specific to the folks at Logilab who created Pylint. That is the way they have +chosen to name those variables. You too can create your own in-house naming +conventions but for the purpose of this tutorial, we want to stick to the PEP-8 +standard. In this case, the variables I declared should follow the convention +of all lowercase. The appropriate rule would be something like: +"should match [a-z\_][a-z0-9\_]{2,30}$". Notice the lowercase letters in the +regular expression (a-z versus A-Z). + +If we run that rule using a --const-rgx='[a-z\_][a-z0-9\_]{2,30}$' option, it +will now be quite quiet: + +.. sourcecode:: bash + + robertk01 Desktop$ pylint --reports=n --include-ids=y --disable=W0402 --const-rgx='[a-z_][a-z0-9_]{2,30}$' simplecaeser.py + No config file found, using default configuration + +Regular expressions can be quite a beast so take my word on this particular +example but go ahead and `read up`_ on them if you want. + +.. tip:: + It would really be a pain in the butt to have to use all these options + on the command line all the time. That's what the rc file is for. We can + configure our Pylint to store our options for us so we don't have to declare + them on the command line. Using the rc file is a nice way of formalizing your + rules and quickly sharing them with others. Invoking 'pylint + --generate-rcfile' will create a sample rcfile with all the options set and + explained in comments. + +That's it for the basic intro. More tutorials will follow. + +.. _`read up`: http://docs.python.org/library/re.html |