[Checkins] SVN: z3c.table/branches/lazyvalues2/ - ``IValues`` conform to ``len`` protocol. ``table.Table`` has new

Godefroid Chapelle gotcha at bubblenet.be
Thu Aug 5 10:11:34 EDT 2010


Log message for revision 115495:
  - ``IValues`` conform to ``len`` protocol. ``table.Table`` has new
    ``allRowsCount`` attribute that surfaces the total number of rows.
  
  - ``table.Table`` modified to use the new ``IValues`` attributes.
  
  - ``IValues`` has two new attributes: ``isSorted`` and ``sortOn``.  
    They can be queried by tables to avoid to sort again when values where 
    initially sorted (for example, values coming from a sorted SQL query). 
  
  - Add tests that verify interfaces for classes in ``value.py``
  
  

Changed:
  U   z3c.table/branches/lazyvalues2/CHANGES.txt
  U   z3c.table/branches/lazyvalues2/src/z3c/table/README.txt
  U   z3c.table/branches/lazyvalues2/src/z3c/table/interfaces.py
  U   z3c.table/branches/lazyvalues2/src/z3c/table/table.py
  U   z3c.table/branches/lazyvalues2/src/z3c/table/tests.py
  U   z3c.table/branches/lazyvalues2/src/z3c/table/value.py

-=-
Modified: z3c.table/branches/lazyvalues2/CHANGES.txt
===================================================================
--- z3c.table/branches/lazyvalues2/CHANGES.txt	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/CHANGES.txt	2010-08-05 14:11:34 UTC (rev 115495)
@@ -2,12 +2,24 @@
 CHANGES
 =======
 
-0.8.2 (unreleased)
+0.9.0 (unreleased)
 ------------------
 
-- Split single doctest file (README.txt) into different files
 
+- ``IValues`` conform to ``len`` protocol. ``table.Table`` has new
+  ``allRowsCount`` attribute that surfaces the total number of rows.
 
+- ``table.Table`` modified to use the new ``IValues`` attributes.
+
+- ``IValues`` has two new attributes: ``isSorted`` and ``sortOn``.  
+  They can be queried by tables to avoid to sort again when values where 
+  initially sorted (for example, values coming from a sorted SQL query). 
+
+- Add tests that verify interfaces for classes in ``value.py``
+
+- Split single doctest file (``README.txt``) into different files
+
+
 0.8.1 (2010-07-31)
 ------------------
 

Modified: z3c.table/branches/lazyvalues2/src/z3c/table/README.txt
===================================================================
--- z3c.table/branches/lazyvalues2/src/z3c/table/README.txt	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/src/z3c/table/README.txt	2010-08-05 14:11:34 UTC (rev 115495)
@@ -76,10 +76,18 @@
   >>> request = TestRequest()
   >>> plainTable = table.Table(container, request)
 
-Now we can update and render the table. As you can see with an empty container
-we will not get anything that looks like a table. We just get an empty string:
 
   >>> plainTable.update()
+
+We can check the number of rows in the container.
+
+  >>> plainTable.allRowsCount
+  3
+
+Now we render the table. As there are no columns,
+we will not get anything that looks like a table. 
+We just get an empty string:
+
   >>> plainTable.render()
   u''
 

Modified: z3c.table/branches/lazyvalues2/src/z3c/table/interfaces.py
===================================================================
--- z3c.table/branches/lazyvalues2/src/z3c/table/interfaces.py	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/src/z3c/table/interfaces.py	2010-08-05 14:11:34 UTC (rev 115495)
@@ -22,7 +22,20 @@
 
     values = zope.interface.Attribute('Iterable table row data sequence.')
 
+    def __len__():
+        """Count of rows"""
 
+    isSorted = zope.schema.Bool(
+        title=_(u'isSorted'),
+        description=_(u'True if values are sorted.'),
+        default=False)
+
+    sortOn = zope.schema.TextLine(
+        title=_(u'Sort on table column id'),
+        description=_(u'Sort on table column id'),
+        default=u'')
+
+
 class ITable(zope.contentprovider.interfaces.IContentProvider):
     """Table provider"""
 
@@ -72,10 +85,10 @@
         required=False)
 
     # sort attributes
