Work in progress: reporter.batch
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1217 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
3d9908f2d5
commit
7a09a7d9df
6 changed files with 229 additions and 9 deletions
|
@ -489,15 +489,26 @@ div.row div.label {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.row span.error {
|
div.error {
|
||||||
background: red;
|
background: #ff80a0;
|
||||||
color: white;
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
padding: 0.1em 0.5em 0.1em 0.5em; /* Same as .itemViews */
|
padding: 0.1em 0.5em 0.1em 0.5em; /* Same as .itemViews */
|
||||||
border: 1px solid red; /* Same as .itemViews */
|
border: 1px solid red; /* Same as .itemViews */
|
||||||
margin: 0;
|
margin: 0;
|
||||||
float: left;
|
float: left;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.summary {
|
||||||
|
background: #c8c4ff;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.1em 0.5em 0.1em 0.5em; /* Same as .itemViews */
|
||||||
|
border: 1px solid #6478b0; /* Same as .itemViews */
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
div.row div.error:before {
|
div.row div.error:before {
|
||||||
content: "\2190 "; /* Left pointing arrow */
|
content: "\2190 "; /* Left pointing arrow */
|
||||||
|
|
|
@ -12,15 +12,47 @@ TO DO...
|
||||||
A Basic API for Reports and Listings
|
A Basic API for Reports and Listings
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
|
Batching
|
||||||
|
--------
|
||||||
|
|
||||||
|
We'll use a fairly simple Iterable:
|
||||||
|
|
||||||
|
>>> it = xrange(14)
|
||||||
|
|
||||||
|
>>> from cybertools.reporter.batch import Batch
|
||||||
|
>>> b = Batch(it, size=5, overlap=1, orphan=2)
|
||||||
|
>>> b.items
|
||||||
|
[0, 1, 2, 3, 4]
|
||||||
|
>>> b.getIndexRelative(1)
|
||||||
|
1
|
||||||
|
>>> b.getIndexAbsolute(-1)
|
||||||
|
2
|
||||||
|
|
||||||
|
>>> b = Batch(it, 2, size=5, overlap=1, orphan=2)
|
||||||
|
>>> b.items
|
||||||
|
[8, 9, 10, 11, 12, 13]
|
||||||
|
|
||||||
|
We are now ready to use the corresponding browser view:
|
||||||
|
|
||||||
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
>>> form = dict(b_page=1, b_size=4)
|
||||||
|
>>> request = TestRequest(form=form)
|
||||||
|
>>> from cybertools.reporter.browser.batch import BatchView
|
||||||
|
>>> bview = BatchView(it, request)
|
||||||
|
|
||||||
|
The real reporting stuff
|
||||||
|
------------------------
|
||||||
|
|
||||||
>>> from cybertools.reporter.data import DataSource
|
>>> from cybertools.reporter.data import DataSource
|
||||||
>>> from cybertools.reporter.interfaces import IResultSet
|
>>> from cybertools.reporter.interfaces import IResultSet
|
||||||
|
|
||||||
|
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
|
||||||
|
>>> from cybertools.reporter.example.contact import Contacts
|
||||||
|
|
||||||
Let's start with the Person class from the example package - we will
|
Let's start with the Person class from the example package - we will
|
||||||
then provide a listing of persons...
|
then provide a listing of persons...
|
||||||
|
|
||||||
>>> from cybertools.organize.party import Person
|
>>> from cybertools.organize.party import Person
|
||||||
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
|
|
||||||
>>> from cybertools.reporter.example.contact import Contacts
|
|
||||||
|
|
||||||
>>> from datetime import date
|
>>> from datetime import date
|
||||||
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
|
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
|
||||||
|
@ -47,6 +79,4 @@ result set and splitting a result into batches.
|
||||||
Sorting
|
Sorting
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Batching
|
|
||||||
--------
|
|
||||||
|
|
||||||
|
|
78
reporter/batch.py
Normal file
78
reporter/batch.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Batching implementation.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
from zope.interface import implements
|
||||||
|
from interfaces import IBatch
|
||||||
|
|
||||||
|
|
||||||
|
class Batch(object):
|
||||||
|
|
||||||
|
lastPage = False
|
||||||
|
|
||||||
|
def __init__(self, iterable, pageIndex=0, size=20, overlap=0, orphan=0):
|
||||||
|
self.iterable = list(iterable)
|
||||||
|
self.pageIndex = pageIndex
|
||||||
|
self.start = pageIndex * (size - overlap)
|
||||||
|
self.size = self.actualSize = size
|
||||||
|
self.overlap = overlap
|
||||||
|
self.orphan = orphan
|
||||||
|
length = len(self.iterable)
|
||||||
|
self.pages = range(0, length, size-overlap)
|
||||||
|
lastPage = self.pages[-1]
|
||||||
|
lastLen = length - lastPage
|
||||||
|
if lastLen <= orphan + overlap:
|
||||||
|
del self.pages[-1]
|
||||||
|
if pageIndex == len(self.pages) - 1: #we're on the last page
|
||||||
|
self.actualSize = size + lastLen #take over the orphans
|
||||||
|
if pageIndex >= len(self.pages) or pageIndex < 0:
|
||||||
|
self.items = []
|
||||||
|
else:
|
||||||
|
self.items = self.iterable[self.start:self.start+self.actualSize]
|
||||||
|
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
return self.items[idx]
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
for item in self.items:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.items)
|
||||||
|
|
||||||
|
def getIndexRelative(self, ridx=1):
|
||||||
|
idx = self.pageIndex + ridx
|
||||||
|
if idx < 0:
|
||||||
|
return 0
|
||||||
|
if idx >= len(self.pages):
|
||||||
|
return len(self.pages) - 1
|
||||||
|
return idx
|
||||||
|
|
||||||
|
def getIndexAbsolute(self, idx=0):
|
||||||
|
if idx < 0:
|
||||||
|
idx = len(self.pages) + idx
|
||||||
|
if idx < 0 or idx >= len(self.pages):
|
||||||
|
return None
|
||||||
|
return idx
|
||||||
|
|
60
reporter/browser/batch.py
Normal file
60
reporter/browser/batch.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
A browser view class for batching to be used by a macro or some other
|
||||||
|
HTML providing template.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cybertools.reporter.batch import Batch
|
||||||
|
|
||||||
|
|
||||||
|
class BatchView(object):
|
||||||
|
|
||||||
|
def __init__(self, context, request):
|
||||||
|
self.context = context
|
||||||
|
self.request = request
|
||||||
|
form = request.form
|
||||||
|
page = int(form.get('b_page', 1))
|
||||||
|
size = int(form.get('b_size', 20))
|
||||||
|
overlap = int(form.get('b_overlap', 0))
|
||||||
|
orphan = int(form.get('b_orphan', 0))
|
||||||
|
self.batch = Batch(context, page-1, size, overlap, orphan)
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return setupUrlParams(self.batch.items)
|
||||||
|
|
||||||
|
def first(self):
|
||||||
|
return setupUrlParams(self.batch.getIndexAbsolute(0))
|
||||||
|
|
||||||
|
def last(self):
|
||||||
|
return setupUrlParams(self.batch.getIndexAbsolute(-1))
|
||||||
|
|
||||||
|
def previous(self):
|
||||||
|
return setupUrlParams(self.batch.getIndexRelative(1))
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return setupUrlParams(self.batch.getIndexRelative(-1))
|
||||||
|
|
||||||
|
def setupUrlParams(self, page):
|
||||||
|
return ('?b_page=%i&b_size=%i&b_overlap=%i&b_orphan=%i'
|
||||||
|
% (page, self.size, self.overlap, self.orphan) )
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,47 @@ import zope
|
||||||
from zope.interface import Interface, Attribute
|
from zope.interface import Interface, Attribute
|
||||||
|
|
||||||
|
|
||||||
# result set
|
# iterable stuff for batching, sorting, filtering of results
|
||||||
|
|
||||||
|
|
||||||
|
class IBatch(Interface):
|
||||||
|
""" Represents a part (sort of a slice) of an iterable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
iterable = Attribute(u'The iterable this batch belongs to')
|
||||||
|
|
||||||
|
start = Attribute(u'The current start index of the batch in the parent iterable')
|
||||||
|
|
||||||
|
def __getitem__(idx):
|
||||||
|
""" Return the item at index idx.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def next():
|
||||||
|
""" Return the next item in the batch. Raise StopIteration if
|
||||||
|
the end of the batch is reached.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __len__():
|
||||||
|
""" Return the number of items in the batch.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def getIndexRelative(relativePageNumber):
|
||||||
|
""" Return the absolute page index based on the current page of
|
||||||
|
the batch object.
|
||||||
|
Using +1 or -1 retrieves the next or previous batch.
|
||||||
|
If a page before the first one is addressed return 0,
|
||||||
|
if a page after the last one is addressed return the index
|
||||||
|
of the last page.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def getIndexAbsolute(pageNumber):
|
||||||
|
""" Return the absolute page index.
|
||||||
|
0 addresses the first batch page, -1 the last.
|
||||||
|
Return None if the corresponding page does not exist.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# result sets, rows, cells...
|
||||||
|
|
||||||
class IResultSet(Interface):
|
class IResultSet(Interface):
|
||||||
"""A sequence of rows provided by a data source, report or
|
"""A sequence of rows provided by a data source, report or
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
import unittest
|
import unittest, doctest
|
||||||
from zope.testing.doctestunit import DocFileSuite
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
from zope.app.testing import ztapi
|
from zope.app.testing import ztapi
|
||||||
from zope.interface.verify import verifyClass
|
from zope.interface.verify import verifyClass
|
||||||
|
@ -18,9 +18,10 @@ class TestReporter(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
return unittest.TestSuite((
|
return unittest.TestSuite((
|
||||||
unittest.makeSuite(TestReporter),
|
unittest.makeSuite(TestReporter),
|
||||||
DocFileSuite('README.txt'),
|
DocFileSuite('README.txt', optionflags=flags),
|
||||||
))
|
))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Add table
Reference in a new issue