Let's code with style

Florent Xicluna

EuroPython 2013 - Tuesday, July 2nd

Presenter Notes

Beautiful is better than ugly

“One of Guido's key insights is that   code is read much more often than it is written."

“Consistency with PEP 8 style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.”

TODO: define a style-guide for your project, based on PEP 8 hopefully.

Clear benefits

  • Readable code
  • Encourage developers to contribute to your project

Presenter Notes

A Foolish Consistency ...

“… is the Hobgoblin of Little Minds.”

Some projects choose to adapt PEP8 rules for valid reasons.

Example:

Twisted does follow much of PEP 8 (as is documented in the Twisted coding standard. However, Twisted prefers camelCase for variables, functions, and methods (whereas PEP 8 recommends underscores) because Twisted predates PEP 8 and converting the entire codebase now is infeasible.

(from Twisted FAQ)

Presenter Notes

Hey look! There are more PEPs

  • PEP 7 - "Style Guide for C Code"

This document gives coding conventions for the C code comprising the C implementation of Python. Please see the companion informational PEP describing style guidelines for Python code.

Note, rules are there to be broken. Two good reasons to break a particular rule...

  • PEP 257 - "Docstring Conventions"

This PEP documents the semantics and conventions associated with Python docstrings.

The aim of this PEP is to standardize the high-level structure of docstrings: what they should contain, and how to say it.

Presenter Notes

Line length and blank lines

Limit all lines to a maximum of 79 characters.

There are still many devices around that are limited to 80 character lines; plus, limiting windows to 80 characters makes it possible to have several windows side-by-side.

Therefore, please limit all lines to a maximum of 79 characters. For flowing long blocks of text (docstrings or comments), limiting the length to 72 characters is recommended.

Blank lines:

  • Separate top-level function and class definitions with two blank lines.
  • Method definitions inside a class are separated by a single blank line.
  • Extra blank lines may be used (sparingly)

Presenter Notes

79 chars on 1280 x 800, really ?!?

Few reasons to limit line length:

  • more readable
  • some console environments are limited
  • share screen between multiple documents
  • good practice because "Flat is better than nested."

However make it fit your own needs. Example:

Presenter Notes

pep8.py helps you

  • A single-file library, < 800 SLOC.
  • Exists since 2006.
  • Support Python 2.5 through 3.4.
  • Your favorite editor has a plugin for it.
  • And some cool features.

Example:

hg diff | pep8 --diff
git diff | pep8 --diff

pep8 --max-line-length 99

Presenter Notes

pep8.py --help

Usage: pep8.py [options] input ...

Options:
  --version            show program's version number and exit
  -h, --help           show this help message and exit
  -v, --verbose        print status messages, or debug with -vv
  -q, --quiet          report only file names, or nothing with -qq
  --first              show first occurrence of each error
  --select=errors      select errors and warnings (e.g. E,W6)
  --ignore=errors      skip errors and warnings (e.g. E4,W)
  --show-source        show source code for each error
  --show-pep8          show text of PEP 8 for each error (implies --first)
  --statistics         count errors and warnings
  --max-line-length=n  set maximum allowed line length (default: 79)
  --format=format      set the error format [default|pylint|<custom>]
  --diff               report only lines changed according to the unified
                       diff received on STDIN

Presenter Notes

pep8.py --help (cont'd)

Configuration:
  The project options are read from the [pep8] section of the tox.ini
  file or the setup.cfg file located in any parent folder of the path(s)
  being processed.  Allowed options are: exclude, filename, select,
  ignore, max-line-length, hang-closing, count, format, quiet, show-
  pep8, show-source, statistics, verbose.

  --config=path      user config file location (default:
                     /Users/user/.config/pep8)

Presenter Notes

pep8.py codes

  • E1xx - Indentation
  • E2xx - Whitespace
  • E3xx - Blank line
  • E4xx - Import
  • E5xx - Line length
  • E7xx - Statement
  • E9xx - Runtime
  • W1xx - Indentation warning
  • W2xx - Whitespace warning
  • W3xx - Blank line warning
  • W6xx - Deprecation warning

Presenter Notes

Whitespace - E22x

Don't:

x             = 1
y             = 2
long_variable = 3

Do:

x = 1
y = 2
long_variable = 3

Presenter Notes

Indentation - E12x

Don't:

# Arguments on first line forbidden when not using vertical alignment
foo = long_function_name(var_one, var_two,
    var_three, var_four)

Do:

# Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

Presenter Notes

Indentation - E12x

Don't:

# Further indentation required as indentation is not distinguishable
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

Do:

# More indentation included to distinguish this from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

Presenter Notes

Indentation - E12x

Do:

my_list = [
    (1, 2, 3),
    (4, 5, 6),
    ]
result = some_function_that_takes_arguments(
    'abc',
    'def',
    )

Do (also):

my_list = [
    (1, 2, 3),
    (4, 5, 6),
]
result = some_function_that_takes_arguments(
    'abc',
    'def',
)

Presenter Notes

More - PyFlakes

PyFlakes checks additional errors:

  • F401 - module imported but unused
  • F402 - import module from line N shadowed by loop variable
  • F403 - 'from module import *' used; unable to detect undefined names
  • F404 - future import(s) name after other statements

  • F811 - redefinition of unused name from line N

  • F812 - list comprehension redefines name from line N
  • F821 - undefined name name
  • F822 - undefined name name in __all__
  • F823 - local variable name ... referenced before assignment

Presenter Notes

More - Flake8

The Flake8 tool is a wrapper tool around:

  • PyFlakes
  • Pep8.py
  • McCabe complexity checker

Main features:

  • is configurable
  • supports the same switches and options as pep8.py
  • provides hooks for Git and Mercurial
  • supports extensions: pep8-naming, flake8-docstrings, ...

Presenter Notes

More - Flake8

Configuration:
  The project options are read from the [flake8] section of the tox.ini
  file or the setup.cfg file located in any parent folder of the path(s)
  being processed.  Allowed options are: exclude, filename, select,
  ignore, max-line-length, hang-closing, count, format, quiet, show-
  pep8, show-source, statistics, verbose, builtins, max-complexity.

  --config=path       user config file location (default:
                      /Users/user/.config/flake8)

Presenter Notes

More - Flake8

Configuration (tox.ini or setup.cfg in your project folder):

[flake8]
ignore = E226,E302,E41
max-line-length = 160

 

 

 

Compare to pep8.py standalone:

[pep8]
ignore = E226,E302,E41
max-line-length = 160

Presenter Notes

More quality tools

Auto-fixers

  • autopep8 formats code to conform to the PEP 8 style guide
  • autoflake removes unused imports and unused variables from Python code

Other linters

  • Pylint is a very comprehensive linting tool, but requires more time to configure

 

 

Your favorite editor/IDE has support for pep8.py/flake8 of course.

Presenter Notes

Thank you

Concerned about code-quality tools?

Subscribe to the mailing-list: code-quality@python.org

Documentation:

Questions?

Twitter: @florentxicluna

 

Built with Landslide: github.com/adamzap/landslide

Presenter Notes

Have fun coding!

Presenter Notes