from itertools import chain
from formencode import schema as fes
from formencode.foreach import ForEach
from formencode import validators as fev
from .validators import TimeConverter, DateConverter, UnicodeString
from .widget import Widget
from .utils import Bunch, safe_getitem
from . import core
[docs]class HiddenField(InputField):
defaults=dict(
InputField.defaults,
show_label=False,
show_errors=False,
field_type='hidden')
[docs]class CompoundField(InputField):
defaults=dict(
InputField.defaults,
errors=None,
hidden_fields=[],
extra_fields=[],
show_labels=True,
error_class='fielderror')
fields=[]
chained_validators = []
@core.validator
[docs] def to_python(self, value, state=None):
schema = self._make_schema()
result = schema.to_python(value, state)
return result
[docs] def from_python(self, value, state=None):
if value is None: return None
try:
if not isinstance(value, dict):
value = dict((k, getattr(value, k)) for k in dir(value))
result = self._make_schema().from_python(value, state)
d = dict(value)
d.update(result)
return d
except:
return value
[docs] def resources(self):
for f in chain(self.fields, self.hidden_fields, self.extra_fields):
for r in f.resources(): yield r
[docs] def prepare_context(self, context):
response = super(CompoundField, self).prepare_context(context)
err = core.widget_context.validation_error
if response.get('errors', None) is None and err:
response['errors'] = err.unpack_errors()
response['value'] = err.value
if getattr(self, 'name', None):
response['errors'] = response['errors'].get(self.name, None)
response['value'] = response['value'].get(self.name, None)
return response
[docs] def context_for(self, field):
context = core.widget_context.render_context
if not field.name:
return Bunch(
name=context.get('name', None),
value=context.get('value', None),
errors=context.get('errors', None))
if context.get('name'):
name = context['name'] + '.' + field.name
else:
name = field.name
r = Bunch(
name=name,
value=safe_getitem(context, 'value', field.name),
errors=safe_getitem(context, 'errors', field.name))
return r
def _all_fields(self):
return chain(self.fields, self.hidden_fields, self.extra_fields)
def _make_schema(self):
kwargs = dict((f.name, f) for f in self._all_fields()
if f.name and getattr(f, 'perform_validation', False))
for f in self.fields:
if f.name: continue
if hasattr(f, '_make_schema'):
kwargs.update(f._make_schema().fields)
kwargs.update(chained_validators=self.chained_validators,
ignore_key_missing=True,
allow_extra_fields=True,
filter_extra_fields=True)
return fes.Schema(**kwargs)
[docs]class FieldSet(CompoundField):
defaults=dict(
CompoundField.defaults,
show_label=False)
[docs]class RowField(CompoundField): pass
[docs]class RepeatedField(InputField):
defaults=dict(
InputField.defaults,
errors=None,
repetitions=3,
error_class='fielderror')
field=None
chained_validators = []
def __init__(self, **kw):
self._name = None
super(RepeatedField, self).__init__(**kw)
@core.validator
[docs] def to_python(self, value, state=None):
return self._make_schema().to_python(value, state)
[docs] def from_python(self, value, state=None):
if value is None: return None
return self._make_schema().from_python(value, state)
[docs] def resources(self):
return self.field.resources()
[docs] def prepare_context(self, context):
response = super(RepeatedField, self).prepare_context(context)
err = core.widget_context.validation_error
if response.get('errors', None) is None and err:
response['errors'] = err.unpack_errors()
response['value'] = err.value
if response.get('value', None) is not None:
response['repetitions'] = len(response['value'])
else:
response['value'] = [ None ] * response['repetitions']
return response
[docs] def context_for(self, repetition):
def get(coll, default=None):
try:
return coll[repetition]
except (IndexError, KeyError):
return default
context = core.widget_context.render_context
value = context.get('value') or []
name = context['name'] + '-' + unicode(repetition)
r = Bunch(
name=name,
value=get(value, None),
errors=None)
if context.get('errors', None) is not None:
r['errors'] = get(context['errors']) or {}
return r
def _get_name(self):
if self._name is None:
if self.field: return self.field.name
else: return self._name
return self._name
def _set_name(self, value):
self._name = value
name = property(_get_name, _set_name)
def _make_schema(self):
return ForEach(self.field, if_missing=[], if_empty=[])
[docs]class TableField(RepeatedField):
show_label = False
fields=[]
hidden_fields=[]
RowField=RowField
def __init__(self, **kw):
super(TableField, self).__init__(**kw)
if self.field is None:
fields = kw.get('fields', self.fields)
hidden_fields = kw.get('hidden_fields', self.hidden_fields)
name = self.name
self.field = self.RowField(name=name, fields=fields, hidden_fields=hidden_fields)
self.name = None
[docs]class TextField(InputField):
validator = UnicodeString()
defaults=dict(
InputField.defaults,
field_type='text')
[docs]class EmailField(TextField):
validator = fev.Email()
[docs]class NumberField(TextField):
validator = fev.Number()
[docs]class IntField(TextField):
validator = fev.Int()
[docs]class DateField(TextField):
validator=DateConverter()
defaults=dict(
TextField.defaults,
attrs={'style':'width:6em'})
[docs]class TimeField(TextField):
validator=TimeConverter(use_seconds=False)
defaults=dict(
TextField.defaults,
attrs={'style':'width:5em'})
[docs]class TextArea(InputField):
validator = UnicodeString()
defaults=dict(
InputField.defaults,
cols=60)
[docs]class Checkbox(InputField):
validator=fev.StringBool(if_empty=False, if_missing=False)
defaults=dict(
InputField.defaults,
show_label=False, # don't show default label
suppress_label=False, # if true, don't label the checkbox
)
[docs] def from_python(self, value, state):
if value: return 'CHECKED'
else: return None
[docs]class HTMLField(Widget):
defaults=dict(
Widget.defaults,
show_label=False,
text='')
perform_validation=False
[docs]class LinkField(Widget):
defaults=dict(
Widget.defaults,
href=None,
attrs=None,
label=None,
text=None,
show_label=False)