/[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 467 by jonathan, Wed Mar 5 18:18:38 2003 UTC revision 818 by bh, Mon May 5 17:18:31 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 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 12  Classes for handling tables of data. Line 13  Classes for handling tables of data.
13  __version__ = "$Revision$"  __version__ = "$Revision$"
14    
15  import dbflib  import dbflib
 from Thuban.common import *  
16    
17  # the field types supported by a Table instance.  # the field types supported by a Table instance.
18  #FIELDTYPE_INT = "int"  FIELDTYPE_INT = "int"
19  #FIELDTYPE_STRING = "string"  FIELDTYPE_STRING = "string"
20  #FIELDTYPE_DOUBLE = "double"  FIELDTYPE_DOUBLE = "double"
21    
22    
23  # map the dbflib constants for the field types to our constants  # map the dbflib constants for the field types to our constants
# Line 25  dbflib_fieldtypes = {dbflib.FTString: FI Line 25  dbflib_fieldtypes = {dbflib.FTString: FI
25                       dbflib.FTInteger: FIELDTYPE_INT,                       dbflib.FTInteger: FIELDTYPE_INT,
26                       dbflib.FTDouble: FIELDTYPE_DOUBLE}                       dbflib.FTDouble: FIELDTYPE_DOUBLE}
27    
 class Table:  
28    
29    class OldTableInterfaceMixin:
30    
31        """Mixin to implement the old table interface using the new one"""
32    
33        def record_count(self):
34            return self.NumRows()
35    
36        def field_count(self):
37            return self.NumColumns()
38    
39        def field_info(self, field):
40            """Return a tuple (type, name, width, prec) for the field no. field
41    
42            type is the data type of the field, name the name, width the
43            field width in characters and prec the decimal precision. width
44            and prec will be zero if the information returned by the Column
45            method doesn't provide values for them.
46            """
47            col = self.Column(field)
48            return (col.type, col.name,
49                   getattr(col, "width", 0), getattr(col, "prec", 0))
50    
51        def field_info_by_name(self, col):
52            try:
53                return self.field_info(col)
54            except KeyError:
55                # FIXME: It may be that field_info raises other exceptions
56                # when the name is not a valid column name.
57                return None
58    
59        def field_range(self, fieldName):
60            min, max = self.ValueRange(fieldName)
61            return ((min, None), (max, None))
62    
63        def GetUniqueValues(self, field):
64            return self.UniqueValues(field)
65    
66        def read_record(self, r):
67            return self.ReadRowAsDict(r)
68    
69    
70    
71    class DBFColumn:
72    
73        """Description of a column in a DBFTable
74    
75        Instances have the following public attributes:
76    
77        name -- Name of the column
78        type -- Type of the column (one of FIELDTYPE_STRING, FIELDTYPE_INT or\
79                FIELDTYPE_DOUBLE)
80        index -- The index of the column
81        width -- the width of the data in the column
82        prec -- The precision of the data (only valid for type == FIELDTYPE_DOUBLE)
83      """      """
     Represent a table of data.  
84    
85      Currently this is basically just a wrapper around dbflib.      def __init__(self, name, type, width, prec, index):
86            self.name = name
87            self.type = type
88            self.width = width
89            self.prec = prec
90            self.index = index
91    
92    
93    class DBFTable(OldTableInterfaceMixin):
94    
95        """
96        Table interface for the data in a DBF file
97      """      """
98    
99      # Implementation strategy regarding writing to a DBF file:      # Implementation strategy regarding writing to a DBF file:
# Line 39  class Table: Line 102  class Table:
102      # important that Thuban can work with read-only files. Therefore the      # important that Thuban can work with read-only files. Therefore the
103      # DBF file is opened only for reading initially. Only when      # DBF file is opened only for reading initially. Only when
104      # write_record is called we try to open the DBF file for writing as      # write_record is called we try to open the DBF file for writing as
105      # well. If that succeeds the dbf read/write DBF file will be used      # well. If that succeeds the read/write DBF file will be used for
106      # for all IO afterwards.      # all IO afterwards.
107      #      #
108      # It's important to use the same DBF file object for both reading      # It's important to use the same DBF file object for both reading
109      # and writing to make sure that reading a records after writing      # and writing to make sure that reading a records after writing
# Line 54  class Table: Line 117  class Table:
117          # If true, self.dbf is open for writing.          # If true, self.dbf is open for writing.
118          self._writable = 0          self._writable = 0
119    
120      def Destroy(self):          # Create the column information objects
121          self.dbf.close()          self.columns = []
122          self.dbf = None          self.column_map = {}
123            for i in range(self.NumColumns()):
124                ftype, name, width, prec = self.dbf.field_info(i)
125                ftype = dbflib_fieldtypes[ftype]
126                index = len(self.columns)
127                col = DBFColumn(name, ftype, width, prec, index)
128                self.columns.append(col)
129                self.column_map[name] = col
130                self.column_map[index] = col
131    
132      def record_count(self):      def NumRows(self):
133          """Return the number of records"""          """Return the number of rows in the table"""
134          return self.dbf.record_count()          return self.dbf.record_count()
135    
136      def field_count(self):      def NumColumns(self):
137          """Return the number of fields in a record"""          """Return the number of columns in the table"""
138          return self.dbf.field_count()          return self.dbf.field_count()
139    
140      def field_info(self, field):      def Columns(self):
141          """Return a tuple (type, name, width, prec) for the field no. field          """Return the table's colum definitions
142    
143          type is the data type of the field, name the name, width the          The return value is a sequence of DBFColumn instances, one for
144          field width in characters and prec the decimal precision.          each column.
145            """
146            return self.columns
147    
148        def Column(self, col):
149            """Return information about the column given by its name or index
150    
151            The returned object is an instance of DBFColumn
152          """          """
153          type, name, width, prec = self.dbf.field_info(field)          return self.column_map[col]
154          type = dbflib_fieldtypes[type]  
155          return type, name, width, prec      def ReadRowAsDict(self, row):
156            """Return the entire row as a dictionary with column names as keys"""
157            return self.dbf.read_record(row)
158    
159      def field_info_by_name(self, fieldName):      def ReadValue(self, row, col):
160          count = self.field_count()          """Return the value of the specified row and column
161    
162          for i in range(count):          The col parameter may be the index of the column or its name.
163              info = self.field_info(i)          """
164              if info[1] == fieldName:          return self.dbf.read_record(row)[self.column_map[col].name]
                 return info  
