PROLOGUE
--------

Coding styles from PEP 8 (http://www.python.org/dev/peps/pep-0008/) should be applied, unless explicitly overriden by rules below.

NAMES
-----

* use underscored_names (python style) for attributes and methods
* use CaptializedNames (java style) for class names
* NB: some "factory" functions are sometimes implemented as classes; those may 
be named in python_style
* `Mixin classes`_ names should always end with "Mixin"

* module names are lowercase, short-names (preferably meaningful).
* packages must be named in python style

* words composing an identifier should always be separated (in the appropriate
style)
* words must not be abbreviated (unless the abbreviation is unambiguous in the
context of the application)

* method names should start with a verb
* boolean property names should be an adjective
* other property names should be a noun
* iterable property names should be plural

SEMANTIC
--------

* read-only properties should be prefered to methods with only self as
parameter, if appropriate
* for method with optional parameters and only self as a required parameter,
a read-only property should also exist if appropriate (see Exceptions_ below)
* it is not appropriate for a method to be replaced by a read-only property
if the method has side-effects (changing the state of self or another object) 
or involves much computing.

Assertions
++++++++++

assert statements must not be relied on to raise en exception in case of an
error, since they are disabled in optimized mode. They are *formal comments*,
stating explicitly the pre-conditions of a method.

Exceptions
++++++++++

When a method can not return the expected result, the default behaviour should
be to raise an exception. However, the raising of an exception should be
avoidable, for optization concerns. A good practice is to accept an optional
parameter which would be the default value to be returned. E.g.:::

  # the following raises an exception if foo is absent
  f = my_package.get_element("foo")
  # the following returns None if foo is absent
  f = my_package.get_element("foo", None)
  # alternative with a keyword optional parameter
  f = my_package.get_element("foo", default=None)

If the optional parameter is a keyword parameter, it should be named "default".

There is an exception (!) to that rule, however: whenever a more pythonic
syntax exists (property, __getitem__) which is equivalent to the method, then
that syntax should raise an exception, while the explicit method call should
return a default value (with None as the default default value). This is
consistent with python dictionaries and the ``[i] vs. get(i)`` alternative.
E.g.:::

  # the following raises an exception if the member is unreachable
  m = my_annotation.media
  # the following returns None if the member is unreachable
  m = my_annotation.get_media()
  # the following returns "error" if the member is unreachable
  m = my_annotation.get_media("error")

Mixin classes
+++++++++++++

Multiple inheritance should only be used with one proper base class and
so-called mixin classes. Classes should precisely document the methods and
attribute they expect from the classes using them. It should also define the
collaborative methods, which should use the super keyword in all their
implementations, although relying on such methods should be avoided when
possible.

Mixin classes should not require initialization (which is what makes them
similar to Traits, and different from classical base classes). If they need
private attributes, one of the following solutions can be used:
 * the methods can check if the attribute is defined, and define it if not
 * an alternative to checking existence is to define a default value at the
   class level
 * the methods can use a class attribute dict, using id(self) as keys

Whichever solution is chosen, mixin attributes must use name mangling ("__"
prefix) to reduce the risk of name clash.


REFERENCES
----------

In order to avoid memory leaks, reference cycles and __del__ methods should be
avoided. The former prevent automatic freeing of memory when objects are
unreachable (the garbage collector has to detect the cycle), while the latter
completely prevent the garbage collector to opperate on reference cycles.
Stricty speaking, cycles without __del__ or __del__ without cycles are ok, but
as a rule of thumb, it is better to avoid both.

To avoid reference cycles, the use of weak references is recommended. For
example, Packages do not keep strong references on their elements (because
there may be too many of them in database-backed packages); it generates them
on demand and keeps a WeakValueDictionary cache of the generated elements to
avoid generating twice the same element.

To avoid __del__ methods, the callback on weak references can be used to react
to the deletion of an object, without interfering with the garbage collector.
The advene.utils.reftools module provides a WeakValueDictWithCallback class,
which allows to define a global callback on all values of the dictionary. For
example, the sqlite backend uses it to detect that a package has been collected
without closing.

Reference Cache
+++++++++++++++

It may be tempting to implement reference caches to prevent objects to be
repeatedly collected and regenerated. Beware however, that the overhead of
python functions involved in cache management may exceed the benefits... If
implemented, this should be thoroughly tested.
