add zutil: Jeep implementation with BTrees; work in progress: organize, composer

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1827 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-07-16 08:43:43 +00:00
parent 96c074aa84
commit e9b8722793
11 changed files with 358 additions and 17 deletions

View file

@ -17,7 +17,7 @@
#
"""
Basic classes for a complex template structures.
Basic classes for complex template structures.
$Id$
"""
@ -43,14 +43,18 @@ class Compound(Component):
implements(ICompound)
componentStorage = Jeep
def __init__(self):
self.parts = Jeep()
self.parts = self.componentStorage()
class Template(object):
implements(ITemplate)
def __init__(self):
self.components = Jeep()
componentStorage = Jeep
def __init__(self):
self.components = self.componentStorage()

View file

@ -31,6 +31,9 @@ class Instance(object):
implements(IInstance)
templateStorage = dict
templateAttributeName = '__ctc_templates__'
aspect = 'composer.default'
def __init__(self, context):
@ -38,11 +41,12 @@ class Instance(object):
self.instances = []
def setTemplate(self, template):
templates = getattr(self.context, '__templates__', {})
templates = getattr(self.context,
self.templateAttributeName, self.templateStorage())
templates.setdefault(self.aspect, template)
self.context.__templates__ = templates
setattr(self.context, self.templateAttributeName, templates)
def getTemplate(self):
templates = getattr(self.context, '__templates__', {})
templates = getattr(self.context, self.templateAttributeName, {})
return templates.get(self.aspect, None)
template = property(getTemplate, setTemplate)

View file

@ -122,6 +122,13 @@ class ITask(Interface):
# services
class IServiceManager(Interface):
""" A manager or container for a set of services.
"""
services = Attribute('A collection of services managed by this object.')
class IServiceGroup(Interface):
""" A group of related services or a general service definition,
e.g. a regular bus service or a series of trainings.

View file

@ -17,21 +17,20 @@
#
"""
Service instance classes.
Service management classes.
$Id$
"""
from zope.interface import implements
from cybertools.organize.interfaces import IService
from cybertools.organize.interfaces import IScheduledService
from cybertools.organize.interfaces import IServiceManager
from cybertools.organize.interfaces import IService, IScheduledService
class Registration(object):
class ServiceManager(object):
def __init__(self, client):
self.client = client
implements(IServiceManager)
class Service(object):
@ -60,3 +59,9 @@ class ScheduledService(Service):
implements(IScheduledService)
class Registration(object):
def __init__(self, client):
self.client = client

View file

@ -65,6 +65,9 @@ class StatesDefinition(object):
return [ self._transitions[t] for t in self._states[state].transitions ]
def registerStatesDefinition(id, definition):
statesDefinitions[id] = definition
statesDefinitions = {
'default': StatesDefinition(),
}

View file

@ -16,17 +16,17 @@
<resource name="edit.gif" file="edit.gif" />
<pages for="loops.interfaces.IResource"
<!--<pages for="*"
class=".browser.ExternalEditorView"
permission="zope.ManageContent">
<page name="external_edit" attribute="load" />
<!--
<page name="save" attribute="save" />
<page name="lock" attribute="lock" />
<page name="unlock" attribute="unlock" />-->
<page name="unlock" attribute="unlock" />
</pages>
</pages>-->
<page for="*"
name="xedit_macros"

26
zutil/README.txt Normal file
View file

@ -0,0 +1,26 @@
========================================
Common Utilities for Zope-based Packages
========================================
$Id$
This package contains a set of miscellaneous utility modules that
are to small for creating a separate package for them.
As each utility is developed further it may eventually get its own
package some time.
Usually each utility has a <name>.py file with an implementation and a
corresponding <name>.txt file with a description that can be run as a
doctest.
The doctests can be run by issuing
python cybertools/zutil/tests.py
in the directory above the cybertools directory or via
bin/test -vs cybertools.zutil
from within a Zope 3 instance that contains the cybertools package in
its python path.

3
zutil/__init__.py Normal file
View file

@ -0,0 +1,3 @@
"""
$Id$
"""

123
zutil/jeep.py Normal file
View file

@ -0,0 +1,123 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
A general purpose (thus 'Jeep') class that provides most of the interfaces
of sequences and dictionaries and in addition allows attribute access to
the dictionary entries.
$Id$
"""
from persistent.list import PersistentList
from BTrees.OOBTree import OOBTree
_notfound = object()
_nodefault = object()
class Jeep(object):
_attributes = ('_sequence', '_mapping')
def __init__(self, seq=[]):
self._sequence = PersistentList()
self._mapping = OOBTree()
for item in seq:
attr, value = item
setattr(self, attr, value)
def __len__(self):
return len(self._sequence)
def __iter__(self):
for key in self._sequence:
yield self[key]
def __getattr__(self, attr, default=_nodefault):
value = self._mapping.get(attr, _notfound)
if value is _notfound:
if default is _nodefault:
raise AttributeError(attr)
else:
return default
return value
def __setattr__(self, attr, value):
if attr in self._attributes:
object.__setattr__(self, attr, value)
else:
if getattr(self, attr, _notfound) is _notfound:
self._sequence.append(attr)
self._mapping[attr] = value
def __delattr__(self, attr):
del self._sequence[self.index(attr)]
del self._mapping[attr]
def __getitem__(self, key):
if type(key) in (int, long):
return getattr(self, self._sequence[key])
value = getattr(self, key, _notfound)
if value is _notfound:
raise KeyError(key)
return value
def __setitem__(self, key, value):
setattr(self, key, value)
def __delitem__(self, key):
delattr(self, key)
def __contains__(self, key):
return getattr(self, key, _notfound) is not _notfound
def keys(self):
return [key for key in self._sequence]
def values(self):
return list(self)
def items(self):
return [(k, self[k]) for k in self._sequence]
def get(self, key, default=None):
return getattr(self, key, default)
def index(self, key):
return self._sequence.index(key)
def append(self, obj):
self.insert(len(self), obj)
def insert(self, idx, obj):
key = getattr(obj, '__name__', getattr(obj, 'name', _notfound))
if key is _notfound:
raise AttributeError("No name attribute present")
if key in self:
raise ValueError("Object already present")
self._sequence.insert(idx, key)
self._mapping[key] = obj
def pop(self, key=-1):
value = self[key]
if type(key) in (int, long):
key = self._sequence[key]
delattr(self, key)
return value

