summaryrefslogtreecommitdiffstats
path: root/HACKING.rst
diff options
context:
space:
mode:
authorAndrew Bogott <abogott@wikimedia.org>2012-03-22 01:20:00 -0500
committerAndrew Bogott <abogott@wikimedia.org>2012-03-22 01:21:59 -0500
commita43bfa116dfaefe199c9b4f02344a4b4176baf01 (patch)
tree57083afd5afc4637fdbc7b4f90bb048f5534b2cb /HACKING.rst
parent1c30f39901be7bdaf94946d1a9b470beb366bcba (diff)
downloadoslo-a43bfa116dfaefe199c9b4f02344a4b4176baf01.tar.gz
oslo-a43bfa116dfaefe199c9b4f02344a4b4176baf01.tar.xz
oslo-a43bfa116dfaefe199c9b4f02344a4b4176baf01.zip
Added a universal style-guide for all OS projects.
Pursuant to a recent mailing list discussion, this file contains the union of all style recommendations from varions openstack projects. The file will be removed from individual projects. Change-Id: I79c118ff749d7c89d7d88302279ec8cb1530868d
Diffstat (limited to 'HACKING.rst')
-rw-r--r--HACKING.rst257
1 files changed, 257 insertions, 0 deletions
diff --git a/HACKING.rst b/HACKING.rst
new file mode 100644
index 0000000..cd2380d
--- /dev/null
+++ b/HACKING.rst
@@ -0,0 +1,257 @@
+OpenStack Style Commandments
+=======================
+
+- Step 1: Read http://www.python.org/dev/peps/pep-0008/
+- Step 2: Read http://www.python.org/dev/peps/pep-0008/ again
+- Step 3: Read on
+
+
+General
+-------
+- Put two newlines between top-level code (funcs, classes, etc)
+- Put one newline between methods in classes and anywhere else
+- Do not write "except:", use "except Exception:" at the very least
+- Include your name with TODOs as in "#TODO(termie)"
+- When defining global constants, define them before functions and classes
+- Do not shadow a built-in or reserved word. Example::
+
+ def list():
+ return [1, 2, 3]
+
+ mylist = list() # BAD, shadows `list` built-in
+
+ class Foo(object):
+ def list(self):
+ return [1, 2, 3]
+
+ mylist = Foo().list() # OKAY, does not shadow built-in
+
+
+TODO vs FIXME
+-------------
+
+- TODO(name): implies that something should be done (cleanup, refactoring,
+ etc), but is expected to be functional.
+- FIXME(name): implies that the method/function/etc shouldn't be used until
+ that code is resolved and bug fixed.
+
+Imports
+-------
+- Do not import objects, only modules
+- Do not import more than one module per line
+- Do not make relative imports
+- Order your imports by the full module path
+- Organize your imports according to the following template
+
+Example::
+
+ # vim: tabstop=4 shiftwidth=4 softtabstop=4
+ {{stdlib imports in human alphabetical order}}
+ \n
+ {{third-party lib imports in human alphabetical order}}
+ \n
+ {{project imports in human alphabetical order}}
+ \n
+ \n
+ {{begin your code}}
+
+
+Human Alphabetical Order Examples
+---------------------------------
+Example::
+
+ import httplib
+ import logging
+ import random
+ import StringIO
+ import time
+ import unittest
+
+ import eventlet
+ import webob.exc
+
+ import nova.api.ec2
+ from nova.api import openstack
+ from nova.auth import users
+ import nova.flags
+ from nova.endpoint import cloud
+ from nova import test
+
+
+Docstrings
+----------
+Example::
+
+ """A one line docstring looks like this and ends in a period."""
+
+
+ """A multiline docstring has a one-line summary, less than 80 characters.
+
+ Then a new paragraph after a newline that explains in more detail any
+ general information about the function, class or method. Example usages
+ are also great to have here if it is a complex class for function.
+
+ When writing the docstring for a class, an extra line should be placed
+ after the closing quotations. For more in-depth explanations for these
+ decisions see http://www.python.org/dev/peps/pep-0257/
+
+ Do not leave an extra newline before the closing triple-double-quote.
+
+ Describe parameters and return values, using the Sphinx format; the
+ appropriate syntax is as follows.
+
+ :param foo: the foo parameter
+ :param bar: the bar parameter
+ :type bar: parameter type for 'bar'
+ :returns: return_type -- description of the return value
+ :returns: description of the return value
+ :raises: AttributeError, KeyError
+ """
+
+
+Dictionaries/Lists
+------------------
+If a dictionary (dict) or list object is longer than 80 characters, its items
+should be split with newlines. Embedded iterables should have their items
+indented. Additionally, the last item in the dictionary should have a trailing
+comma. This increases readability and simplifies future diffs.
+
+Example::
+
+ my_dictionary = {
+ "image": {
+ "name": "Just a Snapshot",
+ "size": 2749573,
+ "properties": {
+ "user_id": 12,
+ "arch": "x86_64",
+ },
+ "things": [
+ "thing_one",
+ "thing_two",
+ ],
+ "status": "ACTIVE",
+ },
+ }
+
+
+Calling Methods
+---------------
+Calls to methods 80 characters or longer should format each argument with
+newlines. This is not a requirement, but a guideline::
+
+ unnecessarily_long_function_name('string one',
+ 'string two',
+ kwarg1=constants.ACTIVE,
+ kwarg2=['a', 'b', 'c'])
+
+
+Rather than constructing parameters inline, it is better to break things up::
+
+ list_of_strings = [
+ 'what_a_long_string',
+ 'not as long',
+ ]
+
+ dict_of_numbers = {
+ 'one': 1,
+ 'two': 2,
+ 'twenty four': 24,
+ }
+
+ object_one.call_a_method('string three',
+ 'string four',
+ kwarg1=list_of_strings,
+ kwarg2=dict_of_numbers)
+
+
+Internationalization (i18n) Strings
+-----------------------------------
+In order to support multiple languages, we have a mechanism to support
+automatic translations of exception and log strings.
+
+Example::
+
+ msg = _("An error occurred")
+ raise HTTPBadRequest(explanation=msg)
+
+If you have a variable to place within the string, first internationalize the
+template string then do the replacement.
+
+Example::
+
+ msg = _("Missing parameter: %s") % ("flavor",)
+ LOG.error(msg)
+
+If you have multiple variables to place in the string, use keyword parameters.
+This helps our translators reorder parameters when needed.
+
+Example::
+
+ msg = _("The server with id %(s_id)s has no key %(m_key)s")
+ LOG.error(msg % {"s_id": "1234", "m_key": "imageId"})
+
+
+Text encoding
+----------
+- All text within python code should be of type 'unicode'.
+
+ WRONG:
+
+ >>> s = 'foo'
+ >>> s
+ 'foo'
+ >>> type(s)
+ <type 'str'>
+
+ RIGHT:
+
+ >>> u = u'foo'
+ >>> u
+ u'foo'
+ >>> type(u)
+ <type 'unicode'>
+
+- Transitions between internal unicode and external strings should always
+ be immediately and explicitly encoded or decoded.
+
+- All external text that is not explicitly encoded (database storage,
+ commandline arguments, etc.) should be presumed to be encoded as utf-8.
+
+ WRONG:
+
+ mystring = infile.readline()
+ myreturnstring = do_some_magic_with(mystring)
+ outfile.write(myreturnstring)
+
+ RIGHT:
+
+ mystring = infile.readline()
+ mytext = s.decode('utf-8')
+ returntext = do_some_magic_with(mytext)
+ returnstring = returntext.encode('utf-8')
+ outfile.write(returnstring)
+
+
+Creating Unit Tests
+-------------------
+For every new feature, unit tests should be created that both test and
+(implicitly) document the usage of said feature. If submitting a patch for a
+bug that had no unit test, a new passing unit test should be added. If a
+submitted bug fix does have a unit test, be sure to add a new one that fails
+without the patch and passes with the patch.
+
+
+openstack-common
+----------------
+
+A number of modules from openstack-common are imported into this project.
+
+These modules are "incubating" in openstack-common and are kept in sync
+with the help of openstack-common's update.py script. See:
+
+ http://wiki.openstack.org/CommonLibrary#Incubation
+
+The copy of the code should never be directly modified here. Please
+always update openstack-common first and then run the script to copy
+the changes across.