Added contained stuff, subtasks, resource allocations

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@108 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2004-09-19 11:42:36 +00:00
parent ab72c568d0
commit fa2d52a342
6 changed files with 301 additions and 120 deletions

View file

@ -1,45 +0,0 @@
#
# Copyright (c) 2004 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
#
"""
Definition of the Entity class.
$Id: entity.py $
"""
from zope.interface import implements
from zope.app.container.ordered import OrderedContainer
from interfaces import IEntity
class Entity(OrderedContainer):
""" A Task is a scheduled piece of work.
Resources may be allocated to a Task.
A Task may depend on subtasks.
"""
implements(IEntity)
def getRelations(self, relationships=None):
return []
def getReverseRelations(self, relationships=None):
return []

View file

@ -27,47 +27,9 @@ from zope.app.container.interfaces import IOrderedContainer
from zope.schema import TextLine
class IEntity(IOrderedContainer):
""" Common base class of the Task and Resource classes.
(Not sure if we really need it...)
"""
def getRelations(relationships=None):
""" Return a list of target objects from relations assiociated
with this Entity, possibly restricted to the relationships given.
"""
def getReverseRelations(relationships=None):
""" Return a list of source objects from relations directed at
this Entity as the target, possibly restricted to the relationships
given.
"""
class DummyIEntity:
def getRelation(target, relationship=None):
""" Return the relation object specified by target and relationship.
"""
def addRelation(target, relationship, **props):
""" Create a new relation object with relationship to target
and assign it to self.
If supported by relationship additional properties may be
given as keyword parameters.
Return relation object.
"""
def removeRelation(target, relationship):
""" Remove the relation to target with relationship from self.
"""
def getController():
""" Return the LoopsController object of this Entity, typically
the parent LoopsManager object or the portal_loops Tool.
"""
class ITask(IOrderedContainer):
""" A Task is a scheduled piece of work.
""" A Task is a piece of work.
Resources may be allocated to a Task.
A Task may depend on subtasks.
"""
@ -79,27 +41,23 @@ class ITask(IOrderedContainer):
required=True)
def getSubtasks(taskTypes=None):
""" Return a list of subtasks of self,
""" Return a tuple of subtasks of self,
possibly restricted to the task types given.
"""
def assignSubtask(task):
""" Assign an existing task to self as a subtask.
Return the relation object that leads to the subtask (Really?).
""" Assign an existing task to self as a subtask..
"""
def getParentTasks():
""" Return a list of tasks to which self has a subtask relationship.
""" Return a tuple of tasks to which self has a subtask relationship.
"""
class DummyITask:
def createSubtask(taskType=None, container=None, id=None, **props):
def createSubtask(taskType=None, container=None, name=None):
""" Create a new task with id in container and assign it to self as a subtask.
container defaults to parent of self.
id will be generated if not given.
Return the relation object that leads to the subtask
(fetch the subtask via relation.getTarget()).
name will be generated if not given.
Return the new subtask.
"""
def deassignSubtask(task):
@ -107,15 +65,19 @@ class DummyITask:
"""
def getAllocatedResources(allocTypes=None, resTypes=None):
""" Return a list of resources allocated to self,
""" Return a tuple of resources allocated to self,
possibly restricted to the allocation types and
target resource types given.
"""
def allocateResource(resource, allocType=None, **props):
def allocateResource(resource, allocType=None):
""" Allocate resource to self. A special allocation type may be given.
"""
def createAndAllocateResource(resourceType='Resource', allocType='standard',
container=None, name=None):
""" Allocate resource to self. A special allocation type may be given.
Additional properties may be given as keyword parameters.
Return relation object that implements the allocation reference.
"""
def deallocateResource(resource):
@ -123,7 +85,7 @@ class DummyITask:
"""
def allocatedUserIds():
""" Returns list of user IDs of allocated Person objects that are portal members.
""" Returns tuple of user IDs of allocated Person objects that are portal members.
Used by catalog index 'allocUserIds'.
"""
@ -134,5 +96,18 @@ class DummyITask:
def getAllAllocTypes():
""" Return a tuple with all available allocation types defined
in the LoopsController object that is responsible for self.
in the controller object that is responsible for self.
"""
class IResource(IOrderedContainer):
""" A Resource is an object - a thing or a person - that may be
allocated to one or more Task objects.
"""
def getTasksAllocatedTo(allocTypes=None, taskTypes=None):
""" Return a list of task to which self is allocated to,
possibly restricted to the allocation types and
source task types given.
"""

