Skip to main content

Collection of named entities

Project description

Dolmen collection offers a collection implementation which permits to manipulate named elements: arrange order, extract part of the collection, enforce a type of component and add new ones easily.

It originated from zeam.form where it was used to implement forms as collections of fields, actions and widgets.

API description

Components

First let’s see the component, that is elements taking parts in collections:

>>> from dolmen.collection.components import Component
>>> c1 = Component(u'The Sun', 'sun')
>>> c1
<Component The Sun>
>>> c1.identifier
'sun'
>>> c1.title
u'The Sun'

It correctly implement IComponent:

>>> from zope.interface.verify import verifyObject
>>> from dolmen.collection import interfaces
>>> verifyObject(interfaces.IComponent, c1)
True

Actually you can create a component without an id, and even using a unicode title:

>>> c2 = Component(u'Moon')
>>> c2
<Component Moon>
>>> c2.identifier
'moon'
>>> c2.title
u'Moon'

Or a number (it won’t be converted to string. Like this, this support Zope translation messages):

>>> c69 = Component(69)
>>> c69.title
69

If by doing so, the title contain spaces, they will be replaced by -. If UTF-8 character are included, the identifiant will be encoded:

>>> c3 = Component(u'Some lost planet')
>>> c3.identifier
'some-lost-planet'
>>> c4 = Component(u'État du désir')
>>> c4.identifier
'c383c2897461742d64752d64c383c2a9736972'

Spaces are normalized:

>>> c5 = Component(' Some unappropriate spacing  ')
>>> c5.identifier
'some-unappropriate-spacing'

You can clone a component and change its identifier:

>>> c3clone = c3.clone('new-world')
>>> c3clone
<Component Some lost planet>
>>> c3clone.identifier
'new-world'
>>> c3clone is c3
False

But you can keep the old one as well:

>>> c4clone = c4.clone()
>>> c4clone.identifier
'c383c2897461742d64752d64c383c2a9736972'
>>> c4clone is c4
False

Collection

Collection are simple objects, implementing ICollection:

>>> from dolmen.collection.components import Collection
>>> s1 = Collection()
>>> s1
<Collection>
>>> len(s1)
0
>>> verifyObject(interfaces.ICollection, s1)
True

Adding components to a collection

Now we can put components in a collection, and list it back in the same order:

>>> s1.append(c1)
>>> list(s1)
[<Component The Sun>]
>>> s1.append(c2)
>>> list(s1)
[<Component The Sun>, <Component Moon>]

But you can’t add twice the same component:

>>> s1.append(c1)
Traceback (most recent call last):
  ...
ValueError: (u'Duplicate identifier', 'sun')

And this need to be a component:

>>> s1.append('home')
Traceback (most recent call last):
  ...
TypeError: (u'Invalid type', 'home')

You create a collection with components or collection as argument:

>>> s2 = Collection(Component('Jupiter'), Component('Saturn'))
>>> list(s2)
[<Component Jupiter>, <Component Saturn>]
>>> len(s2)
2
>>> list(Collection(s2, Component('Uranus')))
[<Component Jupiter>, <Component Saturn>, <Component Uranus>]
>>> Collection(42)
Traceback (most recent call last):
  ...
TypeError: (u'Invalid type', 42)

You can add collections. You will receive a copy with all components. Components will ordered as the addition is:

>>> s3 = s1 + s2
>>> s3
<Collection>
>>> s3 is s1
False
>>> list(s3)
[<Component The Sun>, <Component Moon>,
 <Component Jupiter>, <Component Saturn>]
>>> len(s3)
4
>>> list(s2 + s1)
[<Component Jupiter>, <Component Saturn>,
 <Component The Sun>, <Component Moon>]

You can extend a collection. It work pretty much like the construtor:

>>> s3.extend(Component('Venus'), Component('Uranus'))
>>> list(s3)
[<Component The Sun>, <Component Moon>,
 <Component Jupiter>, <Component Saturn>,
 <Component Venus>, <Component Uranus>]
>>> s3.extend('Kitty')
Traceback (most recent call last):
  ...
TypeError: (u'Invalid type', 'Kitty')

You can copy a collection:

>>> s3copy = s3.copy()
>>> list(s3copy) == list(s3)
True
>>> s3copy is s3
False

You can remove all elements from a collection:

>>> len(s1)
2
>>> s1.clear()
>>> len(s1)
0
Ignoring already defined components
>>> from dolmen.collection.components import IGNORE
>>> ignoring = Collection()
>>> ignoring.behavior = IGNORE
>>> ignoring.append(c1)
>>> list(ignoring)
[<Component The Sun>]
>>> ignoring.append(c2)
>>> list(ignoring)
[<Component The Sun>, <Component Moon>]
>>> c1prime = Component(u'The Sun prime', 'sun')

You can add twice the same component, the second is ignored:

>>> ignoring.append(c1prime)
>>> list(ignoring)
[<Component The Sun>, <Component Moon>]
Overriding already defined components
>>> from dolmen.collection.components import OVERRIDE
>>> overriding = Collection()
>>> overriding.behavior = OVERRIDE
>>> overriding.append(c1)
>>> list(overriding)
[<Component The Sun>]
>>> overriding.append(c2)
>>> list(overriding)
[<Component The Sun>, <Component Moon>]
>>> c1prime = Component(u'The Sun prime', 'sun')

You can add twice the same component, the second overrides the first:

>>> overriding.append(c1prime)
Traceback (most recent call last):
...
NotImplementedError

It needs to be a IMutableCollection:

>>> from dolmen.collection import IMutableCollection
>>> from zope.interface import directlyProvides
>>> directlyProvides(overriding, IMutableCollection)

>>> overriding.append(c1prime)
>>> list(overriding)
[<Component The Sun prime>, <Component Moon>]

Retriving components from a collection

You can retrieve one element of the collection:

>>> s3.get('moon')
<Component Moon>
>>> s3.get('uranus')
<Component Uranus>
>>> s3.get('me')
Traceback (most recent call last):
  ...
KeyError: 'me'
>>> s3.get('me', default=42)
42

And dictionnary like access works:

>>> s3['uranus']
<Component Uranus>
>>> s3['venus']
<Component Venus>
>>> s3['somewhere']
Traceback (most recent call last):
  ...
KeyError: 'somewhere'

You can get all components ids:

>>> s3.keys()
['sun', 'moon', 'jupiter', 'saturn', 'venus', 'uranus']

You can test if a component id is in the collection:

>>> 'moon' in s3
True
>>> 'earth' in s3
False

You can get a new collection with some of the components of the first one:

>>> s4 = s3.select('venus', 'uranus')
>>> s4 is s3
False
>>> list(s4)
[<Component Venus>, <Component Uranus>]
>>> s4.keys()
['venus', 'uranus']

Or the other way around some components of a collection:

>>> s5 = s3.omit('sun', 'moon')
>>> s5 is s3
False
>>> list(s5)
[<Component Jupiter>, <Component Saturn>,
 <Component Venus>, <Component Uranus>]

Sorting components in a collection

The Collection sort call works as the standard python list’s one:

>>> s5.sort()
>>> print list(s5)
[<Component Jupiter>, <Component Saturn>, <Component Uranus>,
 <Component Venus>]

We can use the standard arguments (cmp, key and reverse):

>>> s5.sort(reverse=True)
>>> print list(s5)
[<Component Venus>, <Component Uranus>, <Component Saturn>,
 <Component Jupiter>]

>>> s5.sort(reverse=True, key=lambda el: el.identifier[-1:])
>>> print list(s5)
[<Component Venus>, <Component Uranus>, <Component Jupiter>,
 <Component Saturn>]

>>> def myLengthSort(a1, a2):
...   return cmp(len(a1), len(a2))

>>> s5.sort(reverse=True, key=lambda el: el.identifier, cmp=myLengthSort)
>>> print list(s5)
[<Component Jupiter>, <Component Uranus>, <Component Saturn>,
 <Component Venus>]

The collection can be reversed too, as standard lists:

>>> s5.reverse()
>>> print list(s5)
[<Component Venus>, <Component Saturn>, <Component Uranus>,
 <Component Jupiter>]

It is possible to order the components of a Collection using a given list of ids and the sort_components cmp function:

>>> from dolmen.collection import sort_components

>>> s5.sort(sort_components(['uranus', 'venus', 'jupiter']))
>>> print list(s5)
[<Component Uranus>, <Component Venus>, <Component Jupiter>,
 <Component Saturn>]

The keys are sorted in the process:

>>> print s5.keys()
['uranus', 'venus', 'jupiter', 'saturn']

Successive sortings will leave unspecified fields at their relative places:

>>> s5.sort(sort_components(['saturn', 'uranus']))
>>> print list(s5)
[<Component Saturn>, <Component Uranus>, <Component Venus>,
 <Component Jupiter>]

We can also revert the sorting, as the standard python behavior:

>>> s5.sort(sort_components(['uranus', 'venus']), reverse=True)
>>> print list(s5)
[<Component Saturn>, <Component Jupiter>, <Component Venus>,
 <Component Uranus>]

Errors are raised if the provided list is malformed or smaller than 2 elements:

>>> s5.sort(sort_components(['uranus']))
Traceback (most recent call last):
...
ValueError: Please provide a list of, at least, two component identifiers.

>>> s5.sort(sort_components('something'))
Traceback (most recent call last):
...
ValueError: Please provide a valid list or tuple of component identifiers.

The behavior, if unknow ids are provided, is unchanged:

>>> s5.sort(sort_components(['venus', 'uranus', 'cardassia', 'bajor']))
>>> print list(s5)
[<Component Venus>, <Component Uranus>, <Component Saturn>,
 <Component Jupiter>]

Parameters on collections

You can provides extra parameters on collections that will be set as attributes on the object:

>>> s6 = Collection(s2, name=u'me', city=u'rotterdam')
>>> s6
<Collection>
>>> list(s6)
[<Component Jupiter>, <Component Saturn>]
>>> s6.name
u'me'
>>> s6.city
u'rotterdam'

Those attributes are kept if you use the operations select, omit or copy:

>>> s6copy = s6.copy()
>>> s6copy.name
u'me'
>>> s6copy.city
u'rotterdam'

>>> s6omit = s6.omit('jupiter')
>>> s6omit.name
u'me'
>>> s6omit.city
u'rotterdam'

>>> s6select = s6.select('jupiter')
>>> s6select.name
u'me'
>>> s6select.city
u'rotterdam'

Changes

0.3 (2011-06-13)

  • Added behavior to the collection allowing the override or ignore of the components.

0.2 (2011-04-14)

  • Updated components names for entry points.

0.1 (2011-04-13)

  • Initial release.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dolmen.collection-0.3.tar.gz (10.3 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page