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:
parent
96c074aa84
commit
e9b8722793
11 changed files with 358 additions and 17 deletions
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
@ -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
26
zutil/README.txt
Normal 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
3
zutil/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
123
zutil/jeep.py
Normal file
123
zutil/jeep.py
Normal 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
141
zutil/jeep.txt
Normal 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
25
zutil/tests.py
Executable 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')
|
Loading…
Add table
Reference in a new issue