There are two ways to define a new datatype: sub-classing and instantiating.
All datatypes inherit from the abstract class DataType. To define a new datatype either subclass directly from DateType, or from any other subclass of it.
As an example we are going to define a datatype that loads mimetypes as a two elements tuple:
import mimetypes
from itools.datatypes import DataType
class MimeType(DataType):
default = None
@staticmethod
def decode(data):
return tuple(data.split('/'))
@staticmethod
def encode(value):
return '%s/%s' % value
@staticmethod
def is_valid(data):
return mimetypes.guess_extension(data) is not None
Two things to highlight:
We have set the default value to None, though this is not really needed since the DataType class already defines this variable to None.
Another good default value maybe (’application’, ’octet-stream’).
We have added the method is_valid, which is not defined by any other datatype included in itools. This illustrates that the datatypes can be extended with whatever logic, which we could use later in the application code.
This is a more compact way to specialize a datatype, when the changes are small. For example:
from itools.datatypes import String
WorkflowState = String(default='private')
Here we have defined a workflow state as an string, whose default value is private.
Note that a shortcoming of this approach is that, unlike sub-classing, it is not possible to instantiate a datatype that already is an instance.