Scorpion Python Plug-ins

Design Guidelines

May 21, 2011

GD-2011-0025-A

Thor Vollset

Tordivel AS


Table of Contents

1. Introduction

2. Revision History

3. References

4. Python module header

5. Code layout

Indentation

Tabs or Spaces

Maximum Line Length

Encodings

Imports

White-space in Expressions and Statements

Documentation Strings

Naming Conventions

Naming Conventions

Names to Avoid

Class Names

Exception Names

Global Variable Names

Function Names

Function and method arguments

Method Names and Instance Variables

Constants

Programming Recommendations


1. Introduction

This document describes a coding style to be used when developing python plug-ins for Scorpion.

The document is based on Style Guide for Python Code  from Python Enhancement Proposals.

This documents is a supplement to Python Plugin Interface Specification.

2. Revision History

3. References

[1] http://www.python.org/dev/peps/pep-0008/

[2] Python Plugin Interface Specification

4. Python module header

Each python module must contain module header and revision list.

Module header must contain:

Revision list must contain:

Sample module header with revision list:

##########################################################################

#

# arrlib.py

# Almost complete Arrlib integration in Python.

# Small matrix/vector/pose types represented as Python objects

#

# Version 3.0.0.5

# 18 Jun 2009

#

##########################################################################

# 3.0.0.5  - 18 Jun 2009, TV: added pose objects; bugfixes; long tuple constructors

# 3.0.0.4  - 26 May 2009, RB: (no changes this file)

# 3.0.0.3  - 23 May 2009, LL: (no changes this file)

# 3.0.0.2  - 23 May 2009, RL: bugfixes in _Line, _Box, _Cir; more consistent constructor docs

# 3.0.0.1  - 22 May 2009: Initial version

5. Code layout

Code layout is largely based on [1] but there are differences and some items are removed.

Indentation

Use 2 spaces per indentation level.

Tabs or Spaces

Never mix tabs and spaces. Use spaces instead of tabs.

Maximum Line Length

Limit all lines to a maximum of 120 characters.

Long lines can be broken by wrapping expressions in parentheses. Make sure to indent the continued line appropriately.  In case of binary operator, break  *after* the operator, not before it:

    class Rectangle(Blob):

       def __init__(self, width, height,
                    color='black', emphasis=None, highlight=0):
           if (width == 0 and height == 0 and
               color == 'red' and emphasis == 'strong' or
               highlight > 100):
               raise ValueError("sorry, you lose")
           if width == 0 and height == 0 and (color == 'red' or
                                              emphasis is None):
               raise ValueError("I don't think so -- values are %s, %s" %
                                (width, height))
           Blob.__init__(self, width, height,
                         color, emphasis, highlight)

Encodings

Use the UTF-8.

Imports

White-space in Expressions and Statements

Avoid extra white-space in the following situations:

  print x, y; x, y = y, x

   No:                  if x == 4 :

  print x , y ; x , y = y , x

Other recommendations::

    Yes:
              def complex(real, imag = 0.0):
                 return magic(r = real, i = imag)

     No:
             
def complex(real, imag=0.0):
           return magic(r=real, i=imag)

Documentation Strings

Write docstrings for modules, functions, classes, and methods.

The comment should appear after the "def" line.

Naming Conventions

Naming Conventions

Names to Avoid

Never use the characters `l' (lowercase letter el), `O' (uppercase letter oh), or `I' (uppercase letter eye) as single character variable names (they are indistinguishable from the numerals one and zero).

Package and Module Names

Modules should have short, all-lowercase names.  Underscores can be used in the module name if it improves readability.  Python packages should also have short, all-lowercase names, although the use of underscores is discouraged:

    import copy

    from operator import itemgetter

Class Names

Class names use the CapitalizedWords convention. Classes for internal use have a leading underscore in addition:

    class LineOverlayObject(BaseOverlayObject):

    class _PrivateOverlayObject(BaseOverlayObject):

Exception Names

Exceptions are classes, so  the class naming convention applies here.  However, use the suffix "Error" on your exception names (if the exception actually is an error).

    class CustomError(Exception):

Global Variable Names

The conventions are the same as for functions.
Modules that are designed for use via "
from M import *" should use the __all__ mechanism to prevent exporting globals, or use the older convention of prefixing such globals with an underscore (which you might want to do to indicate these globals are "module non-public").

Function Names

Use mixedCase for function definitions:

    def updateLineEnds(self):

Function and method arguments

Always use 'self' for the first argument to instance methods.

Always use 'cls' for the first argument to class methods.

If a function argument's name clashes with a reserved keyword, it is generally better to append a single trailing underscore rather than use an abbreviation or spelling corruption.  Thus "class_" is better than "cls" (Exception for class methods).  (The best is to avoid such clashes by using a synonym.)

Method Names and Instance Variables

Use one leading underscore only for non-public methods and instance variables.

To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules:

    def __innerUpdateLineEnds(self):

Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a.  (An insistent user could still gain access by calling Foo._Foo__a.)  Double leading underscores are used only to avoid name conflicts with attributes in classes designed to be subclassed.

Constants

Constants are defined on a module level and written in all capital letters with underscores:  

MAX_OVERFLOW.

Designing for inheritance


Programming Recommendations

    class MessageError(Exception):

        """Base class for errors in the email package."""

    try:

        import platform_specific_module

    except ImportError:

        platform_specific_module = None

Yes:

    try:

        value = collection[key]

    except KeyError:

        return key_not_found(key)

    else:

        return handle_value(value)

No:

    try:

        # Too broad!

        return handle_value(collection[key])

    except KeyError:

        # Will also catch KeyError raised by handle_value()

        return key_not_found(key)

Yes:         if foo.startswith('bar'):

No:          if foo[:3] == 'bar':

Yes:         if isinstance(obj, int):

No:          if type(obj) is type(1):

Yes:        if not seq:

             if seq:

No:         if len(seq)

            if not len(seq)