[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