/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/table.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/table.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 806 by jan, Fri May 2 16:43:59 2003 UTC revision 998 by bh, Thu May 22 19:29:39 2003 UTC
# Line 12  Classes for handling tables of data. Line 12  Classes for handling tables of data.
12    
13  __version__ = "$Revision$"  __version__ = "$Revision$"
14    
15    import os
16    import inspect
17    import warnings
18    
19  import dbflib  import dbflib
20    
21  # the field types supported by a Table instance.  # the field types supported by a Table instance.
# Line 25  dbflib_fieldtypes = {dbflib.FTString: FI Line 29  dbflib_fieldtypes = {dbflib.FTString: FI
29                       dbflib.FTInteger: FIELDTYPE_INT,                       dbflib.FTInteger: FIELDTYPE_INT,
30                       dbflib.FTDouble: FIELDTYPE_DOUBLE}                       dbflib.FTDouble: FIELDTYPE_DOUBLE}
31    
 class MemoryTable:  
32    
33      """Quite simple table implementation that operates on a list of tuples.  class OldTableInterfaceMixin:
     All of the data are kept in the memory."""  
34    
35      def __init__(self, fields, data):      """Mixin to implement the old table interface using the new one"""
         """Initialize the MemoryTable  
36    
37          Parameters:      def __deprecation_warning(self):
38          fields -- List of (name, field_type) pairs          """Issue a DeprecationWarning for code hat uses the old interface"""
39          data -- List of tuples, one for each row of data          callername = inspect.currentframe().f_back.f_code.co_name
40          """          warnings.warn("The %s method of the old table interface"
41          self.fields = fields                        " is deprecated" % callername,
42          self.data = data                        DeprecationWarning, stacklevel = 3)
43    
44        def record_count(self):
45            self.__deprecation_warning()
46            return self.NumRows()
47    
48      def field_count(self):      def field_count(self):
49          return len(self.fields)          self.__deprecation_warning()
50            return self.NumColumns()
51    
52      def field_info(self, index):      def field_info(self, field):
53          name, type = self.fields[index]          """Return a tuple (type, name, width, prec) for the field no. field
         return (type, name)  
54    
55      def record_count(self):          type is the data type of the field, name the name, width the
56          return len(self.data)          field width in characters and prec the decimal precision. width
57            and prec will be zero if the information returned by the Column
58            method doesn't provide values for them.
59            """
60            self.__deprecation_warning()
61            col = self.Column(field)
62            return (col.type, col.name,
63                   getattr(col, "width", 0), getattr(col, "prec", 0))
64    
65        def field_info_by_name(self, col):
66            self.__deprecation_warning()
67            try:
68                return self.field_info(col)
69            except KeyError:
70                # FIXME: It may be that field_info raises other exceptions
71                # when the name is not a valid column name.
72                return None
73    
74        def field_range(self, fieldName):
75            self.__deprecation_warning()
76            min, max = self.ValueRange(fieldName)
77            return ((min, None), (max, None))
78    
79        def GetUniqueValues(self, field):
80            self.__deprecation_warning()
81            return self.UniqueValues(field)
82    
83        def read_record(self, r):
84            self.__deprecation_warning()
85            return self.ReadRowAsDict(r)
86    
     def read_record(self, index):  
         return dict([(self.fields[i][0], self.data[index][i])  
                       for i in range(len(self.fields))])  
87    
     def write_record(self, record, values):  
         # TODO: Check for correct lenght and perhaps also  
         # for correct types in case values is a tuple. How to report problems?  
         # TODO: Allow values to be a dictionary and write the single  
         # fields that are specified.  
         self.data[record] = values  
