Unify similar code from Type subclasses in base class

Instead of implementing the `parse()` and `format()` methods and
setting the `null` attribute in subclasses, we set the `model_type`
field and the generic implementations of the two methods take care of
the rest.

Again: No change in behaviour!
This commit is contained in:
Thomas Scholtes 2014-09-14 17:02:58 +02:00
parent 30addc12b4
commit fafc56c95b
2 changed files with 42 additions and 39 deletions

View file

@ -34,30 +34,42 @@ class Type(object):
"""The `Query` subclass to be used when querying the field.
"""
null = None
"""The value to be exposed when the underlying value is None.
model_type = unicode
"""The python type that is used to represent the value in the model.
The model is guaranteed to return a value of this type if the field
is accessed. To this end, the constructor is used by the `normalize`
and `from_sql` methods and the `default` property.
"""
@property
def null(self):
"""The value to be exposed when the underlying value is None.
"""
return self.model_type()
def format(self, value):
"""Given a value of this type, produce a Unicode string
representing the value. This is used in template evaluation.
"""
# Fallback formatter. Convert to Unicode at all cost.
if value is None:
return u''
elif isinstance(value, basestring):
if isinstance(value, bytes):
return value.decode('utf8', 'ignore')
else:
return value
else:
return unicode(value)
value = self.null
if value is None:
value = u''
if isinstance(value, bytes):
value = value.decode('utf8', 'ignore')
return unicode(value)
def parse(self, string):
"""Parse a (possibly human-written) string and return the
indicated value of this type.
"""
return string
try:
return self.model_type(string)
except ValueError:
return self.null
def normalize(self, value):
"""Given a value that will be assigned into a field of this
@ -67,17 +79,29 @@ class Type(object):
if value is None:
return self.null
else:
# TODO This should eventually be replaced by
# `self.model_type(value)`
return value
def from_sql(self, sql_value):
"""Convert a value received from the database adapter to a value
stored in the model object.
"""Receives the value stored in the SQL backend and return the
value to be stored in the model.
For fixed fields the type of `value` is determined by the column
type given in the `sql` property and the SQL to Python mapping
given here:
https://docs.python.org/2/library/sqlite3.html#sqlite-and-python-types
For flexible field the value is a unicode object. The method
must therefore be able to parse them.
"""
return self.normalize(sql_value)
def to_sql(self, model_value):
"""Convert a value as stored in the model object to a value used
by the database adapter.
For flexible field the value is a unicode object. The method
must therefore be able to parse them.
"""
return model_value
@ -85,7 +109,7 @@ class Type(object):
# Reusable types.
class Default(Type):
pass
null = None
class Integer(Type):
@ -93,16 +117,7 @@ class Integer(Type):
"""
sql = u'INTEGER'
query = query.NumericQuery
null = 0
def format(self, value):
return unicode(value or 0)
def parse(self, string):
try:
return int(string)
except ValueError:
return 0
model_type = int
class PaddedInt(Integer):
@ -144,17 +159,11 @@ class Float(Type):
"""
sql = u'REAL'
query = query.NumericQuery
null = 0.0
model_type = float
def format(self, value):
return u'{0:.1f}'.format(value or 0.0)
def parse(self, string):
try:
return float(string)
except ValueError:
return 0.0
class NullFloat(Float):
"""Same as `Float`, but does not normalize `None` to `0.0`.
@ -167,13 +176,6 @@ class String(Type):
"""
sql = u'TEXT'
query = query.SubstringQuery
null = u''
def format(self, value):
return unicode(value) if value else u''
def parse(self, string):
return string
class Boolean(Type):
@ -181,7 +183,7 @@ class Boolean(Type):
"""
sql = u'INTEGER'
query = query.BooleanQuery
null = False
model_type = bool
def format(self, value):
return unicode(bool(value))

View file

@ -87,6 +87,7 @@ class DateType(types.Float):
class PathType(types.Type):
sql = u'BLOB'
query = PathQuery
model_type = str
def format(self, value):
return util.displayable_path(value)