Skip to content
No description or website provided.
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



This package is the successor of zodict.


Data structures could be described as tree. Some are by nature treeish, like XML documents, LDAP directories or filesystem directory trees, while others could be treaten as. Consider SQL as example. A Database has tables, these contain rows which contain columns.

Next, python has elegant ways for customizing all sorts of datamodel related API. The dictionary container type fits almost completely the purpose of representing a node of a tree. The same API is also described in zope.interface.common.mapping.IFullMapping. Additionaly a node must provide hierarchy information. In this case the contract of zope.location.interfaces.ILocation is used.

Having data structures as such trees has some advantages:

  • Unified data access API to different data models and/or sources
  • Trees are traversable in both directions
  • Once in memory, node trees are fast to deal with
  • Software working on node trees may not need to know about internal data structures, as long as the node tree implementation provides the correct interface contracts


node ships with some "ready-to-import-and-use" nodes.

An unordered node. This can be used as base for trees where oder of items doesn't matter:

>>> from node.base import BaseNode
>>> root = BaseNode(name='root')
>>> root['child'] = BaseNode()
>>> root.printtree()
<class 'node.base.BaseNode'>: root
  <class 'node.base.BaseNode'>: child

An ordered node. Order of items is preserved:

>>> from node.base import OrderedNode
>>> root = OrderedNode(name='orderedroot')
>>> root['foo'] = OrderedNode()
>>> root['bar'] = OrderedNode()
>>> root.printtree()
<class 'node.base.OrderedNode'>: orderedroot
  <class 'node.base.OrderedNode'>: foo
  <class 'node.base.OrderedNode'>: bar

>>> root.items()
[('foo', <OrderedNode object 'foo' at ...>),
('bar', <OrderedNode object 'bar' at ...>)]

A full API description of the node interface can be found at node.interfaces.INode.

A more fine granular control of node functionality

node utilizes the plumber package.

Thus, different behaviors of nodes are provided by plumbing parts. Read the documentation of plumber for details about the plumbing system:

>>> from plumber import plumber
>>> from import (
...     Nodespaces,
...     Attributes,
...     Lifecycle,
...     NodeChildValidate,
...     Adopt,
...     DefaultInit,
...     Nodify,
...     OdictStorage,
... )

>>> class CustomNode(object):
...     __metaclass__ = plumber
...     __plumbing__ = (
...         Nodespaces,
...         Attributes,
...         Lifecycle,
...         NodeChildValidate,
...         Adopt,
...         DefaultInit,
...         Nodify,
...         OdictStorage,
...     )

>>> dir(CustomNode)
['__class__', '__contains__', '__delattr__', '__delitem__',
'__dict__', '__doc__', '__format__', '__getattribute__',
'__getitem__', '__hash__', '__implemented__', '__init__',
'__iter__', '__len__', '__metaclass__', '__module__', '__name__',
'__new__', '__nonzero__', '__parent__', '__plumbing__',
'__plumbing_stacks__', '__provides__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__setitem__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'_nodespaces', '_notify_suppress', 'acquire', 'allow_non_node_childs',
'attribute_access_for_attrs', 'attributes', 'attributes_factory',
'attrs', 'clear', 'copy', 'deepcopy', 'detach', 'events', 'filtereditems',
'filtereditervalues', 'filteredvalues', 'get', 'has_key', 'items',
'iteritems', 'iterkeys', 'itervalues', 'keys', 'name', 'noderepr',
'nodespaces', 'parent', 'path', 'pop', 'popitem', 'printtree',
'root', 'setdefault', 'storage', 'update', 'values']

As dir call shows, CustomNode class was plumbed using given parts, now defining a complete INode implementation with some additional behaviours and is now ready to use:

>>> node = CustomNode()
>>> node['child'] = CustomNode()
>>> node.printtree()
<class 'CustomNode'>: None
  <class 'CustomNode'>: child

>>> from node.interfaces import INode
>>> INode.providedBy(node)