64
resource.py Normal file
View file

@ -0,0 +1,64 @@
#
# Copyright (c) 2004 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
#
"""
Definition of the Resource class.
$Id$
"""
from zope.interface import implements
from zope.app.container.ordered import OrderedContainer
from interfaces import IResource
class Resource(OrderedContainer):
implements(IResource)
title = u''
def __init__(self):
OrderedContainer.__init__(self)
self._allocations = {}
def getTasksAllocatedTo(self, allocTypes=None, taskTypes=None):
from sets import Set
allocs = self._allocations
res = Set()
for at in allocs.keys():
if allocTypes is None or at in allocTypes:
res.union_update(allocs[at])
return tuple(res)
# Helper methods:
def _updateAllocations(self, task, allocType):
#called by Task.allocateResource
tList = self._allocations.get(allocType, [])
tList.append(task)
self._allocations[allocType] = tList
def _createResourceName(self):
prefix = 'rsc'
last = max([ int(n[len(prefix):]) for n in self.__parent__.keys() ] or [1])
return prefix + str(last+1)

73
task.py
View file

@ -23,24 +23,25 @@ $Id$
"""
from zope.interface import implements
from zope.app.container.ordered import OrderedContainer
from entity import Entity
from interfaces import ITask
class Task(Entity):
""" A Task is a scheduled piece of work.
Resources may be allocated to a Task.
A Task may depend on subtasks.
"""
class Task(OrderedContainer):
implements(ITask)
title = u''
#title = property(_getTitle, _setTitle)
_subtasks = []
_parentTasks = []
def __init__(self):
OrderedContainer.__init__(self)
self._subtasks = []
self._parentTasks = []
self._resourceAllocs = {}
# subtasks:
def getSubtasks(self, taskTypes=None):
return tuple(self._subtasks)
@ -51,4 +52,58 @@ class Task(Entity):
def assignSubtask(self, task):
self._subtasks.append(task)
task._parentTasks.append(self)
def createSubtask(self, taskType=None, container=None, name=None):
container = container or self.__parent__
task = Task()
name = name or self._createTaskName()
container[name] = task
self.assignSubtask(task)
return task
def deassignSubtask(self, task):
self._subtasks.remove(task)
task._parentTasks.remove(self)
# resources:
def getAllocatedResources(self, allocTypes=None, resTypes=None):
from sets import Set
allocs = self._resourceAllocs
res = Set()
for at in allocs.keys():
if allocTypes is None or at in allocTypes:
res.union_update(allocs[at])
return tuple(res)
def allocateResource(self, resource, allocType=None):
allocType = allocType or 'standard'
allocs = self._resourceAllocs
rList = allocs.get(allocType, [])
rList.append(resource)
allocs[allocType] = rList
resource._updateAllocations(self, allocType)
def createAndAllocateResource(self, resourceType='Resource', allocType='standard',
container=None, id=None):
return None
def deallocateResource(self, resource):
pass
def allocatedUserIds(self):
return ()
def getAllocType(self, resource):
return 'standard'
def getAllAllocTypes(self):
return ('standard',)
# Helper methods:
def _createTaskName(self):
prefix = 'tsk'
last = max([ int(n[len(prefix):]) for n in self.__parent__.keys() ] or [1])
return prefix + str(last+1)

65
tests/test_resource.py Executable file
View file

@ -0,0 +1,65 @@
# $Id$
import unittest
#from zope.testing.doctestunit import DocTestSuite
from zope.interface.verify import verifyClass
#from zope.app.tests.setup import placelessSetUp
#from zope.app.container.tests.test_icontainer import TestSampleContainer
from zope.app.container.interfaces import IContained
from zope.app.folder import Folder
from loops.resource import Resource
from loops.task import Task
from loops.interfaces import IResource
#class Test(TestSampleContainer):
class Test(unittest.TestCase):
"Test methods of the Resource class."
def setUp(self):
#placelessSetUp()
self.f1 = Folder()
self.f1.__name__ = u'f1'
self.r1 = Resource()
self.f1['rsc1'] = self.r1
self.t1 = Task()
self.f1['tsk1'] = self.t1
def tearDown(self):
pass
# the tests...
def testInterface(self):
self.assert_(IResource.providedBy(Resource()),
'Interface IResource is not implemented by class Resource.')
self.assert_(IContained.providedBy(Resource()),
'Interface IContained is not implemented by class Resource.')
verifyClass(IResource, Resource)
def testContained(self):
self.assertEqual(u'rsc1', self.r1.__name__)
self.assertEqual(u'f1', self.r1.__parent__.__name__)
def testTitle(self):
r = Resource()
self.assertEqual(u'', r.title)
r.title = u'First Resource'
self.assertEqual(u'First Resource', r.title)
def testAllocateToTask(self):
t1 = self.t1
r1 = self.r1
self.assertEqual((), r1.getTasksAllocatedTo())
t1.allocateResource(r1)
self.assertEqual((t1,), r1.getTasksAllocatedTo())
def test_suite():
return unittest.TestSuite((
# DocTestSuite('loops.tests.doctests'),
unittest.makeSuite(Test),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')

View file

@ -1,21 +1,43 @@
# $Id$
import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.app.container.tests.test_icontainer import TestSampleContainer
#from zope.testing.doctestunit import DocTestSuite
from zope.interface.verify import verifyClass
#from zope.app.tests.setup import placelessSetUp
#from zope.app.container.tests.test_icontainer import TestSampleContainer
from zope.app.container.interfaces import IContained
from zope.app.folder import Folder
from loops.task import Task
from loops.interfaces import ITask
#class Test(TestSampleContainer):
class Test(unittest.TestCase):
class TestTask(unittest.TestCase):
"Test methods of the Task class."
def setUp(self):
#placelessSetUp()
self.f1 = Folder()
self.f1.__name__ = u'f1'
self.t1 = Task()
self.f1['tsk1'] = self.t1
def tearDown(self):
pass
# the tests...
def testInterface(self):
self.assert_(ITask.providedBy(Task()), 'Interface ITask is not implemented by class Task.')
self.assert_(ITask.providedBy(Task()),
'Interface ITask is not implemented by class Task.')
self.assert_(IContained.providedBy(Task()),
'Interface IContained is not implemented by class Task.')
verifyClass(ITask, Task)
def testContained(self):
self.assertEqual(u'tsk1', self.t1.__name__)
self.assertEqual(u'f1', self.t1.__parent__.__name__)
def testTitle(self):
t = Task()
self.assertEqual(u'', t.title)
@ -24,18 +46,63 @@ class Test(unittest.TestCase):
def testSubtasks(self):
t1 = Task()
self.assertEquals((), t1.getSubtasks())
self.assertEqual((), t1.getSubtasks())
t2 = Task()
self.assertEquals((), t2.getSubtasks())
self.assertEquals((), t2.getParentTasks())
self.assertEqual((), t2.getSubtasks())
self.assertEqual((), t2.getParentTasks())
t1.assignSubtask(t2)
self.assertEquals((t2,), t1.getSubtasks())
self.assertEquals((t1,), t2.getParentTasks())
self.assertEqual((t2,), t1.getSubtasks())
self.assertEqual((t1,), t2.getParentTasks())
def testCreateSubtask(self):
t1 = self.t1
self.assertEqual((), t1.getSubtasks())
t2 = t1.createSubtask()
self.assertEqual((t1,), t2.getParentTasks())
self.assertEqual((t2,), t1.getSubtasks())
def testDeassignSubtask(self):
t1 = self.t1
t2 = t1.createSubtask()
self.assertEqual((t1,), t2.getParentTasks())
t1.deassignSubtask(t2)
self.assertEqual((), t2.getParentTasks())
self.assertEqual((), t1.getSubtasks())
from loops.resource import Resource
class TestTaskResource(unittest.TestCase):
"Test methods of the Task class related to Resource allocations."
def setUp(self):
#placelessSetUp()
self.f1 = Folder()
self.f1.__name__ = u'f1'
self.t1 = Task()
self.r1 = Resource()
self.f1['tsk1'] = self.t1
self.r1['rsc1'] = self.r1
def tearDown(self):
pass
# the tests...
def testAllocateResource(self):
t1 = self.t1
r1 = self.r1
self.assertEqual((), t1.getAllocatedResources())
t1.allocateResource(r1)
self.assertEqual((r1,), t1.getAllocatedResources())
def test_suite():
return unittest.TestSuite((
DocTestSuite('loops.tests.doctests'),
unittest.makeSuite(Test),
# DocTestSuite('loops.tests.doctests'),
unittest.makeSuite(TestTask),
unittest.makeSuite(TestTaskResource),
))
if __name__ == '__main__':