← Back to team overview

openerp-expert-framework team mailing list archive

Re: Coding guidelines and standards - additional info

 

Hi !


I think we have a wiki page on the OpenERP doc website here:

http://doc.openerp.com/contribute/index.html#how-to-contribute-link

And here more precisely :

http://doc.openerp.com/contribute/developing_modules.html#coding-guidelines

We decide part of those things during the last developper meeting. I think it's good to complete this here, and why not add a link into those page for developer here :

http://doc.openerp.com/developer/index.html#book-develop-link


Cheers,


Joël


Le 15 déc. 2009 à 16:26, Sharoon Thomas a écrit :

> Hi Ferdinand,
> 
> Is there a wiki for these guidelines?
> 
> On Tue, Dec 15, 2009 at 2:29 PM, Ferdinand Gassauer <office@xxxxxxxxxx> wrote:
> some additional ideas
> 
> we also prefer to code table descriptions for better readability
> (see screen shot)
> * fixed column width for name and filed type
> (I know sometimes the name is to short ....)
> * alphabetical order of fields
> * split long lines
> 
> 
> 
> The Syntax is "MoinMoin"-Wiki.
> 
> -------------------------------------------------------------
> --
> Best Regards
> 
> ChriCar Beteiligungs- und Beratungs- GmbH
> http://www.chricar.at/ChriCar/index.html
> Dr. Ferdinand Gassauer
> Official Tiny Partner
> 
> 
> = Introduction =
> 
> These rules augment the rules stated in PEP-0008 (http://www.python.org/dev/peps/pep-0008/).
> 
> == Purpose ==
> Coding guidelines help to:
>  * '''ensure maintainability''' -- any programmer should feel "at home" when reading any source code. Therefore, any source code needs to have a uniform structure. Moreover, it is essential to disallow difficult-to-read code fragments requiring a lot of time to be understood.
>  * '''ensure automatization''' -- so that we can automatically rewrite code and generate documentation, for example, API documentations and reference manuals.
>  * '''avoid faulty software''' -- following the below guidelines will help programmers to avoid or circumvent common errors and pitfalls.
> 
> == Scope ==
>  * These coding guidelines apply to Python files only. However, major parts can be adapted to other languages as well.
>  * '''Any Python file must conform with these coding guidelines,''' regardless of whether it is a library, a tool-specific file, a "goodies" script or just a quick hack for rapid prototyping.
>  *  However, there might be some cases where it makes sense to break a rule. It is up to you as careful and intelligent programmers to identify these cases and handle them in a proper way:
>   * If it appears to be a single case, the item shall be documented in the artefact itself.
>   * If the violation is considered to be systemic and should be taken into account in the guidelines, file a change-request against the documents. See section 6 how to do so.
> 
> == Terminology ==
>  * The word "shall" is used for requirements. You need to have a very good reason not to use "shall" where it is mandatory, and you have to document, why you have done so.
>  * The word "should" is used for recommendations, good practices and hints.
> 
> == General Advice ==
>  * Program '''defensively'''. Consider in particular that parameters of a function may be incomplete (for example, filename without extension or full path) or have a different type (`int` instead of `float`, `tuple` instead of `list`, ...).
>  * Program for '''portability'''. For example, use `os.path.join` instead of concatenating strings with "/".
>  * Program '''unambiguously'''. Define unique values only once.
>  * Avoid defining "magic" numbers in the source code. Use definitions instead of hard-coded numbers.
>  * Use '''symbolic names'''. This improves readability, makes the program easier to maintain, reduces the potential for errors, and requires less development effort.
> 
> 
> = Formatting =
> 
> == General ==
>  1. There shall be no trailing spaces
> 
> == Header ==
> 
>  1. Every file shall start with a header.
>   This header shall include:
>   * the Python coding cookie. You had best use the `iso-8859-1` charset.
>   * licence information.
>   * The name of the file, as it would be imported by Python. For the `App_Type` module in the`_TTA` package, this would be `_TTA.App_Type`.
>   * the purpose of the file.
>   * revision dates including the Bugtracking  number.
>  2. The header shall ''not'' include:
>   * hash-bangs so that the Python script can be executed just by calling it (that is, "`#! \usr\bin\env python`"). When the Python version is changed, it can be very hard to find errors caused by these hash-bangs.
> 
>     '''Hint:'''
>     It is good practice to check the header of every file you edit.
> 
>  3. The header shall have the following format. (Two different licenses are given as example.)
>    {{{
> #!python
> # -*- coding: iso-8859-1 -*-
> # Copyright (C) 2000-2004 Swing GmBH. All rights reserved.
> # Gruenlandgasse 1, 2620 Neunkirchen, Austria. office@xxxxxxxxxxxxxxxx
> #
> #++
> # Name
> #    _TTA.App_Type
> #
> # Purpose
> #    Define application types for TTA tools
> #
> # Revision Dates
> #     7-Nov-2000 (GK) Creation
> #    28-Jul-2002 (GK) [4711] Adapted to packaging of `TOM`
> #     2-Apr-2004 (GK) [4712, 4713] `NODE__cluster` added to definition of `NDT`
> #    ««revision-date»»···
> #--
>    }}}
> 
>    {{{
> #!python
> # -*- coding: iso-8859-1 -*-
> # Copyright (C) 2000-2004 Swing GmBH. All rights reserved.
> # Gruenlandgasse 1, 2620 Neunkirchen, Austria. office@xxxxxxxxxxxxxxxx
> #
> # ****************************************************************************
> # This library is free software; you can redistribute it and/or
> # modify it under the terms of the GNU Library General Public
> # License, as published by the Free Software Foundation; either
> # version 2 of the License, or (at your option) any later version.
> #
> # This library is distributed in the hope that it will be useful,
> # but WITHOUT ANY WARRANTY; without even the implied warranty of
> # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> # Library General Public License for more details.
> #
> # You should have received a copy of the GNU Library General Public
> # License along with this library; if not, write to the Free
> # Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> # ****************************************************************************
> #
> #++
> # Name
> #    _TFL.DL_List
> #
> # Purpose
> #    Doubly linked list
> #
> # Revision Dates
> #    11-Sep-2003 (GK) Creation
> #    12-Sep-2003 (GK) Creation continued
> #     9-Mar-2004 (GK) [4714] `_doc_test` changed to not use `import`
> #    ««revision-date»»···
> #--
>    }}}
> 
> == Footer ==
>  1. Every file shall end with the following comment, repeating the name of the header.
>    {{{
> #!python
> ### __END__ TTA.App_Type
>    }}}
> 
> == End of Classes and Functions ==
>  1. Every class shall have a closing comment with the syntax as shown below.
>  2. Every method shall have a closing comment with the syntax as shown below.
>    '''Example:'''
>    {{{
> #!python
> class Coding_Guidelines (Guidelines) :
>    """General and abstract guidelines."""
> 
>    def __init__ (self, name) :
>        self._name = name
>    # end def __init__
> 
>    def formatted_name (self) :
>        """Returns the internal variable `_name` nicely formatted.
>        """
> 
>        return ">>%s<<" % self._name
>    # end def formatted_name
> # end class Coding_Guidelines
>    }}}
> 
> == Indentation and Spacing ==
> (See http://en.wikipedia.org/wiki/Bracket on a definition of brackets, parentheses and braces.)
> 
>  1. Source files shall not contain consecutive multiple blank lines.
>  1. There shall exactly be one blank line between a method and a class definition.
>  1. You shall use a blank space before `\` or `:`
>  1. You shall use a blank space before and after any operator.
>  1. You shall use a blank space after `,` or  `;` or `:`
>  1. You shall not place spaces after openings and before closings.
>  1. You should concentrate args, but never keywords.
>    '''Example:'''
>    {{{
> #!python
>    CSE_Object_Selector.__init__ \
>        ( self, r_map, master
>        , label = "Subsystem"
>        , list  = list
>        , name  = "subsystem_selector"
>        )
>    }}}
> 
> == Alignment ==
>  1. If, and only if, a call or definition exceeds one line, it shall immediately be broken after the name, keyword or (assignment) operator.
>  1. Exception names shall be in the same line as `raise` or `except` to be able to ''grep'' for them.
>    '''Example:'''
>    {{{
> #!python
>    raise TypeError, \
>        "%s needs a list as first argument, not a %s." % (self.name, type (x))
>    }}}
>  1. If the remaining line is still too long, one line shall be used for every parameter.
>  1. Brackets and commas shall be aligned horizontally.
>  1. If a closing bracket is on a different line than its opening bracket, both shall be in the same column.
>  1. `=` signs for keyword defaults shall be aligned horizontally.
>  1. `=` signs shall be aligned horizontally, in consecutive lines of statements.
>  1. Triple-quotes (`"""`) shall be normally indented and horizontally aligned.
>  1. Expressions shall be aligned so that their visual appearance matches their logical structure.
>    '''Example:'''
>    {{{
> #!python
> class Function_Definitions (Coding_Guidelines) :
>    """More about function definitions. Several lines are welcome,
>       and they do not affect the general layout of this class or
>       function description.
>    """
> 
>    def __init__ \
>        ( self, typ, version
>        , a_default_parameter    = "something"
>        , a_long_parameter_name  = 1
>        , another_parameter      = "something other"
>        ) :
> 
>        self.typ          = typ
>        self.version      = version
>        self.r_map.tag_highlight \
>            (event, self.f_tag, self.r_map.frame_high, "current_frame")
>        self.name         = self.r_map.name + self.version
>        self.userints [i] = self.map_from_object \
>            (self.r_map, self, rtag, i + 1, typ = "host")
>        CSE_Object_Selector.__init__ \
>            ( self, r_map, master
>            , label = "Subsystem"
>            , list  = list
>            , name  = "subsystem_selector"
>            )
>    # end def __init__
> # end class Function_Definitions
>    }}}
> 
> == EOL Quotes ==
>  1. You shall use the EOL quote (backslash + carriage_return) only if really necessary. The only exception is right after a function name, a keyword or an assignment operator, if the line would otherwise be too long.
>  1. There shall be no more than one EOL quote per statement.
>  1. Adjacent text literals on multiple lines shall be put in parentheses, instead of quoting the line ends with backslashes. See example below.
>  1. You shall factor as much as possible, even in text literals.
>  1. Expressions spanning multiple lines shall also be parenthesized.
>    '''Example:'''
>    {{{
> #!python
>    Abbreviations = "\n".join \
>        ( ( "`bb` ... bytes_bus effective length of the frame on the bus"
>          , "`vs` ... validity_span duration in which the frame is valid "
>            " in the CNI, starting at the next slot"
>          , "`tt` ... transmission_time duration of the transmission phase on"
>            " the bus"
>          , "`d`  ... duration slot duration"
>          , "`s`  ... size net size of the frame in bytes"
>          )
>        )
>    }}}
>  1. You shall not use an EOL quote, if the subsequent opening bracket is below the EOL quote or to the right of it.
>    '''Bad Example:'''
>    {{{
> #!python
>    if \
>        ( long_expression
>        and another_long_expression
>        ) :
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>    if  (   long_expression
>        and another_long_expression
>        ) :
>    }}}
>  1. Long strings shall be broken into pieces or written with triple-quotes. The new line shall be aligned with the beginning of the string at the same level on the previous line.
>    '''Example:'''
>    {{{
> #!python
>    a_rather_long_string = \
>        ( "A very long string "
>          "split over multiple lines."
>        )
>    another_rather_long_string = \
>        """A very long string
>           split over multiple lines.
>        """
>    }}}
> 
> = Structure =
> 
> == Module and Class ==
>  1. Every file shall have a file history documenting any modification made.
> 
> == Order of Definitions ==
>  1. The most important class should be the last one.
>  1. Within a class, you shall first define the attributes of this class, then properties if any, then the methods.
>  1. The methods of a class shall be sorted in the following order:
>   * First `__new__`, then `__init__`, then `__call__`.
>   * Then the public interface (that is, externally used methods) shall follow. Such methods look like "`x`".
>   * Then non-public methods shall follow. Such methods look like "`_x`".
>   * Then other special methods shall follow. Such methods look like "`__x__`".
>   * Name-mangled methods (looking like "`__x`") shall not be used.
>  1. Within the above sections, methods should be sorted in a natural way (for example, most important first, according to the control flow, grouped logically), else in alphabetical order.
>  1. The `__main__` script shall be at the end of a module.
>  1. If there are long lists of attributes, keywords, or other items, for example, they should be sorted alphabetically (or numerically, if applicable).
>  1. '_' shall be ignored when sorting, but underscores should be grouped. For example, `affe`, `ameise`, `_aachen`, `_amsterdam`, `bingo`, ...
> 
> == Package Name Space ==
>  1. Related modules shall be grouped into a Python package.
>  1. Each package shall be implemented as a Package_Namespace.
>   * The name of the package shall start with a single underscore, for example, `_Foo`.
>   * The name of the package namespace shall be the same as that of the package, with the exception of the leading underscore, for example, `Foo`.
>   * The package file `__init__.py` shall define the package namespace instance (see package `TOM` for an example).
>   * All the modules of the namespace package shall contain an export statement guarded by `__name__ != "__main__"` at the bottom of the file.
>    '''Example:'''
>    {{{
> #!python
> if __name__ != "__main__" :
>    TFL._Export ("*")
>    }}}
>  1. Any access to objects of a namespace package shall use a qualified name which shall start with the name of the namespace package, for example, `Foo.bar ()`.
>    '''Example:'''
>    {{{
> #!python
> from _TFL import TFL
> import _TFL.DL_List
> ...
> l = TFL.DL_List ()
>    }}}
>  1. `From` `import` shall not be used to import objects from a namespace package.
>    '''Bad Example:'''
>    {{{
> #!python
> from _TFL.DL_List import DL_List
>    }}}
> 
> == Nesting and Recursion ==
>  1. Nested function definitions should be avoided.
>  1. Recursion shall be used only, if it substantially simplifies the code.
> 
> = Semantics =
> 
> == Documentation ==
>  1. Any comments and descriptions documenting a source file shall be written in '''English'''.
>  1. Any documentation in the source code has the following objectives:
>   * Defining a uniform structure of all source code modules.
>   * Providing an easy way to find information on the file contents.
>   * Making it easier to maintain files.
>   * Providing information on how a certain problem has been solved.
>   * Facilitating to generate additional documentation (such as reference manuals) automatically.
>  1. If actual names or values appear in any documentation, they shall be enclosed by backquotes (`).
> 
> == Docstrings ==
> 
> There is '''no''' reason (IP-protection, etc.) to '''not''' write docstrings.
> 
>  1. Docstrings presented to the user shall have appropriate wording and may contain whatever is necessary for the specific purpose and due to usability considerations.
>  1. Docstrings that are not presented to the user shall contain a brief description of the relevant class or method. This description should not contain any redundant information (and repeat, for example, the default value) or misleading information (for example, requiring an int although any numeric would do).
>  1. The constructor should not have a description.
>  1. Docstrings should contain doctests whereever feasible.
>  1. Docstrings shall be concise. About the content see sub-section "Detailed Documentation" below.
> 
> == Detailed Documentation ==
> 
> The intention is to document any Python package or module using Sphinx.
> 
>  1. A Python package shall be documented in the `__init__.py` file by using Sphinx. The generated documentation shall explain the purpose of the package and its structure and components.
>  1. A Python module shall be documented by the module docstring using Sphinx. The generated documentation shall explain the purpose of the module, its primary use case(es) and its structure.
>  1. Detailed documentation should contain design decisions, rationales, background information, usage examples and other helpful information for developers. It shall not repeat what is obvious from the code.
>  1. Detailed package or module documentation shall be done inline (docstring) or in a dedicated directory. For lib/python, this is `_DOC/Sphinx/packages`, maintaining the same structure as the source code.
>  1. Detailed documentation of concepts shall be done in a dedicated directory. For lib/python, this is `_DOC/Sphinx/concepts`.
>  1. As scripts are usually seen and used without the context of lib/python, all necessary documentation shall be in the same file as the source code itself.
>  1. Detailed documentation shall reference but not repeat other documents (SDD, customer's specifications, standards, etc.).
>  1. For detailed documentation in other files, a reference to this location shall be given. The location may be omitted if it is obvious. For Sphinx, use:
>    {{{
> #!python
>    # SPHINX_DOC [location]
>     }}}
> 
> 
> == Comments ==
> Always consider that someone who sees your code for the first time has to be able to understand it.
>  1. You should use doctests (or at least docstrings) instead of comments.
>  1. Comments shall describe why something is done in a particular way, and not what is done or how something is done. This is documented by the code itself!
>  1. You shall place comments after a line, if possible (length). Otherwise, place it above the line of code to which it belongs.
>  1. You shall use the "`### XXX`" prefix for comments relating to future versions or constituing hints how to fix a problem.
>    '''Example:'''
>    {{{
> #!python
>        another_function \
>            ( first_very_long_parameter
>            , (some * complicated + expression)
>            , elapsed_time # in microseconds
>            )
>        # avoid rounding errors
>        e = ((w_x * (ttime + self.ifg_in_ns)) / self.duration_in_ns) - d
>        ### XXX adapt to improved Package_Namespace
>        pkg_namespace_import_pat = Regexp (r"x", re.X)
>    }}}
>  1. You shall use self-explanatory names instead of comments.
>    '''Bad Example:'''
>    {{{
> #!python
>    a_function \
>        ( first_long_parameter
>        , 42 # number of lines
>        )
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>    a_function \
>        ( first_long_parameter
>        , number_of_lines = 42
>        )
>    }}}
> 
> == Naming ==
>  1. The name of a module shall have the extension ".py".
>  1. The base name of the module shall be identical to the name of the (only or most important) class.
>  1. If a module contains no class, its base name should refer to the intended use.
>  1. The name of the identifier shall be unambiguous and self-explanatory to specify the purpose of the identifier.
>  1. The larger the scope of visibility, the longer a name should be (and vice versa), this means that loop variables should be as short as possible, global names should be long enough to convey sufficient meaning.
>  1. If the name comprises multiple words, they shall be separated by underscores ("`_`").
>  1. `CamelCaseWordsLikeThisOne` shall not be used.
>  1. Magic names, to be specific, names with two leading and two trailing underscores, shall not be used except when magic methods are to be defined, as is defined by Python (otherwise existing code might become invalid in future Python versions, when the set of official magic gets bigger).
>  1. Any class name shall start with a capital letter (to be specific, with a capital letter at the beginning of the name and after every underscore). The rest are lowercase letters, underscore or digits. Exceptions are allowed when the name consists of an abbreviation (for example, `PCP_Driver`) or when the class implements an association (for example, `Host_uses_Message`).
>  1. Constants shall be all uppercase with words separated by underscores or digits.
>  1. The other identifiers (which can also have an underscore as the first letter) shall be all lowercase with words separated by underscores or digits. Exceptions are allowed for names being abbreviations.
>  1. Class names shall be nouns or noun phrases, in mixed case, with the first letter of each internal word capitalized (see above).
>  1. Mixin class names shall be adjectives or nouns having the "`_mixin`" suffix.
>  1. Names of states that change functions shall be verbs (for example, `connect`, `schedule`) or verb phrases.
>  1. Names of states that query functions shall be adjectives, noun-verb-adjective combinations or verb-noun combinations (for example, `connected`, `is_valid`, `has_key`).
>  1. You shall avoid "`get_`" prefixes.
>    '''Bad Example:'''
>    {{{
> #!python
>    def get_version (self) :
>        return "%s.%s.%s" % (self.major, self.minor, self.patchlevel)
>    # end def get_version
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>    def version (self) :
>        """Returns the version as <major>.<minor>.<patchlevel>."""
> 
>        return "%s.%s.%s" % (self.major, self.minor, self.patchlevel)
>    # end def version
>    }}}
>  1. Non-public names shall start and end with a single underscore ("`_`").
> 
> = Pragmatics =
> 
> == Avoid redundancy ==
> 
>  1. Do not repeat yourself (DRY!). This also applies to
>   * literals: use named constants,
>   * (sub)-expressions: assign them to named variables,
>   * blocks of code: factor them into functions or methods,
>   * sets of methods: factor tem into common ancestors.
>  1. You shall be brief and concise.
>    '''Bad Example:'''
>    {{{
> #!python
>        (x, y) = (self.current_slot [0], self.current_slot [1])
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>        (x, y) = self.current_slot [:2]
>    }}}
>  1. You shall make the closing clearly visible.
>    '''Example:'''
>    {{{
> #!python
>        (time, value) = reduce \
>            ( lambda l, r, o = grid_opt : min (l, (o / r + r / o, r))
>            , self.time_list
>            , (2 * self.time_list [-1], ) * 2
>            )
>        r_slot = filter \
>            ( lambda l, rs = rs : l.r_slot.round == rs.round
>              and l.slot.number == rs.slot
>              ### XXX place filter condition for Cluster_Mode here
>            , r_slot
>            ) [0].r_slot
>        return \
>            ( self.slot.duration * self.r_map.pix_per_MT_x
>            + 2                  * self.r_map.frame_border_x
>            )
>    }}}
> 
> == New-style classes ==
>  1. For newly written code, new-style classes shall be used whenever possible, which is unfortunately not yet feasible for exceptions or descendents of some classic classes already existing.
>  1. New-style classes should normally inherit directly or indirectly from `TFL.Meta.Object`.
> 
> == Reference to Ancestor Class ==
>  1. For new-style classes, `__super` shall be used to upchain method calls (`__super` is provided by the `TFL.Meta.M_Autosuper` meta-class).
>  1. Every classic class shall define an ancestor attribute which shall be used throughout the class to upchain method calls.
> 
> == Import order ==
>  1. The role types of an TOM association shall be imported before the association itself. Role types are the object types connected ("linked") with the association.
>    '''Good Example:'''
>    {{{
> #!python
>    from _TTA import TTA
>    import TTA.Message
>    import TTA.Subsystem
>    import TTA.Subsystem_sends_Message
>    }}}
> 
>    '''Bad Example:'''
>    {{{
> #!python
>    from _TTA import TTA
>    import TTA.Subsystem_sends_Message
>    import TTA.Message
>    import TTA.Subsystem
>    }}}
> 
> == Use of properties ==
> For new-style classes, properties shall be used whenever control over attribute access is called for. A Python property associates an attribute name with methods to get, set, and delete the attribute's value and to an optional documentation for the attribute.
>  1. Properties shall be only used inside new-style classes.
>  * Using properties for readonly attributes:
>    {{{
> #!python
>    class Foo (TFL.Meta.Object) :
>        ro = property (lambda s : s._ro)
>        def __init__ (self, x = 0) :
>            self._ro = x
>    }}}
>    {{{
> 
> >>>>>> f = Foo (1)
> >>>>>> f.ro
> 
> 1
> 
> >>>>>> f.ro = 3
> 
> Traceback (most recent call last):
>  File "<stdin>", line 1, in ?
> AttributeError: can't set attribute
>    }}}
>  * Using properties for read/write attributes:
>    {{{
> #!python
>    class Complex (TFL.Meta.Object) :
> 
>        def _get_r (self) :
>            return math.sqrt (self.x ** 2 + self.y ** 2)
>        # end def _get_r
> 
>        def _set_r (self, r) :
>            theta  = math.atan2 (self.y, self.x)
>            self.x = r * math.cos (theta)
>            self.y = r * math.sin (theta)
>        # end def _set_r
> 
>        r = property (_get_r, _set_r)
>    }}}
> 
>  1. Properties shall be used instead of parameterless access functions.
>    '''Bad Example:'''
>    {{{
> #!python
>    class Foo (TFL.Meta.Object) :
>        def position (self) :
>            return self._position
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>    class Foo (TFL.Meta.Object) :
>        position = property (lambda s : s._position, doc = "attribute documentation")
>    }}}
> 
> == Scope of Visibility ==
>  1. Do not make an identifier visible outside the scope for which it is required.
>  1. The larger the scope of visibility, the longer an identifier should be.
> 
> == Identity vs. Equality ==
>  1. `is` shall be used to check for identity. As a general rule, identity checks should be used only for singleton objects.
>  1. `is` shall not be used to check immutable objects, such as numbers, strings, and tuples.
>  1. `==` shall be used to check for equality.
>  1. `==` shall not be used to check, whether a name refers to `None`.
>  1. To check for a specific type, use `isinstance (i, o)`.
>    '''Bad Example:'''
>    {{{
> #!python
> type (s) == type ("")
> type (s) is type ("")
> import types
> type (s) == types.StringType
> isinstance (s, type (""))
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> isinstance (s, str)
> isinstance (s, (str, unicode))
>    }}}
> 
> == Boolean Expressions ==
>  1. Boolean values shall not be compared against `True` or `False`.
>    '''Bad Example:'''
>    {{{
> #!python
> if x == True :
>    do_something ()
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> if x :
>    do_something ()
>    }}}
>  2. To test, if a list or dictionary contains elements, you shall not use `len`.
>    '''Bad Example:'''
>    {{{
> #!python
> if len (x) == 0 :
>    do_something ()
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> if not x :
>    do_something ()
>    }}}
>  3. To test, if a name refers to `None`, identity testing shall be used.
>    '''Bad Example:'''
>    {{{
> #!python
> if not x : ### will be entered for any empty structure or zero-valued number
>    do_something ()
> if x != None : ### calls `__cmp__` of x.__class__
>    do_some_otherthing ()
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> if x is not None :
>    do_something ()
>    }}}
> 
> == Parentheses ==
>  1. You should use rather more than less parentheses.
>  1. You shall avoid redundant parentheses, like in `if (x == 5) :`.
>  1. You shall avoid precedence gotchas.
>    '''Bad example:'''
>    {{{
> #!python
>    a = b and not c or d
>    }}}
>    '''Good example:'''
>    {{{
> #!python
>    a = (b and (not c)) or d
>    }}}
>  1. You should do the optical layout in a such way that the code can be read correctly. If unsure, use parentheses.
>    '''Bad example (actually incorrect code, see bug report 9073):'''
>    {{{
> #!python
>    return int \
>        ( self.home_scope.TTA.Cluster.root.max_delay
>        + preamble_bits
>        + (start_of_frame_bits[self.home_scope.TTA.Cluster.root.physical_interface]
>        + self.protocol.header_bits
>        + databits
>        + self.protocol.crc_bits
>        ) * (1E6 / speed) # convert kbit/sec to nanoseconds/bit
>        )
>    }}}
>    '''Good example:'''
>    {{{
> #!python
>    TTA = self.home_scope.TTA
>    return int \
>        ( TTA.Cluster.root.max_delay
>        + ( preamble_bits
>          + start_of_frame_bits [TTA.Cluster.root.physical_interface]
>          + self.protocol.header_bits
>          + databits
>          + self.protocol.crc_bits
>          )
>        * (1E6 / speed) # convert kbit/sec to nanoseconds/bit
>        )
>    }}}
> 
> == Avoid Numeric Indices ==
>  1. You should provide names for command line arguments instead of accessing them by index. You had best use the `Command_Line` module.
>  1. You shall extend lists and tuples by meaningful names, not by index.
>    '''Bad Example:'''
>    {{{
> #!python
>    for t in self.type_list :
>        c_name = "%s_%s (%s)" % (t[0], t[1], t[2])
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
>    for (t_name, t_def, t_len) in self.type_list :
>        c_name = "%s_%s (%s)" % (t_name, t_len, t_def)
>    }}}
> 
> == Avoid Long Lines ==
>  1. You shall start with operators to avoid EOL quotes.
>    '''Example:'''
>    {{{
> #!python
> mc_y_min = \
>    ( (r_map.mchange_clear_y_min * 100)
>    / (100 - r_map.mchange_y_min_percent)
>    + r_map.frame_border_y
>    )
>    }}}
>  1. You should precompute a value to shorten the subsequent function call or expression and improve its readability.
>    '''Example:'''
>    {{{
> #!python
> y_ui_0 = y      + self.frame_y_m
> y_ui_1 = y_ui_0 + self.ui_y_b
> self.userints [0].insert (canvas, x, y_ui_0, bx, 0, typ_label, self)
> self.userints [1].insert (canvas, x, y_ui_1, bx, 0, typ_label, self)
>    }}}
>  1. You shall use one format string to assemble strings from several parts.
>    '''Bad Example:'''
>    {{{
> #!python
> result = (result + ", tt = %d us, IFG = %d us, idle = %d us"
>       % (ttime, ifg, idle))
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> result = \
>    ( "%s, tt = %d us, IFG = %d us, idle = %d us"
>    % (result, ttime, ifg, idle)
>    )
>    }}}
> 
> == Exceptions ==
>  1. No strings shall be used as exceptions.
>  1. All exceptions shall end with `_Error` and follow the naming guidelines for classes.
>  1. All exceptions shall be derived from `StandardError`.
>    '''Example:'''
>    {{{
> #!python
> class TGW_Error (StandardError) :
>    pass
> # end class TGW_Error
>    }}}
>  1. There should be a file `Errors.py` in every package which defines a significant number of package-specific errors. The `Errors.py` file shall define all the exceptions specific to this package.
>  1. You shall catch only the exceptions you really know. However, sometimes you have to catch all Python-related exceptions, for example, when interpreting a string entered by the user.
>  1. If you want to print a traceback and go on, you should do as shown below. The import statement should be at the top of the file (and should thus not be conditional).
>    '''Example:'''
>    {{{
> #!python
> def test_it_again ():
>    try :
>        x.run (cmd)
>    except KeyboardInterrupt :
>        raise
>    except I_Expect_Error :
>        # Do whatever you have to do.
>    except StandardError :
>        import traceback
>        traceback.print_exc ()
> # end def test_it_again
>    }}}
> 
> == Performance gotchas ==
>  1. Strings shall not be concatened by the `+` operator. Its repeated use in a loop can result in major performance bottlenecks.
>   * Implicit concatenation shall be used to concatenate string literals.
>   * The `%` operator shall be used to concatenate a fixed set of variable strings.
>   * The `join` method shall be used to concatenate a dynamic set of strings.
>    '''Bad Example:'''
>    {{{
> #!python
> lit_cat = "first" + "second"
> message = str (n) + "errors " + x + "detected"
> 
> result = ""
> for x in some_list :
>    result += str (x)
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> lit_cat = \
>    ( "first"
>      "second"
>    )
> message = "%d errors %s detected" % (n, x)
> r = []
> for x in some_list :
>    r.append (str (x))
> result = "".join (r)
>    }}}
>    '''Even better Example:'''
>    {{{
> #!python
> lit_cat = "firstsecond"
> result  = "".join ([str (x) for x in some_list])
>    }}}
>  1. The `in` operator shall not be used for repeated membership tests in lists.
>  1. The `keys` method of dictionaries shall not be used for membership tests.
>    '''Bad Example:'''
>    {{{
> #!python
> if x in d.keys () :
>    do_something ()
>    }}}
>    '''Good Example:'''
>    {{{
> #!python
> if x in d :
>    do_something ()
>    }}}
> 
> = Revisions of these Coding Guidelines =
> 
> If you encounter an error or would like to change or add something to these coding guidelines, the following process applies:
> 
>  * write an email to your team leader
>  * your request will be discussed in the Teamleader Meeting
>  * in the Teamleader Meeting it also will be decided if and how to apply the changes
>  * the changes will be made by one of the maintainers of these guidelines (currently AloisGoller and GerhardKönighofer) and announced to the public
>  * several change requestes might be grouped, and handled en-bloc by the Teamleader Meeting
> 
> == Ideas for extension of these guidelines ==
>  * guidelines on ''generators''
>  * only use doctest, since U_Test is far too complex
>  * no 'else' for unit tests:
> '''Bad Example:'''
> {{{
> if __name__ != "__main" :
>     TGW._Export ("*")
> else :
>     import U_Test
> 
>     def _doc_test () :
>         return U_Test.run_module_doc_tests ("_TGW.Menu")
>     # end def _doc_test
> 
>     def _test () :
>         _doc_test  ()
>     # end def _test
> 
>     _test ()
> 
> ### __END__ TGW.Menu
> }}}
> '''Good Example:'''
> {{{
> if __name__ != "__main" :
>     TGW._Export ("*")
> ### __END__ TGW.Menu
> }}}
> 
>  * pass arguments with name and value if the name and/or position is different in the called method
> 
> 
> == Proposal for middle-requirements ==
> 
> Coding guidelines help to:
> 
>  * '''ensure readability''' -- any programmer should feel "at home" when reading any source code. Therefore, any source code needs to have a uniform structure. Moreover, it is essential to avoid difficult-to-read code fragments requiring a lot of time to be understood.
> 
>    * self-explanatory names
>    * well structured code
>    * short functions and methods
> 
>  * '''ensure maintainability''' -- a programmer should be able to understand and change a code fragment quickly and without reading the complete code and understanding every single detail. Therefore, it is important to accurately and consistently represent the logical structure of the code and to keep things local and modular. In addition to readability, it is also important that the change can be made easily and does not require to change the whole file.
> 
>    * comments commenting the why, not the how
>    * no complicated or complex expressions
>    * simple formatting rules so that lines easily can be extended
>    * comments about future changes
> 
>  * '''facilitate automatization''' -- so that one can automatically rewrite code and generate documentation, e.g., API documentations and reference manuals; and that there is no need to manually cleanup things afterwards.
> 
>  * '''ensure correctness''' -- as well as intended behavior. The programmer thus can avoid or circumvent common errors and pitfalls. Correct and supporting documentation and test cases inlined in the source code also help to avoid misunderstandings and thus errors.
> 
>    * use parantheses
>    * align "," and parantheses in multi-line statements
>    * describe the signature and functionality in docstrings
>    * use (various kinds of) unit tests
> 
>  * '''ensure conciseness''' -- so that a programmer can see (and then comprehend) as much as possible without navigating around. Moreover, to improve performance of the code. Conciseness contributes to efficiency as well as maintainability.
> 
>    * few blank lines
>    * 80 columns max, so that 2 pages can be displayed on one screen
>    * short names
>    * refactor where possible and meaningful (i.e. Don't Repeat Yourself)
>    * use / harness the syntactic features of the language
> _______________________________________________
> Mailing list: https://launchpad.net/~openerp-expert-framework
> Post to     : openerp-expert-framework@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~openerp-expert-framework
> More help   : https://help.launchpad.net/ListHelp
> 
> 
> 
> 
> -- 
> Sharoon Thomas
> Business Analyst & ERP Consultant
> http://bit.ly/5FAJKU
> _______________________________________________
> Mailing list: https://launchpad.net/~openerp-expert-framework
> Post to     : openerp-expert-framework@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~openerp-expert-framework
> More help   : https://help.launchpad.net/ListHelp

-- 

Joël Grand-Guillaume 
OpenERP Consultant
Business Solutions

Camptocamp SA
PSE A, CH-1015 Lausanne
 www.camptocamp.com 

Phone: +41 21 619 10 28
Office: +41 21 619 10 10
Fax: +41 21 619 10 00
Email: joel.grandguillaume@xxxxxxxxxxxxxx
http://www.camptocamp.com/fr/business-solutions/formations


References