Permalink
Cannot retrieve contributors at this time
Fetching contributors…

MondoReport Documentation | |
Version 0.01 alpha 24-Nov-2001. iron@mso.oz.net or mso@oz.net. | |
Copyright (c) 2001 Mike Orr. License: same as Python or Cheetah. | |
* * * * * | |
STATUS: previous/next batches and query string are not implemented yet. | |
Sorting not designed yet. Considering "click on this column header to sort by | |
this field" and multiple ascending/descending sort fields for a future version. | |
Tested with Python 2.2b1. May work with Python 2.1 or 2.0. | |
* * * * * | |
OVERVIEW | |
MondoReport -- provide information about a list that is useful in generating | |
any kind of report. The module consists of one main public class, and some | |
generic functions you may find useful in other programs. This file contains an | |
overview, syntax reference and examples. The module is designed both for | |
standalone use and for integration with the Cheetah template system | |
(http://www.cheetahtemplate.org/), so the examples are in both Python and | |
Cheetah. The main uses of MondoReport are: | |
(A) to iterate through a list. In this sense MR is a for-loop enhancer, | |
providing information that would be verbose to calculate otherwise. | |
(B) to separate a list into equal-size "pages" (or "batches"--the two terms are | |
interchangeable) and only display the current page, plus limited information | |
about the previous and next pages. | |
(C) to extract summary statistics about a certain column ("field") in the list. | |
* * * * * | |
MAIN PUBLIC CLASS | |
To create a MondoReport instance, supply a list to operate on. | |
mr = MondoReport(origList) | |
The list may be a list of anything, but if you use the 'field' argument in any | |
of the methods below, the elements must be instances or dictionaries. | |
MondoReport assumes it's operating on an unchanging list. Do not modify the | |
list or any of its elements until you are completely finished with the | |
ModoReport object and its sub-objects. Otherwise, you may get an exception or | |
incorrect results. | |
MondoReport instances have three methods: | |
.page(size, start, overlap=0, orphan=0 | |
sort=None, reverse=False) => list of (r, a, b). | |
'size' is an integer >= 1. 'start', 'overlap' and 'orphan' are integers >= 0. | |
The list returned contains one triple for each record in the current page. 'r' | |
is the original record. 'a' is a BatchRecord instance for the current record | |
in relation to all records in the origList. 'b' is a BatchRecord instance for | |
the current record in relation to all the records in that batch/page. (There | |
is a .batch method that's identical to .page.) | |
The other options aren't implemented yet, but 'overlap' duplicates this many | |
records on adjacent batches. 'orphan' moves this many records or fewer, if | |
they are on a page alone, onto the neighboring page. 'sort' (string) specifies | |
a field to sort the records by. It may be suffixed by ":desc" to sort in | |
descending order. 'reverse' (boolean) reverses the sort order. If both | |
":desc" and 'reverse' are specified, they will cancel each other out. This | |
sorting/reversal happens on a copy of the origList, and all objects returned | |
by this method use the sorted list, except when resorting the next time. | |
To do more complicated sorting, such as a hierarchy of columns, do it to the | |
original list before creating the ModoReport object. | |
.all(sort=None, reverse=False) => list of (r, a). | |
Same, but the current page spans the entire origList. | |
.summary() => Summary instance. | |
Summary statistics for the entire origList. | |
In Python, use .page or .all in a for loop: | |
from Cheetah.Tools.MondoReport import MondoReport | |
mr = MondoReport(myList) | |
for r, a, b in mr.page(20, 40): | |
# Do something with r, a and b. The current page is the third page, | |
# with twenty records corresponding to origList[40:60]. | |
if not myList: | |
# Warn the user there are no records in the list. | |
It works the same way in Cheetah, just convert to Cheetah syntax. This example | |
assumes the template doubles as a Webware servlet, so we use the servlet's | |
'$request' method to look up the CGI parameter 'start'. The default value is 0 | |
for the first page. | |
#from Cheetah.Tools.MondoReport import MondoReport | |
#set $mr = $MondoReport($bigList) | |
#set $start = $request.field("start", 0) | |
#for $o, $a, $b in $mr.page(20, $start) | |
... do something with $o, $a and $b ... | |
#end for | |
#unless $bigList | |
This is displayed if the original list has no elements. | |
It's equivalent to the "else" part Zope DTML's <dtml-in>. | |
#end unless | |
* * * * * | |
USING 'r' RECORDS | |
Use 'r' just as you would the original element. For instance: | |
print r.attribute # If r is an instance. | |
print r['key'] # If r is a dictionary. | |
print r # If r is numeric or a string. | |
In Cheetah, you can take advantage of Universal Dotted Notation and autocalling: | |
$r.name ## 'name' may be an attribute or key of 'r'. If 'r' and/or | |
## 'name' is a function or method, it will be called without | |
## arguments. | |
$r.attribute | |
$r['key'] | |
$r | |
$r().attribute()['key']() | |
If origList is a list of name/value pairs (2-tuples or 2-lists), you may | |
prefer to do this: | |
for (key, value), a, b in mr.page(20, 40): | |
print key, "=>", value | |
#for ($key, $value), $a, $b in $mr.page(20, $start) | |
$key => $value | |
#end for | |
* * * * * | |
STATISTICS METHODS AND FIELD VALUES | |
Certain methods below have an optional argument 'field'. If specified, | |
MondoReport will look up that field in each affected record and use its value | |
in the calculation. MondoReport uses Cheetah's NameMapper if available, | |
otherwise it uses a minimal NameMapper substitute that looks for an attribute | |
or dictionary key called "field". You'll get an exception if any record is a | |
type without attributes or keys, or if one or more records is missing that | |
attribute/key. | |
If 'field' is None, MondoReport will use the entire record in its | |
calculation. This makes sense mainly if the records are a numeric type. | |
All statistics methods filter out None values from their calculations, and | |
reduce the number of records accordingly. Most filter out non-numeric fields | |
(or records). Some raise NegativeError if a numeric field (or record) is | |
negative. | |
* * * * * | |
BatchRecord METHODS | |
The 'a' and 'b' objects of MondoReport.page() and MondoReport.all() provide | |
these methods. | |
.index() | |
The current subscript. For 'a', this is the true subscript into origList. | |
For 'b', this is relative to the current page, so the first record will be 0. | |
Hint: In Cheetah, use autocalling to skip the parentheses: '$b.index'. | |
.number() | |
The record's position starting from 1. This is always '.index() + 1'. | |
.Letter() | |
The letter ("A", "B", "C") corresponding to .number(). Undefined if .number() | |
> 26. The current implementation just adds the offset to 'a' and returns | |
whatever character it happens to be. | |
To make a less dumb implementation (e.g., "Z, AA, BB" or "Z, A1, B1"): | |
1) Subclass BatchRecord and override the .Letter method. | |
2) Subclass MondoReport and set the class variable .BatchRecordClass to your | |
new improved class. | |
.letter() | |
Same but lower case. | |
.Roman() | |
The Roman numeral corresponding to .number(). | |
.roman() | |
Same but lower case. | |
.even() | |
True if .number() is even. | |
.odd() | |
True if .number() is odd. | |
.even_i() | |
True if .index() is even. | |
.odd_i() | |
True if .index() is odd. | |
.length() | |
For 'a', number of records in origList. For 'b', number of records on this | |
page. | |
.item() | |
The record itself. You don't need this in the normal case since it's the same | |
as 'r', but it's useful for previous/next batches. | |
.size() | |
The 'size' argument used when this BatchRecord was created. | |
'a.size() == b.size()'. | |
.first() | |
True if this is the first record. | |
.last() | |
True if this is the last record. | |
.firstValue(field=None) | |
True if there is no previous record, or if the previous field/record has a | |
different value. Used for to print section headers. For instance, if you | |
are printing addresses by country, this will be true at the first occurrance | |
of each country. Or for indexes, you can have a non-printing field showing | |
which letter of the alphablet this entry starts with, and then print a "B" | |
header before printing the first record starting with "B". | |
.lastValue(field=None) | |
True if this is the last record containing the current value in the | |
field/record. | |
.percentOfTotal(field=None, suffix="%", default="N/A", decimals=2) | |
Returns the percent that the current field/record is of all fields/records. | |
If 'suffix' is None, returns a number; otherwise it returns a string with | |
'suffix' suffixed. If the current value is non-numeric, returns 'default' | |
instead (without 'suffix'). 'decimals' tells the number of decimal places to | |
return; if 0, there will be no decimal point. | |
.prev() | |
Returns a PrevNextBatch instance for the previous page. If there is no | |
previous page, returns None. [Not implemented yet.] | |
.next() | |
Returns a PrevNextBatch instance for the next page. If there is no next page, | |
returns None. [Not implemented yet.] | |
.prevPages() | |
Returns a list of PrevNextPage instances for every previous page, or [] if no | |
previous pages. [Not implemented yet.] | |
.nextPages() | |
Returns a list of PrevNextPage instances for every next page, or [] if no next | |
pages. [Not implemented yet.] | |
.query(start=None, label=None, attribName="start", attribs=[]) | |
[Not implemented yet.] | |
With no arguments, returns the HTML query string with start value removed (so | |
you can append a new start value in your hyperlink). The query string is taken | |
from the 'QUERY_STRING' environmental variable, or "" if missing. (This is | |
Webware compatible.) | |
With 'start' (an integer >= 0), returns the query string with an updated start | |
value, normally for the next or previous batch. | |
With 'label' (a string), returns a complete HTML hyperlink: | |
'<A HREF="?new_query_string">label</A>'. You'll get a TypeError if you specify | |
'label' but not 'start'. | |
With 'attribName' (a string), uses this attribute name rather than "start". | |
Useful if you have another CGI parameter "start" that's used for something | |
else. | |
With 'attribs' (a dictionary), adds these attributes to the hyperlink. | |
For instance, 'attribs={"target": "_blank"}'. Ignored unless 'label' is | |
specified too. | |
This method assumes the start parameter is a GET variable, not a POST variable. | |
.summary() | |
Returns a Summary instance. 'a.summary()' refers to all records in the | |
origList, so it's the same as MondoReport.summary(). 'b.summary()' refers only | |
to the records on the current page. [Not implemented yet.] | |
* * * * * | |
PrevNextPage INSTANCES | |
[Not implemented yet.] | |
PrevNextPage instances have the following methods: | |
.start() | |
The index (true index of origList) that that page starts at. You may also use | |
'.start().index()', '.start().number()', etc. Also | |
'.start().item(field=None)'. (Oh, so *that*'s what .item is for!) | |
.end() | |
The index (true index of origList) that that page ends at. You may also use | |
'.end().index()', '.end().number()', etc. Also | |
'.end().item(field=None)'. | |
.length() | |
Number of records on that page. | |
.query(label=None, attribName="start", attribs={}, before="", after="") | |
[Not implemented yet.] | |
Similar to 'a.query()' and 'b.query()', but automatically calculates the start | |
value for the appropriate page. | |
For fancy HTML formatting, 'before' is prepended to the returned text and | |
'after' is appended. (There was an argument 'else_' for if there is no such | |
batch, but it was removed because you can't even get to this method at all in | |
that case.) | |
* * * * * * | |
SUMMARY STATISTICS | |
These methods are supported by the Summary instances returned by | |
MondoReport.Summary(): | |
.sum(field=None) | |
Sum of all numeric values in a field, or sum of all records. | |
.total(field=None) | |
Same. | |
.count(field=None) | |
Number of fields/records with non-None values. | |
.min(field=None) | |
Minimum value in that field/record. Ignores None values. | |
.max(field=None) | |
Maximum value in that field/record. Ignores None values. | |
.mean(field=None) | |
The mean (=average) of all numeric values in that field/record. | |
.average(field=None) | |
Same. | |
.median(field=None) | |
The median of all numeric values in that field/record. This is done by sorting | |
the values and taking the middle value. | |
.variance(field=None), .variance_n(field=None) | |
.standardDeviation(field=None), .standardDeviation_n(field=None) | |
[Not implemented yet.] | |
* * * * * | |
To run the regression tests (requires unittest.py, which is standard with | |
Python 2.2), run MondoReportTest.py from the command line. The regression test | |
double as usage examples. | |
# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79 |