Commits

Gustavo Picon committed 73987d0

Updating docstrings

Comments (0)

Files changed (10)

 treebeard/models.py
 treebeard/al_tree.py
 treebeard/mp_tree.py
+treebeard/ns_tree.py
 treebeard/numconv.py
 treebeard/tests.py
+docs/README
 docs/conf.py
 docs/index.rst
 docs/Makefile
 
-:mod:`treebeard` --- Efficient Materialized Path tree implementation for Django
-===============================================================================
+:mod:`treebeard` --- Efficient tree model implementations for Django
+====================================================================
 
 .. automodule:: treebeard
 
       :show-inheritance:
 
       .. automethod:: add_root
-
       .. automethod:: add_child
       .. automethod:: add_sibling
       .. automethod:: delete
       .. automethod:: get_descendants
       .. automethod:: get_descendant_count
       .. automethod:: get_first_child
+      .. automethod:: get_last_child
       .. automethod:: get_first_sibling
+      .. automethod:: get_last_sibling
+      .. automethod:: get_prev_sibling
       .. automethod:: get_next_sibling
       .. automethod:: get_parent
-      .. automethod:: get_prev_sibling
       .. automethod:: get_root
       .. automethod:: get_siblings
       .. automethod:: is_child_of
       .. automethod:: is_leaf
       .. automethod:: move
       .. automethod:: save
-
       .. automethod:: get_first_root_node
       .. automethod:: get_last_root_node
       .. automethod:: get_root_nodes
    .. autoexception:: MissingNodeOrderBy
 
 
-:mod:`treebeard.mp_tree` --- Efficient Materialized Path tree implementation for Django
-=======================================================================================
+:mod:`treebeard.mp_tree` --- Materialized Path tree
+===================================================
 
 .. automodule:: treebeard.mp_tree
 
       .. automethod:: fix_tree
 
 
-:mod:`treebeard.al_tree` --- Adjacency List tree implementation for Django
-==========================================================================
+:mod:`treebeard.al_tree` --- Adjacency List tree
+================================================
 
 .. automodule:: treebeard.al_tree
 
    .. autoclass:: AL_Node
+      :show-inheritance:
 
       .. automethod:: get_depth
 
 
-:mod:`tbbench` --- tree
-=======================
+
+:mod:`treebeard.ns_tree` --- Nested Sets tree
+=============================================
+
+.. automodule:: treebeard.ns_tree
+
+   .. autoclass:: NS_Node
+      :show-inheritance:
+
+      .. automethod:: get_tree
+
+
+:mod:`tbbench` --- Benchmarks
+=============================
 
 .. automodule:: tbbench
 
+
 Indices and tables
 ==================
 

tbbench/__init__.py

 
    .. note::
        If the `django-mptt`_ package is also installed, both libraries will
-       be tested with the exact same data an operations.
+       be tested with the exact same data and operations.
 
    Currently, the available tests are:
 
     |             |              +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
     |             |              |  no tx  |    tx   |  no tx  |    tx   |  no tx  |    tx   |  no tx  |    tx   |  no tx  |    tx   |
     +=============+==============+=========+=========+=========+=========+=========+=========+=========+=========+=========+=========+
-    | Inserts     | TB MP        |    3194 |    2661 |    3210 |    2676 |    2958 |    2585 |    2515 |    2343 |    2257 |    1937 |
+    | Inserts     | TB MP        |    3220 |    2660 |    3181 |    2766 |    2859 |    2542 |    2540 |    2309 |    2205 |    1934 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL        |    1976 |    1931 |    1941 |    1935 |    1940 |    1772 |    1749 |    1640 |    1554 |    1485 |
+    |             | TB AL        |    1963 |    1905 |    1998 |    1936 |    1937 |    1775 |    1736 |    1631 |    1583 |    1457 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT         |    7030 |    9189 |    7015 |    9206 |    5213 |   16115 |    4657 |    9259 |    3532 |    3119 |
+    |             | TB NS        |    3386 |    3438 |    3359 |    3420 |    4061 |    7242 |    3536 |    4401 |    2794 |    2554 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB MP Sorted |    4549 |    5532 |    4087 |    5731 |    3943 |    5638 |    3549 |    3845 |    3175 |    2895 |
+    |             | MPTT         |    7559 |    9280 |    7525 |    9028 |    5202 |   14969 |    4764 |    6022 |    3781 |    3484 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL Sorted |    1308 |    1031 |    1077 |    1012 |    1182 |     988 |    1035 |     881 |     848 |     704 |
+    |             | TB MP Sorted |    4732 |    5627 |    5038 |    5215 |    4022 |    4808 |    3415 |    3942 |    3250 |    3045 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT Sorted  |    8055 |    9551 |    8113 |   10615 |    6117 |    8962 |    5563 |    6307 |    4636 |    4195 |
+    |             | TB AL Sorted |    1096 |    1052 |    1092 |    1033 |    1239 |     999 |    1049 |     896 |     860 |     705 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | TB NS Sorted |    6637 |    6373 |    6283 |    6313 |    7548 |   10053 |    6717 |   10941 |    5907 |    5461 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | MPTT Sorted  |    8564 |   10729 |    7947 |   10221 |    6077 |    7567 |    5490 |    6894 |    4842 |    4284 |
     +-------------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    | Descendants | TB MP        |    6245 |     N/A |    6377 |     N/A |    7822 |     N/A |    7168 |     N/A |   10652 |     N/A |
