/[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 590 by bh, Wed Apr 2 15:03:19 2003 UTC revision 998 by bh, Thu May 22 19:29:39 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4    # Jan-Oliver Wagner <[email protected]>
5  #  #
6  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
7  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 11  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 24  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 Table:  
32    
33    class OldTableInterfaceMixin:
34    
35        """Mixin to implement the old table interface using the new one"""
36    
37        def __deprecation_warning(self):
38            """Issue a DeprecationWarning for code hat uses the old interface"""
39            callername = inspect.currentframe().f_back.f_code.co_name
40            warnings.warn("The %s method of the old table interface"
41                          " is deprecated" % callername,
42                          DeprecationWarning, stacklevel = 3)
43    
44        def record_count(self):
45            self.__deprecation_warning()
46            return self.NumRows()
47    
48        def field_count(self):
49            self.__deprecation_warning()
50            return self.NumColumns()
51    
52        def field_info(self, field):
53            """Return a tuple (type, name, width, prec) for the field no. field
54    
55            type is the data type of the field, name the name, width the
56            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    
87    
88    
89    class DBFColumn:
90    
91        """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      """      """
     Represent a table of data.  
102    
103      Currently this is basically just a wrapper around dbflib.      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
115      """      """
116    
117      # Implementation strategy regarding writing to a DBF file:      # Implementation strategy regarding writing to a DBF file:
# Line 53  class Table: Line 135  class Table:
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            return self.columns
172    
173        def Column(self, col):
174            """Return information about the column given by its name or index
175    
176            The returned object is an instance of DBFColumn
177            """
178            return self.column_map[col]
179    
180        def HasColumn(self, col):
181            """Return whether the table has a column with the given name or index
182          """          """
183          type, name, width, prec = self.dbf.field_info(field)          return self.column_map.has_key(col)
184          type = dbflib_fieldtypes[type]  
185          return type, name, width, prec      def ReadRowAsDict(self, row):
186            """Return the entire row as a dictionary with column names as keys"""
187            return self.dbf.read_record(row)
188    
189      def field_info_by_name(self, fieldName):      def ReadValue(self, row, col):
190          count = self.field_count()          """Return the value of the specified row and column
191    
192          for i in range(count):          The col parameter may be the index of the column or its name.
193              info = self.field_info(i)          """
194              if info[1] == fieldName:          return self.dbf.read_record(row)[self.column_map[col].name]
                 return info  
195    
196          return None      def ValueRange(self, col):
197            """Return the minimum and maximum values of the values in the column
198    
199      def read_record(self, record):          The return value is a tuple (min, max) unless the table is empty
200          """Return the record no. record as a dict mapping field names to values          in which case the return value is None.
201          """          """
202          return self.dbf.read_record(record)          count = self.NumRows()
203    
204            if count == 0:
205                return None
206    
207            min = max = self.ReadValue(0, col)
208            for i in range(1, count):
209                value = self.ReadValue(i, col)
210                if value < min:
211                    min = value
212                elif value > max:
213                    max = value
214    
215            return (min, max)
216    
217        def UniqueValues(self, col):
218            """Return a sorted list of all unique values in the column col"""
219            dict = {}
220    
221            for i in range(self.NumRows()):
222                value = self.ReadValue(i, col)
223                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        # DBF specific interface parts.
234    
235        def Destroy(self):
236            self.dbf.close()
237            self.dbf = None
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 111  class Table: Line 257  class Table:
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            The return value is a tuple (min, max) unless the table is empty
346            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.590  
changed lines
  Added in v.998

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26