summaryrefslogtreecommitdiff
path: root/src/tablib/packages/dbfpy3/fields.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/tablib/packages/dbfpy3/fields.py')
-rw-r--r--src/tablib/packages/dbfpy3/fields.py466
1 files changed, 0 insertions, 466 deletions
diff --git a/src/tablib/packages/dbfpy3/fields.py b/src/tablib/packages/dbfpy3/fields.py
deleted file mode 100644
index ad63c28..0000000
--- a/src/tablib/packages/dbfpy3/fields.py
+++ /dev/null
@@ -1,466 +0,0 @@
-"""DBF fields definitions.
-
-TODO:
- - make memos work
-"""
-"""History (most recent first):
-26-may-2009 [als] DbfNumericFieldDef.decodeValue: strip zero bytes
-05-feb-2009 [als] DbfDateFieldDef.encodeValue: empty arg produces empty date
-16-sep-2008 [als] DbfNumericFieldDef decoding looks for decimal point
- in the value to select float or integer return type
-13-mar-2008 [als] check field name length in constructor
-11-feb-2007 [als] handle value conversion errors
-10-feb-2007 [als] DbfFieldDef: added .rawFromRecord()
-01-dec-2006 [als] Timestamp columns use None for empty values
-31-oct-2006 [als] support field types 'F' (float), 'I' (integer)
- and 'Y' (currency);
- automate export and registration of field classes
-04-jul-2006 [als] added export declaration
-10-mar-2006 [als] decode empty values for Date and Logical fields;
- show field name in errors
-10-mar-2006 [als] fix Numeric value decoding: according to spec,
- value always is string representation of the number;
- ensure that encoded Numeric value fits into the field
-20-dec-2005 [yc] use field names in upper case
-15-dec-2005 [yc] field definitions moved from `dbf`.
-"""
-
-__version__ = "$Revision: 1.14 $"[11:-2]
-__date__ = "$Date: 2009/05/26 05:16:51 $"[7:-2]
-
-__all__ = ["lookupFor",] # field classes added at the end of the module
-
-import datetime
-import struct
-import sys
-
-from . import utils
-
-## abstract definitions
-
-class DbfFieldDef(object):
- """Abstract field definition.
-
- Child classes must override ``type`` class attribute to provide datatype
- information of the field definition. For more info about types visit
- `http://www.clicketyclick.dk/databases/xbase/format/data_types.html`
-
- Also child classes must override ``defaultValue`` field to provide
- default value for the field value.
-
- If child class has fixed length ``length`` class attribute must be
- overridden and set to the valid value. None value means, that field
- isn't of fixed length.
-
- Note: ``name`` field must not be changed after instantiation.
-
- """
-
- __slots__ = ("name", "decimalCount",
- "start", "end", "ignoreErrors")
-
- # length of the field, None in case of variable-length field,
- # or a number if this field is a fixed-length field
- length = None
-
- # field type. for more information about fields types visit
- # `http://www.clicketyclick.dk/databases/xbase/format/data_types.html`
- # must be overridden in child classes
- typeCode = None
-
- # default value for the field. this field must be
- # overridden in child classes
- defaultValue = None
-
- def __init__(self, name, length=None, decimalCount=None,
- start=None, stop=None, ignoreErrors=False,
- ):
- """Initialize instance."""
- assert self.typeCode is not None, "Type code must be overridden"
- assert self.defaultValue is not None, "Default value must be overridden"
- ## fix arguments
- if len(name) >10:
- raise ValueError("Field name \"%s\" is too long" % name)
- name = str(name).upper()
- if self.__class__.length is None:
- if length is None:
- raise ValueError("[%s] Length isn't specified" % name)
- length = int(length)
- if length <= 0:
- raise ValueError("[%s] Length must be a positive integer"
- % name)
- else:
- length = self.length
- if decimalCount is None:
- decimalCount = 0
- ## set fields
- self.name = name
- # FIXME: validate length according to the specification at
- # http://www.clicketyclick.dk/databases/xbase/format/data_types.html
- self.length = length
- self.decimalCount = decimalCount
- self.ignoreErrors = ignoreErrors
- self.start = start
- self.end = stop
-
- def __cmp__(self, other):
- return cmp(self.name, str(other).upper())
-
- def __hash__(self):
- return hash(self.name)
-
- def fromString(cls, string, start, ignoreErrors=False):
- """Decode dbf field definition from the string data.
-
- Arguments:
- string:
- a string, dbf definition is decoded from. length of
- the string must be 32 bytes.
- start:
- position in the database file.
- ignoreErrors:
- initial error processing mode for the new field (boolean)
-
- """
- assert len(string) == 32
- _length = string[16]
- return cls(utils.unzfill(string)[:11].decode('utf-8'), _length,
- string[17], start, start + _length, ignoreErrors=ignoreErrors)
- fromString = classmethod(fromString)
-
- def toString(self):
- """Return encoded field definition.
-
- Return:
- Return value is a string object containing encoded
- definition of this field.
-
- """
- if sys.version_info < (2, 4):
- # earlier versions did not support padding character
- _name = self.name[:11] + "\0" * (11 - len(self.name))
- else:
- _name = self.name.ljust(11, '\0')
- return (
- _name +
- self.typeCode +
- #data address
- chr(0) * 4 +
- chr(self.length) +
- chr(self.decimalCount) +
- chr(0) * 14
- )
-
- def __repr__(self):
- return "%-10s %1s %3d %3d" % self.fieldInfo()
-
- def fieldInfo(self):
- """Return field information.
-
- Return:
- Return value is a (name, type, length, decimals) tuple.
-
- """
- return (self.name, self.typeCode, self.length, self.decimalCount)
-
- def rawFromRecord(self, record):
- """Return a "raw" field value from the record string."""
- return record[self.start:self.end]
-
- def decodeFromRecord(self, record):
- """Return decoded field value from the record string."""
- try:
- return self.decodeValue(self.rawFromRecord(record))
- except:
- if self.ignoreErrors:
- return utils.INVALID_VALUE
- else:
- raise
-
- def decodeValue(self, value):
- """Return decoded value from string value.
-
- This method shouldn't be used publicly. It's called from the
- `decodeFromRecord` method.
-
- This is an abstract method and it must be overridden in child classes.
- """
- raise NotImplementedError
-
- def encodeValue(self, value):
- """Return str object containing encoded field value.
-
- This is an abstract method and it must be overridden in child classes.
- """
- raise NotImplementedError
-
-## real classes
-
-class DbfCharacterFieldDef(DbfFieldDef):
- """Definition of the character field."""
-
- typeCode = "C"
- defaultValue = b''
-
- def decodeValue(self, value):
- """Return string object.
-
- Return value is a ``value`` argument with stripped right spaces.
-
- """
- return value.rstrip(b' ').decode('utf-8')
-
- def encodeValue(self, value):
- """Return raw data string encoded from a ``value``."""
- return str(value)[:self.length].ljust(self.length)
-
-
-class DbfNumericFieldDef(DbfFieldDef):
- """Definition of the numeric field."""
-
- typeCode = "N"
- # XXX: now I'm not sure it was a good idea to make a class field
- # `defaultValue` instead of a generic method as it was implemented
- # previously -- it's ok with all types except number, cuz
- # if self.decimalCount is 0, we should return 0 and 0.0 otherwise.
- defaultValue = 0
-
- def decodeValue(self, value):
- """Return a number decoded from ``value``.
-
- If decimals is zero, value will be decoded as an integer;
- or as a float otherwise.
-
- Return:
- Return value is a int (long) or float instance.
-
- """
- value = value.strip(b' \0')
- if b'.' in value:
- # a float (has decimal separator)
- return float(value)
- elif value:
- # must be an integer
- return int(value)
- else:
- return 0
-
- def encodeValue(self, value):
- """Return string containing encoded ``value``."""
- _rv = ("%*.*f" % (self.length, self.decimalCount, value))
- if len(_rv) > self.length:
- _ppos = _rv.find(".")
- if 0 <= _ppos <= self.length:
- _rv = _rv[:self.length]
- else:
- raise ValueError("[%s] Numeric overflow: %s (field width: %i)"
- % (self.name, _rv, self.length))
- return _rv
-
-class DbfFloatFieldDef(DbfNumericFieldDef):
- """Definition of the float field - same as numeric."""
-
- typeCode = "F"
-
-class DbfIntegerFieldDef(DbfFieldDef):
- """Definition of the integer field."""
-
- typeCode = "I"
- length = 4
- defaultValue = 0
-
- def decodeValue(self, value):
- """Return an integer number decoded from ``value``."""
- return struct.unpack("<i", value)[0]
-
- def encodeValue(self, value):
- """Return string containing encoded ``value``."""
- return struct.pack("<i", int(value))
-
-class DbfCurrencyFieldDef(DbfFieldDef):
- """Definition of the currency field."""
-
- typeCode = "Y"
- length = 8
- defaultValue = 0.0
-
- def decodeValue(self, value):
- """Return float number decoded from ``value``."""
- return struct.unpack("<q", value)[0] / 10000.
-
- def encodeValue(self, value):
- """Return string containing encoded ``value``."""
- return struct.pack("<q", round(value * 10000))
-
-class DbfLogicalFieldDef(DbfFieldDef):
- """Definition of the logical field."""
-
- typeCode = "L"
- defaultValue = -1
- length = 1
-
- def decodeValue(self, value):
- """Return True, False or -1 decoded from ``value``."""
- # Note: value always is 1-char string
- if value == "?":
- return -1
- if value in "NnFf ":
- return False
- if value in "YyTt":
- return True
- raise ValueError("[%s] Invalid logical value %r" % (self.name, value))
-
- def encodeValue(self, value):
- """Return a character from the "TF?" set.
-
- Return:
- Return value is "T" if ``value`` is True
- "?" if value is -1 or False otherwise.
-
- """
- if value is True:
- return "T"
- if value == -1:
- return "?"
- return "F"
-
-
-class DbfMemoFieldDef(DbfFieldDef):
- """Definition of the memo field.
-
- Note: memos aren't currently completely supported.
-
- """
-
- typeCode = "M"
- defaultValue = " " * 10
- length = 10
-
- def decodeValue(self, value):
- """Return int .dbt block number decoded from the string object."""
- #return int(value)
- raise NotImplementedError
-
- def encodeValue(self, value):
- """Return raw data string encoded from a ``value``.
-
- Note: this is an internal method.
-
- """
- #return str(value)[:self.length].ljust(self.length)
- raise NotImplementedError
-
-
-class DbfDateFieldDef(DbfFieldDef):
- """Definition of the date field."""
-
- typeCode = "D"
- defaultValue = utils.classproperty(lambda cls: datetime.date.today())
- # "yyyymmdd" gives us 8 characters
- length = 8
-
- def decodeValue(self, value):
- """Return a ``datetime.date`` instance decoded from ``value``."""
- if value.strip():
- return utils.getDate(value)
- else:
- return None
-
- def encodeValue(self, value):
- """Return a string-encoded value.
-
- ``value`` argument should be a value suitable for the
- `utils.getDate` call.
-
- Return:
- Return value is a string in format "yyyymmdd".
-
- """
- if value:
- return utils.getDate(value).strftime("%Y%m%d")
- else:
- return " " * self.length
-
-
-class DbfDateTimeFieldDef(DbfFieldDef):
- """Definition of the timestamp field."""
-
- # a difference between JDN (Julian Day Number)
- # and GDN (Gregorian Day Number). note, that GDN < JDN
- JDN_GDN_DIFF = 1721425
- typeCode = "T"
- defaultValue = utils.classproperty(lambda cls: datetime.datetime.now())
- # two 32-bits integers representing JDN and amount of
- # milliseconds respectively gives us 8 bytes.
- # note, that values must be encoded in LE byteorder.
- length = 8
-
- def decodeValue(self, value):
- """Return a `datetime.datetime` instance."""
- assert len(value) == self.length
- # LE byteorder
- _jdn, _msecs = struct.unpack("<2I", value)
- if _jdn >= 1:
- _rv = datetime.datetime.fromordinal(_jdn - self.JDN_GDN_DIFF)
- _rv += datetime.timedelta(0, _msecs / 1000.0)
- else:
- # empty date
- _rv = None
- return _rv
-
- def encodeValue(self, value):
- """Return a string-encoded ``value``."""
- if value:
- value = utils.getDateTime(value)
- # LE byteorder
- _rv = struct.pack("<2I", value.toordinal() + self.JDN_GDN_DIFF,
- (value.hour * 3600 + value.minute * 60 + value.second) * 1000)
- else:
- _rv = "\0" * self.length
- assert len(_rv) == self.length
- return _rv
-
-
-_fieldsRegistry = {}
-
-def registerField(fieldCls):
- """Register field definition class.
-
- ``fieldCls`` should be subclass of the `DbfFieldDef`.
-
- Use `lookupFor` to retrieve field definition class
- by the type code.
-
- """
- assert fieldCls.typeCode is not None, "Type code isn't defined"
- # XXX: use fieldCls.typeCode.upper()? in case of any decign
- # don't forget to look to the same comment in ``lookupFor`` method
- _fieldsRegistry[fieldCls.typeCode] = fieldCls
-
-
-def lookupFor(typeCode):
- """Return field definition class for the given type code.
-
- ``typeCode`` must be a single character. That type should be
- previously registered.
-
- Use `registerField` to register new field class.
-
- Return:
- Return value is a subclass of the `DbfFieldDef`.
-
- """
- # XXX: use typeCode.upper()? in case of any decign don't
- # forget to look to the same comment in ``registerField``
- return _fieldsRegistry[chr(typeCode)]
-
-## register generic types
-
-for (_name, _val) in list(globals().items()):
- if isinstance(_val, type) and issubclass(_val, DbfFieldDef) \
- and (_name != "DbfFieldDef"):
- __all__.append(_name)
- registerField(_val)
-del _name, _val
-
-# vim: et sts=4 sw=4 :