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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1019 - (hide annotations)
Fri May 23 12:56:34 2003 UTC (21 years, 9 months ago) by jan
Original Path: trunk/thuban/Thuban/Model/table.py
File MIME type: text/x-python
File size: 11533 byte(s)
(DBFTable, MemoryTable): mix-in TitledObject and call its init-method with
a default title. Remove Title() method.

1 bh 590 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4 jan 806 # Jan-Oliver Wagner <[email protected]>
5 bh 6 #
6     # This program is free software under the GPL (>=v2)
7     # Read the file COPYING coming with Thuban for details.
8    
9     """
10     Classes for handling tables of data.
11     """
12    
13     __version__ = "$Revision$"
14    
15 bh 998 import os
16 bh 839 import inspect
17     import warnings
18    
19 jan 1019 from base import TitledObject
20    
21 bh 6 import dbflib
22    
23     # the field types supported by a Table instance.
24 jonathan 474 FIELDTYPE_INT = "int"
25     FIELDTYPE_STRING = "string"
26     FIELDTYPE_DOUBLE = "double"
27 bh 6
28    
29     # map the dbflib constants for the field types to our constants
30     dbflib_fieldtypes = {dbflib.FTString: FIELDTYPE_STRING,
31     dbflib.FTInteger: FIELDTYPE_INT,
32     dbflib.FTDouble: FIELDTYPE_DOUBLE}
33    
34 jan 806
35 bh 818 class OldTableInterfaceMixin:
36 jan 806
37 bh 818 """Mixin to implement the old table interface using the new one"""
38 jan 806
39 bh 839 def __deprecation_warning(self):
40     """Issue a DeprecationWarning for code hat uses the old interface"""
41     callername = inspect.currentframe().f_back.f_code.co_name
42     warnings.warn("The %s method of the old table interface"
43     " is deprecated" % callername,
44     DeprecationWarning, stacklevel = 3)
45    
46 bh 818 def record_count(self):
47 bh 839 self.__deprecation_warning()
48 bh 818 return self.NumRows()
49 jan 806
50     def field_count(self):
51 bh 839 self.__deprecation_warning()
52 bh 818 return self.NumColumns()
53 jan 806
54 bh 818 def field_info(self, field):
55     """Return a tuple (type, name, width, prec) for the field no. field
56 jan 806
57 bh 818 type is the data type of the field, name the name, width the
58     field width in characters and prec the decimal precision. width
59     and prec will be zero if the information returned by the Column
60     method doesn't provide values for them.
61     """
62 bh 839 self.__deprecation_warning()
63 bh 818 col = self.Column(field)
64     return (col.type, col.name,
65     getattr(col, "width", 0), getattr(col, "prec", 0))
66 jan 806
67 bh 818 def field_info_by_name(self, col):
68 bh 839 self.__deprecation_warning()
69 bh 818 try:
70     return self.field_info(col)
71     except KeyError:
72     # FIXME: It may be that field_info raises other exceptions
73     # when the name is not a valid column name.
74     return None
75 jan 806
76 bh 818 def field_range(self, fieldName):
77 bh 839 self.__deprecation_warning()
78 bh 818 min, max = self.ValueRange(fieldName)
79     return ((min, None), (max, None))
80 jan 806
81 bh 818 def GetUniqueValues(self, field):
82 bh 839 self.__deprecation_warning()
83 bh 818 return self.UniqueValues(field)
84 jan 806
85 bh 818 def read_record(self, r):
86 bh 839 self.__deprecation_warning()
87 bh 818 return self.ReadRowAsDict(r)
88 bh 6
89 bh 818
90    
91     class DBFColumn:
92    
93     """Description of a column in a DBFTable
94    
95     Instances have the following public attributes:
96    
97     name -- Name of the column
98     type -- Type of the column (one of FIELDTYPE_STRING, FIELDTYPE_INT or\
99     FIELDTYPE_DOUBLE)
100     index -- The index of the column
101     width -- the width of the data in the column
102     prec -- The precision of the data (only valid for type == FIELDTYPE_DOUBLE)
103 bh 6 """
104 bh 818
105     def __init__(self, name, type, width, prec, index):
106     self.name = name
107     self.type = type
108     self.width = width
109     self.prec = prec
110     self.index = index
111    
112    
113 jan 1019 class DBFTable(TitledObject, OldTableInterfaceMixin):
114 bh 818
115     """
116 bh 765 Table interface for the data in a DBF file
117 bh 6 """
118    
119 bh 286 # Implementation strategy regarding writing to a DBF file:
120     #
121     # Most of the time Thuban only needs to read from a table and it is
122     # important that Thuban can work with read-only files. Therefore the
123     # DBF file is opened only for reading initially. Only when
124     # write_record is called we try to open the DBF file for writing as
125 bh 590 # well. If that succeeds the read/write DBF file will be used for
126     # all IO afterwards.
127 bh 286 #
128     # It's important to use the same DBF file object for both reading
129     # and writing to make sure that reading a records after writing
130     # returns the new values. With two separate objects this wouldn't
131     # work because a DBF file object buffers some data
132    
133 bh 6 def __init__(self, filename):
134     self.filename = filename
135 jan 1019 title = os.path.basename(self.filename)
136     TitledObject.__init__(self, title)
137 bh 284 self.dbf = dbflib.DBFFile(filename)
138 bh 6
139 bh 286 # If true, self.dbf is open for writing.
140     self._writable = 0
141    
142 bh 818 # Create the column information objects
143     self.columns = []
144     self.column_map = {}
145     for i in range(self.NumColumns()):
146     ftype, name, width, prec = self.dbf.field_info(i)
147     ftype = dbflib_fieldtypes[ftype]
148     index = len(self.columns)
149     col = DBFColumn(name, ftype, width, prec, index)
150     self.columns.append(col)
151     self.column_map[name] = col
152     self.column_map[index] = col
153 bh 257
154 bh 818 def NumRows(self):
155     """Return the number of rows in the table"""
156 bh 6 return self.dbf.record_count()
157    
158 bh 818 def NumColumns(self):
159     """Return the number of columns in the table"""
160 bh 6 return self.dbf.field_count()
161    
162 bh 818 def Columns(self):
163     """Return the table's colum definitions
164 bh 6
165 bh 818 The return value is a sequence of DBFColumn instances, one for
166     each column.
167 bh 6 """
168 bh 818 return self.columns
169 bh 6
170 bh 818 def Column(self, col):
171     """Return information about the column given by its name or index
172 jonathan 467
173 bh 818 The returned object is an instance of DBFColumn
174     """
175     return self.column_map[col]
176 jonathan 467
177 bh 839 def HasColumn(self, col):
178     """Return whether the table has a column with the given name or index
179     """
180     return self.column_map.has_key(col)
181    
182 bh 818 def ReadRowAsDict(self, row):
183     """Return the entire row as a dictionary with column names as keys"""
184     return self.dbf.read_record(row)
185 jonathan 467
186 bh 818 def ReadValue(self, row, col):
187     """Return the value of the specified row and column
188 jonathan 628
189 bh 818 The col parameter may be the index of the column or its name.
190     """
191     return self.dbf.read_record(row)[self.column_map[col].name]
192 jonathan 628
193 bh 818 def ValueRange(self, col):
194     """Return the minimum and maximum values of the values in the column
195 jonathan 628
196 bh 818 The return value is a tuple (min, max) unless the table is empty
197     in which case the return value is None.
198 jonathan 628 """
199 bh 818 count = self.NumRows()
200 jonathan 628
201     if count == 0:
202     return None
203    
204 bh 818 min = max = self.ReadValue(0, col)
205 jonathan 628 for i in range(1, count):
206 bh 818 value = self.ReadValue(i, col)
207     if value < min:
208     min = value
209     elif value > max:
210     max = value
211 jonathan 628
212 bh 818 return (min, max)
213 jonathan 628
214 bh 818 def UniqueValues(self, col):
215     """Return a sorted list of all unique values in the column col"""
216     dict = {}
217 jonathan 628
218 bh 818 for i in range(self.NumRows()):
219     value = self.ReadValue(i, col)
220     dict[value] = 0
221 jonathan 628
222 bh 818 values = dict.keys()
223     values.sort()
224     return values
225 jonathan 628
226 bh 984 def Dependencies(self):
227     """Return an empty sequence. The DBFTable doesn't depend on anything"""
228     return ()
229 jonathan 628
230 bh 818 # DBF specific interface parts.
231 jonathan 628
232 bh 818 def Destroy(self):
233     self.dbf.close()
234     self.dbf = None
235 jonathan 628
236 bh 274 def write_record(self, record, values):
237     """Write the values into the record
238    
239     The values parameter may either be a dictionary or a sequence.
240    
241     If it's a dictionary the keys must be the names of the fields
242     and their value must have a suitable type. Only the fields
243     actually contained in the dictionary are written. Fields for
244     which there's no item in the dict are not modified.
245    
246     If it's a sequence, all fields must be present in the right
247     order.
248     """
249 bh 286 if not self._writable:
250     new_dbf = dbflib.DBFFile(self.filename, "r+b")
251     self.dbf.close()
252     self.dbf = new_dbf
253     self._writable = 1
254     self.dbf.write_record(record, values)
255     self.dbf.commit()
256 jonathan 467
257 bh 994 def FileName(self):
258     """Return the filename the DBFTable was instantiated with"""
259     return self.filename
260 bh 765
261    
262 bh 818 class MemoryColumn:
263    
264     def __init__(self, name, type, index):
265     self.name = name
266     self.type = type
267     self.index = index
268    
269 jan 1019 class MemoryTable(TitledObject, OldTableInterfaceMixin):
270 bh 818
271     """Very simple table implementation that operates on a list of tuples"""
272    
273     def __init__(self, fields, data):
274     """Initialize the MemoryTable
275    
276     Parameters:
277     fields -- List of (name, field_type) pairs
278     data -- List of tuples, one for each row of data
279     """
280     self.data = data
281 jan 1019 title = 'MemoryTable'
282     TitledObject.__init__(self, title)
283 bh 818
284     # Create the column information objects
285     self.columns = []
286     self.column_map = {}
287     for name, ftype in fields:
288     index = len(self.columns)
289     col = MemoryColumn(name, ftype, index)
290     self.columns.append(col)
291     self.column_map[name] = col
292     self.column_map[index] = col
293    
294     def NumColumns(self):
295     """Return the number of columns in the table"""
296     return len(self.columns)
297    
298     def Column(self, col):
299     """Return information about the column given by its name or index
300    
301     The returned object is an instance of MemoryColumn.
302     """
303     return self.column_map[col]
304    
305     def Columns(self):
306     """Return the table's colum definitions
307    
308     The return value is a sequence of MemoryColumn instances, one
309     for each column.
310     """
311     return self.columns
312    
313 bh 839 def HasColumn(self, col):
314     """Return whether the table has a column with the given name or index
315     """
316     return self.column_map.has_key(col)
317    
318 bh 818 def NumRows(self):
319     """Return the number of rows in the table"""
320     return len(self.data)
321    
322     def ReadValue(self, row, col):
323     """Return the value of the specified row and column
324    
325     The col parameter may be the index of the column or its name.
326     """
327     return self.data[row][self.column_map[col].index]
328    
329     def ReadRowAsDict(self, index):
330     """Return the entire row as a dictionary with column names as keys"""
331     return dict([(col.name, self.data[index][col.index])
332     for col in self.columns])
333    
334     def ValueRange(self, col):
335     """Return the minimum and maximum values of the values in the column
336    
337     The return value is a tuple (min, max) unless the table is empty
338     in which case the return value is None.
339     """
340    
341     index = self.column_map[col].index
342     values = [row[index] for row in self.data]
343     if not values:
344     return None
345    
346     return min(values), max(values)
347    
348     def UniqueValues(self, col):
349     """Return a sorted list of all unique values in the column col"""
350     dict = {}
351    
352     for i in range(self.NumRows()):
353     value = self.ReadValue(i, col)
354     dict[value] = 0
355    
356     values = dict.keys()
357     values.sort()
358     return values
359    
360 bh 984 def Dependencies(self):
361     """Return an empty sequence. The MemoryTable doesn't depend on anything
362     """
363     return ()
364 bh 818
365     def write_record(self, record, values):
366     # TODO: Check for correct lenght and perhaps also
367     # for correct types in case values is a tuple. How to report problems?
368     # TODO: Allow values to be a dictionary and write the single
369     # fields that are specified.
370     self.data[record] = values

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26