Package dbf
[hide private]

Source Code for Package dbf

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