Package dbf :: Module _io
[hide private]

Source Code for Module dbf._io

  1  """Routines for saving, retrieving, and creating fields""" 
  2   
  3  import struct 
  4  from decimal import Decimal 
  5  from dbf.exceptions import DbfError, DataOverflow 
  6  from dbf.dates import Date, DateTime, Time 
  7  from math import floor 
  8   
  9   
 10  # Constants 
 11  VFPTIME = 1721425 
 12   
13 -def packShortInt(value, bigendian=False):
14 "Returns a two-bye integer from the value, or raises DbfError" 15 # 256 / 65,536 16 if value > 65535: 17 raise DateOverflow("Maximum Integer size exceeded. Possible: 65535. Attempted: %d" % value) 18 if bigendian: 19 return struct.pack('>H', value) 20 else: 21 return struct.pack('<H', value)
22 -def packLongInt(value, bigendian=False):
23 "Returns a four-bye integer from the value, or raises DbfError" 24 # 256 / 65,536 / 16,777,216 25 if value > 4294967295: 26 raise DateOverflow("Maximum Integer size exceeded. Possible: 4294967295. Attempted: %d" % value) 27 if bigendian: 28 return struct.pack('>L', value) 29 else: 30 return struct.pack('<L', value)
31 -def packDate(date):
32 "Returns a group of three bytes, in integer form, of the date" 33 return "%c%c%c" % (date.year-1900, date.month, date.day)
34 -def packStr(string):
35 "Returns an 11 byte, upper-cased, null padded string suitable for field names; raises DbfError if the string is bigger than 10 bytes" 36 if len(string) > 10: 37 raise DbfError("Maximum string size is ten characters -- %s has %d characters" % (string, len(string))) 38 return struct.pack('11s', string.upper())
39 -def unpackShortInt(bytes, bigendian=False):
40 "Returns the value in the two-byte integer passed in" 41 if bigendian: 42 return struct.unpack('>H', bytes)[0] 43 else: 44 return struct.unpack('<H', bytes)[0]
45 -def unpackLongInt(bytes, bigendian=False):
46 "Returns the value in the four-byte integer passed in" 47 if bigendian: 48 return int(struct.unpack('>L', bytes)[0]) 49 else: 50 return int(struct.unpack('<L', bytes)[0])
51 -def unpackDate(bytestr):
52 "Returns a Date() of the packed three-byte date passed in" 53 year, month, day = struct.unpack('<BBB', bytestr) 54 year += 1900 55 return Date(year, month, day)
56 -def unpackStr(chars):
57 "Returns a normal, lower-cased string from a null-padded byte string" 58 field = struct.unpack('%ds' % len(chars), chars)[0] 59 name = [] 60 for ch in field: 61 if ch == '\x00': 62 break 63 name.append(ch.lower()) 64 return ''.join(name)
65 -def convertToBool(value):
66 """Returns boolean true or false; normal rules apply to non-string values; string values 67 must be 'y','t', 'yes', or 'true' (case insensitive) to be True""" 68 if type(value) == str: 69 return bool(value.lower() in ['t', 'y', 'true', 'yes']) 70 else: 71 return bool(value)
72 -def unsupportedType(something, field, memo=None, typ=None):
73 "called if a data type is not supported for that style of table" 74 raise DbfError('field type is not supported.')
75 -def retrieveCharacter(bytes, fielddef={}, memo=None, typ=None):
76 "Returns the string in bytes with trailing white space removed" 77 return typ(bytes.tostring().rstrip())
78 -def updateCharacter(string, fielddef, memo=None):
79 "returns the string, truncating if string is longer than it's field" 80 string = str(string) 81 return string.rstrip()
82 -def retrieveCurrency(bytes, fielddef={}, memo=None, typ=None):
83 value = struct.unpack('<q', bytes)[0] 84 return typ(("%de-4" % value).strip())
85 -def updateCurrency(value, fielddef={}, memo=None):
86 currency = int(value * 10000) 87 if not -9223372036854775808 < currency < 9223372036854775808: 88 raise DataOverflow("value %s is out of bounds" % value) 89 return struct.pack('<q', currency)
90 -def retrieveDate(bytes, fielddef={}, memo=None):
91 "Returns the ascii coded date as a Date object" 92 return Date.fromymd(bytes.tostring())
93 -def updateDate(moment, fielddef={}, memo=None):
94 "returns the Date or datetime.date object ascii-encoded (yyyymmdd)" 95 if moment: 96 return "%04d%02d%02d" % moment.timetuple()[:3] 97 return ' '
98 -def retrieveDouble(bytes, fielddef={}, memo=None, typ=None):
99 return float(struct.unpack('<d', bytes)[0])
100 -def updateDouble(value, fielddef={}, memo=None):
101 return struct.pack('<d', float(value))
102 -def retrieveInteger(bytes, fielddef={}, memo=None, typ=None):
103 "Returns the binary number stored in bytes in little-endian format" 104 if typ is None or typ == 'default': 105 return struct.unpack('<i', bytes)[0] 106 else: 107 return typ(struct.unpack('<i', bytes)[0])
108 -def updateInteger(value, fielddef={}, memo=None):
109 "returns value in little-endian binary format" 110 try: 111 value = int(value) 112 except Exception: 113 raise DbfError("incompatible type: %s(%s)" % (type(value), value)) 114 if not -2147483648 < value < 2147483647: 115 raise DataOverflow("Integer size exceeded. Possible: -2,147,483,648..+2,147,483,647. Attempted: %d" % value) 116 return struct.pack('<i', int(value))
117 -def retrieveLogical(bytes, fielddef={}, memo=None):
118 "Returns True if bytes is 't', 'T', 'y', or 'Y', None if '?', and False otherwise" 119 bytes = bytes.tostring() 120 if bytes == '?': 121 return None 122 return bytes in ['t','T','y','Y']
123 -def updateLogical(logical, fielddef={}, memo=None):
124 "Returs 'T' if logical is True, 'F' otherwise" 125 if type(logical) != bool: 126 logical = convertToBool(logical) 127 if type(logical) <> bool: 128 raise DbfError('Value %s is not logical.' % logical) 129 return logical and 'T' or 'F'
130 -def retrieveMemo(bytes, fielddef, memo, typ):
131 "Returns the block of data from a memo file" 132 stringval = bytes.tostring() 133 if stringval.strip(): 134 block = int(stringval.strip()) 135 else: 136 block = 0 137 return memo.get_memo(block, fielddef)
138 -def updateMemo(string, fielddef, memo):
139 "Writes string as a memo, returns the block number it was saved into" 140 block = memo.put_memo(string) 141 if block == 0: 142 block = '' 143 return "%*s" % (fielddef['length'], block)
144 -def retrieveNumeric(bytes, fielddef, memo=None, typ=None):
145 "Returns the number stored in bytes as integer if field spec for decimals is 0, float otherwise" 146 string = bytes.tostring() 147 if string[0:1] == '*': # value too big to store (Visual FoxPro idiocy) 148 return None 149 if not string.strip(): 150 string = '0' 151 if typ == 'default': 152 if fielddef['decimals'] == 0: 153 return int(string) 154 else: 155 return float(string) 156 else: 157 return typ(string.strip())
158 -def updateNumeric(value, fielddef, memo=None):
159 "returns value as ascii representation, rounding decimal portion as necessary" 160 try: 161 value = float(value) 162 except Exception: 163 raise DbfError("incompatible type: %s(%s)" % (type(value), value)) 164 decimalsize = fielddef['decimals'] 165 if decimalsize: 166 decimalsize += 1 167 maxintegersize = fielddef['length']-decimalsize 168 integersize = len("%.0f" % floor(value)) 169 if integersize > maxintegersize: 170 raise DataOverflow('Integer portion too big') 171 return "%*.*f" % (fielddef['length'], fielddef['decimals'], value)
172 -def retrieveVfpDateTime(bytes, fielddef={}, memo=None):
173 """returns the date/time stored in bytes; dates <= 01/01/1981 00:00:00 174 may not be accurate; BC dates are nulled.""" 175 # two four-byte integers store the date and time. 176 # millesecords are discarded from time 177 time = retrieveInteger(bytes[4:]) 178 microseconds = (time % 1000) * 1000 179 time = time // 1000 # int(round(time, -3)) // 1000 discard milliseconds 180 hours = time // 3600 181 mins = time % 3600 // 60 182 secs = time % 3600 % 60 183 time = Time(hours, mins, secs, microseconds) 184 possible = retrieveInteger(bytes[:4]) 185 possible -= VFPTIME 186 possible = max(0, possible) 187 date = Date.fromordinal(possible) 188 return DateTime.combine(date, time)
189 -def updateVfpDateTime(moment, fielddef={}, memo=None):
190 """sets the date/time stored in moment 191 moment must have fields year, month, day, hour, minute, second, microsecond""" 192 bytes = [0] * 8 193 hour = moment.hour 194 minute = moment.minute 195 second = moment.second 196 millisecond = moment.microsecond // 1000 # convert from millionths to thousandths 197 time = ((hour * 3600) + (minute * 60) + second) * 1000 + millisecond 198 bytes[4:] = updateInteger(time) 199 bytes[:4] = updateInteger(moment.toordinal() + VFPTIME) 200 return ''.join(bytes)
201 -def retrieveVfpMemo(bytes, fielddef, memo, typ=None):
202 "Returns the block of data from a memo file" 203 block = struct.unpack('<i', bytes)[0] 204 return memo.get_memo(block, fielddef)
205 -def updateVfpMemo(string, fielddef, memo):
206 "Writes string as a memo, returns the block number it was saved into" 207 block = memo.put_memo(string) 208 return struct.pack('<i', block)
209 -def addCharacter(format):
210 if format[1] != '(' or format[-1] != ')': 211 raise DbfError("Format for Character field creation is C(n), not %s" % format) 212 length = int(format[2:-1]) 213 if not 0 < length < 255: 214 raise ValueError 215 decimals = 0 216 return length, decimals
217 -def addDate(format):
218 length = 8 219 decimals = 0 220 return length, decimals
221 -def addLogical(format):
222 length = 1 223 decimals = 0 224 return length, decimals
225 -def addMemo(format):
226 length = 10 227 decimals = 0 228 return length, decimals
229 -def addNumeric(format):
230 if format[1] != '(' or format[-1] != ')': 231 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format) 232 length, decimals = format[2:-1].split(',') 233 length = int(length) 234 decimals = int(decimals) 235 if not 0 < length < 18: 236 raise ValueError 237 if decimals and not 0 < decimals <= length - 2: 238 raise ValueError 239 return length, decimals
240 -def addVfpCurrency(format):
241 length = 8 242 decimals = 0 243 return length, decimals
244 -def addVfpDateTime(format):
245 length = 8 246 decimals = 8 247 return length, decimals
248 -def addVfpDouble(format):
249 length = 8 250 decimals = 0 251 return length, decimals
252 -def addVfpInteger(format):
253 length = 4 254 decimals = 0 255 return length, decimals
256 -def addVfpMemo(format):
257 length = 4 258 decimals = 0 259 return length, decimals
260 -def addVfpNumeric(format):
261 if format[1] != '(' or format[-1] != ')': 262 raise DbfError("Format for Numeric field creation is N(n,n), not %s" % format) 263 length, decimals = format[2:-1].split(',') 264 length = int(length) 265 decimals = int(decimals) 266 if not 0 < length < 21: 267 raise ValueError 268 if decimals and not 0 < decimals <= length - 2: 269 raise ValueError 270 return length, decimals
271