SQLObject Developer Guide

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

-- Ian Bicking

Development Installation

First install FormEncode:

$ 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 for more.

Style Guide

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

  • With a few exceptions sources must be flake8-clean (and hence pep8-clean). Please consider using pre-commit hook installed by running flake8 --install-hook.
  • 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
    if x==4: do stuff
    func(arg1 = 'a', arg2 = '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).


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.

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.

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:



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)

Get SQLObject at SourceForge.net. Fast, secure and Free Open Source software downloads