-    sortOn = zope.schema.Int(
-        title=_(u'Sort on table index'),
-        description=_(u'Sort on table index'),
-        default=0)
+    sortOn = zope.schema.TextLine(
+        title=_(u'Sort on table column id'),
+        description=_(u'Sort on table column id'),
+        default=u'')
 
     sortOrder = zope.schema.TextLine(
         title=_(u'Sort order'),

Modified: z3c.table/branches/lazyvalues2/src/z3c/table/table.py
===================================================================
--- z3c.table/branches/lazyvalues2/src/z3c/table/table.py	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/src/z3c/table/table.py	2010-08-05 14:11:34 UTC (rev 115495)
@@ -78,6 +78,8 @@
     sortColumn = None
     sortOrder = u'ascending'
     reverseSortOrderNames = [u'descending', u'reverse', u'down']
+    hasSortedValues = False
+    valuesSortedOn = 0
 
     # batch attributes
     batchProviderName = 'batch'
@@ -116,6 +118,9 @@
     def values(self):
         adapter = zope.component.getMultiAdapter(
             (self.context, self.request, self), interfaces.IValues)
+        self.allRowsCount = len(adapter)
+        self.hasSortedValues = adapter.isSorted
+        self.valuesSortedOn = adapter.sortOn
         return adapter.values
 
 # setup
@@ -185,8 +190,20 @@
         return self.request.get(self.prefix + '-sortOrder',
             self.sortOrder)
 
+    def _mustSort(self):
+        return (
+            # There is data to sort
+            (self.rows and self.columns)
+            # and there is a sort criteria
+            and (self.sortOn is not None)
+            # and, or values are not sorted
+            and (not self.hasSortedValues
+            # or, even though values are sorted,
+            # they are not sorted on the right criteria
+            or (self.hasSortedValues and self.valuesSortedOn != self.sortOn)))
+
     def sortRows(self):
-        if self.sortOn is not None and self.rows and self.columns:
+        if self._mustSort():
             sortOnIdx = self.columnIndexById.get(self.sortOn, 0)
             sortKeyGetter = getSortMethod(sortOnIdx)
             rows = sorted(self.rows, key=sortKeyGetter)

Modified: z3c.table/branches/lazyvalues2/src/z3c/table/tests.py
===================================================================
--- z3c.table/branches/lazyvalues2/src/z3c/table/tests.py	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/src/z3c/table/tests.py	2010-08-05 14:11:34 UTC (rev 115495)
@@ -18,7 +18,11 @@
 
 import unittest
 import doctest
+
+from zope.interface import Interface
+from zope.component import getSiteManager
 from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces.browser import IBrowserRequest
 
 import z3c.testing
 from z3c.batching.batch import Batch
@@ -27,6 +31,7 @@
 from z3c.table import table
 from z3c.table import column
 from z3c.table import batch
+from z3c.table import value
 
 
 class FakeContainer(object):
@@ -34,7 +39,10 @@
     def values(self):
         pass
 
+    def __len__(self):
+        return 0
 
+
 # table
 class TestTable(z3c.testing.InterfaceBaseTest):
 
@@ -63,9 +71,46 @@
         return table.SequenceTable
 
     def getTestPos(self):
-        return (None, TestRequest())
+        return ([], TestRequest())
 
 
+# values
+class TestValuesForContainer(z3c.testing.InterfaceBaseTest):
+
+    def setUp(test):
+        testing.setUpAdapters()
+
+    def getTestInterface(self):
+        return interfaces.IValues
+
+    def getTestClass(self):
+        return value.ValuesForContainer
+
+    def getTestPos(self):
+        container = FakeContainer()
+        request = TestRequest()
+        tableInstance = table.Table(container, request)
+        return (container, request, tableInstance)
+
+
+class TestValuesForSequence(z3c.testing.InterfaceBaseTest):
+
+    def setUp(test):
+        testing.setUpAdapters()
+
+    def getTestInterface(self):
+        return interfaces.IValues
+
+    def getTestClass(self):
+        return value.ValuesForSequence
+
+    def getTestPos(self):
+        container = FakeContainer()
+        request = TestRequest()
+        tableInstance = table.Table(container, request)
+        return (container, request, tableInstance)
+
+
 # column
 class TestColumn(z3c.testing.InterfaceBaseTest):
 
@@ -147,6 +192,80 @@
         return ({}, TestRequest(), t)
 
 
+class NumberColumn(column.Column):
+
+    weight = 10
+    header = u'Number'
+
+    def renderCell(self, item):
+        return item
+
+
+SORT_ON_ID = "table-number-1"
+
+
+def sortedValues(valuesAreSorted):
+
+    class SortedValues(value.ValuesForSequence):
+
+        sortOn = SORT_ON_ID
+        isSorted = valuesAreSorted
+
+    return SortedValues
+
+
+def withIValuesAdapter(klass):
+
+    def decorator(func):
+
+        def decorated(self):
+            self.sm.registerAdapter(klass,
+                (Interface, IBrowserRequest, interfaces.ISequenceTable),
+                interfaces.IValues)
+            func(self)
+            self.sm.unregisterAdapter(klass,
+                (Interface, IBrowserRequest, interfaces.ISequenceTable),
+                interfaces.IValues)
+        return decorated
+    return decorator
+
+
+class TestSortedValues(unittest.TestCase):
+
+    def setUp(self):
+        self.sm = sm = getSiteManager()
+        sm.registerAdapter(NumberColumn,
+            (None, None, interfaces.ITable),
+            interfaces.IColumn, name='number')
+
+    @withIValuesAdapter(sortedValues(True))
+    def testHasSortedValuesRightCriteria(self):
+        request = TestRequest(form={'table-sortOn': 'table-number-1'})
+        tableInstance = table.SequenceTable([1], request)
+        tableInstance.update()
+        self.failUnless(tableInstance.hasSortedValues)
+        self.assertEquals(tableInstance.valuesSortedOn, SORT_ON_ID)
+        self.failIf(tableInstance._mustSort())
+
+    @withIValuesAdapter(sortedValues(True))
+    def testHasSortedValuesWrongCriteria(self):
+        request = TestRequest(form={'table-sortOn': 'table-number-2'})
+        tableInstance = table.SequenceTable([1], request)
+        tableInstance.update()
+        self.failUnless(tableInstance.hasSortedValues)
+        self.assertNotEquals(tableInstance.sortOn, SORT_ON_ID)
+        self.assertEquals(tableInstance.valuesSortedOn, SORT_ON_ID)
+        self.failUnless(tableInstance._mustSort())
+
+    @withIValuesAdapter(sortedValues(False))
+    def testHasNoSortedValues(self):
+        request = TestRequest(form={'table-sortOn': 'table-number-2'})
+        tableInstance = table.SequenceTable([1], request)
+        tableInstance.update()
+        self.failIf(tableInstance.hasSortedValues)
+        self.failUnless(tableInstance._mustSort())
+
+
 def test_suite():
     return unittest.TestSuite((
         doctest.DocFileSuite('README.txt',
@@ -176,6 +295,9 @@
             ),
         unittest.makeSuite(TestTable),
         unittest.makeSuite(TestSequenceTable),
+        unittest.makeSuite(TestValuesForContainer),
+        unittest.makeSuite(TestValuesForSequence),
+        unittest.makeSuite(TestSortedValues),
         unittest.makeSuite(TestColumn),
         unittest.makeSuite(TestNoneCell),
         unittest.makeSuite(TestNameColumn),

Modified: z3c.table/branches/lazyvalues2/src/z3c/table/value.py
===================================================================
--- z3c.table/branches/lazyvalues2/src/z3c/table/value.py	2010-08-05 12:59:56 UTC (rev 115494)
+++ z3c.table/branches/lazyvalues2/src/z3c/table/value.py	2010-08-05 14:11:34 UTC (rev 115495)
@@ -18,6 +18,7 @@
 
 import zope.interface
 from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.schema.fieldproperty import FieldProperty
 
 from z3c.table import interfaces
 
@@ -27,12 +28,18 @@
 
     zope.interface.implements(interfaces.IValues)
 
+    isSorted = FieldProperty(interfaces.IValues['isSorted'])
+    sortOn = FieldProperty(interfaces.IValues['sortOn'])
+
     def __init__(self, context, request, table):
         self.context = context
         self.request = request
         self.table = table
 
+    def __len__(self):
+        return len(self.context)
 
+
 class ValuesForContainer(ValuesMixin):
     """Values from a simple IContainer."""
 



More information about the checkins mailing list