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