+    | Descendants | TB MP        |    6298 |     N/A |    6460 |     N/A |    7643 |     N/A |    7132 |     N/A |   10415 |     N/A |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL        |   57767 |     N/A |   56616 |     N/A |   55590 |     N/A |   51321 |     N/A |   51235 |     N/A |
+    |             | TB AL        |   56850 |     N/A |  116550 |     N/A |   54249 |     N/A |   50682 |     N/A |   50521 |     N/A |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT         |    5332 |     N/A |    5344 |     N/A |    9603 |     N/A |    5439 |     N/A |    5382 |     N/A |
+    |             | TB NS        |    5595 |     N/A |    5824 |     N/A |   10080 |     N/A |    5840 |     N/A |    5965 |     N/A |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB MP Sorted |    6806 |     N/A |    6818 |     N/A |    8100 |     N/A |    7720 |     N/A |   10725 |     N/A |
+    |             | MPTT         |    5268 |     N/A |    5306 |     N/A |    9394 |     N/A |    8745 |     N/A |    5197 |     N/A |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL Sorted |   58547 |     N/A |   58055 |     N/A |   55914 |     N/A |   52505 |     N/A |   51991 |     N/A |
+    |             | TB MP Sorted |    6698 |     N/A |    6408 |     N/A |    8248 |     N/A |    7265 |     N/A |   10513 |     N/A |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT Sorted  |    5163 |     N/A |    5443 |     N/A |    9661 |     N/A |    8930 |     N/A |    5192 |     N/A |
+    |             | TB AL Sorted |   59817 |     N/A |   59718 |     N/A |   56767 |     N/A |   52574 |     N/A |   53458 |     N/A |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | TB NS Sorted |    5631 |     N/A |    5858 |     N/A |    9980 |     N/A |    9210 |     N/A |    6026 |     N/A |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | MPTT Sorted  |    5186 |     N/A |    5453 |     N/A |    9723 |     N/A |    8912 |     N/A |    5333 |     N/A |
     +-------------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    | Move        | TB MP        |     874 |    1008 |     781 |    1131 |     756 |    1049 |     617 |     754 |     490 |     465 |
+    | Move        | TB MP        |     837 |    1156 |     992 |    1211 |     745 |    1040 |     603 |     740 |     497 |     468 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL        |    8870 |    8767 |    8833 |    8858 |    7263 |    7209 |    6842 |    6821 |    7187 |    7008 |
+    |             | TB AL        |    8708 |    8684 |    9798 |    8890 |    7243 |    7213 |    6721 |    6757 |    7051 |    6863 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT         |    6222 |    7419 |    6505 |    7666 |    5270 |   22285 |    3383 |    7052 |     894 |     879 |
+    |             | TB NS        |     683 |     658 |     660 |     679 |    1266 |    2000 |     650 |     907 |     672 |     637 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB MP Sorted |    7308 |    7026 |    6879 |    7312 |    6241 |   23016 |    3623 |   12396 |    2514 |    2451 |
+    |             | MPTT         |    6449 |    7793 |    6356 |    7003 |    4993 |   20743 |    4445 |    8977 |     921 |     896 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL Sorted |    4046 |    3707 |    3959 |    3636 |    3570 |    3560 |    3409 |    3349 |    3671 |    3355 |
+    |             | TB MP Sorted |    6730 |    7036 |    6743 |    7023 |    6410 |   19294 |    3622 |   12380 |    2622 |    2487 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT Sorted  |    6943 |   11181 |    6646 |   10331 |    5060 |   18968 |    4650 |    8174 |     927 |     922 |
+    |             | TB AL Sorted |    3866 |    3731 |    3873 |    3717 |    3587 |    3599 |    3394 |    3371 |    3491 |    3416 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | TB NS Sorted |    2017 |    2017 |    1958 |    2078 |    4397 |    7981 |    3892 |    8110 |    1543 |    1496 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | MPTT Sorted  |    6563 |   10540 |    6427 |    9358 |    5132 |   20426 |    4601 |    9428 |     957 |     955 |
     +-------------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    | Delete      | TB MP        |     738 |     644 |     713 |     655 |     706 |     696 |     604 |     566 |     623 |     561 |
