summaryrefslogtreecommitdiff
path: root/src/tablib/packages/dbfpy3/dbfnew.py
blob: 8fab27508f526ba7a4e3f2d3cd47b3e0bb4374d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/python
""".DBF creation helpers.

Note: this is a legacy interface.  New code should use Dbf class
    for table creation (see examples in dbf.py)

TODO:
  - handle Memo fields.
  - check length of the fields accoring to the
    `http://www.clicketyclick.dk/databases/xbase/format/data_types.html`

"""
"""History (most recent first)
04-jul-2006 [als]   added export declaration;
                    updated for dbfpy 2.0
15-dec-2005 [yc]    define dbf_new.__slots__
14-dec-2005 [yc]    added vim modeline; retab'd; added doc-strings;
                    dbf_new now is a new class (inherited from object)
??-jun-2000 [--]    added by Hans Fiby
"""

__version__ = "$Revision: 1.4 $"[11:-2]
__date__ = "$Date: 2006/07/04 08:18:18 $"[7:-2]

__all__ = ["dbf_new"]

from .dbf import *
from .fields import *
from .header import *
from .record import *


class _FieldDefinition(object):
    """Field definition.

    This is a simple structure, which contains ``name``, ``type``,
    ``len``, ``dec`` and ``cls`` fields.

    Objects also implement get/setitem magic functions, so fields
    could be accessed via sequence iterface, where 'name' has
    index 0, 'type' index 1, 'len' index 2, 'dec' index 3 and
    'cls' could be located at index 4.

    """

    __slots__ = "name", "type", "len", "dec", "cls"

    # WARNING: be attentive - dictionaries are mutable!
    FLD_TYPES = {
        # type: (cls, len)
        "C": (DbfCharacterFieldDef, None),
        "N": (DbfNumericFieldDef, None),
        "L": (DbfLogicalFieldDef, 1),
        # FIXME: support memos
        # "M": (DbfMemoFieldDef),
        "D": (DbfDateFieldDef, 8),
        # FIXME: I'm not sure length should be 14 characters!
        # but temporary I use it, cuz date is 8 characters
        # and time 6 (hhmmss)
        "T": (DbfDateTimeFieldDef, 14),
    }

    def __init__(self, name, type, len=None, dec=0):
        _cls, _len = self.FLD_TYPES[type]
        if _len is None:
            if len is None:
                raise ValueError("Field length must be defined")
            _len = len
        self.name = name
        self.type = type
        self.len = _len
        self.dec = dec
        self.cls = _cls

    def getDbfField(self):
        "Return `DbfFieldDef` instance from the current definition."
        return self.cls(self.name, self.len, self.dec)

    def appendToHeader(self, dbfh):
        """Create a `DbfFieldDef` instance and append it to the dbf header.

        Arguments:
            dbfh: `DbfHeader` instance.

        """
        _dbff = self.getDbfField()
        dbfh.addField(_dbff)


class dbf_new(object):
    """New .DBF creation helper.

    Example Usage:

        dbfn = dbf_new()
        dbfn.add_field("name",'C',80)
        dbfn.add_field("price",'N',10,2)
        dbfn.add_field("date",'D',8)
        dbfn.write("tst.dbf")

    Note:
        This module cannot handle Memo-fields,
        they are special.

    """

    __slots__ = ("fields",)

    FieldDefinitionClass = _FieldDefinition

    def __init__(self):
        self.fields = []

    def add_field(self, name, typ, len, dec=0):
        """Add field definition.

        Arguments:
            name:
                field name (str object). field name must not
                contain ASCII NULs and it's length shouldn't
                exceed 10 characters.
            typ:
                type of the field. this must be a single character
                from the "CNLMDT" set meaning character, numeric,
                logical, memo, date and date/time respectively.
            len:
                length of the field. this argument is used only for
                the character and numeric fields. all other fields
                have fixed length.
                FIXME: use None as a default for this argument?
            dec:
                decimal precision. used only for the numric fields.

        """
        self.fields.append(self.FieldDefinitionClass(name, typ, len, dec))

    def write(self, filename):
        """Create empty .DBF file using current structure."""
        _dbfh = DbfHeader()
        _dbfh.setCurrentDate()
        for _fldDef in self.fields:
            _fldDef.appendToHeader(_dbfh)

        _dbfStream = open(filename, "wb")
        _dbfh.write(_dbfStream)
        _dbfStream.close()


if __name__ == '__main__':
    # create a new DBF-File
    dbfn = dbf_new()
    dbfn.add_field("name", 'C', 80)
    dbfn.add_field("price", 'N', 10, 2)
    dbfn.add_field("date", 'D', 8)
    dbfn.write("tst.dbf")
    # test new dbf
    print("*** created tst.dbf: ***")
    dbft = Dbf('tst.dbf', readOnly=0)
    print(repr(dbft))
    # add a record
    rec = DbfRecord(dbft)
    rec['name'] = 'something'
    rec['price'] = 10.5
    rec['date'] = (2000, 1, 12)
    rec.store()
    # add another record
    rec = DbfRecord(dbft)
    rec['name'] = 'foo and bar'
    rec['price'] = 12234
    rec['date'] = (1992, 7, 15)
    rec.store()

    # show the records
    print("*** inserted 2 records into tst.dbf: ***")
    print(repr(dbft))
    for i1 in range(len(dbft)):
        rec = dbft[i1]
        for fldName in dbft.fieldNames:
            print('%s:\t %s' % (fldName, rec[fldName]))
        print()
    dbft.close()

# vim: set et sts=4 sw=4 :