I l@ve RuBoard Previous Section Next Section

C.10 Chapter 10

  1. Faking the Web. What you need to do is to create instances of a class that has the fieldnames attribute and appropriate instance variables. One possible solution is:

    class FormData:
        def __init__(self, dict):
            for k, v in dict.items():
                setattr(self, k, v)
    class FeedbackData(FormData):
        """ A FormData generated by the comment.html form. """
        fieldnames = ('name', 'address', 'email', 'type', 'text')
        def __repr__(self):
            return "%(type)s from %(name)s on %(time)s" % vars(self)
    
    fake_entries = [
        {'name': "John Doe",
         'address': '500 Main St., SF CA 94133',
         'email': 'john@sf.org',
         'type': 'comment',
         'text': 'Great toothpaste!'},
        {'name': "Suzy Doe",
         'address': '500 Main St., SF CA 94133',
         'email': 'suzy@sf.org',
         'type': 'complaint',
         'text': "It doesn't taste good when I kiss John!"},
        ]
    
    DIRECTORY = r'C:\complaintdir'
    if __name__ == '__main__':
        import tempfile, pickle, time
        tempfile.tempdir = DIRECTORY
        for fake_entry in fake_entries:
            data = FeedbackData(fake_entry)
            filename = tempfile.mktemp()
            data.time = time.asctime(time.localtime(time.time()))
            pickle.dump(data, open(filename, 'w'))

    As you can see, the only thing you really had to change was the way the constructor for FormData works, since it has to do the setting of attributes from a dictionary as opposed to a FieldStorage object.

  2. Cleaning up. There are many ways to deal with this problem. One easy one is to modify the formletter.py program to keep a list of the filenames that it has already processed (in a pickled file, of course!). This can be done by modifying the if __main__ == '__name__' test to read something like this (new lines are in bold):

    if __name__ == '__main__':
        import os, pickle
        CACHEFILE = 'C:\cache.pik'
        from feedback import DIRECTORY#, FormData, FeedbackData
        if os.path.exists(CACHEFILE):
            processed_files = pickle.load(open(CACHEFILE))
        else:
            processed_files = []
        for filename in os.listdir(DIRECTORY):
            if filename in processed_files: continue  # skip this filename
            processed_files.append(filename)
            data = pickle.load(open(os.path.join(DIRECTORY, filename)))
            if data.type == 'complaint':
                print "Printing letter for %(name)s." % vars(data)
                print_formletter(data)
            else:
                print "Got comment from %(name)s, skipping printing." % \
                      vars(data)
        pickle.dump(processed_file, open(CACHEFILE, 'w')

    As you can tell, you simply load a list of the previous filenames if it exists (and use an empty list otherwise) and compare the filenames with entries in the list to determine which to skip. If you don't skip one, it needs to be added to the list. Finally, at program exit, pickle the new list.

  3. Adding parametric plotting to grapher.py. This exercise is quite simple, as all that's needed is to change the drawing code in the Chart class. Specifically, the code between xmin, xmax = 0, N-1 and graphics.fillPolygon(...) should be placed in an if test, so that the new code reads:

    if not hasattr(self.data[0], '__len__'):   # it's probably a number (1D)
           xmin, xmax = 0, N-1
                                            # code from existing program, up to
           graphics.fillPolygon(xs, ys, len(xs))
    elif len(self.data[0]) == 2:               # we'll only deal with 2-D
           xmin = reduce(min, map(lambda d: d[0], self.data))
           xmax = reduce(max, map(lambda d: d[0], self.data))
    
           ymin = reduce(min, map(lambda d: d[1], self.data))
           ymax = reduce(max, map(lambda d: d[1], self.data))
    
           zero_y = y_offset - int(-ymin/(ymax-ymin)*height)
           zero_x = x_offset + int(-xmin/(xmax-xmin)*width)
    
           for i in range(N):
               xs[i] = x_offset + int((self.data[i][0]-xmin)/(xmax-xmin)*width)
               ys[i] = y_offset - int((self.data[i][1]-ymin)/(ymax-ymin)*height)
           graphics.color = self.color
           if self.style == "Line":
               graphics.drawPolyline(xs, ys, len(xs))
           else:
               xs.append(xs[0]); ys.append(ys[0])
               graphics.fillPolygon(xs, ys, len(xs))
I l@ve RuBoard Previous Section Next Section