All computer source code presented on this page, unless it includes attribution to another author, is provided by Ed Halley under the Artistic License. Use such code freely and without any expectation of support. I would like to know if you make anything cool with the code, or need questions answered.
python/
    bindings.py
    boards.py
    buzz.py
    cache.py
    cards.py
    constraints.py
    english.py
    getopts.py
    gizmos.py
    goals.py
    improv.py
    interpolations.py
    namespaces.py
    nihongo.py
    nodes.py
    octalplus.py
    patterns.py
    persist.py
    physics.py
    pieces.py
    quizzes.py
    recipes.py
    relays.py
    romaji.py
    ropen.py
    sheets.py
    strokes.py
    subscriptions.py
    svgbuild.py
    testing.py
    things.py
    timing.py
    ucsv.py
    useful.py
    uuid.py
    vectors.py
    weighted.py
java/
    GlobFilenameFilter.java
    RegexFilenameFilter.java
    StringBufferOutputStream.java
    ThreadSet.java
    TracingThread.java
    Utf8ConsoleTest.java
perl/
    CVQM.pm
    Kana.pm
    Typo.pm
cxx/
    CCache.h
    equalish.cpp
# -*- python -*-

'''

sheets - Generic spreadsheet-like data, a list of rows with named columns.

This module works with basic tabular data, such as found in CSV files.
We assume the first non-comment line consists of column header names, and
that all other columns are of equal width.  Each bit of data is converted
to a number if it appears to be numeric.

The data structure can be accessed like a list, in which case the rows
will be returned as dicts with the column headers as keys.  Either a
plain row or a similar dict can be assigned to a row, and the necessary
conversions happen internally.

SYNOPSIS

    >>> import sheets

    >>> sheet = Sheet('GOOG.csv')
    >>> print sheet.headers
        ['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']

    >>> sheet.sort(key='Date')
    >>> print sheet[0]              # (day of google ipo)
        { 'Date': '2004-08-19',
          'Open': 100.0,
          'High': 104.06,
          'Low': 95.96,
          'Close': 100.34,
          'Volume': 22351900,
          'Adj Close': 100.34 }

AUTHOR

    Ed Halley (ed@halley.cc) 24 January 2010

'''

#----------------------------------------------------------------------------

import os
import csv
import recipes

class Sheet (object):
    '''A list of rows, with named columns, such as from a .csv file.'''

    def __init__(self, file=None):
        self.filename = None
        self.columns = []
        self.headers = []
        self.points = []
        self.cursor = -1
        self.load(file)

    def load(self, file):
        self.file = file
        if isinstance(file, (str, unicode)):
            if os.path.exists(file):
                self.filename = file
                self.file = file = open(file, 'r')
        if (file):
            self.loadCsv(file)

    def loadCsv(self, file):
        c = csv.reader(file)
        self.headers = h = c.next()
        self.columns = dict( (h[k],k) for k in range(len(h)) )
        for row in c:
            row = map(recipes.num, row)
            self.points.append(row)
        return len(self.points)

    def __len__(self):
        return len(self.points)

    def __getitem__(self, index):
        return dict(zip(self.headers, self.points[index]))

    def __setitem__(self, index, row):
        if isinstance(row, dict):
            row = [ row[h] for h in self.headers ]
        if isinstance(row, (tuple, list)) and len(row) == len(self.headers):
            self.points[index] = list(row)
            return
        raise TypeError, 'given row value does not match sheet headers'

    def next(self):
        if self.cursor < 0: self.cursor = -1
        self.cursor += 1
        if self.cursor >= len(self.points):
            return None
        return self[self.cursor]

    def prev(self):
        if self.cursor >= len(self.points): self.cursor = len(self.points)
        self.cursor -= 1
        if self.cursor < 0:
            return None
        return self[self.cursor]

    def find(self, key, value, start=0):
        for i in range(start, len(self.points)):
            point = self[i]
            if point[key] == value:
                return point
        return None

    def sort(self, cmp=None, key=None, reverse=False):
        if key in self.headers:
            name = key
            key = lambda x: x[self.columns[name]]
        self.points.sort(cmp=cmp, key=key, reverse=reverse)

    def csv(self, point):
        if isinstance(point, int):
            point = self.points[point]
        if isinstance(point, dict):
            point = [ point[h] for h in self.headers ]
        return ','.join([ str(x) for x in point ])

#----------------------------------------------------------------------------

def __test__():
    from testing import __ok__
    __ok__(True)

if __name__ == '__main__':
    from testing import __report__
    __test__()
    __report__()


Contact Ed Halley by email at ed@halley.cc.
Text, code, layout and artwork are Copyright © 1996-2008 Ed Halley.
Copying in whole or in part, with author attribution, is expressly allowed.
Any references to trademarks are illustrative and are controlled by their respective owners.
Make donations with PayPal - it's fast, free and secure!