2
# This program is free software; you can redistribute it and/or modify
3
# it under the terms of the GNU General Public License as published by
4
# the Free Software Foundation; either version 2 of the License, or
5
# (at your option) any later version.
7
# This program is distributed in the hope that it will be useful,
8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
# GNU General Public License for more details.
12
# You should have received a copy of the GNU General Public License
13
# along with this program; if not, write to the Free Software
14
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
__docformat__ = 'restructuredtext'
26
from BTrees.OOBTree import OOBTree
29
from zope.interface import implements
30
from zope.component import adapts
31
from zope.annotation.interfaces import IAnnotations
32
from zope.container.contained import Contained, containedEvent
33
from zope.lifecycleevent import ObjectRemovedEvent
34
from zope.location import location
35
from zope.keyreference.interfaces import IKeyReference
36
from zope.traversing.api import getParent, getName
38
from schooltool.requirement import interfaces
41
EVALUATIONS_KEY = "schooltool.evaluations"
44
def getRequirementList(req, recurse=True):
46
for value in req.values(): # loop through your children
48
result += getRequirementList(value) # append their children...
50
result.append(value) # just append the child
51
result.append(req) # append the object itself
55
class Evaluations(persistent.Persistent, Contained):
56
"""Evaluations mapping.
58
This particular implementation uses the ``zope.keyreference`` package
59
to generate the keys of the requirements. Any key that is passed in could
60
be the requirement or the ``IKeyReference`` of the requirement. This
61
implementation will always convert the key to provide ``IKeyReference``
62
before treating it as a true key.
64
Another feature of this implementation is that if you set an evaluation
65
for a requirement that has already an evaluation, then the old evaluation
66
is simply overridden. The ``IContainer`` interface would raise a duplicate
69
implements(interfaces.IEvaluations)
71
def __init__(self, items=None):
72
super(Evaluations, self).__init__()
73
self._btree = OOBTree()
74
for name, value in items or []:
77
def __getitem__(self, key):
78
"""See zope.interface.common.mapping.IItemMapping"""
79
return self._btree[IKeyReference(key)]
81
def __delitem__(self, key):
82
"""See zope.interface.common.mapping.IWriteMapping"""
84
del self._btree[IKeyReference(key)]
85
event = ObjectRemovedEvent(value, self)
86
zope.event.notify(event)
88
def __setitem__(self, key, value):
89
"""See zope.interface.common.mapping.IWriteMapping"""
90
self._btree[IKeyReference(key)] = value
91
value, event = containedEvent(value, self)
92
zope.event.notify(event)
94
def get(self, key, default=None):
95
"""See zope.interface.common.mapping.IReadMapping"""
101
def __contains__(self, key):
102
"""See zope.interface.common.mapping.IReadMapping"""
103
return IKeyReference(key) in self._btree
106
"""See zope.interface.common.mapping.IEnumerableMapping"""
107
# For now I decided to return the activities (as I think it is more
108
# natural), though they are not the true keys as we know
109
return [key() for key in self._btree.keys()]
112
"""See zope.interface.common.mapping.IEnumerableMapping"""
113
return iter(self.keys())
116
"""See zope.interface.common.mapping.IEnumerableMapping"""
117
return self._btree.values()
120
"""See zope.interface.common.mapping.IEnumerableMapping"""
121
return [(key(), value) for key, value in self._btree.items()]
124
"""See zope.interface.common.mapping.IEnumerableMapping"""
125
return len(self._btree)
127
def addEvaluation(self, evaluation):
128
"""See interfaces.IEvaluations"""
129
self[evaluation.requirement] = evaluation
131
def getEvaluationsForRequirement(self, req, recurse=True):
132
"""See interfaces.IEvaluations"""
133
requirements = getRequirementList(req, recurse)
135
for name, ev in self.items()
136
if ev.requirement in requirements]
137
result = Evaluations(result)
138
location.locate(result, getParent(self), getName(self))
141
def getEvaluationsOfEvaluator(self, evaluator):
142
"""See interfaces.IEvaluations"""
144
for name, ev in self.items()
145
if ev.evaluator == evaluator]
146
result = Evaluations(result)
147
location.locate(result, getParent(self), getName(self))
152
parent = getParent(self)
155
return '<%s for %r>' % (self.__class__.__name__, parent)
158
class Evaluation(Contained):
160
implements(interfaces.IEvaluation)
162
def __init__(self, requirement, scoreSystem, value, evaluator):
164
self.requirement = requirement
165
self.scoreSystem = scoreSystem
167
self.evaluator = evaluator
174
def set(self, value):
175
if not self.scoreSystem.isValidScore(value):
176
raise ValueError('%r is not a valid score.' %value)
178
# XXX mg: since it is a very bad idea to mix datetimes with tzinfo
179
# and datetimes without tzinfo, I suggest using datetimes with
180
# tzinfo everywhere. Most of SchoolTool follows this convention,
181
# (with the painful exception of schooltool.timetable).
182
self.time = datetime.datetime.utcnow()
184
return property(get, set)
189
return getParent(getParent(self))
191
raise ValueError('Evaluation is not yet assigned to a evaluatee')
194
return '<%s for %r, value=%r>' % (self.__class__.__name__,
195
self.requirement, self.value)
198
class AbstractQueryAdapter(object):
200
adapts(interfaces.IEvaluations)
201
implements(interfaces.IEvaluationsQuery)
203
def __init__(self, context):
204
self.context = context
206
def _query(self, *args, **kwargs):
209
def __call__(self, *args, **kwargs):
210
"""See interfaces.IEvaluationsQuery"""
211
result = Evaluations(self._query(*args, **kwargs))
213
result, getParent(self.context), getName(self.context))
217
def getEvaluations(context):
218
"""Adapt an ``IHaveEvaluations`` object to ``IEvaluations``."""
219
annotations = IAnnotations(context)
221
return annotations[EVALUATIONS_KEY]
223
evaluations = Evaluations()
224
annotations[EVALUATIONS_KEY] = evaluations
225
location.locate(evaluations, zope.proxy.removeAllProxies(context),
228
# Convention to make adapter introspectable
229
getEvaluations.factory = Evaluations