Package dbf
[hide private]

Source Code for Package dbf

  1  """ 
  2  Copyright 
  3  ========= 
  4      - Copyright: 2008-2011 Ad-Mail, Inc -- All rights reserved. 
  5      - Author: Ethan Furman 
  6      - Contact: ethanf@admailinc.com 
  7      - Organization: Ad-Mail, Inc. 
  8      - Version: 0.88.019 as of 10 Mar 2011 
  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  __docformat__ = 'epytext' 
 48   
 49  import os 
 50  import csv 
 51   
 52  from dbf.dates import Date, DateTime, Time 
 53  from dbf.exceptions import DbfWarning, Bof, Eof, DbfError, DataOverflow, FieldMissing, DoNotIndex 
 54  from dbf.tables import DbfTable, Db3Table, VfpTable, FpTable, List, DbfCsv 
 55  from dbf.tables import sql, ascii, codepage, encoding, version_map 
 56  from decimal import Decimal 
 57   
 58  version = (0, 88, 20) 
 59   
 60  default_type = 'db3'    # default format if none specified 
 61  sql_user_functions = {}      # user-defined sql functions 
 62   
 63  table_types = { 
 64      'db3' : Db3Table, 
 65      'fp'  : FpTable, 
 66      'vfp' : VfpTable, 
 67      'dbf' : DbfTable, 
 68      } 
 69   
70 -def Table( 71 filename, 72 field_specs='', 73 memo_size=128, 74 ignore_memos=False, 75 read_only=False, 76 keep_memos=False, 77 meta_only=False, 78 dbf_type=None, 79 codepage=None, 80 numbers='default', 81 strings=str, 82 currency=Decimal, 83 ):
84 "returns an open table of the correct dbf_type, or creates it if field_specs is given" 85 if dbf_type is None and isinstance(filename, DbfTable): 86 return filename 87 if field_specs and dbf_type is None: 88 dbf_type = default_type 89 if dbf_type is not None: 90 dbf_type = dbf_type.lower() 91 table = table_types.get(dbf_type) 92 if table is None: 93 raise DbfError("Unknown table type: %s" % dbf_type) 94 return table(filename, field_specs, memo_size, ignore_memos, read_only, keep_memos, meta_only, codepage, numbers, strings, currency) 95 else: 96 possibles = guess_table_type(filename) 97 if len(possibles) == 1: 98 return possibles[0][2](filename, field_specs, memo_size, ignore_memos, \ 99 read_only, keep_memos, meta_only, codepage, numbers, strings, currency) 100 else: 101 for type, desc, cls in possibles: 102 if type == default_type: 103 return cls(filename, field_specs, memo_size, ignore_memos, \ 104 read_only, keep_memos, meta_only, codepage, numbers, strings, currency) 105 else: 106 types = ', '.join(["%s" % item[1] for item in possibles]) 107 abbrs = '[' + ' | '.join(["%s" % item[0] for item in possibles]) + ']' 108 raise DbfError("Table could be any of %s. Please specify %s when opening" % (types, abbrs))
109 -def index(sequence):
110 "returns integers 0 - len(sequence)" 111 for i in xrange(len(sequence)): 112 yield i
113 -def guess_table_type(filename):
114 reported = table_type(filename) 115 possibles = [] 116 version = reported[0] 117 for tabletype in (Db3Table, FpTable, VfpTable): 118 if version in tabletype._supported_tables: 119 possibles.append((tabletype._versionabbv, tabletype._version, tabletype)) 120 if not possibles: 121 raise DbfError("Tables of type %s not supported" % str(reported)) 122 return possibles
123 -def table_type(filename):
124 "returns text representation of a table's dbf version" 125 base, ext = os.path.splitext(filename) 126 if ext == '': 127 filename = base + '.dbf' 128 if not os.path.exists(filename): 129 raise DbfError('File %s not found' % filename) 130 fd = open(filename) 131 version = fd.read(1) 132 fd.close() 133 fd = None 134 if not version in version_map: 135 raise DbfError("Unknown dbf type: %s (%x)" % (version, ord(version))) 136 return version, version_map[version]
137
138 -def add_fields(table, field_specs):
139 "adds fields to an existing table" 140 table = Table(table) 141 try: 142 table.add_fields(field_specs) 143 finally: 144 table.close()
145 -def delete_fields(table, field_names):
146 "deletes fields from an existing table" 147 table = Table(table) 148 try: 149 table.delete_fields(field_names) 150 finally: 151 table.close()
152 -def export(table, filename='', fields='', format='csv', header=True):
153 "creates a csv or tab-delimited file from an existing table" 154 if fields is None: 155 fields = [] 156 table = Table(table) 157 try: 158 table.export(filename=filename, field_specs=fields, format=format, header=header) 159 finally: 160 table.close()
161 -def first_record(table):
162 "prints the first record of a table" 163 table = Table(table) 164 try: 165 print str(table[0]) 166 finally: 167 table.close()
168 -def from_csv(csvfile, to_disk=False, filename=None, field_names=None, extra_fields=None, dbf_type='db3', memo_size=64, min_field_size=1):
169 """creates a Character table from a csv file 170 to_disk will create a table with the same name 171 filename will be used if provided 172 field_names default to f0, f1, f2, etc, unless specified (list) 173 extra_fields can be used to add additional fields -- should be normal field specifiers (list)""" 174 reader = csv.reader(open(csvfile)) 175 if field_names: 176 field_names = ['%s M' % fn for fn in field_names] 177 else: 178 field_names = ['f0 M'] 179 mtable = Table(':memory:', [field_names[0]], dbf_type=dbf_type, memo_size=memo_size) 180 fields_so_far = 1 181 for row in reader: 182 while fields_so_far < len(row): 183 if fields_so_far == len(field_names): 184 field_names.append('f%d M' % fields_so_far) 185 mtable.add_fields(field_names[fields_so_far]) 186 fields_so_far += 1 187 mtable.append(tuple(row)) 188 if filename: 189 to_disk = True 190 if not to_disk: 191 if extra_fields: 192 mtable.add_fields(extra_fields) 193 else: 194 if not filename: 195 filename = os.path.splitext(csvfile)[0] 196 length = [min_field_size] * len(field_names) 197 for record in mtable: 198 for i in index(record.field_names): 199 length[i] = max(length[i], len(record[i])) 200 fields = mtable.field_names 201 fielddef = [] 202 for i in index(length): 203 if length[i] < 255: 204 fielddef.append('%s C(%d)' % (fields[i], length[i])) 205 else: 206 fielddef.append('%s M' % (fields[i])) 207 if extra_fields: 208 fielddef.extend(extra_fields) 209 csvtable = Table(filename, fielddef, dbf_type=dbf_type) 210 for record in mtable: 211 csvtable.append(record.scatter_fields()) 212 return csvtable 213 return mtable
214 -def get_fields(table):
215 "returns the list of field names of a table" 216 table = Table(table) 217 return table.field_names
218 -def info(table):
219 "prints table info" 220 table = Table(table) 221 print str(table)
222 -def rename_field(table, oldfield, newfield):
223 "renames a field in a table" 224 table = Table(table) 225 try: 226 table.rename_field(oldfield, newfield) 227 finally: 228 table.close()
229 -def structure(table, field=None):
230 "returns the definition of a field (or all fields)" 231 table = Table(table) 232 return table.structure(field)
233 -def hex_dump(records):
234 "just what it says ;)" 235 for index,dummy in enumerate(records): 236 chars = dummy._data 237 print "%2d: " % index, 238 for char in chars[1:]: 239 print " %2x " % ord(char), 240 print
241