Welcome, guest | Sign In | My Account | Store | Cart

If you prefer to write reports based on sorted by fields records manually rather than using automatic report generators, then this recipe can help you by concentrating on the writing of record details, headers and footers. No output page control is included however in this simple example. The code is based on a finite state machine.

Python, 114 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
title        control-break example
author       Ernesto P. Adorio
description  Control break implementation example using finite state machine.
             Actual report formatting to be provided by Python programmer.
"""

# control-break example on branch and salesman sample records.
records = [("branch1",  "sales1", 100),
           ("branch1",  "sales1", 50),
           ("branch1",  "sales2", 10),
           ("branch2",  "sales1", 104),
           ("branch2",  "sales2", 56),
           ("branch2",  "sales2", 156)]

totrecords = len(records)
maxlevels  = 3  # 2 (counting branch and salesman) + 1
EOF        = False

nrecord    = 0
total      = [0] * (maxlevels+1)
oldfields  = [0] * (maxlevels) 
newfields  = [0] * (maxlevels)


def getrecord():
    """
    Rewrite this for specific applications. Must set EOF to True
    if there are no more records.
    """
    global nrecord, totrecords, EOF
    
    nrecord = nrecord + 1
    if nrecord > totrecords:
        EOF = True
        return ()
    return records[nrecord-1]

def header(level):
    print
    print "\t" * level,
    if (level == 0) :
        print "Header Company reports."
    elif level == 1:
        print "Header Branch ", oldfields[level-1] 
    elif level == 2:
        print "Header Salesman ", oldfields[level-1]

def footer(level):
    global total

    print "\t" * level,
    if level == 0:
        print "Footer Company total ", total[level]
    elif level == 1:
        print "Footer Branch total ",  total[level]
    elif level == 2:
        print "Footer Salesman total", total[level]
    print

def detail(level, record, total):
    # Detail line. Shows records and arrays of totals.
    print "\t" * level, record, "total = ", total


# Finite state machine.
def state1(level):
    global total, oldfields, newfields, maxlevels

    if level == maxlevels:
        total[level] = newfields[2]
        detail(level, newfields, total)
        oldfields    = newfields
        newfields    = getrecord()        
        level        = level -1
        state3(level)
    else:
        total[level] = 0
        oldfields     = newfields
        header(level)
        state2(level)

def state2(level):
    global oldfields, newfields
    
    if (not EOF):
        # Compare record fields.
        if oldfields[0:level] != newfields[0:level]:
            state4(level)
        else:
            level += 1
            state1(level)
    else:
        state4(level)

def state3(level):
    global total
    
    total[level] += total[level+1]
    total[level+1] = 0
    state2(level)

def state4(level):
    global total

    footer(level)
    if level > 0:
        level = level - 1
        state3(level)


# Test.
newfields = getrecord()
state1(0)

This code is to enable the Python programmer to modify only the detail, header, and footer routines. The actual FSM is independent of the number of control-break levels.

Created by Ernesto Adorio on Mon, 6 Feb 2006 (PSF)
Python recipes (4591)
Ernesto Adorio's recipes (9)

Required Modules

  • (none specified)

Other Information and Tasks