text: from __future__ import unicode_literals
  
  from django.core.exceptions import ImproperlyConfigured
  from django import forms
  from django.forms.extras import SelectDateWidget
  from django.utils.translation import ugettext_lazy as _
  
  from mezzanine.conf import settings
  from mezzanine.core.forms import SplitSelectDateTimeWidget
  from mezzanine.utils.importing import import_dotted_path
  
  
  # Constants for all available field types.
  TEXT = 1
  TEXTAREA = 2
  EMAIL = 3
  CHECKBOX = 4
  CHECKBOX_MULTIPLE = 5
  SELECT = 6
  SELECT_MULTIPLE = 7
  RADIO_MULTIPLE = 8
  FILE = 9
  DATE = 10
  DATE_TIME = 11
  HIDDEN = 12
  NUMBER = 13
  URL = 14
  DOB = 15
  
  # Names for all available field types.
  NAMES = (
      (TEXT, _("Single line text")),
      (TEXTAREA, _("Multi line text")),
      (EMAIL, _("Email")),
      (NUMBER, _("Number")),
      (URL, _("URL")),
      (CHECKBOX, _("Check box")),
      (CHECKBOX_MULTIPLE, _("Check boxes")),
      (SELECT, _("Drop down")),
      (SELECT_MULTIPLE, _("Multi select")),
      (RADIO_MULTIPLE, _("Radio buttons")),
      (FILE, _("File upload")),
      (DATE, _("Date")),
      (DATE_TIME, _("Date/time")),
      (DOB, _("Date of birth")),
      (HIDDEN, _("Hidden")),
  )
  
  # Field classes for all available field types.
  CLASSES = {
      TEXT: forms.CharField,
      TEXTAREA: forms.CharField,
      EMAIL: forms.EmailField,
      CHECKBOX: forms.BooleanField,
      CHECKBOX_MULTIPLE: forms.MultipleChoiceField,
      SELECT: forms.ChoiceField,
      SELECT_MULTIPLE: forms.MultipleChoiceField,
      RADIO_MULTIPLE: forms.ChoiceField,
      FILE: forms.FileField,
      DATE: forms.DateField,
      DATE_TIME: forms.DateTimeField,
      DOB: forms.DateField,
      HIDDEN: forms.CharField,
      NUMBER: forms.FloatField,
      URL: forms.URLField,
  }
  
  # Widgets for field types where a specialised widget is required.
  WIDGETS = {
      TEXTAREA: forms.Textarea,
      CHECKBOX_MULTIPLE: forms.CheckboxSelectMultiple,
      RADIO_MULTIPLE: forms.RadioSelect,
      DATE: SelectDateWidget,
      DATE_TIME: SplitSelectDateTimeWidget,
      DOB: SelectDateWidget,
      HIDDEN: forms.HiddenInput,
  }
  
  # Some helper groupings of field types.
  CHOICES = (CHECKBOX, SELECT, RADIO_MULTIPLE)
  DATES = (DATE, DATE_TIME, DOB)
  MULTIPLE = (CHECKBOX_MULTIPLE, SELECT_MULTIPLE)
  
  # HTML5 Widgets
  html5_field = lambda name, base: type(str(""), (base,), {"input_type": name})
  if getattr(settings, "FORMS_USE_HTML5", False):
      WIDGETS.update({
          DATE: html5_field("date", forms.DateInput),
          DATE_TIME: html5_field("datetime", forms.DateTimeInput),
          DOB: html5_field("date", forms.DateInput),
          EMAIL: html5_field("email", forms.TextInput),
          NUMBER: html5_field("number", forms.TextInput),
          URL: html5_field("url", forms.TextInput),
      })
  
  # Allow extra fields types to be defined via the FORMS_EXTRA_FIELDS
  # setting, which should contain a sequence of three-item sequences,
  # each containing the ID, dotted import path for the field class,
  # and field name, for each custom field type.
  extra_fields = getattr(settings, "FORMS_EXTRA_FIELDS", [])
  for field_id, field_path, field_name in extra_fields:
      if field_id in CLASSES:
          err = "ID %s for field %s in FORMS_EXTRA_FIELDS already exists"
          raise ImproperlyConfigured(err % (field_id, field_name))
      CLASSES[field_id] = import_dotted_path(field_path)
      NAMES += ((field_id, _(field_name)),)
  
  # Similar to above but for widgets - expects a sequence of pairs,
  # each with a field ID as per above, and a dotted path to the custom
  # widget class to use for the corresponding form field.
  extra_widgets = getattr(settings, "FORMS_EXTRA_WIDGETS", [])
  for field_id, widget_path in extra_widgets:
      if field_id not in CLASSES:
          err = "ID %s in FORMS_EXTRA_WIDGETS does not match a field"
          raise ImproperlyConfigured(err % field_id)
      WIDGETS[field_id] = import_dotted_path(widget_path)
  