node package provides several plumbing parts:
Plumbing part providing default __init__ function on node. See node.interfaces.IDefaultInit.
Plumbing part to Fill in gaps for full INode API. See node.interfaces.INodify.
Plumbing part that provides adoption of children. See node.interfaces.IAdopt.
Plumbing part for child node validation. See node.interfaces.INodeChildValidate.
Plumbing part to ensure unicode for keys and string values. See node.interfaces.IUnicodeAware.
Plumbing part that provides aliasing of child keys. See node.interfaces.IAlias.
Plumbing part to get node as IAttributeAccess implementation. See node.interfaces.IAsAttrAccess.
Plumbing part providing child factories which are invoked at __getitem__ if object by key is not present at plumbing endpoint yet. See node.interfaces.IChildFactory.
Plumbing part that initializes a fixed dictionary as children. See node.interfaces.IFixedChildren.
Plumbing part for child access via __getattr__, given the attribute name is unused. See node.interfaces.IGetattrChildren.
Plumbing part for providing nodespaces on node. See node.interfaces.INodespaces.
Plumbing part to provide attributes on node. Requires part. See node.interfaces.IAttributes.
Plumbing part taking care of lifecycle events. See node.interfaces.ILifecycle.
Plumbing part for handling ifecycle events at attributes manipulation. See node.interfaces.IAttributesLifecycle.
Plumbing part for node invalidation. See node.interfaces.Invalidate.
Plumbing part for caching. See node.interfaces.ICache.
Plumbing part for ordering support. See node.interfaces.IOrder.
Plumbing part providing a uuid on nodes. See node.interfaces.IUUIDAware.
Plumbing part holding an index of all nodes contained in the tree. See node.interfaces.IReference.
Provide dictionary storage. See node.interfaces.IStorage.
Provide ordered dictionary storage. See node.interfaces.IStorage.


A node which behaves like zodict.Node is contained at node.base.Node. This node is supposed to be used for migration from zodict.

It's also useful to take a look of which parts the original node is build of.

Probably an implementation does not need all the parts at once. In this case define the node plumbing directly on node class instead of inheriting from node.base.Node.


Summary of the test coverage report:

lines   cov%   module
   53   100%   node.base
   14   100%
  127   100%   node.interfaces
   23   100%   node.locking
   11   100%
   46   100%
   38   100%
   50   100%
  116   100%
   52   100%
  113   100%
   31   100%
   79   100%
  109   100%
   81   100%
   26   100%
    1   100%   node.testing.__init__
   62   100%   node.testing.base
   19   100%   node.testing.env
  214   100%   node.testing.fullmapping
    1   100%   node.tests.__init__
   31   100%   node.tests.test_node
  125   100%   node.utils




  • Move aliaser objects from node.aliasing to [rnix, 2012-05-18]
  • Remove composition module. [rnix, 2012-05-18]
  • Remove bbb module. [rnix, 2012-05-18]
  • nor supports deepcopy. [rnix, 2012-05-18]
  • use zope.interface.implementer instead of zope.interface.implements all over the place. [rnix, 2012-05-18]


  • Do not inherit from [rnix, 2012-01-30]
  • Set uuid in plumb. [rnix, 2012-01-30]


  • add function. [rnix, 2011-12-05]
  • add plumbing part. [rnix, 2011-12-04]
  • add plumbing part. [rnix, 2011-12-02]
  • fix in order to work with pickled nodes. [rnix, 2011-11-28]
  • use instead of node.__name__ in [rnix, 2011-11-17]
  • add swap to [rnix, 2011-10-05]
  • add insertfirst and insertlast to [rnix, 2011-10-02]


  • add node.utils.debug decorator. [rnix, 2011-07-23]
  • remove non storage contract specific properties from node.aliasing.AliasedNodespace [rnix, 2011-07-18]
  • node.aliasing test completion [rnix, 2011-07-18]
  • Add non strict functionality to node.aliasing.DictAliaser for accessing non aliased keys as is as fallback [rnix, 2011-07-18]
  • Consider INode implementing objects in node.utils.StrCodec [rnix, 2011-07-16]
  • Remove duplicate implements in storage parts [rnix, 2011-05-16]


  • Increase test coverage [rnix, 2011-05-09]
  • Add interfaces IFixedChildren and IGetattrChildren for related parts. [rnix, 2011-05-09]
  • Rename Unicode part to UnicodeAware. [rnix, 2011-05-09]
  • Add node.utils.StrCodec. [rnix, 2011-05-09]
  • Inherit INodify interface from INode. [rnix, 2011-05-08]
  • Locking tests. Add time.sleep after thread start. [rnix, 2011-05-08]
  • Cleanup BaseTester, remove sorted_output flag (always sort), also search class bases for detection in wherefrom. [rnix, 2011-05-08]
  • Remove useless try/except in utils.AttributeAccess. [rnix, 2011-05-08]
  • Add instance_property decorator to utils. [rnix, 2011-05-06]
  • Add FixedChildren and GetattrChildren parts. [chaoflow, 2011-04-22]


  • Add __nonzero__ on Nodifiy part always return True. [rnix, 2011-03-15]


  • Provide node.base.Node with same behavior like zodict.Node for migration purposes. [rnix, 2011-02-08]


  • Make it work [rnix, chaoflow, et al]
Something went wrong with that request. Please try again.