+    | Delete      | TB MP        |     714 |     651 |     733 |     686 |     699 |     689 |     595 |     561 |     636 |     557 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL        |     978 |    1085 |     987 |    1099 |     754 |     848 |     728 |     834 |     846 |     944 |
+    |             | TB AL        |     975 |    1093 |    2199 |     991 |     758 |     847 |     714 |     804 |     843 |     921 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT         |    2839 |    4973 |    2902 |    3453 |   82047 |  148736 |   15706 |   21539 |    1648 |    1659 |
+    |             | TB NS        |     745 |     745 |     742 |     763 |     555 |     698 |     430 |     506 |     530 |     513 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB MP Sorted |     813 |     757 |     875 |     737 |     932 |    1052 |     629 |     753 |     579 |     544 |
+    |             | MPTT         |    2928 |    4473 |    2914 |    4814 |   69385 |  167777 |   18186 |   26270 |    1617 |    1635 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | TB AL Sorted |    1022 |    1007 |    1001 |     998 |     787 |     768 |     748 |     719 |     867 |     852 |
+    |             | TB MP Sorted |     811 |     751 |     808 |     737 |     798 |    1180 |     648 |    1101 |     612 |     565 |
     |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-    |             | MPTT Sorted  |    4687 |    6370 |    4355 |    4112 |   58553 |  139216 |   15206 |  106658 |    1986 |    1743 |
+    |             | TB AL Sorted |    1030 |    1030 |    1055 |     987 |     797 |    1023 |     760 |     969 |     884 |     859 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | TB NS Sorted |     756 |     750 |     728 |     758 |     807 |     847 |     576 |     748 |     501 |     490 |
+    |             +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+    |             | MPTT Sorted  |    3729 |    5108 |    3833 |    4776 |   86545 |  148596 |   34059 |  127125 |    2024 |    1787 |
     +-------------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 
 