88    
89    class DBFColumn:
90    
91  class DBFTable:      """Description of a column in a DBFTable
92    
93        Instances have the following public attributes:
94    
95        name -- Name of the column
96        type -- Type of the column (one of FIELDTYPE_STRING, FIELDTYPE_INT or\
97                FIELDTYPE_DOUBLE)
98        index -- The index of the column
99        width -- the width of the data in the column
100        prec -- The precision of the data (only valid for type == FIELDTYPE_DOUBLE)
101        """
102    
103        def __init__(self, name, type, width, prec, index):
104            self.name = name
105            self.type = type
106            self.width = width
107            self.prec = prec
108            self.index = index
109    
110    
111    class DBFTable(OldTableInterfaceMixin):
112    
113      """      """
114      Table interface for the data in a DBF file      Table interface for the data in a DBF file
# Line 89  class DBFTable: Line 135  class DBFTable:
135          # If true, self.dbf is open for writing.          # If true, self.dbf is open for writing.
136          self._writable = 0          self._writable = 0
137    
138      def Destroy(self):          # Create the column information objects
139          self.dbf.close()          self.columns = []
140          self.dbf = None          self.column_map = {}
141            for i in range(self.NumColumns()):
142                ftype, name, width, prec = self.dbf.field_info(i)
143                ftype = dbflib_fieldtypes[ftype]
144                index = len(self.columns)
145                col = DBFColumn(name, ftype, width, prec, index)
146                self.columns.append(col)
147                self.column_map[name] = col
148                self.column_map[index] = col
149    
150      def record_count(self):      def Title(self):
151          """Return the number of records"""          """Return the title of the table.
152    
153            The title is simply the basename of the filename
154            """
155            return os.path.basename(self.filename)
156    
157        def NumRows(self):
158            """Return the number of rows in the table"""
159          return self.dbf.record_count()          return self.dbf.record_count()
160    
161      def field_count(self):      def NumColumns(self):
162          """Return the number of fields in a record"""          """Return the number of columns in the table"""
163          return self.dbf.field_count()          return self.dbf.field_count()
164    
165      def field_info(self, field):      def Columns(self):
166          """Return a tuple (type, name, width, prec) for the field no. field          """Return the table's colum definitions
167    
168          type is the data type of the field, name the name, width the          The return value is a sequence of DBFColumn instances, one for
169          field width in characters and prec the decimal precision.          each column.
170          """          """
171          type, name, width, prec = self.dbf.field_info(field)          return self.columns
         type = dbflib_fieldtypes[type]  
         return type, name, width, prec  
   
     def field_info_by_name(self, fieldName):  
         count = self.field_count()  
172    
173          for i in range(count):      def Column(self, col):
174              info = self.field_info(i)          """Return information about the column given by its name or index
             if info[1] == fieldName:  
                 return info  
175    
176          return None          The returned object is an instance of DBFColumn
177            """
178      def field_range(self, fieldName):          return self.column_map[col]
         """Finds the first occurences of the minimum and maximum values  
         in the table for the given field.  
179    
180          This assumes that the standard comparison operators (<, >, etc.)      def HasColumn(self, col):
181          will work for the given data.          """Return whether the table has a column with the given name or index
182            """
183            return self.column_map.has_key(col)
184    
185          Returns a tuple ((min, rec), (max, rec)) where:      def ReadRowAsDict(self, row):
186              min is the minimum value          """Return the entire row as a dictionary with column names as keys"""
187              max is the maximum value          return self.dbf.read_record(row)
             rec is the record number where the value was found. One  
                 should check that the record number of min is not  
                 the same as the record number of max.  
188    
189          Returns None if there are no records      def ReadValue(self, row, col):
190            """Return the value of the specified row and column
191    
192            The col parameter may be the index of the column or its name.
193          """          """
194            return self.dbf.read_record(row)[self.column_map[col].name]
195    
196        def ValueRange(self, col):
197            """Return the minimum and maximum values of the values in the column
198    
199          count = self.record_count()          The return value is a tuple (min, max) unless the table is empty
200            in which case the return value is None.
201            """
202            count = self.NumRows()
203    
204          if count == 0:          if count == 0:
205              return None              return None
206    
207          rec = self.read_record(0)          min = max = self.ReadValue(0, col)
   
         min = rec[fieldName]  
         min_rec = 0  
   
         max = rec[fieldName]  
         max_rec = 0  
   
208          for i in range(1, count):          for i in range(1, count):
209              rec = self.read_record(i)              value = self.ReadValue(i, col)
210              data = rec[fieldName]              if value < min:
211                    min = value
212                elif value > max:
213                    max = value
214    
215              if data < min:          return (min, max)
                 min = data  
                 min_rec = rec  
             elif data > max:  
                 max = data  
                 max_rec = rec  
   
         return ((min, min_rec), (max, max_rec))  
   
     def GetUniqueValues(self, fieldName):  
         """Return a list of all unique entries in the table for the given  
         field name.  
         """  
