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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 765 - (show annotations)
Tue Apr 29 12:42:14 2003 UTC (21 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/table.py
File MIME type: text/x-python
File size: 5169 byte(s)
Next step of table implementation. Introduce a transient database
using SQLite that some of the data is copied to on demand. This
allows us to do joins and other operations that require an index
for good performance with reasonable efficiency. Thuban now needs
SQLite 2.8.0 and pysqlite 0.4.1. Older versions may work but I
haven't tested that.

* Thuban/Model/transientdb.py: New. Transient database
implementation.

* test/test_transientdb.py: New. Tests for the transient DB
classes.

* Thuban/Model/session.py (AutoRemoveFile, AutoRemoveDir): New
classes to help automatically remove temporary files and
directories.
(Session.__init__): New instance variables temp_dir for the
temporary directory and transient_db for the SQLite database
(Session.temp_directory): New. Create a temporary directory if not
yet done and return its name. Use AutoRemoveDir to have it
automatically deleted
(Session.TransientDB): Instantiate the transient database if not
done yet and return it.

* Thuban/Model/data.py (ShapefileStore.__init__): Use an
AutoTransientTable so that data is copied to the transient DB on
demand.
(SimpleStore): New class that simply combines a table and a
shapefile

* Thuban/Model/table.py (Table, DBFTable): Rename Table into
DBFTable and update its doc-string to reflect the fact that this
is only the table interface to a DBF file. Table is now an alias
for DBFTable for temporary backwards compatibility.

* Thuban/UI/application.py (ThubanApplication.OnExit): Make sure
the last reference to the session goes away so that the temporary
files are removed properly.

* test/test_load.py (LoadSessionTest.tearDown): Remove the
reference to the session to make sure the temporary files are
removed.

1 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with Thuban for details.
7
8 """
9 Classes for handling tables of data.
10 """
11
12 __version__ = "$Revision$"
13
14 import dbflib
15
16 # the field types supported by a Table instance.
17 FIELDTYPE_INT = "int"
18 FIELDTYPE_STRING = "string"
19 FIELDTYPE_DOUBLE = "double"
20
21
22 # map the dbflib constants for the field types to our constants
23 dbflib_fieldtypes = {dbflib.FTString: FIELDTYPE_STRING,
24 dbflib.FTInteger: FIELDTYPE_INT,
25 dbflib.FTDouble: FIELDTYPE_DOUBLE}
26
27 class DBFTable:
28
29 """
30 Table interface for the data in a DBF file
31 """
32
33 # Implementation strategy regarding writing to a DBF file:
34 #
35 # Most of the time Thuban only needs to read from a table and it is
36 # important that Thuban can work with read-only files. Therefore the
37 # DBF file is opened only for reading initially. Only when
38 # write_record is called we try to open the DBF file for writing as
39 # well. If that succeeds the read/write DBF file will be used for
40 # all IO afterwards.
41 #
42 # It's important to use the same DBF file object for both reading
43 # and writing to make sure that reading a records after writing
44 # returns the new values. With two separate objects this wouldn't
45 # work because a DBF file object buffers some data
46
47 def __init__(self, filename):
48 self.filename = filename
49 self.dbf = dbflib.DBFFile(filename)
50
51 # If true, self.dbf is open for writing.
52 self._writable = 0
53
54 def Destroy(self):
55 self.dbf.close()
56 self.dbf = None
57
58 def record_count(self):
59 """Return the number of records"""
60 return self.dbf.record_count()
61
62 def field_count(self):
63 """Return the number of fields in a record"""
64 return self.dbf.field_count()
65
66 def field_info(self, field):
67 """Return a tuple (type, name, width, prec) for the field no. field
68
69 type is the data type of the field, name the name, width the
70 field width in characters and prec the decimal precision.
71 """
72 type, name, width, prec = self.dbf.field_info(field)
73 type = dbflib_fieldtypes[type]
74 return type, name, width, prec
75
76 def field_info_by_name(self, fieldName):
77 count = self.field_count()
78
79 for i in range(count):
80 info = self.field_info(i)
81 if info[1] == fieldName:
82 return info
83
84 return None
85
86 def field_range(self, fieldName):
87 """Finds the first occurences of the minimum and maximum values
88 in the table for the given field.
89
90 This assumes that the standard comparison operators (<, >, etc.)
91 will work for the given data.
92
93 Returns a tuple ((min, rec), (max, rec)) where:
94 min is the minimum value
95 max is the maximum value
96 rec is the record number where the value was found. One
97 should check that the record number of min is not
98 the same as the record number of max.
99
100 Returns None if there are no records
101
102 """
103
104
105 count = self.record_count()
106
107 if count == 0:
108 return None
109
110 rec = self.read_record(0)
111
112 min = rec[fieldName]
113 min_rec = 0
114
115 max = rec[fieldName]
116 max_rec = 0
117
118 for i in range(1, count):
119 rec = self.read_record(i)
120 data = rec[fieldName]
121
122 if data < min:
123 min = data
124 min_rec = rec
125 elif data > max:
126 max = data
127 max_rec = rec
128
129 return ((min, min_rec), (max, max_rec))
130
131 def GetUniqueValues(self, fieldName):
132 """Return a list of all unique entries in the table for the given
133 field name.
134 """
135
136 dict = {}
137
138 for i in range(0, self.record_count()):
139 rec = self.read_record(i)
140 data = rec[fieldName]
141
142 if not dict.has_key(data):
143 dict[data] = 0
144
145 return dict.keys()
146
147 def read_record(self, record):
148 """Return the record no. record as a dict mapping field names to values
149 """
150 return self.dbf.read_record(record)
151
152 def write_record(self, record, values):
153 """Write the values into the record
154
155 The values parameter may either be a dictionary or a sequence.
156
157 If it's a dictionary the keys must be the names of the fields
158 and their value must have a suitable type. Only the fields
159 actually contained in the dictionary are written. Fields for
160 which there's no item in the dict are not modified.
161
162 If it's a sequence, all fields must be present in the right
163 order.
164 """
165 if not self._writable:
166 new_dbf = dbflib.DBFFile(self.filename, "r+b")
167 self.dbf.close()
168 self.dbf = new_dbf
169 self._writable = 1
170 self.dbf.write_record(record, values)
171 self.dbf.commit()
172
173
174
175 # Temporary backwards compatibility
176 Table = DBFTable

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26