-
    .. _`django-mptt`: http://code.google.com/p/django-mptt/
 
 """
     time_start = time.time()
     total = 0
     # retrieve all the descendants of all nodes, *lots* of times
-    for i in range(10):
+    for _ in range(10):
         for obj in nodemodel.objects.all():
             total += len(obj.get_descendants())
     return time.time() - time_start
         poschild = 'last-child'
 
     # move to root nodes (several times)
-    for i in range(numnodes/10):
+    for _ in range(numnodes/10):
         move(nodemodel,
              root_nodes_func()[0],
              root_nodes_func().reverse()[0],
          ('Descendants', get_descendants),
          ('Move', moves_test),
          ('Delete', delete_test)]
-TREE_MODELS = [
-               ('TB MP', TbNode),
+TREE_MODELS = [('TB MP', TbNode),
                ('TB AL', AlNode),
                ('TB NS', NsNode),
                ('MPTT', MpttNode),
                ('MPTT Sorted', MpttSortedNode),
                ]
 
-MAXNODES = (100, 1000)
-MAXNODES = (1000,)
+
+NUMNODES = 1000
+
 
 def main():
 
     sys.stderr.write('\nBenchmarking... please wait.\n')
     results = {}
+
     for model_desc, model in TREE_MODELS:
-        for numnodes in MAXNODES:
-            for want_tx in (False, True):
-                for test_desc, test_func in TESTS:
-                    key = (test_desc, numnodes, model_desc)
-                    if not model or \
-                          (test_desc == 'Descendants' and want_tx):
-                        res = 'N/A'
+        if not model:
+            continue
+        for want_tx in (False, True):
+            mod_res = []
+            for test_desc, test_func in TESTS:
+                key = (test_desc, model_desc)
+                if test_desc == 'Descendants' and want_tx:
+                    res = 'N/A'
+                    mod_res.append(-1)
+                else:
+                    if want_tx:
+                        func = transaction.commit_on_success(test_func)
+                        test_desc = '%s+TX' % (test_desc,)
                     else:
-                        if want_tx:
-                            func = transaction.commit_on_success(test_func)
-                        else:
-                            func = test_func
-                        res = func(model, numnodes)
-                    #if model_desc == 'MPTT Sorted' and test_desc == 'Move':
-                    #    res = 'N/A'
-                    sys.stderr.write('.')
-                    sys.stderr.flush()
-                    if key in results:
-                        results[key].append(res)
-                    else:
-                        results[key] = [res]
+                        func = test_func
+                    res = int(func(model, NUMNODES)*1000)
+                    mod_res.append(res)
+
+                sys.stderr.write('.')
+                sys.stderr.flush()
+                results.setdefault(key, []).append(res)
+
     maxlen_test = max([len(test[0]) for test in TESTS])
     maxlen_model = max([len(model[0]) for model in TREE_MODELS])
-    maxlen_num = len(str(max(MAXNODES)))
     maxlen_dur = 7
-    decimals_dur = 3
     output = []
-    prev_test, prev_num = None, None
+    prev_test = None
     for test_desc, test_func in TESTS:
-        for numnodes in MAXNODES:
-            for model_desc, model in TREE_MODELS:
-                ln1, ln2 = [], []
-                if prev_test != test_desc:
-                    ln1.append('+-%s-' % ('-' * maxlen_test,))
-                    ln2.append('| %s ' % (test_desc.ljust(maxlen_test),))
+        for model_desc, model in TREE_MODELS:
+            if not model:
+                continue
+            ln1, ln2 = [], []
+            if prev_test != test_desc:
+                ln1.append('+-%s-' % ('-' * maxlen_test,))
+                ln2.append('| %s ' % (test_desc.ljust(maxlen_test),))
+            else:
+                tmpstr = '| %s ' % (' ' * maxlen_test,)
+                ln1.append(tmpstr)
+                ln2.append(tmpstr)
+            ln1.append('+-%s-' % ('-' * maxlen_model,))
+            ln2.append('| %s ' % (model_desc.ljust(maxlen_model),))
+            res = results[(test_desc, model_desc)]
+            for dur in res:
+                ln1.append('+-%s-' % ('-' * maxlen_dur,))
+                if dur in ('N/A',):
+                    ln2.append('| %s ' % (dur.rjust(maxlen_dur),))
+                elif dur:
+                    ln2.append('| %s ' % ('%%%dd' % (maxlen_dur,) % (dur,)))
                 else:
-                    tmpstr = '| %s ' % (' ' * maxlen_test,)
-                    ln1.append(tmpstr)
-                    ln2.append(tmpstr)
-                if len(MAXNODES) > 1:
-                    if prev_num != numnodes:
-                        ln1.append('+-%s-' % ('-' * maxlen_num,))
-                        ln2.append('| %s ' % (str(numnodes).rjust(maxlen_num),))
-                    else:
-                        tmpstr = '| %s ' % (' ' * maxlen_num,)
-                        ln1.append(tmpstr)
-                        ln2.append(tmpstr)
-                ln1.append('+-%s-' % ('-' * maxlen_model,))
-                ln2.append('| %s ' % (model_desc.ljust(maxlen_model),))
-                for dur in results[(test_desc, numnodes, model_desc)]:
-                    ln1.append('+-%s-' % ('-' * maxlen_dur,))
-                    if dur in ('N/A',):
-                        ln2.append('| %s ' % (dur.rjust(maxlen_dur),))
-                    elif dur:
-                        ln2.append('| %s ' % ('%%%dd' % (maxlen_dur,) % (dur*1000,)))
-                    else:
-                        ln2.append('| %s ' % ('-'.ljust(maxlen_dur),))
-                ln1.append('+')
-                ln2.append('|')
-                output.extend([''.join(ln1), ''.join(ln2)])
-                prev_test, prev_num = test_desc, numnodes
+                    ln2.append('| %s ' % ('-'.ljust(maxlen_dur),))
+            ln1.append('+')
+            ln2.append('|')
+            output.extend([''.join(ln1), ''.join(ln2)])
+            prev_test = test_desc
 
     ln = ['+-%s-' % ('-' * maxlen_test,)]
-    if len(MAXNODES) > 1:
-        ln.append('+-%s-' % ('-' * maxlen_num,))
     ln.extend(['+-%s-' % ('-' * maxlen_model,), 
                '+-%s-' % ('-' * maxlen_dur,),
                '+-%s-+' % ('-' * maxlen_dur,)])

treebeard/__init__.py

        3. Add ``'treebeard'`` to the ``INSTALLED_APPS`` section in your django
           settings file.
        4. Create a new model that inherits from one of ``django-treebeard``'s
-          abstract tree models: :class:`mp_tree.MP_Node`
+          abstract tree models: :class:`mp_tree.MP_Node` (materialized path),
+          :class:`ns_tree.NS_Node` (nested sets) or :class:`al_tree.AL_Node`
+          (adjacency list).
        5. Run :command:`python manage.py syncdb`
 
 

treebeard/al_tree.py

         Adds a root node to the tree.
 
         See: :meth:`treebeard.Node.add_root`
-
-        :raise PathOverflow: when no more root objects can be added
         """
         newobj = cls(**kwargs)
         newobj._cached_depth = 1

