we should go over them once more to make sure we didn't miss anything, but testing validation should probably be done after that. Verify that the record ordering enforcement code is correct, then start thinking of how to get data from external sources into the record generator.
222 lines
6.6 KiB
Python
222 lines
6.6 KiB
Python
import decimal, datetime
|
|
import inspect
|
|
import enums
|
|
|
|
class ValidationError(Exception):
|
|
def __init__(self, msg, field=None):
|
|
self.msg = msg
|
|
self.field = field
|
|
|
|
def __str__(self):
|
|
if self.field:
|
|
return "(%s.%s) %s" % (self.field.parent_name, self.field.name, self.msg)
|
|
else:
|
|
return repr(self.msg)
|
|
|
|
class Field(object):
|
|
creation_counter = 0
|
|
|
|
def __init__(self, name=None, max_length=0, required=True, uppercase=True):
|
|
self.name = name
|
|
self._value = None
|
|
self.max_length = max_length
|
|
self.required = required
|
|
self.uppercase = uppercase
|
|
self.creation_counter = Field.creation_counter
|
|
Field.creation_counter += 1
|
|
|
|
def validate(self):
|
|
raise NotImplemented
|
|
|
|
def get_data(self):
|
|
raise NotImplemented
|
|
|
|
def __setvalue(self, value):
|
|
self._value = value
|
|
|
|
def __getvalue(self):
|
|
return self._value
|
|
|
|
value = property(__getvalue, __setvalue)
|
|
|
|
def read(self, fp):
|
|
if fp.tell() + self.max_length <= fp.len:
|
|
data = fp.read(self.max_length)
|
|
return self.parse(data)
|
|
return None
|
|
|
|
def parse(self, s):
|
|
self.value = s.strip()
|
|
|
|
|
|
class TextField(Field):
|
|
def validate(self):
|
|
if self.value == None and self.required:
|
|
raise ValidationError("value required", field=self)
|
|
if len(self.get_data()) > self.max_length:
|
|
raise ValidationError("value is too long", field=self)
|
|
|
|
def get_data(self):
|
|
value = self.value or ""
|
|
if self.uppercase:
|
|
value = value.upper()
|
|
return value.ljust(self.max_length).encode('ascii')
|
|
|
|
|
|
class StateField(TextField):
|
|
def __init__(self, name=None, required=True, use_numeric=False):
|
|
super(StateField, self).__init__(name=name, max_length=2, required=required)
|
|
self.use_numeric = use_numeric
|
|
|
|
def get_data(self):
|
|
value = self.value or ""
|
|
if value.strip() and self.use_numeric:
|
|
return str(enums.state_postal_numeric[value.upper()]).zfill(self.max_length)
|
|
else:
|
|
return value.ljust(self.max_length).encode('ascii')
|
|
|
|
def validate(self):
|
|
super(StateField, self).validate()
|
|
if self.value and self.value.upper() not in enums.state_postal_numeric.keys():
|
|
raise ValidationError("%s is not a valid state abbreviation" % self.value, field=self)
|
|
|
|
def parse(self, s):
|
|
if s.strip() and self.use_numeric:
|
|
states = dict( [(v,k) for (k,v) in enums.state_postal_numeric.items()] )
|
|
self.value = states[int(s)]
|
|
else:
|
|
self.value = s
|
|
|
|
class EmailField(TextField):
|
|
def __init__(self, name=None, required=True, max_length=None):
|
|
return super(EmailField, self).__init__(name=name, max_length=max_length,
|
|
required=required, uppercase=False)
|
|
|
|
class NumericField(TextField):
|
|
def validate(self):
|
|
super(NumericField, self).validate()
|
|
if self.value:
|
|
try:
|
|
int(self.value)
|
|
except ValueError:
|
|
raise ValidationError("field contains non-numeric characters", field=self)
|
|
|
|
|
|
def get_data(self):
|
|
value = self.value or ""
|
|
return str(value).zfill(self.max_length)
|
|
|
|
def parse(self, s):
|
|
self.value = int(s)
|
|
|
|
|
|
class StaticField(TextField):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(StaticField, self).__init__(name=name, required=required,
|
|
max_length=len(value))
|
|
self._value = value
|
|
|
|
def parse(self, s):
|
|
pass
|
|
|
|
class BlankField(TextField):
|
|
def __init__(self, name=None, max_length=0, required=False):
|
|
super(TextField, self).__init__(name=name, max_length=max_length, required=required, uppercase=False)
|
|
|
|
def get_data(self):
|
|
return " " * self.max_length
|
|
|
|
def parse(self, s):
|
|
pass
|
|
|
|
class BooleanField(Field):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(BooleanField, self).__init__(name=name, required=required, max_length=1)
|
|
self._value = value
|
|
|
|
def validate(self):
|
|
pass
|
|
|
|
def get_data(self):
|
|
return '1' if self._value else '0'
|
|
|
|
def parse(self, s):
|
|
self.value = (s == '1')
|
|
|
|
|
|
class MoneyField(Field):
|
|
def validate(self):
|
|
if self.value == None and self.required:
|
|
raise ValidationError("value required", field=self)
|
|
if len(str(int((self.value or 0)*100))) > self.max_length:
|
|
raise ValidationError("value is too long", field=self)
|
|
|
|
def get_data(self):
|
|
return str(int((self.value or 0)*100)).encode('ascii').zfill(self.max_length)
|
|
|
|
def parse(self, s):
|
|
self.value = decimal.Decimal(s) * decimal.Decimal('0.01')
|
|
|
|
|
|
class DateField(TextField):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(TextField, self).__init__(name=name, required=required, max_length=8)
|
|
if value:
|
|
self.value = value
|
|
|
|
def get_data(self):
|
|
if self._value:
|
|
return self._value.strftime('%m%d%Y')
|
|
return '0' * self.max_length
|
|
|
|
def parse(self, s):
|
|
if int(s) > 0:
|
|
self.value = datetime.date(*[int(x) for x in s[4:8], s[0:2], s[2:4]])
|
|
else:
|
|
self.value = None
|
|
|
|
def __setvalue(self, value):
|
|
if isinstance(value, datetime.date):
|
|
self._value = value
|
|
elif value:
|
|
self._value = datetime.date(*[int(x) for x in value[4:8], value[0:2], value[2:4]])
|
|
else:
|
|
self._value = None
|
|
|
|
def __getvalue(self):
|
|
return self._value
|
|
|
|
value = property(__getvalue, __setvalue)
|
|
|
|
|
|
class MonthYearField(TextField):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(TextField, self).__init__(name=name, required=required, max_length=6)
|
|
|
|
if value:
|
|
self.value = value
|
|
|
|
def get_data(self):
|
|
if self._value:
|
|
return self._value.strftime("%m%Y")
|
|
return '0' * self.max_length
|
|
|
|
def parse(self, s):
|
|
if int(s) > 0:
|
|
self.value = datetime.date(*[int(x) for x in s[2:6], s[0:2], 1])
|
|
else:
|
|
self.value = None
|
|
|
|
def __setvalue(self, value):
|
|
if isinstance(value, datetime.date):
|
|
self._value = value
|
|
elif value:
|
|
self._value = datetime.date(*[int(x) for x in value[2:6], value[0:2], 1])
|
|
else:
|
|
self._value = None
|
|
|
|
def __getvalue(self):
|
|
return self._value
|
|
|
|
value = property(__getvalue, __setvalue)
|
|
|