class DateField(TextField): """Simple date input field.""" missing = None error_msg = _('"${val}" is not a date object') error_invalid_date = _('Invalid date') def to_form(self, value): if value is null: return null if isinstance(value, datetime.datetime): value = value.date() if not isinstance(value, datetime.date): raise Invalid(self.error_msg, self, {'val': value}) return value.isoformat() def to_field(self, value): if not value: return null try: result = iso8601.parse_date(value) result = result.date() except (iso8601.ParseError, TypeError): try: year, month, day = map(int, value.split('-', 2)) result = datetime.date(year, month, day) except Exception: raise Invalid(self.error_invalid_date, self) return result
class BoolField(BaseChoiceField): __doc__ = _('Boolean input widget.') vocabulary = vocabulary.SimpleVocabulary.from_items( (True, 'true', _('yes')), (False, 'false', _('no'))) tmpl_input = 'ptah.form:templates/fields/bool-input.pt'
class Range(object): """ Validator which succeeds if the value it is passed is greater or equal to ``min`` and less than or equal to ``max``. If ``min`` is not specified, or is specified as ``None``, no lower bound exists. If ``max`` is not specified, or is specified as ``None``, no upper bound exists. ``min_err`` is used to form the ``msg`` of the :exc:`ptah.form.Invalid` error when reporting a validation failure caused by a value not meeting the minimum. If ``min_err`` is specified, it must be a string. The string may contain the replacement targets ``${min}`` and ``${val}``, representing the minimum value and the provided value respectively. If it is not provided, it defaults to ``'${val} is less than minimum value ${min}'``. ``max_err`` is used to form the ``msg`` of the :exc:`ptah.form.Invalid` error when reporting a validation failure caused by a value exceeding the maximum. If ``max_err`` is specified, it must be a string. The string may contain the replacement targets ``${max}`` and ``${val}``, representing the maximum value and the provided value respectively. If it is not provided, it defaults to ``'${val} is greater than maximum value ${max}'``. """ min_err = _('${val} is less than minimum value ${min}') max_err = _('${val} is greater than maximum value ${max}') def __init__(self, min=None, max=None, min_err=None, max_err=None): self.min = min self.max = max if min_err is not None: self.min_err = min_err if max_err is not None: self.max_err = max_err def __call__(self, field, value): if self.min is not None: if value < self.min: min_err = _(self.min_err, mapping={ 'val': value, 'min': self.min }) raise Invalid(min_err, field) if self.max is not None: if value > self.max: max_err = _(self.max_err, mapping={ 'val': value, 'max': self.max }) raise Invalid(max_err, field)
def __call__(self, field, value): if self.min is not None: if len(value) < self.min: min_err = _('Shorter than minimum length ${min}', mapping={'min': self.min}) raise Invalid(field, min_err) if self.max is not None: if len(value) > self.max: max_err = _('Longer than maximum length ${max}', mapping={'max': self.max}) raise Invalid(field, max_err)
def __call__(self, field, value): if self.min is not None: if len(value) < self.min: min_err = _('Shorter than minimum length ${min}', mapping={'min': self.min}) raise Invalid(min_err, field) if self.max is not None: if len(value) > self.max: max_err = _('Longer than maximum length ${max}', mapping={'max': self.max}) raise Invalid(max_err, field)
def __call__(self, field, value): if self.min is not None: if value < self.min: min_err = _(self.min_err, mapping={'val': value, 'min': self.min}) raise Invalid(field, min_err) if self.max is not None: if value > self.max: max_err = _(self.max_err, mapping={'val': value, 'max': self.max}) raise Invalid(field, max_err)
class TimezoneField(ChoiceField): """ Timezone field. Field name is ``timezone``.""" error_msg = _('Invalid timezone "${val}"') _tzs = dict((str(tz).lower(), str(tz)) for tz in pytz.all_timezones) vocabulary = vocabulary.Vocabulary( *[(str(tz).lower(), str(tz).lower(), str(tz)) for tz in pytz.all_timezones]) def to_form(self, value): if value is null: return null return str(value).lower() def to_field(self, value): if value is null or not value: return null try: v = str(value).lower() if v.startswith('gmt'): v = 'etc/%s' % v try: return pytz.timezone(v) except: return pytz.timezone(self._tzs[v]) except: raise Invalid(self.error_msg, self, {'val': value})
class LinesField(TextAreaField): __doc__ = _('Text area based widget, each line is treated as ' 'sequence element.') klass = 'textlines-widget' loads = Field.loads def serialize(self, value): if value is null or not value: return null try: return '\n'.join(value) except Exception: raise Invalid(self, _('"${val}" is not a list', mapping={'val': value}), ) def deserialize(self, value): if not value: return null try: return [s.strip() for s in value.split()] except Exception: raise Invalid(self, _('"${val}" is not a list', mapping={'val': value}), )
def deserialize(self, value): if not value: return null try: return datetime.datetime.strptime(value, "%m/%d/%Y").date() except Exception as e: raise Invalid(self, _("Invalid date", mapping={"val": value, "err": e}))
class DateField(TextField): __doc__ = _('Simple date input field.') tmpl_display = 'ptah.form:templates/fields/date-display.pt' def serialize(self, value): if value is null: return null if isinstance(value, datetime.datetime): value = value.date() if not isinstance(value, datetime.date): raise Invalid(self, _('"${val}" is not a date object', mapping={'val': value})) return value.isoformat() def deserialize(self, value): if not value: return null try: result = iso8601.parse_date(value) result = result.date() except (iso8601.ParseError, TypeError): try: year, month, day = map(int, value.split('-', 2)) result = datetime.date(year, month, day) except Exception as e: raise Invalid( self, _('Invalid date', mapping={'val': value, 'err': e})) return result
class BaseChoiceField(VocabularyField): """ base choice field """ error_msg = _('"${val}" is not in vocabulary') def to_form(self, value): try: return self.vocabulary.get_term(value).token except LookupError: raise Invalid(self.error_msg, self, {'val': value}) def to_field(self, value): if not value: return null try: return self.vocabulary.get_term_bytoken(value).value except LookupError: raise Invalid(self.error_msg, self, {'val': value}) def is_checked(self, term): return 'checked' if term.token == self.form_value else None def update(self): super(BaseChoiceField, self).update() self.update_items() def extract(self): value = super(BaseChoiceField, self).extract() if not value or value == self.no_value_token: return null return value
def validate(self, value): """ validate value """ if value is required: raise Invalid(self, _('Required')) if self.validator is not None: self.validator(self, value)
class DecimalField(Number, InputField): __doc__ = _('Decimal input widget') klass = 'decimal-widget' def num(self, val): return decimal.Decimal(str(val))
def __init__(self, msg=None): if msg is None: msg = _("Invalid email address") super(Email, self).__init__('(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$', msg=msg)
class PasswordField(TextField): __doc__ = _('HTML Password input widget.') klass = 'password-widget' tmpl_input = 'ptah.form:templates/fields/password-input.pt' tmpl_display = 'ptah.form:templates/fields/password-display.pt'
def deserialize(self, value): if not value: return null try: return datetime.datetime.strptime(value, '%m/%d/%Y').date() except Exception as e: raise Invalid( self, _('Invalid date', mapping={'val': value, 'err': e}))
def deserialize(self, value): if value != 0 and not value: return null try: return self.num(value) except Exception: raise Invalid( self, _('"${val}" is not a number', mapping={'val': value}))
def serialize(self, value): if value is null: return null try: return self.vocabulary.get_term(value).token except Exception: raise Invalid( self, _('"${val}" is not in vocabulary', mapping={'val':value}))
def __call__(self, field, value): if self.min is not None: if value < self.min: min_err = _(self.min_err, mapping={ 'val': value, 'min': self.min }) raise Invalid(min_err, field) if self.max is not None: if value > self.max: max_err = _(self.max_err, mapping={ 'val': value, 'max': self.max }) raise Invalid(max_err, field)
def deserialize(self, value): if not value: return null try: return self.vocabulary.get_term_bytoken(value).value except Exception: raise Invalid( self, _('"${val}" is not in vocabulary', mapping={'val':value}))
def __init__(self, regex, msg=None): if isinstance(regex, string_types): self.match_object = re.compile(regex) else: self.match_object = regex if msg is None: self.msg = _("String does not match expected pattern") else: self.msg = msg
def __call__(self, field, value): if not value in self.choices: choices = ', '.join(['%s' % x for x in self.choices]) err = _('"${val}" is not one of ${choices}', mapping={ 'val': value, 'choices': choices }) raise Invalid(field, err)
def deserialize(self, value): if not value: return null try: return self.vocabulary.get_term_bytoken(value).value except Exception: raise Invalid( self, _('"${val}" is not in vocabulary', mapping={'val': value}))
class TextAreaField(TextField): __doc__ = _('HTML Text Area input widget') klass = 'textarea-widget' value = '' rows = 5 cols = 40 tmpl_input = 'ptah.form:templates/fields/textarea-input.pt'
def serialize(self, value): if value is null: return null try: return self.vocabulary.get_term(value).token except Exception: raise Invalid( self, _('"${val}" is not in vocabulary', mapping={'val': value}))
def serialize(self, value): if value is null: return null try: return str(self.num(value)) except Exception: raise Invalid(self, _('"${val}" is not a number', mapping={'val': value}), )
def serialize(self, value): if value is null or not value: return null try: return '\n'.join(value) except Exception: raise Invalid(self, _('"${val}" is not a list', mapping={'val': value}), )
class TextField(InputField): __doc__ = _('HTML Text input widget') klass = 'text-widget' value = '' def loads(self, s): if not s.startswith('"'): s = '"{0}"'.format(s) return super(TextField, self).loads(s)
def deserialize(self, value): if not value: return null try: return [s.strip() for s in value.split()] except Exception: raise Invalid(self, _('"${val}" is not a list', mapping={'val': value}), )
class BaseMultiChoiceField(VocabularyField): """ multi choice field """ missing = [] error_msg = _('"${val}" is not in vocabulary') def to_form(self, value): val = value try: res = [] for val in value: res.append(self.vocabulary.get_term(val).token) return res except: raise Invalid(self.error_msg, self, {'val': val}) def to_field(self, value): if not value: return null val = value try: res = [] for val in value: res.append(self.vocabulary.get_term_bytoken(val).value) return res except: raise Invalid(self.error_msg, self, {'val': val}) def extract(self): if self.name not in self.params: return null value = [] tokens = self.params.getall(self.name) for token in tokens: if token == self.no_value_token: continue value.append(token) return value def is_checked(self, term): return 'checked' if term.token in self.form_value else None def update(self): super(BaseMultiChoiceField, self).update() if self.form_value in (null, None): self.form_value = [] self.update_items()
def serialize(self, value): if value is null: return null try: res = [] for val in value: res.append(self.vocabulary.get_term(val).token) return res except (LookupError, TypeError): raise Invalid( self, _('"${val}" is not in vocabulary', mapping={'val': value}))
def serialize(self, value): if value is null: return null if isinstance(value, datetime.datetime): value = value.date() if not isinstance(value, datetime.date): raise Invalid(self, _('"${val}" is not a date object', mapping={'val': value})) return value.isoformat()
def serialize(self, value): if value is null or value is None: return null if isinstance(value, datetime.datetime): value = value.date() if not isinstance(value, datetime.date): raise Invalid(self, _('"${val}" is not a date object', mapping={'val': value})) return value.strftime('%m/%d/%Y')
class DateTimeField(TextField): default_tzinfo = iso8601.Utc() missing = None error_msg = _('"${val}" is not a datetime object') error_invalid_date = _('Invalid date') def to_form(self, value): if value is null or value is None or not value: return null if type(value) is datetime.date: # cannot use isinstance; dt subs date value = datetime.datetime.combine(value, datetime.time()) if not isinstance(value, datetime.datetime): raise Invalid(self.error_msg, self, {'val': value}) if value.tzinfo is None: value = value.replace(tzinfo=self.default_tzinfo) return value.isoformat() def to_field(self, value): if not value: return null try: result = iso8601.parse_date( value, default_timezone=self.default_tzinfo) except (iso8601.ParseError, TypeError): try: year, month, day = map(int, value.split('-', 2)) result = datetime.datetime(year, month, day, tzinfo=self.default_tzinfo) except Exception: raise Invalid(self.error_invalid_date, self) return result
class ChoiceField(BaseChoiceField): __doc__ = _('HTML Select input widget.') size = 1 klass = 'select-widget' multiple = None promptMessage = _('select a value ...') tmpl_input = 'ptah.form:templates/fields/select-input.pt' def update_items(self): super(ChoiceField, self).update_items() if not self.required: self.items.insert(0, { 'id': self.id + '-novalue', 'name': self.name, 'value': self.noValueToken, 'label': self.promptMessage, 'checked': self.form_value is null, 'description': '', })
def deserialize(self, value): if value is null or not value: return null try: v = str(value).lower() if v.startswith('gmt'): v = 'etc/%s' % v try: return pytz.timezone(v) except: return pytz.timezone(self._tzs[v]) except: raise Invalid(self, _('"${val}" is not a timezone', mapping={'val': value}))