+++++++++++++++++++++++++
SQLObject Developer Guide
+++++++++++++++++++++++++

.. contents::
   :backlinks: none

.. _start:

These are some notes on developing SQLObject.  I'll try to expand them
as things come up.

  -- Ian Bicking

Development Installation
========================

First install `FormEncode <http://www.formencode.org/en/latest/download.html>`_::

    $ git clone git://github.com/formencode/formencode.git
    $ cd formencode
    $ sudo python setup.py develop

Then do the same for SQLObject::

    $ git clone git clone git://git.code.sf.net/p/sqlobject/sqlobject
    $ cd sqlobject
    $ sudo python setup.py develop

Voila!  The packages are globally installed, but the files from the
checkout were not copied into ``site-packages``.  See `setuptools
<http://pythonhosted.org/setuptools/>`_ for more.

Style Guide
===========

Generally you should follow the recommendations in `PEP 8`_, the
Python Style Guide.  Some things to take particular note of:

.. _PEP 8: http://www.python.org/peps/pep-0008.html

* **No tabs**.  Not anywhere.  Always indent with 4 spaces.

* I don't stress too much on line length.  But try to break lines up
  by grouping with parenthesis instead of with backslashes (if you
  can).  Do asserts like::

    assert some_condition(a, b), (
        "Some condition failed, %r isn't right!" % a)

* But if you are having problems with line length, maybe you should
  just break the expression up into multiple statements.

* Blank lines between methods, unless they are very small and closely
  bound to each other.

* *Never* use the form ``condition and trueValue or falseValue``.
  Break it out and use a variable.

* Careful of namespace pollution.  SQLObject does allow for ``from
  sqlobject import *`` so names should be fairly distinct, or they
  shouldn't be exported in ``sqlobject.__init__``.

* I'm very picky about whitespace.  There's one and only one right way
  to do it.  Good examples::

    short = 3
    longerVar = 4

    if x == 4:
        do stuff

    func(arg1='a', arg2='b')
    func((a + b)*10)

  **Bad** examples::

    short    =3
    longerVar=4

    if x==4: do stuff

    func(arg1 = 'a', arg2 = 'b')
    func(a,b)
    func( a, b )
    [ 1, 2, 3 ]

  To me, the poor use of whitespace seems lazy.  I'll think less of
  your code (justified or not) for this very trivial reason.  I will
  fix all your code for you if you don't do it yourself, because I
  can't bear to look at sloppy whitespace.

* Use ``@@`` to mark something that is suboptimal, or where you have a
  concern that it's not right.  Try to also date it and put your
  username there.

* Docstrings are good.  They should look like::

    class AClass(object):
        """
        doc string...
        """

  Don't use single quotes (''').  Don't bother trying make the string
  less vertically compact.

* Comments go right before the thing they are commenting on.

* Methods never, ever, ever start with capital letters.  Generally
  only classes are capitalized.  But definitely never methods.

* mixedCase is preferred.

* Use ``cls`` to refer to a class.  Use ``meta`` to refer to a
  metaclass (which also happens to be a class, but calling a metaclass
  ``cls`` will be confusing).

* Use ``isinstance`` instead of comparing types.  E.g.::

    if isinstance(var, str): ...
    # Bad:
    if type(var) is StringType: ...

* Never, ever use two leading underscores.  This is annoyingly
  private.  If name clashes are a concern, use name mangling instead
  (e.g., ``_SO_blahblah``).  This is essentially the same thing as
  double-underscore, only it's transparent where double underscore
  obscures.

* Module names should be unique in the package.  Subpackages shouldn't
  share module names with sibling or parent packages.  Sadly this
  isn't possible for ``__init__``, but it's otherwise easy enough.

* Module names should be all lower case, and probably have no
  underscores (smushedwords).


Testing
=======

Tests are important.  Tests keep everything from falling apart.  All
new additions should have tests.

Testing uses py.test, an alternative to ``unittest``.  It is available at
http://pytest.org/ and http://pypi.python.org/pypi/pytest.  Read its `getting
started`_ document for more.

.. _getting started: http://pytest.org/latest/getting-started.html

To actually run the test, you have to give it a database to connect to.
You do so with the option ``-D``. You can either give a complete URI or
one of several shortcuts like ``mysql`` (these shortcuts are defined in
the top of ``tests/dbtest.py``).

All the tests are modules in ``sqlobject/tests``.  Each module tests
one kind of feature, more or less.  If you are testing a module, call
the test module ``tests/test_modulename.py`` -- only modules that
start with ``test_`` will be picked up by py.test.

The "framework" for testing is in ``tests/dbtest``.  There's a couple of
important functions:

``setupClass(soClass)`` creates the tables for the class.  It tries to
avoid recreating tables if not necessary.

``supports(featureName)`` checks if the database backend supports the
named feature.  What backends support what is defined at the top of
``dbtest``.

If you ``import *`` you'll also get py.test's version of raises_, an
``inserts`` function that can create instances for you, and a couple
miscellaneous functions.

.. _raises: http://pytest.org/latest/assert.html#assertions-about-expected-exceptions

If you submit a patch or implement a feature without a test, I'll be
forced to write the test.  That's no fun for me, to just be writing
tests.  So please, write tests; everything at least needs to be
exercised, even if the tests are absolutely complete.

We now use Travis CI to run tests. See the status:

.. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=2.1
  :target: https://travis-ci.org/sqlobject/sqlobject

Documentation
=============

Please write documentation.  Documentation should live in the docs/
directory.  Pudge converts documentation from Restructured Text to
HTML.  It presently requires kid 0.9.3, which must be obtained
separately (for instance, from http://pypi.python.org/pypi/kid/0.9.3)

.. image:: http://sflogo.sourceforge.net/sflogo.php?group_id=74338&type=10
   :target: http://sourceforge.net/projects/sqlobject
   :class: noborder
   :align: center
   :height: 15
   :width: 80
   :alt: Get SQLObject at SourceForge.net. Fast, secure and Free Open Source software downloads
