From b7097a09c5d3239401fa93ba84c887cc637f2fa9 Mon Sep 17 00:00:00 2001 From: helmutm Date: Fri, 21 Mar 2008 17:51:30 +0000 Subject: [PATCH] added stateful package for assigning simple workflows to loops objects git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2467 fd906abe-77d9-0310-91a1-e0d9ade77398 --- organize/personal/README.txt | 4 +-- organize/setup.py | 7 +++-- stateful/README.txt | 59 ++++++++++++++++++++++++++++++++++++ stateful/__init__.py | 3 ++ stateful/base.py | 47 ++++++++++++++++++++++++++++ stateful/configure.zcml | 22 ++++++++++++++ stateful/tests.py | 28 +++++++++++++++++ xmlrpc/README.txt | 4 +-- 8 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 stateful/README.txt create mode 100644 stateful/__init__.py create mode 100644 stateful/base.py create mode 100644 stateful/configure.zcml create mode 100755 stateful/tests.py diff --git a/organize/personal/README.txt b/organize/personal/README.txt index a7dd4c9..e076c97 100644 --- a/organize/personal/README.txt +++ b/organize/personal/README.txt @@ -118,10 +118,10 @@ So we are now ready to query the favorites. >>> favs = favorites.query(userName=johnCId) >>> favs - [] + [] >>> list(favAdapted.list(johnC)) - ['27'] + ['29'] >>> util.getObjectForUid(favs[0].taskId) is resources['d001.txt'] True diff --git a/organize/setup.py b/organize/setup.py index 67fcb6f..80d46a1 100644 --- a/organize/setup.py +++ b/organize/setup.py @@ -27,7 +27,7 @@ from zope.interface import implements, Interface from loops.concept import Concept from loops.interfaces import ITypeConcept -from loops.organize.interfaces import IPerson +from loops.organize.interfaces import IPerson, ITask from loops.setup import SetupManager as BaseSetupManager @@ -39,10 +39,13 @@ class SetupManager(BaseSetupManager): predicate = concepts['predicate'] person = self.addObject(concepts, Concept, 'person', title=u'Person', - conceptType=type) + conceptType=type) aPerson = ITypeConcept(person) if not aPerson.typeInterface: # allow overriding by other packages aPerson.typeInterface = IPerson owner = self.addObject(concepts, Concept, 'ownedby', title=u'owned by', conceptType=predicate) + + task = self.addAndConfigureObject(concepts, Concept, 'task', title=u'Task', + conceptType=type, typeInterface=ITask) diff --git a/stateful/README.txt b/stateful/README.txt new file mode 100644 index 0000000..5eaca2a --- /dev/null +++ b/stateful/README.txt @@ -0,0 +1,59 @@ +=============================================================== +loops - Linked Objects for Organization and Processing Services +=============================================================== + + ($Id$) + + >>> from zope import component + >>> from zope.traversing.api import getName + +First we set up a loops site with basic and example concepts and resources. + + >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown + >>> site = placefulSetUp(True) + + >>> from loops.organize.setup import SetupManager + >>> component.provideAdapter(SetupManager, name='organize') + >>> from loops.tests.setup import TestSite + >>> t = TestSite(site) + >>> concepts, resources, views = t.setup() + >>> loopsRoot = site['loops'] + + +Stateful Objects +================ + +Let's start with registering the states definitions and adapters needed. +The states definition (aka 'workflow') is registered as a utility; for +making an object statful we'll use an adapter. + + >>> from cybertools.stateful.interfaces import IStatesDefinition, IStateful + >>> from cybertools.stateful.publishing import simplePublishing + >>> component.provideUtility(simplePublishing, IStatesDefinition, + ... name='loops.simple_publishing') + + >>> from loops.stateful.base import SimplePublishable + >>> component.provideAdapter(SimplePublishable, name='loops.simple_publishing') + +We may now take a document and adapt it to IStateful so that we may +check the document's state and perform transitions to other states. + + >>> doc01 = resources['d001.txt'] + >>> statefulDoc01 = component.getAdapter(doc01, IStateful, + ... name='loops.simple_publishing') + + >>> statefulDoc01.state + 'draft' + + >>> statefulDoc01.doTransition('publish') + >>> statefulDoc01.state + 'published' + +Let's check if the state is really stored in the underlying object and +not just kept in the adapter. + + >>> statefulDoc01_x = component.getAdapter(doc01, IStateful, + ... name='loops.simple_publishing') + + >>> statefulDoc01.state + 'published' diff --git a/stateful/__init__.py b/stateful/__init__.py new file mode 100644 index 0000000..38314f3 --- /dev/null +++ b/stateful/__init__.py @@ -0,0 +1,3 @@ +""" +$Id$ +""" diff --git a/stateful/base.py b/stateful/base.py new file mode 100644 index 0000000..25a3e74 --- /dev/null +++ b/stateful/base.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2008 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 +# + +""" +Basic implementations for stateful objects and adapters. + +$Id$ +""" + +from zope import component +from zope.component import adapts + +from cybertools.stateful.base import Stateful as BaseStateful +from cybertools.stateful.base import StatefulAdapter +from cybertools.stateful.interfaces import IStatesDefinition +from loops.interfaces import ILoopsObject + + +class Stateful(BaseStateful): + + def getStatesDefinition(self): + return component.getUtility(IStatesDefinition, self.statesDefinition) + + +class StatefulLoopsObject(Stateful, StatefulAdapter): + + adapts(ILoopsObject) + + +class SimplePublishable(StatefulLoopsObject): + + statesDefinition = 'loops.simple_publishing' diff --git a/stateful/configure.zcml b/stateful/configure.zcml new file mode 100644 index 0000000..38aaca8 --- /dev/null +++ b/stateful/configure.zcml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/stateful/tests.py b/stateful/tests.py new file mode 100755 index 0000000..169a064 --- /dev/null +++ b/stateful/tests.py @@ -0,0 +1,28 @@ +#! /usr/bin/python + +""" +Tests for the 'loops.stateful' package. + +$Id$ +""" + +import unittest, doctest +from zope.testing.doctestunit import DocFileSuite + + +class Test(unittest.TestCase): + "Basic tests for the storage package." + + def testBasicStuff(self): + pass + + +def test_suite(): + flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + return unittest.TestSuite(( + unittest.makeSuite(Test), + DocFileSuite('README.txt', optionflags=flags), + )) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/xmlrpc/README.txt b/xmlrpc/README.txt index 762d01e..5c8aa9d 100755 --- a/xmlrpc/README.txt +++ b/xmlrpc/README.txt @@ -166,14 +166,14 @@ Updating the concept map >>> topicId = xrf.getObjectByName('topic')['id'] >>> xrf.createConcept(topicId, u'zope2', u'Zope 2') - {'description': u'', 'title': u'Zope 2', 'type': '22', 'id': '56', + {'description': u'', 'title': u'Zope 2', 'type': '24', 'id': '56', 'name': u'zope2'} The name of the concept is checked by a name chooser; if the corresponding parameter is empty, the name will be generated from the title. >>> xrf.createConcept(topicId, u'', u'Python') - {'description': u'', 'title': u'Python', 'type': '22', 'id': '58', + {'description': u'', 'title': u'Python', 'type': '24', 'id': '58', 'name': u'python'} Changing the attributes of a concept