blob: 1d18a16b0f2698f2e5dbe4f20a390487daf0c103 [file] [log] [blame]
#summary Style guide for Python code contributed to Melange
#labels Contents-Complete,Phase-Guidelines,Importance-Featured,Featured
Melange follows the [http://google-styleguide.googlecode.com/svn/trunk/pyguide.html Google Python Style Guide]; this document describes only those respects in which Melange's style differs from what is laid out in that document.
The [SoCOverview SoC framework], and
[MelangeIntro Melange web applications] built upon it, are implemented in
Python (it is one of the programming language besides Java and Go which are currently supported by
[http://code.google.com/appengine/ Google App Engine]). The Google Python Style Guide and these amendments to it are a
list of dos and don'ts for Python contributions to the Melange project.
The rules below are not guidelines or recommendations, but strict rules. You
may not disregard the rules we list below except as approved on a need-to-use
basis. But note also the advice on consistency at the end of the guide.
If you have questions about these guidelines, you can send mail to the
[MailingListsGuidelines#Developer_list developer mailing list].
Please put *Python style:* in the subject line to make it easier to locate
these discussions in the mailing list archives.
Since this style guide is documented in the Melange wiki, it can be changed via
the existing [DocumentationReviews documentation review process]. However,
changes to the style guide should not be made lightly, since
[PythonStyleGuide#Conclusion consistency] is one of the key goals
of this style guide, and old code will not necessarily be updated for new
style guide changes.
= Summary =
== Python Language Rules ==
# [PythonStyleGuide#Imports Imports]: _Import only modules and only by name *(no wildcard imports)*_
# [PythonStyleGuide#Function_Arguments Function Arguments]: _Pass positional arguments positionally and keyword arguments by keyword._
# [PythonStyleGuide#Threading Threading]: _*For now, do not use* (but it is on its way as part of [https://code.google.com/p/soc/issues/detail?id=1596 issue 1596])_
== Python Style Rules ==
Programs are much easier to maintain when all files have a consistent
style. Here is the canonical Melange Python style.
# [PythonStyleGuide#Indentation Indentation]: _*2* spaces (*no tabs*),_ *differs from [http://www.python.org/dev/peps/pep-0008/ PEP8]*
# [PythonStyleGuide#Python_Interpreter Python Interpreter]: _Variable, either omitted, `#!/usr/bin/python`, or `#!/usr/bin/python2.7`_
# [PythonStyleGuide#Copyright_And_License_Notices Copyright And License Notices]: _Include in every file._
# [PythonStyleGuide#Imports_grouping_and_order Imports grouping, order and sorting]: _One per line, grouped and ordered by packages, sorted alphabetically_
# [PythonStyleGuide#Naming Naming]: _`foo_bar.py` not `foo-bar.py`,_ *some differ from [http://www.python.org/dev/peps/pep-0008/ PEP8]*
# [PythonStyleGuide#Conclusion Conclusion]: _Look at what's around you!_
= Python Language Rules =
== Imports ==
*What it is:* Mechanism for making use of code between modules.
*Pros:* Very flexible relative to other languages. Packages, modules, classes,
functions, and fields all may be imported.
*Cons:* `from foo import *` or `import bar.baz.Spar` is very nasty and can
lead to serious maintenance issues because it makes it hard to find module
dependencies.
*Decision:* Import only modules. Use `as` to resolve name conflicts if
necessary. Use `from` for all imports below top-level. Use only absolute
imports; do not use relative imports. Do not import packages, classes,
functions, fields, or anything that is not a module.
{{{
import os
import sys
from models.graphics import views as graphics_views
from models.sounds import views as sounds_views
from sound.effects import echo
...
echo.echofilter(input, output, delay=0.7, atten=4)
}}}
Even if the module is in the same package, do not directly import the module
without the full package name. This might cause the package to be imported
twice and have unintended side effects.
== Function Arguments ==
*What they are:* Arguments passed to functions either by position or by name.
*Pros:* Passing arguments always by name can help code be self-documenting.
*Cons:* Passing positional arguments by name can make a call site appear as
though all arguments are optional. Passing keyword arguments by position can
make a call site appear as though all arguments are required.
*Decision:* Always pass positional arguments positionally and keyword
arguments by keyword.
== Threading ==
Melange as of January 2013 is not thread-safe. Work to support thread safety
is happening as part of [https://code.google.com/p/soc/issues/detail?id=1596
issue 1596], but for now avoid threading.
= Python Style Rules =
== Indentation ==
_Note that this differs from
[http://www.python.org/dev/peps/pep-0008/ PEP8]
and instead follows the original Google Python Style guide from which
this style guide originated._
Indent your code blocks with 2 spaces. Never use tabs or mix tabs and
spaces. In cases of implied line continuation, you should align wrapped
elements either vertically, as per the examples in the line length
section; or using a hanging indent of *4* spaces (not 2, so as not to be
confused with an immediately-following nested block), in which case there
should be no argument on the first line.
*Yes:*
{{{
# Aligned with opening delimiter
foo = longFunctionName(var_one, var_two,
var_three, var_four)
# 4-space hanging indent; nothing on first line
foo = longFunctionName(
var_one, var_two, var_three,
var_four)
}}}
*No:*
{{{
# Stuff on first line forbidden
foo = longFunctionName(var_one, var_two,
var_three, var_four)
# 2-space hanging indent forbidden
foo = longFunctionName(
var_one, var_two, var_three,
var_four)
}}}
=== Python Interpreter ==
Modules which are not intended for direct execution (and which have no effect if executed) should not include a shebang line.
Modules intended for direct execution should begin with a shebang line specifying the Python interpreter used to execute the program, most likely `#!/usr/bin/python` or `#!/usr/bin/python2.7`.
== Copyright And License Notices ==
Every module should feature the following either at the top or just below
the module's shebang and blank-comment-following-shebang lines.
{{{
# Copyright [current year] the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
}}}
== Imports grouping and order ==
Imports should be on separate lines, e.g.:
*Yes:*
{{{
import os
import sys
}}}
*No:*
{{{
import sys, os
}}}
Imports are always put at the top of the file, just after any module
comments and `__doc__` strings and before module globals and constants.
Imports should be grouped with the order being most generic to least
generic:
* standard library imports
* third-party library imports
* Google App Engine imports
* django framework imports
* SoC framework imports
* SoC-based module imports
* application specific imports
* imports from "tests/" - test utilities and Melange-specific test modules
Sorting should be done alphabetically.
{{{
import a_standard
import b_standard
import a_third_party
import b_third_party
from a_soc import f
from a_soc import g
from b_soc import d
}}}
Resolution of clashing names between soc-framework and soc-module modules should be done by prefixing the soc-module module with the name of the soc-module from which it was imported:
{{{
from soc.views.helper import url_patterns
from soc.modules.gsoc.views.helper import url_patterns as gsoc_url_patterns
}}}
== Naming ==
=== Names to avoid ===
* single character names, except for counters or iterators
* dashes (`-`) in any package/module name
* `__double_leading_and_trailing_underscore__` names (reserved by Python)
=== Naming convention ===
_Note that some naming conventions differ from
[http://www.python.org/dev/peps/pep-0008/ PEP8]
and instead follow the original Google Python Style guide from which
this style guide originated._
* "Internal" means internal to a module or protected or private within a class.
* Prepending a single underscore (`_`) has some support for protecting module variables and functions (not included with `import * from`).
* Prepending a double underscore (`__`) to an instance variable or method effectively serves to make the variable or method private to its class (using name mangling).
* Place related classes and top-level functions together in a module. Unlike Java, there is no need to limit yourself to one class per module. However, make sure the classes and top-level functions in the same module have [http://en.wikipedia.org/wiki/Cohesion_(computer_science) high cohesion].
* Use `CapWords` for class names, but `lower_with_under.py` for module names.
=== Naming examples ===
|| *Type* || *Public* || *Internal* ||
|| _Packages_ || `lower_with_under` || ||
|| _Modules_ || `lower_with_under` || `_lower_with_under` ||
|| _Classes_ || `CapWords` || `_CapWords` ||
|| _Exceptions_ || `CapWords` || ||
|| _Functions_ || `firstLowerCapWords()` || `_firstLowerCapWords()` ||
|| _Global/Class Constants_ || `CAPS_WITH_UNDER` || `_CAPS_WITH_UNDER` ||
|| _Global/Class Variables_ || `lower_with_under` || `_lower_with_under` ||
|| _Instance Variables_ || `lower_with_under` || `_lower_with_under` _(protected)_ or `__lower_with_under` _(private)_ ||
|| _Method Names_^*^ || `firstLowerCapWords()` || `_firstLowerCapWords()` _(protected)_ or `__firstLowerCapWords()` _(private)_ ||
|| _Function/Method Parameters_ || `lower_with_under` || ||
|| _Local Variables_ || `lower_with_under` || ||
^*^ Consider just using
[PythonStyleGuide#Access_control direct access to public attributes]
in preference to getters and setters, as function calls are expensive
in Python, and `property` can be used later to turn attribute access into a
function call without changing the access syntax.
== Conclusion ==
_BE CONSISTENT._
If you are editing code, take a few minutes to look at the code around
you and determine its style. If spaces are used around the `if` clauses,
you should, too. If the comments have little boxes of stars around them,
make your comments have little boxes of stars around them, too.
The point of having style guidelines is to have a common vocabulary
of coding so people can concentrate on what you are saying rather than
on how you are saying it. We present global style rules here so people
know the vocabulary, but local style is also important. If code you add
to a file looks drastically different from the existing code around it,
it throws readers out of their rhythm when they go to read it. Try to
avoid this.
----
_Copyright 2008 Google Inc._
_This work is licensed under a_
[http://soc.googlecode.com/svn/wiki/html/licenses/cc-by-attribution-2_5.html Creative Commons Attribution 2.5 License].
[http://creativecommons.org/licenses/by/2.5/ http://soc.googlecode.com/svn/wiki/html/licenses/cc-by-2_5-88x31.png]