165    
166          return None      def ValueRange(self, col):
167            """Return the minimum and maximum values of the values in the column
168    
169      def read_record(self, record):          The return value is a tuple (min, max) unless the table is empty
170          """Return the record no. record as a dict mapping field names to values          in which case the return value is None.
171          """          """
172          return self.dbf.read_record(record)          count = self.NumRows()
173    
174            if count == 0:
175                return None
176    
177            min = max = self.ReadValue(0, col)
178            for i in range(1, count):
179                value = self.ReadValue(i, col)
180                if value < min:
181                    min = value
182                elif value > max:
183                    max = value
184    
185            return (min, max)
186    
187        def UniqueValues(self, col):
188            """Return a sorted list of all unique values in the column col"""
189            dict = {}
190    
191            for i in range(self.NumRows()):
192                value = self.ReadValue(i, col)
193                dict[value] = 0
194    
195            values = dict.keys()
196            values.sort()
197            return values
198    
199    
200        # DBF specific interface parts.
201    
202        def Destroy(self):
203            self.dbf.close()
204            self.dbf = None
205    
206      def write_record(self, record, values):      def write_record(self, record, values):
207          """Write the values into the record          """Write the values into the record
# Line 112  class Table: Line 224  class Table:
224          self.dbf.write_record(record, values)          self.dbf.write_record(record, values)
225          self.dbf.commit()          self.dbf.commit()
226    
227    
228    
229    # Temporary backwards compatibility
230    Table = DBFTable
231    
232    
233    
234    class MemoryColumn:
235    
236        def __init__(self, name, type, index):
237            self.name = name
238            self.type = type
239            self.index = index
240    
241    class MemoryTable(OldTableInterfaceMixin):
242    
243        """Very simple table implementation that operates on a list of tuples"""
244    
245        def __init__(self, fields, data):
246            """Initialize the MemoryTable
247    
248            Parameters:
249            fields -- List of (name, field_type) pairs
250            data -- List of tuples, one for each row of data
251            """
252            self.data = data
253    
254            # Create the column information objects
255            self.columns = []
256            self.column_map = {}
257            for name, ftype in fields:
258                index = len(self.columns)
259                col = MemoryColumn(name, ftype, index)
260                self.columns.append(col)
261                self.column_map[name] = col
262                self.column_map[index] = col
263    
264        def NumColumns(self):
265            """Return the number of columns in the table"""
266            return len(self.columns)
267    
268        def Column(self, col):
269            """Return information about the column given by its name or index
270    
271            The returned object is an instance of MemoryColumn.
272            """
273            return self.column_map[col]
274    
275        def Columns(self):
276            """Return the table's colum definitions
277    
278            The return value is a sequence of MemoryColumn instances, one
279            for each column.
280            """
281            return self.columns
282    
283        def NumRows(self):
284            """Return the number of rows in the table"""
285            return len(self.data)
286    
287        def ReadValue(self, row, col):
288            """Return the value of the specified row and column
289    
290            The col parameter may be the index of the column or its name.
291            """
292            return self.data[row][self.column_map[col].index]
293    
294        def ReadRowAsDict(self, index):
295            """Return the entire row as a dictionary with column names as keys"""
296            return dict([(col.name, self.data[index][col.index])
297                          for col in self.columns])
298    
299        def ValueRange(self, col):
300            """Return the minimum and maximum values of the values in the column
301    
302            The return value is a tuple (min, max) unless the table is empty
303            in which case the return value is None.
304            """
305    
306            index = self.column_map[col].index
307            values = [row[index] for row in self.data]
308            if not values:
309                return None
310    
311            return min(values), max(values)
312    
313        def UniqueValues(self, col):
314            """Return a sorted list of all unique values in the column col"""
315            dict = {}
316    
317            for i in range(self.NumRows()):
318                value = self.ReadValue(i, col)
319                dict[value] = 0
320    
321            values = dict.keys()
322            values.sort()
323            return values
324    
325    
326        def write_record(self, record, values):
327            # TODO: Check for correct lenght and perhaps also
328            # for correct types in case values is a tuple. How to report problems?
329            # TODO: Allow values to be a dictionary and write the single
330            # fields that are specified.
331            self.data[record] = values

Legend:
Removed from v.467  
changed lines
  Added in v.818

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26