141
zutil/jeep.txt Normal file
View file

@ -0,0 +1,141 @@
==============================
Jeep - a General Purpose Class
==============================
$Id$
>>> from cybertools.zutil.jeep import Jeep
>>> jeep = Jeep()
>>> jeep.first = 'first value'
>>> jeep.second = 'second value'
>>> jeep.first
'first value'
In addition to the usual access via dot notation all attributes can be
accessed via dictionary notation:
The third type of interface provided by Jeep objects is the sequence or
iterator interface. Converting a jeep object to a list iterates over its
values (that is different from the dictionary behaviour, but is what
you want usually; use the ``.keys()`` method to get at the keys, see below):
>>> list(jeep)
['first value', 'second value']
Direct index access to certain entries gives the corresponding value,
not the key:
>>> jeep[1]
'second value'
Changing Jeep Objects
---------------------
Assignment by dictionary or attribute access appends the newly assigned
attribute:
>>> jeep['third'] = 'third value'
>>> jeep.third
'third value'
>>> list(jeep)
['first value', 'second value', 'third value']
Assigning a new value to an already existing attribute does not change the
order but only changes the attribute's value
>>> jeep.second = 'new second value'
>>> list(jeep)
['first value', 'new second value', 'third value']
>>> jeep[1]
'new second value'
More Dictionary Methods
-----------------------
>>> jeep.keys()
['first', 'second', 'third']
>>> jeep.values()
['first value', 'new second value', 'third value']
>>> jeep.items()
[('first', 'first value'), ('second', 'new second value'), ('third', 'third value')]
>>> jeep.get('second')
'new second value'
>>> jeep.get('fourth', 'default')
'default'
>>> jeep.get('fourth') is None
True
>>> jeep['fourth']
Traceback (most recent call last):
...
KeyError: 'fourth'
>>> dict(jeep)
{'second': 'new second value', 'third': 'third value', 'first': 'first value'}
More Methods and Operators
--------------------------
>>> 'third' in jeep
True
>>> jeep.pop()
'third value'
>>> len(jeep)
2
>>> 'third' in jeep
False
>>> jeep.index('second')
1
>>> jeep.index('third')
Traceback (most recent call last):
...
ValueError: ...not in list
Sequence Additions with Named Objects
-------------------------------------
Objects that have a ``__name__`` attribute can be appended
to a Jeep object as the dictionary key can be obtained from these attribute.
>>> class Term(object):
... def __init__(self, token, title=None, value=None):
... self.__name__ = self.token = token
... self.title = title or token
... self.value = value or title or token
>>> t1 = Term('term1', 'title 1')
>>> jeep.append(t1)
>>> jeep.keys()
['first', 'second', 'term1']
>>> jeep.term1.title
'title 1'
>>> jeep.insert(1, Term('term2', 'title 2'))
>>> jeep.keys()
['first', 'term2', 'second', 'term1']
>>> jeep[1].title
'title 2'
Inserting or appending an object with a name that's already present raises
an exception:
>>> jeep.append(t1)
Traceback (most recent call last):
...
ValueError: ...already present
Constructors
------------
>>> jeep2 = Jeep((('f', '1st'), ('s', '2nd'), ('t', '3rd')))
>>> list(jeep2)
['1st', '2nd', '3rd']

25
zutil/tests.py Executable file
View file

@ -0,0 +1,25 @@
# $Id$
import unittest, doctest
from zope.testing.doctestunit import DocFileSuite
import cybertools.zutil.jeep
class Test(unittest.TestCase):
"Basic tests for modules in the util package."
def testBasicStuff(self):
pass
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
return unittest.TestSuite((
#unittest.makeSuite(Test), # we don't need this
#doctest.DocTestSuite(cybertools.zutil.property, optionflags=flags),
DocFileSuite('jeep.txt', optionflags=flags),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')