treebeard/models.py

 class Node(models.Model):
     """ Node class.
 
-    Right now there is only one class that inherits from Node: MP_Node for
-    Materialized Path trees.
+    This is the base class that defines the API of all tree models in this
+    library:
+
+        - :class:`mp_tree.MP_Node` (materialized path)
+        - :class:`ns_tree.NS_Node` (nested sets)
+        - :class:`al_tree.AL_Node` (adjacency list)
+
     """
 
 

treebeard/mp_tree.py

     to the node will be stored. This has the advantage of needing very simple
     and fast queries, at the risk of inconsistency because of the
     denormalization of ``parent``/``child`` foreign keys. This can be prevented
-    with transactions (and of course you are already using them, right?).
+    with transactions.
 
     ``django-treebeard`` uses a particular approach: every step in the path has
     a fixed width and has no separators. This makes queries predictable and

treebeard/ns_tree.py

 
     treebeard.ns_tree
     -----------------
+
+    Nested Sets Tree.
+
+    :copyright: 2008 by Gustavo Picon
+    :license: Apache License 2.0
+
+    An implementation of Nested Sets trees for Django 1.0+, as described by
+    `Joe Celko`_ in `Trees and Hierarchies in SQL for Smarties`_.
+
+    Nested sets have very efficient reads at the cost of high maintenance on
+    write/delete operations.
+
+
+    .. _`Joe Celko`: http://www.celko.com/
+    .. _`Trees and Hierarchies in SQL for Smarties`:
+      http://www.elsevier.com/wps/find/bookdescription.cws_home/702605/description
 """
 
 import operator
 
 
 class NS_Node(Node):
+    """
+    Abstract model to create your own Nested Sets Trees.
+
+    .. attribute:: node_order_by
+
+       Attribute: a list of model fields that will be used for node
+       ordering. When enabled, all tree operations will assume this ordering.
+
+       Example::
+
+          node_order_by = ['field1', 'field2', 'field3']
+
+    .. attribute:: depth
+
+       ``PositiveIntegerField``, depth of a node in the tree. A root node
+       has a depth of *1*.
+
+    .. attribute:: lft
+
+       ``PositiveIntegerField``
+
+    .. attribute:: rgt
+
+       ``PositiveIntegerField``
+
+    .. attribute:: tree_id
+
+       ``PositiveIntegerField``
+    """
     node_order_by = []
 
     lft = models.PositiveIntegerField(db_index=True)
 
         See: :meth:`treebeard.Node.add_child`
         """
-        
-
         if not self.is_leaf():
             # there are child nodes, delegate insertion to add_sibling
             if self.node_order_by:
             else:
                 pos = 'last-sibling'
             last_child = self.get_last_child()
+            tmp = self.__class__.objects.get(pk=self.id)
             last_child._cached_parent_obj = self
             return last_child.add_sibling(pos, **kwargs)
 
     @classmethod
     def load_bulk(cls, bulk_data, parent=None, keep_ids=False):
         """
+        Loads a list/dictionary structure to the tree.
+
+        See: :meth:`treebeard.Node.move`
         """
 
         # tree, iterative preorder
         return self.__class__.get_tree(self).exclude(pk=self.id)
 
 
+    def get_descendant_count(self):
+        """
+        :returns: the number of descendants of a node.
+
+        See: :meth:`treebeard.Node.get_descendant_count`
+        """
+        return (self.rgt - self.lft - 1) / 2
+
+
     def get_ancestors(self):
         """
         :returns: A queryset containing the current node object's ancestors,

treebeard/tests.py

         def _multi_test(self):
             try:
 
-                if True:
+                try:
+                    self.set_MP() ; f(self)
+                finally:
+                    transaction.rollback()
 
-                    try:
-                        self.set_MP() ; f(self)
-                    finally:
-                        transaction.rollback()
-
-                    try:
-                        self.set_AL() ; f(self)
-                    finally:
-                        transaction.rollback()
+                try:
+                    self.set_AL() ; f(self)
+                finally:
+                    transaction.rollback()
 
                 try:
                     self.set_NS() ; f(self)