From 9c62571b9f4acff8a20e28b2e3015c08f1070873 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Wed, 18 Sep 2013 11:55:02 -0700 Subject: [PATCH] Move the hacking guidelines to sphinx docs Step one in publishing them to an actual place. Change-Id: I579e7c889f3addc2cd40bce0c584bbc70bf435e2 --- HACKING.rst | 326 ----------------------------------------- MANIFEST.in | 1 - README.rst | 15 +- doc/source/conf.py | 8 +- doc/source/index.rst | 333 ++++++++++++++++++++++++++++++++++++++++-- hacking/core.py | 2 +- setup.cfg | 7 +- test-requirements.txt | 1 + 8 files changed, 339 insertions(+), 354 deletions(-) delete mode 100644 HACKING.rst diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 34b076b..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,326 +0,0 @@ -OpenStack Style Guidelines -========================== - -- 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) -- Use only UNIX style newlines ("\n"), not Windows style ("\r\n") -- Put one newline between methods in classes and anywhere else -- Long lines should be wrapped in parentheses - in preference to using a backslash for line continuation. -- Do not write "except:", use "except Exception:" at the very least -- Include your name with TODOs as in "#TODO(termie)" -- 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 - -- Use the "is not" operator when testing for unequal identities. Example:: - - if not X is Y: # BAD, intended behavior is ambiguous - pass - - if X is not Y: # OKAY, intuitive - pass - -- Use the "not in" operator for evaluating membership in a collection. Example:: - - if not X in Y: # BAD, intended behavior is ambiguous - pass - - if X not in Y: # OKAY, intuitive - pass - - if not (X in Y or X in Z): # OKAY, still better than all those 'not's - pass - - -Imports -------- -- Do not import objects, only modules (*) -- Do not import more than one module per line (*) -- Do not use wildcard ``*`` import (*) -- Do not make relative imports -- Order your imports by the full module path -- Organize your imports according to the following template - -(*) exceptions are: - -- imports from ``migrate`` package -- imports from ``sqlalchemy`` package -- imports from ``nova.db.sqlalchemy.session`` module -- imports from ``nova.db.sqlalchemy.migration.versioning_api`` package - -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 - from nova.endpoint import cloud - import nova.flags - from nova import test - - -Docstrings ----------- -Example:: - - """A one line docstring looks like this and ends in a period.""" - - - """A multi line 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/ - - If you are going to describe parameters and return values, use Sphinx, the - appropriate syntax is as follows. - - :param foo: the foo parameter - :param bar: the bar parameter - :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", - }, - } - -Do not use ``locals()`` for formatting strings, it is not clear as using -explicit dictionaries and can hide errors during refactoring. - -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"}) - - -Python 3.x compatibility ------------------------- -OpenStack code should become Python 3.x compatible. That means all Python 2.x-only -constructs or dependencies should be avoided. An example is - - except x,y: - -Use - - except x as y: - -instead. Also Python 3.x has become more strict regarding octal string -literals. Use "0o755" instead of "0755". Similarly, explicit use of long -literals (01234L) should be avoided. - -Other Python 3.x compatibility issues, like e.g. print operator -can be avoided in new code by using - - from __future__ import print_function - -at the top of your module. - - -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. - - -oslo-incubator ----------------- - -A number of modules from oslo-incubator are imported into the project. - -These modules are "incubating" in oslo-incubator and are kept in sync -with the help of oslo-incubator's update.py script. See: - - https://wiki.openstack.org/wiki/Oslo#Incubation - - -The copy of the code should never be directly modified here. Please -always update oslo-incubator first and then run the script to copy -the changes across. - - -OpenStack Trademark -------------------- - -OpenStack is a registered trademark of the OpenStack Foundation, and uses the -following capitalization: - - OpenStack - - -OpenStack Licensing -------------------- - -Newly contributed Source Code should be licensed under the Apache 2.0 license. -All source files should have the following header: - - # 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. - - -Commit Messages ---------------- -Using a common format for commit messages will help keep our git history -readable. Follow these guidelines: - - First, provide a brief summary of 50 characters or less. Summaries - of greater then 72 characters will be rejected by the gate. - - The first line of the commit message should provide an accurate - description of the change, not just a reference to a bug or - blueprint. It must not end with a period and must be followed by - a single blank line. - - If the change relates to a specific driver (libvirt, xenapi, qpid, etc...), - begin the first line of the commit message with the driver name, lowercased, - followed by a colon. - - Following your brief summary, provide a more detailed description of - the patch, manually wrapping the text at 72 characters. This - description should provide enough detail that one does not have to - refer to external resources to determine its high-level functionality. - - Once you use 'git review', two lines will be appended to the commit - message: a blank line followed by a 'Change-Id'. This is important - to correlate this commit with a specific review in Gerrit, and it - should not be modified. - -For further information on constructing high quality commit messages, -and how to split up commits into a series of changes, consult the -project wiki: - - https://wiki.openstack.org/GitCommitMessages - -Further Reading --------------- - - http://google-styleguide.googlecode.com/svn/trunk/pyguide.html diff --git a/MANIFEST.in b/MANIFEST.in index 96acc57..0aceb71 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include AUTHORS include ChangeLog include README.rst -include HACKING.rst include requirements.txt include test-requirements.txt exclude .gitignore diff --git a/README.rst b/README.rst index 29d1720..39a96d2 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,8 @@ Introduction ============ -hacking is a set of flake8 plugins that test and enforce the OpenStack Style Commandments, `HACKING.rst `_. +hacking is a set of flake8 plugins that test and enforce the `OpenStack +Style Guidlines `_. Origin ====== @@ -17,7 +18,11 @@ Since then, a few more OpenStack specific ones have been added or modified. Versioning ========== -hacking uses the major.minor.maintenance release notation, where maintenance releases cannot contain new checks. This way projects can gate on hacking by pinning on the major.minor number while accepting maintenance updates without being concerned that a new version will break the gate with a new check. +hacking uses the major.minor.maintenance release notation, where maintenance +releases cannot contain new checks. This way projects can gate on hacking +by pinning on the major.minor number while accepting maintenance updates +without being concerned that a new version will break the gate with a new +check. Adding additional checks @@ -30,7 +35,10 @@ Each check is a pep8 plugin so read Requirements ------------ - The check must already have community support. We do not want to dictate style, only enforce it. -- The canonical source of the OpenStack Style Commandments is `HACKING.rst `_, and hacking just enforces them; so when adding a new check, it must be in HACKING.rst +- The canonical source of the OpenStack Style Guidelines is + `doc/source/index.rst + `_, and hacking just enforces + them; so when adding a new check, it must be in docs/source/index.rst - False negatives are ok, but false positives are not - Cannot be project specific, project specific checks should be `Local Checks`_ - Docstring tests @@ -58,4 +66,3 @@ register. Such as: [hacking] local-check-factory = nova.tests.hacking.factory - diff --git a/doc/source/conf.py b/doc/source/conf.py index 01dc3b5..7630e48 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -8,7 +8,7 @@ sys.path.insert(0, os.path.abspath('../..')) # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'oslo.sphinx'] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. @@ -39,12 +39,6 @@ pygments_style = 'sphinx' # -- Options for HTML output -------------------------------------------------- -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme_path = ["."] -html_theme = '_theme' -html_static_path = ['static'] - # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project diff --git a/doc/source/index.rst b/doc/source/index.rst index 4bf30d4..2a2b0bf 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,21 +1,326 @@ -hacking -======= +OpenStack Style Guidelines +========================== -hacking is a set of flake8 plugins to test or enforce the more stringent -style guidelines that the OpenStack project operates under. +- 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 -Contents --------- +General +------- +- Put two newlines between top-level code (funcs, classes, etc) +- Use only UNIX style newlines ("\n"), not Windows style ("\r\n") +- Put one newline between methods in classes and anywhere else +- Long lines should be wrapped in parentheses + in preference to using a backslash for line continuation. +- Do not write "except:", use "except Exception:" at the very least +- Include your name with TODOs as in "#TODO(termie)" +- Do not shadow a built-in or reserved word. Example:: -.. toctree:: - :maxdepth: 1 + def list(): + return [1, 2, 3] - api/autoindex + mylist = list() # BAD, shadows `list` built-in -Indices and tables -================== + class Foo(object): + def list(self): + return [1, 2, 3] -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + mylist = Foo().list() # OKAY, does not shadow built-in +- Use the "is not" operator when testing for unequal identities. Example:: + + if not X is Y: # BAD, intended behavior is ambiguous + pass + + if X is not Y: # OKAY, intuitive + pass + +- Use the "not in" operator for evaluating membership in a collection. Example:: + + if not X in Y: # BAD, intended behavior is ambiguous + pass + + if X not in Y: # OKAY, intuitive + pass + + if not (X in Y or X in Z): # OKAY, still better than all those 'not's + pass + + +Imports +------- +- Do not import objects, only modules (*) +- Do not import more than one module per line (*) +- Do not use wildcard ``*`` import (*) +- Do not make relative imports +- Order your imports by the full module path +- Organize your imports according to the following template + +(*) exceptions are: + +- imports from ``migrate`` package +- imports from ``sqlalchemy`` package +- imports from ``nova.db.sqlalchemy.session`` module +- imports from ``nova.db.sqlalchemy.migration.versioning_api`` package + +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 + from nova.endpoint import cloud + import nova.flags + from nova import test + + +Docstrings +---------- +Example:: + + """A one line docstring looks like this and ends in a period.""" + + + """A multi line 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/ + + If you are going to describe parameters and return values, use Sphinx, the + appropriate syntax is as follows. + + :param foo: the foo parameter + :param bar: the bar parameter + :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", + }, + } + +Do not use ``locals()`` for formatting strings, it is not clear as using +explicit dictionaries and can hide errors during refactoring. + +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"}) + + +Python 3.x compatibility +------------------------ +OpenStack code should become Python 3.x compatible. That means all Python 2.x-only +constructs or dependencies should be avoided. An example is + + except x,y: + +Use + + except x as y: + +instead. Also Python 3.x has become more strict regarding octal string +literals. Use "0o755" instead of "0755". Similarly, explicit use of long +literals (01234L) should be avoided. + +Other Python 3.x compatibility issues, like e.g. print operator +can be avoided in new code by using + + from __future__ import print_function + +at the top of your module. + + +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. + + +oslo-incubator +---------------- + +A number of modules from oslo-incubator are imported into the project. + +These modules are "incubating" in oslo-incubator and are kept in sync +with the help of oslo-incubator's update.py script. See: + + https://wiki.openstack.org/wiki/Oslo#Incubation + + +The copy of the code should never be directly modified here. Please +always update oslo-incubator first and then run the script to copy +the changes across. + + +OpenStack Trademark +------------------- + +OpenStack is a registered trademark of the OpenStack Foundation, and uses the +following capitalization: + + OpenStack + + +OpenStack Licensing +------------------- + +Newly contributed Source Code should be licensed under the Apache 2.0 license. +All source files should have the following header: + + # 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. + + +Commit Messages +--------------- +Using a common format for commit messages will help keep our git history +readable. Follow these guidelines: + + First, provide a brief summary of 50 characters or less. Summaries + of greater then 72 characters will be rejected by the gate. + + The first line of the commit message should provide an accurate + description of the change, not just a reference to a bug or + blueprint. It must not end with a period and must be followed by + a single blank line. + + If the change relates to a specific driver (libvirt, xenapi, qpid, etc...), + begin the first line of the commit message with the driver name, lowercased, + followed by a colon. + + Following your brief summary, provide a more detailed description of + the patch, manually wrapping the text at 72 characters. This + description should provide enough detail that one does not have to + refer to external resources to determine its high-level functionality. + + Once you use 'git review', two lines will be appended to the commit + message: a blank line followed by a 'Change-Id'. This is important + to correlate this commit with a specific review in Gerrit, and it + should not be modified. + +For further information on constructing high quality commit messages, +and how to split up commits into a series of changes, consult the +project wiki: + + https://wiki.openstack.org/GitCommitMessages + +Further Reading +--------------- + + http://google-styleguide.googlecode.com/svn/trunk/pyguide.html diff --git a/hacking/core.py b/hacking/core.py index 9155e6c..8b440fe 100755 --- a/hacking/core.py +++ b/hacking/core.py @@ -924,7 +924,7 @@ class OnceGitCheckCommitTitleBug(GitCheck): class OnceGitCheckCommitTitleLength(GitCheck): """Check git commit message length. - HACKING.rst recommends commit titles 50 chars or less, but enforces + HACKING recommends commit titles 50 chars or less, but enforces a 72 character limit H802 Title limited to 72 chars diff --git a/setup.cfg b/setup.cfg index 5bcd26c..553e96a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ author = OpenStack author-email = openstack-dev@lists.openstack.org summary = OpenStack Hacking Guidline Enforcement description-file = - HACKING.rst + README.rst home-page = http://github.com/openstack-dev/hacking classifier = Development Status :: 4 - Beta @@ -48,6 +48,11 @@ flake8.extension = H901 = hacking.core:hacking_is_not H902 = hacking.core:hacking_not_in +[build_sphinx] +all_files = 1 +build-dir = doc/build +source-dir = doc/source + [egg_info] tag_build = tag_date = 0 diff --git a/test-requirements.txt b/test-requirements.txt index 91a162e..04bf1a4 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,6 +3,7 @@ discover fixtures>=0.3.14 python-subunit sphinx>=1.1.2 +oslo.sphinx testrepository>=0.0.17 testscenarios>=0.4 testtools>=0.9.32