Scorpion Python Plug-ins
Design Guidelines
May 21, 2011
GD-2011-0025-A
Thor Vollset
Tordivel AS
Table of Contents
White-space in Expressions and Statements
Method Names and Instance Variables
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.
[1] http://www.python.org/dev/peps/pep-0008/
[2] Python Plugin Interface Specification
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
Code layout is largely based on [1] but there are differences and some items are removed.
Use 2 spaces per indentation level.
Never mix tabs and spaces. Use spaces instead of tabs.
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)
Use the UTF-8.
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)
Write docstrings for modules, functions, classes, and methods.
The comment should appear after the "def" line.
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 use the CapitalizedWords convention. Classes for internal use have a leading underscore in addition:
class LineOverlayObject(BaseOverlayObject):
class _PrivateOverlayObject(BaseOverlayObject):
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):
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").
Use mixedCase for function definitions:
def updateLineEnds(self):
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.)
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 are defined on a module level and written in all capital letters with underscores:
MAX_OVERFLOW.
Designing for inheritance
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)