1 """
2 Copyright
3 =========
4 - Copyright: 2008-2009 Ad-Mail, Inc -- All rights reserved.
5 - Author: Ethan Furman
6 - Contact: ethanf@admailinc.com
7 - Organization: Ad-Mail, Inc.
8 - Version: 0.87.003 as of 03 Dec 2009
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12 - Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 - Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 - Neither the name of Ad-Mail, Inc nor the
18 names of its contributors may be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY Ad-Mail, Inc ''AS IS'' AND ANY
22 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL Ad-Mail, Inc BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 B{I{Summary}}
33
34 Python package for reading/writing dBase III and VFP 6 tables and memos
35
36 The entire table is read into memory, and all operations occur on the in-memory
37 table, with data changes being written to disk as they occur.
38
39 Goals: programming style with databases
40 - C{table = dbf.table('table name' [, fielddesc[, fielddesc[, ....]]])}
41 - fielddesc examples: C{name C(30); age N(3,0); wisdom M; marriage D}
42 - C{record = [ table.current() | table[int] | table.append() | table.[next|prev|top|bottom|goto]() ]}
43 - C{record.field | record['field']} accesses the field
44
45 NOTE: Of the VFP data types, auto-increment and null settings are not implemented.
46 """
47 import os
48 import csv
49
50 from dbf.dates import Date, DateTime, Time
51 from dbf.exceptions import DbfWarning, Bof, Eof, DbfError, DataOverflow, FieldMissing
52 from dbf.tables import DbfTable, Db3Table, VfpTable, FpTable, DbfList, DbfCsv
53 from dbf.tables import ascii, codepage, encoding, version_map
54
55 version = (0, 87, 13)
56
57 __docformat__ = 'epytext'
58
59 -def Table(filename, field_specs='', memo_size=128, ignore_memos=False, \
60 read_only=False, keep_memos=False, meta_only=False, dbf_type=None, codepage=None):
61 "returns an open table of the correct dbf_type, or creates it if field_specs is given"
62 if dbf_type is not None:
63 dbf_type = dbf_type.lower()
64 if dbf_type == 'db3':
65 return Db3Table(filename, field_specs, memo_size, ignore_memos, read_only, keep_memos, meta_only, codepage)
66 elif dbf_type == 'fp':
67 return FpTable(filename, field_specs, memo_size, ignore_memos, read_only, keep_memos, meta_only, codepage)
68 elif dbf_type == 'vfp':
69 return VfpTable(filename, field_specs, memo_size, ignore_memos, read_only, keep_memos, meta_only, codepage)
70 elif dbf_type == 'dbf':
71 return DbfTable(filename, field_specs, memo_size, ignore_memos, read_only, keep_memos, meta_only, codepage)
72 else:
73 raise TypeError("Unknown table type: %s" % dbf_type)
74 else:
75 possibles = guess_table_type(filename)
76 if len(possibles) == 1:
77 return possibles[0][2](filename, field_specs, memo_size, ignore_memos, \
78 read_only, keep_memos, meta_only)
79 elif len(possibles) > 1:
80 types = ', '.join(["%s" % item[1] for item in possibles])
81 abbrs = '[' + ' | '.join(["%s" % item[0] for item in possibles]) + ']'
82 raise DbfError("Table could be any of %s. Please specify %s when opening" % (types, abbrs))
83 else:
84 raise DbfError("Shouldn't have gotten here -- yell at programmer!")
86 "returns integers 0 - len(sequence)"
87 for i in xrange(len(sequence)):
88 yield i
113
115 "adds fields to an existing table"
116 table = Table(table)
117 try:
118 table.add_fields(field_specs)
119 finally:
120 table.close()
128 -def export(table, filename='', fields='', format='csv', header=True):
129 "creates a csv or tab-delimited file from an existing table"
130 if fields is None:
131 fields = []
132 table = Table(table)
133 try:
134 table.export(filename=filename, field_specs=fields, format=format, header=header)
135 finally:
136 table.close()
138 "prints the first record of a table"
139 table = Table(table)
140 try:
141 print str(table[0])
142 finally:
143 table.close()
144 -def from_csv(csvfile, to_disk=False, filename=None, field_names='', extra_fields='', dbf_type='db3'):
145 """creates a Character table from a csv file
146 to_disk will create a table with the same name
147 filename will be used if provided
148 field_names default to f0, f1, f2, etc, unless specified (list)
149 extra_fields can be used to add additional fields -- should be normal field specifiers (list)"""
150 reader = csv.reader(open(csvfile))
151 if field_names:
152 field_names = ['%s M' % fn for fn in field_names]
153 else:
154 field_names = ['f0 M']
155 mtable = Table(':memory:', [field_names[0]], dbf_type=dbf_type)
156 fields_so_far = 1
157 for row in reader:
158 while fields_so_far < len(row):
159 if fields_so_far == len(field_names):
160 field_names.append('f%d M' % fields_so_far)
161 mtable.add_fields(field_names[fields_so_far])
162 fields_so_far += 1
163 mtable.append(tuple(row))
164 if not to_disk:
165 if extra_fields:
166 mtable.add_fields(extra_fields)
167 else:
168 if not filename:
169 filename = os.path.splitext(csvfile)[0]
170 length = [1] * len(field_names)
171 for record in mtable:
172 for i in index(record.field_names):
173 length[i] = max(length[i], len(record[i]))
174 fields = mtable.field_names
175 fielddef = []
176 for i in index(length):
177 if length[i] < 255:
178 fielddef.append('%s C(%d)' % (fields[i], length[i]))
179 else:
180 fielddef.append('%s M' % (fields[i]))
181 if extra_fields:
182 fielddef.extend(extra_fields)
183 csvtable = Table(filename, fielddef, dbf_type=dbf_type)
184 for record in mtable:
185 csvtable.append(record.scatter_fields())
186 return csvtable
187 return mtable
189 "returns the list of field names of a table"
190 table = Table(table)
191 return table.field_names
193 "prints table info"
194 table = Table(table)
195 print str(table)
197 "renames a field in a table"
198 table = Table(table)
199 try:
200 table.rename_field(oldfield, newfield)
201 finally:
202 table.close()
204 "returns the definition of a field (or all fields)"
205 table = Table(table)
206 return table.structure(field)
208 "just what it says ;)"
209 for index,dummy in enumerate(records):
210 chars = dummy._data
211 print "%2d: " % index,
212 for char in chars[1:]:
213 print " %2x " % ord(char),
214 print
215