[Checkins] SVN: lovely.rating/trunk/src/ Initial import from Lovely
Systems repository
Jodok Batlogg
jodok.batlogg at lovelysystems.com
Sat Aug 12 10:31:00 EDT 2006
Log message for revision 69429:
Initial import from Lovely Systems repository
Changed:
A lovely.rating/trunk/src/
A lovely.rating/trunk/src/lovely/
A lovely.rating/trunk/src/lovely/__init__.py
A lovely.rating/trunk/src/lovely/rating/
A lovely.rating/trunk/src/lovely/rating/README.txt
A lovely.rating/trunk/src/lovely/rating/__init__.py
A lovely.rating/trunk/src/lovely/rating/definition.py
A lovely.rating/trunk/src/lovely/rating/interfaces.py
A lovely.rating/trunk/src/lovely/rating/manager.py
A lovely.rating/trunk/src/lovely/rating/rating.py
A lovely.rating/trunk/src/lovely/rating/tests.py
-=-
Added: lovely.rating/trunk/src/lovely/__init__.py
===================================================================
Property changes on: lovely.rating/trunk/src/lovely/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/README.txt
===================================================================
--- lovely.rating/trunk/src/lovely/rating/README.txt 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/README.txt 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,143 @@
+==============
+Rating Package
+==============
+
+The rating package implements a rating system which can be plugged to any
+content type.
+
+ >>> from lovely import rating
+
+Let's first create an object that can be rated:
+
+ >>> import zope.annotation
+ >>> import zope.interface
+
+ >>> class Application(object):
+ ... zope.interface.implements(zope.annotation.IAttributeAnnotatable,
+ ... rating.interfaces.IRatable)
+ ... def __init__(self, name):
+ ... self.name = name
+ ...
+ ... def __repr__(self):
+ ... return '<%s %r>' % (self.__class__.__name__, self.name)
+
+ >>> kde = Application(u'KDE')
+
+In order for an object to be ratable, it also must be annotatable. The easiest
+is to make it attribute-annotatble. Now we register an adapter that can adapt
+``IRatable`` providing objects to ``IRatingsManagers``.
+
+ >>> import zope.component
+ >>> zope.component.provideAdapter(rating.getRatingsManager)
+
+ >>> from zope.annotation import attribute
+ >>> zope.component.provideAdapter(attribute.AttributeAnnotations)
+
+
+It is now trivial to get the ratings manager.
+
+ >>> manager = rating.interfaces.IRatingsManager(kde)
+ >>> manager
+ <RatingsManager for <Application u'KDE'>>
+
+The ratings manager manages all ratings that can be made for an object. For
+example, you might want to be able to rate an application for usability,
+functionality, stability and documentation. The rating manager would then
+manage the ratings of those four points of interest.
+
+Before we can rate the application, we have to create a rating definition for
+each of the four points of interest. To do this, we first have to
+create a score system for the ratings:
+
+ >>> from decimal import Decimal
+ >>> from schooltool.requirement import scoresystem
+
+ >>> fiveSteps = scoresystem.DiscreteValuesScoreSystem(
+ ... u'Five Steps', u' A five step scoring system',
+ ... [(u'Awesome', Decimal(4)), (u'Good', Decimal(3)),
+ ... (u'Okay', Decimal(2)), (u'Poor', Decimal(1)),
+ ... (u'Crap', Decimal(0))])
+
+Note: For more details on score systems see the documentation in the
+``schooltool.requirement`` package.
+
+Now we can create the rating definition and register it as a utility:
+
+ >>> usability = rating.RatingDefinition(
+ ... u'Usability', fiveSteps, u'How is the usability of the application?')
+ >>> zope.component.provideUtility(
+ ... usability, rating.interfaces.IRatingDefinition, name='usability')
+
+We are finally ready to rate KDE for usability:
+
+ >>> manager.rate('usability', u'Good', u'srichter')
+ >>> manager.rate('usability', u'Okay', u'kartnaller')
+
+The ``rate()`` method's arguments are the id of the rating definition, the
+value and the user id of the user making the rating. Note that you cannot add
+invalid ratings:
+
+ >>> manager.rate('usability', u'Divine', u'jodok')
+ Traceback (most recent call last):
+ ...
+ ValueError: Invalid rating value u'Divine' for 'usability'.
+
+ >>> manager.rate('stability', u'Awesome', u'jodok')
+ Traceback (most recent call last):
+ ...
+ ValueError: No rating definition named 'stability' found.
+
+The rest of the rating manager API deals with retrieving the ratings. First
+you can ask for all ratings made for a rating definition:
+
+ >>> sorted([rating.__repr__() for rating in manager.getRatings('usability')])
+ ["<Rating u'Good' by u'srichter'>", "<Rating u'Okay' by u'kartnaller'>"]
+
+You can also ask for the rating of a particular user:
+
+ >>> manager.getRating('usability', u'srichter')
+ <Rating u'Good' by u'srichter'>
+
+The rating has the following attributes:
+
+ >>> manager.getRating('usability', u'srichter').value
+ u'Good'
+ >>> manager.getRating('usability', u'srichter').user
+ u'srichter'
+ >>> manager.getRating('usability', u'srichter').timestamp
+ datetime.datetime(...)
+
+Note that the rating object is read-only:
+
+ >>> manager.getRating('usability', u'srichter').value = u'Awesome'
+ Traceback (most recent call last):
+ ...
+ AttributeError: can't set attribute
+
+A new rating can be given by rating the application again:
+
+ >>> manager.rate('usability', u'Awesome', u'srichter')
+ >>> manager.getRating('usability', u'srichter')
+ <Rating u'Awesome' by u'srichter'>
+
+Ratings are removed using the following:
+
+ >>> manager.rate('usability', u'Crap', u'badcarma')
+ >>> manager.getRating('usability', u'badcarma')
+ <Rating u'Crap' by u'badcarma'>
+
+ >>> manager.remove('usability', 'badcarma')
+ >>> manager.getRating('usability', u'badcarma')
+
+Finally, the manager also provides some basic statistical features:
+
+ >>> manager.computeAverage('usability')
+ Decimal("3")
+
+ >>> manager.countScores('usability')
+ [((u'Awesome', Decimal("4")), 1),
+ ((u'Good', Decimal("3")), 0),
+ ((u'Okay', Decimal("2")), 1),
+ ((u'Poor', Decimal("1")), 0),
+ ((u'Crap', Decimal("0")), 0)]
+
Property changes on: lovely.rating/trunk/src/lovely/rating/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/__init__.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/__init__.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/__init__.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,8 @@
+# Make a package
+
+import zope.i18nmessageid
+_ = zope.i18nmessageid.MessageFactory('rating')
+
+from manager import getRatingsManager
+from definition import RatingDefinition
+from rating import Rating
Property changes on: lovely.rating/trunk/src/lovely/rating/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/definition.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/definition.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/definition.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,40 @@
+##############################################################################
+#
+# Copyright (c) 2006 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Rating definition
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import persistent
+import zope.interface
+from zope.schema import fieldproperty
+from zope.app.container import contained
+
+from lovely.rating import interfaces
+
+class RatingDefinition(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IRatingDefinition)
+
+ title = fieldproperty.FieldProperty(
+ interfaces.IRatingDefinition['title'])
+ scoreSystem = fieldproperty.FieldProperty(
+ interfaces.IRatingDefinition['scoreSystem'])
+ description = fieldproperty.FieldProperty(
+ interfaces.IRatingDefinition['description'])
+
+ def __init__(self, title, scoreSystem, description=None):
+ self.title = title
+ self.scoreSystem = scoreSystem
+ if description is not None:
+ self.description = description
Property changes on: lovely.rating/trunk/src/lovely/rating/definition.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/interfaces.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/interfaces.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/interfaces.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,109 @@
+##############################################################################
+#
+# Copyright (c) 2006 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Rating interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+import zope.schema
+
+from schooltool.requirement import interfaces
+
+class IRatingDefinition(zope.interface.Interface):
+ """Defines the a rating.
+
+ The purpose of this interface is to specify the purpose of the rating (or
+ what is being rated) and the way it is rated, in other words, the score
+ system.
+ """
+
+ title = zope.schema.TextLine(
+ title=u'Title',
+ description=u'The title of the rating survey.',
+ required=True)
+
+ scoreSystem = zope.schema.Object(
+ title=u'Score System',
+ description=u'The score system used for rating.',
+ schema=interfaces.IScoreSystem,
+ required=True)
+
+ description = zope.schema.Text(
+ title=u'Description',
+ description=u'A longer explanation of the purpose of the survey.',
+ required=False)
+
+
+class IRatable(zope.interface.Interface):
+ """A marker interface marking an object as being ratable."""
+
+
+class IRatingsManager(zope.interface.Interface):
+ """Manages all ratings for one object."""
+
+ def rate(id, value, user):
+ """Create a rating for the definition with 'id'.
+
+ This method should override existing ratings, if applicable.
+ """
+
+ def remove(id, user):
+ """Remove the rating for the definition and user.
+
+ If no rating exists, do nothing and simply return.
+ """
+
+ def getRatings(id):
+ """Get all ratings for a particular definition.
+
+ The result will be a sequence of ``IRating`` objects.
+ """
+
+ def getRating(id, user):
+ """Get a rating for the definition and user.
+
+ The result will be an ``IRating`` object. If no rating is found, rais
+ a ``ValueError``.
+ """
+
+ def computeAverage(id):
+ """Compute the average rating value for the specified definition."""
+
+ def countScores(id):
+ """Count how many times each value was giving for a definition.
+
+ The result will be a list of tuples of the type ``(score,
+ amount)``. ``score`` is in turn a tuple of ``(name, value)``.
+ """
+
+
+class IRating(zope.interface.Interface):
+ """A single rating for a definition and user."""
+
+ value = zope.schema.Object(
+ title=u'Value',
+ description=u'A scoresystem-valid score that represents the rating.',
+ schema=zope.interface.Interface,
+ required=True)
+
+ user = zope.schema.TextLine(
+ title=u'User',
+ description=u'The id of the entity having made the rating.',
+ required=True)
+
+ timestamp = zope.schema.Datetime(
+ title=u'Timestamp',
+ description=u'The time the rating was given.')
Property changes on: lovely.rating/trunk/src/lovely/rating/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/manager.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/manager.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/manager.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2006 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Ratings Manager
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import persistent
+import zope.component
+import zope.interface
+from BTrees import OOBTree
+from zope import annotation
+from zope.app.container import contained
+
+from lovely.rating import interfaces, rating
+
+class RatingsManager(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IRatingsManager)
+ zope.component.adapts(interfaces.IRatable)
+
+ def __init__(self):
+ self._storage = OOBTree.OOBTree()
+
+ def _getDefinition(self, id):
+ defn = zope.component.queryUtility(interfaces.IRatingDefinition, id)
+ if defn is None:
+ raise ValueError('No rating definition named %r found.' % id)
+ return defn
+
+ def rate(self, id, value, user):
+ """See interfaces.IRatingsManager"""
+ defn = self._getDefinition(id)
+
+ if not defn.scoreSystem.isValidScore(value):
+ raise ValueError('Invalid rating value %r for %r.' %(value, id))
+
+ if id not in self._storage:
+ self._storage[id] = OOBTree.OOBTree()
+ contained.contained(self._storage[id], self._storage, id)
+
+ self._storage[id][user] = rating.Rating(id, value, user)
+ contained.contained(self._storage[id][user], self._storage[id], user)
+
+ def remove(self, id, user):
+ """See interfaces.IRatingsManager"""
+ # Just get the definition to make sure it exists.
+ defn = self._getDefinition(id)
+
+ if id not in self._storage or user not in self._storage[id]:
+ return
+ del self._storage[id][user]
+ if len(self._storage[id]) == 0:
+ del self._storage[id]
+
+ def getRatings(self, id):
+ """See interfaces.IRatingsManager"""
+ # Just get the definition to make sure it exists.
+ defn = self._getDefinition(id)
+
+ return list(self._storage.get(id, {}).values())
+
+ def getRating(self, id, user):
+ """See interfaces.IRatingsManager"""
+ # Just get the definition to make sure it exists.
+ defn = self._getDefinition(id)
+
+ if id not in self._storage or user not in self._storage[id]:
+ return
+
+ return self._storage[id][user]
+
+ def computeAverage(self, id):
+ """See interfaces.IRatingsManager"""
+ # Just get the definition to make sure it exists.
+ defn = self._getDefinition(id)
+ ratings = self._storage.get(id, {}).values()
+ total = sum([defn.scoreSystem.getNumericalValue(rating.value)
+ for rating in ratings])
+ return total/len(ratings)
+
+ def countScores(self, id):
+ """See interfaces.IRatingsManager"""
+ defn = self._getDefinition(id)
+
+ value_count = {}
+ for rating in self._storage.get(id, {}).values():
+ value_count.setdefault(rating.value, 0)
+ value_count[rating.value] += 1
+
+ return [(score, value_count.get(score[0], 0))
+ for score in defn.scoreSystem.scores]
+
+ def __repr__(self):
+ return '<%s for %r>' %(self.__class__.__name__, self.__parent__)
+
+
+getRatingsManager = annotation.factory(RatingsManager)
Property changes on: lovely.rating/trunk/src/lovely/rating/manager.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/rating.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/rating.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/rating.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2006 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Rating definition
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import datetime
+import persistent
+import zope.interface
+from zope.app.container import contained
+
+from lovely.rating import interfaces
+
+class Rating(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IRating)
+
+ id = property(lambda self: self._id)
+ value = property(lambda self: self._value)
+ user = property(lambda self: self._user)
+ timestamp = property(lambda self: self._timestamp)
+
+ def __init__(self, id, value, user):
+ self._id = id
+ self._value = value
+ self._user = user
+ self._timestamp = datetime.datetime.now()
+
+ def __repr__(self):
+ return '<%s %r by %r>' %(self.__class__.__name__, self.value, self.user)
Property changes on: lovely.rating/trunk/src/lovely/rating/rating.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.rating/trunk/src/lovely/rating/tests.py
===================================================================
--- lovely.rating/trunk/src/lovely/rating/tests.py 2006-08-12 14:26:28 UTC (rev 69428)
+++ lovely.rating/trunk/src/lovely/rating/tests.py 2006-08-12 14:30:59 UTC (rev 69429)
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2006 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Rating test setup
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import doctest
+import unittest
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing import placelesssetup
+
+def test_suite():
+ return unittest.TestSuite((
+ DocFileSuite('README.txt',
+ setUp=placelesssetup.setUp,
+ tearDown=placelesssetup.tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: lovely.rating/trunk/src/lovely/rating/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Checkins
mailing list