216    
217        def UniqueValues(self, col):
218            """Return a sorted list of all unique values in the column col"""
219          dict = {}          dict = {}
220    
221          for i in range(0, self.record_count()):          for i in range(self.NumRows()):
222              rec = self.read_record(i)              value = self.ReadValue(i, col)
223              data = rec[fieldName]              dict[value] = 0
224    
225            values = dict.keys()
226            values.sort()
227            return values
228    
229        def Dependencies(self):
230            """Return an empty sequence. The DBFTable doesn't depend on anything"""
231            return ()
232    
233              if not dict.has_key(data):      # DBF specific interface parts.
                 dict[data] = 0  
234    
235          return dict.keys()      def Destroy(self):
236            self.dbf.close()
237      def read_record(self, record):          self.dbf = None
         """Return the record no. record as a dict mapping field names to values  
         """  
         return self.dbf.read_record(record)  
238    
239      def write_record(self, record, values):      def write_record(self, record, values):
240          """Write the values into the record          """Write the values into the record
# Line 208  class DBFTable: Line 257  class DBFTable:
257          self.dbf.write_record(record, values)          self.dbf.write_record(record, values)
258          self.dbf.commit()          self.dbf.commit()
259    
260        def FileName(self):
261            """Return the filename the DBFTable was instantiated with"""
262            return self.filename
263    
264    
265    class MemoryColumn:
266    
267        def __init__(self, name, type, index):
268            self.name = name
269            self.type = type
270            self.index = index
271    
272    class MemoryTable(OldTableInterfaceMixin):
273    
274        """Very simple table implementation that operates on a list of tuples"""
275    
276        def __init__(self, fields, data):
277            """Initialize the MemoryTable
278    
279            Parameters:
280            fields -- List of (name, field_type) pairs
281            data -- List of tuples, one for each row of data
282            """
283            self.data = data
284    
285            # Create the column information objects
286            self.columns = []
287            self.column_map = {}
288            for name, ftype in fields:
289                index = len(self.columns)
290                col = MemoryColumn(name, ftype, index)
291                self.columns.append(col)
292                self.column_map[name] = col
293                self.column_map[index] = col
294    
295        def Title(self):
296            """Return 'MemoryTable'
297    
298            Override in derived classes to have a more meaningful title.
299            """
300            return "MemoryTable"
301    
302        def NumColumns(self):
303            """Return the number of columns in the table"""
304            return len(self.columns)
305    
306        def Column(self, col):
307            """Return information about the column given by its name or index
308    
309            The returned object is an instance of MemoryColumn.
310            """
311            return self.column_map[col]
312    
313        def Columns(self):
314            """Return the table's colum definitions
315    
316            The return value is a sequence of MemoryColumn instances, one
317            for each column.
318            """
319            return self.columns
320    
321        def HasColumn(self, col):
322            """Return whether the table has a column with the given name or index
323            """
324            return self.column_map.has_key(col)
325    
326        def NumRows(self):
327            """Return the number of rows in the table"""
328            return len(self.data)
329    
330        def ReadValue(self, row, col):
331            """Return the value of the specified row and column
332    
333            The col parameter may be the index of the column or its name.
334            """
335            return self.data[row][self.column_map[col].index]
336    
337        def ReadRowAsDict(self, index):
338            """Return the entire row as a dictionary with column names as keys"""
339            return dict([(col.name, self.data[index][col.index])
340                          for col in self.columns])
341    
342        def ValueRange(self, col):
343            """Return the minimum and maximum values of the values in the column
344    
345  # Temporary backwards compatibility          The return value is a tuple (min, max) unless the table is empty
346  Table = DBFTable          in which case the return value is None.
347            """
348    
349            index = self.column_map[col].index
350            values = [row[index] for row in self.data]
351            if not values:
352                return None
353    
354            return min(values), max(values)
355    
356        def UniqueValues(self, col):
357            """Return a sorted list of all unique values in the column col"""
358            dict = {}
359    
360            for i in range(self.NumRows()):
361                value = self.ReadValue(i, col)
362                dict[value] = 0
363    
364            values = dict.keys()
365            values.sort()
366            return values
367    
368        def Dependencies(self):
369            """Return an empty sequence. The MemoryTable doesn't depend on anything
370            """
371            return ()
372    
373        def write_record(self, record, values):
374            # TODO: Check for correct lenght and perhaps also
375            # for correct types in case values is a tuple. How to report problems?
376            # TODO: Allow values to be a dictionary and write the single
377            # fields that are specified.
378            self.data[record] = values

Legend:
Removed from v.806  
changed lines
  Added in v.998

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26