dbf.old

Package dbf :: Package old |
[hide private]

# Source Code for Package dbf.old

      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, 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, 07)
     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 DbfError("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!")
     85 -def index(sequence):
     86      "returns integers 0 - len(sequence)"
     87      for i in xrange(len(sequence)):
     88          yield i
     89 -def guess_table_type(filename):
     90      reported = table_type(filename)
     91      possibles = []
     92      version = reported[0]
     93      for tabletype in (Db3Table, FpTable, VfpTable):
     94          if version in tabletype._supported_tables:
     95              possibles.append((tabletype._versionabbv, tabletype._version, tabletype))
     96      if not possibles:
     97          raise DbfError("Tables of type %s not supported" % str(reported))
     98      return possibles
     99 -def table_type(filename):
    100      "returns text representation of a table's dbf version"
    101      base, ext = os.path.splitext(filename)
    102      if ext == '':
    103          filename = base + '.dbf'
    104      if not os.path.exists(filename):
    105          raise DbfError('File %s not found' % filename)
    106      fd = open(filename)
    107      version = fd.read(1)
    108      fd.close()
    109      fd = None
    110      if not version in version_map:
    111          raise DbfError("Unknown dbf type: %s (%x)" % (version, ord(version)))
    112      return version, version_map[version]
    113
    114 -def add_fields(table, field_specs):
    115      "adds fields to an existing table"
    116      table = Table(table)
    117      try:
    118          table.add_fields(field_specs)
    119      finally:
    120          table.close()
    121 -def delete_fields(table, field_names):
    122      "deletes fields from an existing table"
    123      table = Table(table)
    124      try:
    125          table.delete_fields(field_names)
    126      finally:
    127          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()
    137 -def first_record(table):
    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=None, extra_fields=None, dbf_type='db3', memo_size=64, min_field_size=1):
    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, memo_size=memo_size)
    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 = [min_field_size] * 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
    188 -def get_fields(table):
    189      "returns the list of field names of a table"
    190      table = Table(table)
    191      return table.field_names
    192 -def info(table):
    193      "prints table info"
    194      table = Table(table)
    195      print str(table)
    196 -def rename_field(table, oldfield, newfield):
    197      "renames a field in a table"
    198      table = Table(table)
    199      try:
    200          table.rename_field(oldfield, newfield)
    201      finally:
    202          table.close()
    203 -def structure(table, field=None):
    204      "returns the definition of a field (or all fields)"
    205      table = Table(table)
    206      return table.structure(field)
    207 -def hex_dump(records):
    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