FunFormKit Users Guide

Version 0.4.1, written for Webware for Python 0.8

Contents


Overview

FunFormKit automates form handling in a number of ways:

Form validation:
Fields can be validated, and if the values are valid the user is given an error message and an opportunity to resubmit corrected input.
Value conversion:
Simultaneously with validation, values can be converted. For instance, an integer can be returned (and if the user doesn't return an integer, they will be given an error message).
HTML generation:
Simple layout can be performed when a basic layout is given. This layout is typically good enough for 75% of forms.
HTML widgets:
HTML has basic widgets, like text input, drop-down lists, etc. FunFormKit introduces more complicated widgets which are formed out these basic widgets, and some Javascript -- but the programmer can use them like any other widget. (A widget that I use often is OrderingField, which allows the user to order a set of options)
Quoting:
FunFormKit quotes all the of the input you give it. You don't have to worry about double-quoting something, or in laziness not quote something and later encounter a value with a " in it.
Thread safety:
FunFormKit is designed to be reentrant, which is to say that it is fundamentally thread-safe. While this does not ensure that all portions of your form-handling system are thread safe, it will tend to encourage a similar style of programming. It also encourages a programming style that accounts for the stateless nature of HTTP.

The Form Definition

Creating the Form Definition

Each form in FunFormKit is an instance of Form.FormDefinition. An example of a form definition:

formDef = Form.FormDefinition(
              '/formHandlerURL',
              [Field.TextField('username'),
               Field.PasswordField('password'),
              ])

The first arguments to the constructor are:

handlerServletURL:
The URL of the servlet that handles this form (this will be the servlet that includes the Servlet Interface)
fields:
A list of fields in the form (see Field Definitions)
formValidators:
A list of FormValidator instances. (optional)
method:
GET or POST methods. POST is the default. (optional)
enctype:
The enctype attribute for the <form>. Usually this will handled automatically. (optional)
name:
The name of the form -- to distinguish two forms that are handled by the same servlet. This is generally resolved without intervention. (optional)
errorFormatter:
errorFormatter is a function that formats error messages for the user. The function should take a single string error message, or a list of string error messages, and return a string (formatted in HTML). By default, error messages are presented with a red background and white text. (optional)

The form definition is not mutable. That means, once you have created the form definition, you cannot change it. There are a number of ways you still are able to create dynamic forms, however. The definition cannot be mutable, because two different servlets may be accessed when the user first requests the form, and then when they submit it.

It's usually easiest to store the FormDefinition in a module-level global, in the same module as the servlet that handles the form. Other servlets can still still include the form in their pages by importing

Setting up the form for display

Any dynamicism of the form is added when the form is displayed. This is where you can make dynamic select boxes, hide some fields, add default values, etc.

In a servlet method, call self.renderableForm(...) (inherited through FormServlet, see Servlet Interface). renderableForm takes several arguments, all of which should be passed as keyword arguments:

formDefinition:
The FormDefinition instance you want to render. If the servlet only implements one form, you can leave this argument out.
defaults:
This is a dictionary. The keys are field names, and the values are the default to be inserted into the field. So if you have a username field, and you wish to fill it in from a cookie you set earlier, you might pass defaults={'username': self.request().cookie('username', '')}
rawDefaults:
These are default values that haven't been passed through any of the processing of FunFormKit. This is so that you can take the results of an unvalidated form, and reinsert them into a form later. The most likely use of this would be a "back" button in a multi-page form, where you want to save the values, but you won't demand they be valid yet. (Note: not well tested yet)
optionSet:
A dictionary, these are options for the form and fields. Different fields have different options (see Field Options). Options for the field are passed with the 'form' key.

These arguments -- particularly optionSet -- make up for the non-mutable nature of FormDefinition instances.

Displaying the form

Once you've created the renderable version of the form, you can display it. Remember -- this may not be the first time the user has seen the form, and there may be errors that should be shown to the user.

The easiest way to render a form is with two simple layouts: htFormTable and htFormLayout. htFormTable is the easiest of all -- it will lay out the form in a table, with the form elements in the same order as you defined them. It's good for setting up a quick form, for testing, and for administrative interfaces where you don't care about the look. You use it like:

rf = self.renderableForm(...)
self.write(rf.htFormTable())

htFormTable can take one optional argument, which is the background color of the table (like rf.htFormTable('#ddddff')). The output ends up looking more or less like:

<form action="...">
...hidden fields...
<table>
 <tr>
  <td align=right>Text Field:</td>
  <td><input type="text" name="textField"></td>
 </tr>
 <tr>
  <td align=right>Select Box:</td>
  <td><select name="selectBox">
   <option value="...">...</option>
   </select></td>
 </tr>
 <tr>
  <td colspan=2 align=center><input type="submit" value="submit"></td>
 </tr>
</table>
</form>

htFormLayout is a somewhat more sophisticated way to lay out a form. This lays out the form with field descriptions above the field, and potentially with more than one field on a line. This is good for forms with lots of small fields, or forms that need a more polished look. This is flexible enough of a layout for a large number of forms. htFormLayout takes four arguments:

layout:

The layout is a list. Each item in the list is a new row in the form. Fields are represented by a string (the name of the field). So a standard address layout would look like:

[['title', 'firstName', 'MI', 'lastName', 'suffix'],
 'streetAddress1',
 'streetAddress2',
 ['city', 'state', 'zip']]

With multiple fields on a line, you use a list (or tuple) for that line. If there's just one field, you don't need a list (though you can use one). You can control the labels separately from the field names with the use of the description keyword option in the Field constructors.

You can also include a field without it's description by prefixing the name with ":", as in ':title'. If you want to include plain text -- something to split the form into sections, for instance, or some extra help text -- you can start an item with "=", and the rest of the text will be included in place of a field (you can include HTML in this text). Like: '=<i>Please give your billing address</i>'.

descriptionClass:
The CSS class to be used for descriptions, so you can control font size and color. (optional)
bgcolor:
The background color to use for the tables. (optional)
spacing:
An integer -- the number of &nbsp;'s to put between fields (to space out the field). (optional)

Otherwise, it works mostly like htFormTable. You use it like:

rf = self.renderableForm(...)
layout = [['title', 'firstName', ...], ...]
self.write(rf.htFormLayout(layout))

If you want to lay out a form on your own, you can access the fields from the renderable form on your own. The important methods are:

__getitem__:
In other words, array access (like rf['title']). This returns the RenderableField for the given field name. RenderableField methods described below. You can also use renderableField(name).
htStartForm(includeHiddenFields=False):
The HTML to start the form -- the action, and certain automatically-created hidden fields. If you pass includeHiddenFields=True then the HTML for all the hidden fields will also be returned. You can also use start()
htEndForm():
HTML to end the form (generally just </form>). You can also use end().
htHiddenFields():
The HTML for all the hidden fields in the form. You can also use hidden().
error():
The (formatted) error message for the form as a whole. If you want the error text without the error formatting, use errorText().
fields():
A list of all the fields in the form (as RenderableFields).
hiddenFields():
All the fields that are hidden.
visibleFields():
All the fields that aren't hidden.
submitFields():
All the submit-button fields.

To render the form, you also have to render the fields (as returned by array access or via one of the other accessors). Each RenderableField object has these methods:

html():
The HTML for the field's input. Doesn't include any error messages. You can also use str(someRenderableField).
error():
The formatted error text for the field. Use errorText() if you want to format it yourself.
description():
The description of the field, meant for humans to read.
name():
The name of the field (how you access it).
isSubmit():
True if field is submit button.
isHidden():
True if field is hidden.
isCompount():
True if field is compound (see CompoundField )

Rendering on your own is seriously complicated if you use repeating fields. Right now I would not recommend it.

Servlet Interface

Form.FormServlet is a mixin for the servlet that handles the form action. As a mixin, you include it by including it as a subclass. You must also call FormServlet.__init__ with the form definition that the servlet will handle. Your servlet definition will look something like this:

from FunFormKit.Form import FormServlet, FormDefinition

formDef = FormDefinition(...)

class MyServlet(SitePage, FormServlet):

    def __init__(self):
        SitePage.__init__(self)
        FormServlet.__init__(self, formDef)

A servlet can also handle more than one form definition. In that case you will pass a list of definitions.

The only other methods in FormServlet are renderableForm (explained above) and processForm.

processForm should be called before you render the form. It returns a tuple (formProcessed, data) -- if formProcessed is false, then no form was submitted successfully (either the user wasn't submitting a form, or there were errors). data only applies if the form was submitted without errors. It is either a dictionary of fieldName: value, or the return value from the function invoked via the submit button (see SubmitButton).

Field Definitions

What we've left out so far is creating the actual fields. All fields included with FunFormKit are located in the FunFormKit.Fields module. It is reasonably safe to do from FunFormKit.Fields import * -- a number of Field classes will be imported, and all end in Field (except for SubmitButton, ImageSubmit, StaticText, and the helper class UploadedFile).

Field Constructors

Field constructors vary, but all have certain features:

name:
The first argument (and the only argument you don't need to pass by keyword). The name of the field -- should contain no spaces or puntuation. All other arguments are optional.
validators:
A list of Validator/Converters that will be used to process user input.
description:
A readable description of the field (used in layout). If you don't give one, a modified version of name will be used ("mixedCaseStyle" will be turned to "mixed case style").
options:
Default options for the field. These can be overrided with the optionSet argument when the form is rendered. This is a dictionary of option names and values -- the meaning of the options is dependent on the kind of field (though there are some common options shared by all fields).
extraHTML:
Not all fields support this, but fields that translate into simple HTML will allow you to pass in extra HTML that should be put inside the tag.
repeatable:
Whether the field may be repeated in the form. If you do not give a value here, it will depend on whether the "repetitions" option is passed in the optionSet/options. (see repeating fields)
required:
Essentially a form of description, if you pass a true value then the description will have a red star appended.

Field Options

Fields also have options, which can be set at render-time. All fields share these options:

hide:
If set to true, the field will be hidden. You can still give a default value, which will be kept in the hidden field.
static:
Replace the field with a static (uneditable text) version of the widget.
repeat:
If you give an integer here, the field will be repeated that many times. The return value will be an ordered list of values for the different instances. If you want to repeat a number of fields together (for instance, a name field associated with a phone number field) use CompoundField

Dynamic Fields

Some fields are dynamic, in that the HTML that gets rendered will change during the life of the FormDefinition. The most common case is a drop-down select box, which is filled in with values from a database or other source.

What applies here applies to a certain set of fields, all of which present a set of options for the user. Those fields are:

Each of these fields support a selections constructor argument. This allows you to define the selections. If you do not provide a selections argument, however, they are implied to be dynamic.

If the field is dynamic, you must pass an option, "selections". This is a list, similar to the list for selections. This list will look like [("optionKey1", "option 1 description"), ("optionKey2", "option 2 description"), ...]. That is, a list of tuples, with the first item of the tuple being the key, and the second being the description you see.

All keys must be strings, and only strings will be returned (if you predefine the selections this restriction does not exist).

Repeating Fields

Fields can be set to repeat (This feature is somewhat experimental, and you might find breakage in some circumstances)

You set a field to repeat by first setting repeatable=1 in the field constructor, and then using the repeat option when rendering the form (you will give the number of repetitions the field should have).

You can only repeat a single field, not a form. However, using CompoundField you can take several fields and turn them into one. Then the CompoundField can be repeated. CompoundFields can be nested, and multiple levels of repeating can exist (for instance, you can have a list for contact information, with one CompoundField encompassing a person, and have a repeating field for the phone number, so each person can have multiple phone numbers).

Special Fields

There are some special types of fields that shouldn't be lumped in with the rest:

SubmitButton

Each form should have a SubmitButton, but a form can also have multiple buttons. It takes several arguments to its constructor:

methodToInvoke:
This should be a string, referring to the servlet method to invoke if this button is hit. If the button is used, and the method is called, the return value from the method will be returned as the data to processForm. The method will be called with one argument: a dictionary of values from the form. This is optional, and if you don't give a method then the field values will be returned as data, and the caller of processForm will have to handle the form action. (optional)
defaultSubmit:
Give a true value if this button should have been considered hit if no other button was hit. In certain browsers (e.g., Internet Explorer) when the user hits enter, no button information is sent, but the form is submitted. (optional -- default false)
confirm:
If you give a string, the user will be asked to confirm their push of the button (using a Javascript alert box). This is useful with a delete button, for instance (like confirm="are you sure you want to delete this item?"). (optional)
invokeAsFunction:
(experimental) If true, then the method that is invoked will be called with keyword arguments -- for instance, if the form contains a "username" and "password" field, the method will be called like method(username=usernameValue, password=passwordValue) (optional -- default False)
noneAsDefault:
For user with invokeAsFunction, if a field value is None then it won't be explicitly sent as a keyword argument.
suppressValidation:
(experimental) No validation will be sent with the form, and a dictionary of raw results will be returned. The primary use of this is for a button that should save the form for finishing later (for instance, a back button in a multi-page form). You can feed this dictionary in with the rawDefaults argument to FormServlet.renderableForm().

ImageSubmit

ImageSubmit is mostly equivalent to SubmitButton, only it uses an image. Instead of using description for the text, you pass the arguments imgSrc (the URL of the image), imgWidth, imgHeight, and border.

HiddenField

A Hidden field puts a piece of data in the form. You can also use the hidden option. The value of the field will be the value passed in defaults (via FormServlet.renderableForm())

SecureHiddenField

SecureHiddenField is like HiddenField, but uses an MD5 hash to confirm that the user hasn't modified the value. This currently uses a randomly-generated salt to ensure the security, but this salt will change on AppServer reboot (and keep people from submitting forms generated before the reboot).

CompoundField

CompoundField is a way to group a number of fields together. You give it a list of fields to group together, and optionally a formValidator (see Form Validators).

The CompoundField itself has a name, so if you create one like:

CompoundField("fullName", 
              [TextField("firstName"),
               TextField("lastName")])

The resulting value of the field will be something like {"fullName": {"firstName": "John", "lastName": "Doe"}}.

The embedded fields can have their own validation and all other flexibility in their specification.

Normal Fields

The other fields follow normal patters, so the description will be more brief. Each will include an example of the HTML generated, any special arguments to the constructor, and potentially a description.

TextField

<input type="text" name="name" value="defaultValue" maxlength="10" 
 size="5">
size:
Specifies the size of the field (should be number of characters, but browsers seem to size the fields based on a smallish letter). (default: browser specified)
maxLength:
An integer specifying the maximum length of the field. This is also enforced server-side. (default: no maximum length)

TextAreaField

<textarea name="name" rows="10" cols="60" wrap="SOFT">
HTML-quoted default text</textarea>
rows:
Number of rows in the form (i.e., height). (default: 10)
cols:
Number of columns (i.e., width). (default: 60)
wrap:
How wrapping should work. "SOFT" means that the text area should wrap, but the text will be sent with newlines only where the user hit enter. "HARD" means there will be wrapping, and where the text wraps the text sent will have a newline. The empty string implies no wrapping. (default: SOFT)

PasswordField

<input type="password" name="name" size="10" maxLength="20">
size:
Specifies the size of the field. (default: browser specified)
maxLength:
An integer specifying the maximum length of the field. This is also enforced server-side. (default: no maximum length)

MD5PasswordField

Works mostly like PasswordField, but attempts to keep the password from being sent in plain text. Sends a hash of the password, combined with a salt. I recommend using TimedMD5PasswordField, which manages the salt for you.

TimeMD5PasswordField

Uses MD5PasswordField, but generates the salt on its own, and confirms that the salt has not expired. While someone can intercept the password's hash and login using that information, they will have a limited amount of time to do so. Takes PasswordField arguments in addition to these extra arguments:

timeToExpire:
Number of seconds the user has to complete the form. (default: 20min)
allowInsecure:
Reject logins that were not done securely (probably because client has Javascript turned off). (default: True)

SelectField

<select name="name" size="3">
    <option value="1">red</option>
    ...
</select>
selections:
The selections to fill the select box. This is a list of tuples, as [("value1", "description 1"), ("value2", "description 2")...]. The values do not have to be strings -- if not, encoding will occur. If you want the options to be dynamic, see Dynamic Fields. (default: [])
nullInput:
You can pass a string which will describe the field (for instance, "Gender"). If the form is resubmitted or a default is given, this description will not be shown. If you want to force the user to enter a value, you must use NotEmpty. (default: no null input)
dynamic:
If you want a dynamic select box (as decribed in Dynamic Fields), pass True. It is implied if you pass an empty list for selections, or do not indicate your selections.
size:
The size of the select box (i.e., number of items to display). (default: 1)

OrderingField

The OrderField allows the user to order a number of selections. The options are presented as a sized select box, and the user will select an option and use "up" and "down" to move the items around. This is done with Javascript. The return value is a list of values, ordered as the user wanted them.

selections:
The selections, same as for SelectField.
dynamic:
Same as for SelectField.
showReset:
Give a "reset" button that allows the user to undo all their changes. (default: False)

OrderingDeletingField

Like OrderingField, but also allows deleting entries. The return value is a list of values, ordered as the user wanted them. Deleted values are omitted from this list. It has all the same arguments as OrderingField as well as:

confirmOnDelete:
If a string is given, the user will be asked to confirm the delete. (default: no confirmation)

RadioField

<input type="radio" name="name" value="value" id="name_1">
<label for="name_1"> description of option</label><br>
....

This field is functionally equivalent to SelectField, but uses radio buttons instead. The <label ...> allows the user to hit the description text to select the option (in modern browsers).

MultiSelectField

Like SelectField, but allows the user to select multiple options. A list is returned. Also has these arguments:

listValidators:
Other validators will be applied to the individual selections. However, if you want to validate the entire list of items, you must pass a list of validators here. For instance, giving [Validator.NotEmpty()] here would make the user select at least one option. Using Validator.NotEmpty() in the validators list would only ensure that the user selected no empty options. (default: no validators)
size:
The size of the field. If no size is given, the select box is sized according to the number of selections, or 10, whichever is smaller.

MultiCheckboxField

<input type="checkbox" name="name" value="value" id="name_1">
<label for="name_1">description...</label><br>
....

Like MultiSelectField, except presents options as checkboxes. The <label ...> allows the user to hit the description text to select the option (in modern browsers).

CheckboxField

The checkbox field, description is not used (you must include a description yourself). True or False is returned.

DateField

<input type="text" name="name-day" value="10" size=2 maxLength=2>
<select name="name-month">
    <option value="1">January</option> ....
</select>
<input type="year" name="name-year" value="2002" size=4 maxLength=4>

I do not recommend using this field. It's stupid UI -- people know how to enter dates. Use a text field with DateConverter and DateValidator instead.

I'm not even going to bother documenting this.

FileField

<input type="file" name="name" accept="text/plain,text/html" size="10">
mimeTypes:
The MIME types that should be accepted. Ideally, the browser will only show appropriate files in the file-selection dialog. For the most part this is ignored. (default: no MIME types specified)
size:
The size of the box. (default: browser determines)
returnString:
This will return a cgi FieldStorage normally, but you can have it return the text of the file instead by passing True here. (default: false)

TextareaFileField

<textarea name="name" rows="10" cols="60" wrap="SOFT">
HTML-encoded text...</textarea><br>
<input type="file" name="name-upload" accept="text/plain">

This field is mostly like TextareaField, except that the user is also allowed to upload a text file. The uploaded file overrides anything in the textarea. The biggest advantage of this is that, unlike a file upload, if the user has to resubmit the form they will not have to reupload the file (since the contents will be put back into the textarea).

ImageFileUploadField

<img src="/path/to/tmp-img.jpg" width="100" height="100"><br>
<input type="hidden" name="name-filename" value="/path/to/tmp-img.jpg">
<input type="file" name="name" accept="image/gif,image/jpg,image/png">
uploadPath:
The path where image files should be uploaded to. (required)
uploadURL:
The URL that points to that path. (required)

This is like FileField, except if there is an error the user won't have to reupload the image. They will also see the image they uploaded. Some security is preserved by signing the filename in the "name-filename" field, but generally the file has to be uploaded to someplace publicly accessible. Requires PIL (Python Imaging Library).

This returns an instance of UploadedImage. UploadedImage just has a few convenient methods:

copyTo(destinationPath):
Copies the file to the destination path.
moveTo(destinationPath):
Moves the file.
filename:
Instance variable: the filename the image was originally uploaded as. Also the filename that will be used to save the file. If the filename already exists, "-1" is appended (incremented as necessary).
fullpath:
Instance variable: The full path to the source file.

FileUploadField

This is like ImageFileUploadField, except no image preview is available. An instance of UploadedFile is returned. UploadedFile has all the same methods and instances as UploadedImage.

StaticText

StaticText is a fake field, which allows you to insert text in a layout. It's for hacks.

ColorPickerField

ColorPickerField gives a fancy color picker. You can enter a color like FF0000 (red) or click on a button and get a popup window giving colors. It takes one argument, colorPickerURL, which is the URL to the ColorPicker servlet (located in Examples/). That servlet displays the popup.

If you use the popup, or have a default color, a preview is given (using CSS).

VerifyField

VerifyField is a compound field. It provides two fields, and confirms that the user enters the same value for both fields.

fieldClass:
The class of the field you are constructing (such as TextField or PasswordField). (required)
fieldKW:
Keyword arguments to the field constructors (for instance, description, size, etc). (optional)

PasswordVerifyField

Like VerifyField, using PasswordField. Also, you can pass keyword arguments slightly more easily. So to create the standard password/verify field:

PasswordVerifyField("password", 
                    size=20, 
                    validators=[Validator.NotEmpty()])

CityStateZipField

An example of a compound field for city, state, and zip code. It returns a dictionary with "city", `"state", and "zip" keys. It verifies that the state code entered exists, that the zip code is valid (either ##### or #####-####). Someday it might confirm that the zip matches the state.

CreditCardField

CreditCardField is a compound field for credit card type, number, and expiration date. It verifies that the number is valid for the card type, and that the card has not expired. It takes one argument:

cards:

A list of credit card types that you accept. Available types: * amex (American Express) * mastercard (Master Card) * visa (Visa) * optima (Optima -- no number validation) * discover (Discover Card) * discover/novus (Discover/NOVUS -- just a different description) * diners (Diner's Club)

By default, amex, mastercard, and visa are given.

Validators and Converters

Validation and conversion are done simultaneously in FunFormKit. Wherever "validator" is used, you can assume that conversion can also take place.

The Validator module contains classes to perform many common tasks, but you should also expect to write your own validators at some point (it is quite simple). See Creating a Validator.

Like Fields, Validators take a variety of arguments to their constructors. All Validators take these two arguments:

ifInvalid:
If this validator fails, it instead returns the value you pass in here. If you do not provide this and if the validator fails, the user will see the error message and have to resubmit the form (which is usually what you want).
ifEmpty:
If the user doesn't enter anything for the field, this value will be returned. Some validators don't work with empty fields -- Email for instance -- so if you want the entry to be optional this will only validate the field if the user actually enters something. Otherwise they may get an error message.
messages:
A dictionary of error messages. All error messages that Validators give can be overridden with this argument (though stock messages are provided). Some error messages take arguments -- the invalid value, for instance -- and may use % substitution (with dictionaries).

Special Validators

These validators are essentially ways of constructing logical statements using the other validators.

Lists of validators

Many places take lists of validators (the validators argument to fields, for instance). In this case, each validator is called in turn, the results of the previous validator passed to the next. If any of the validators fail, validation will stop and the error returned.

ValidateAny

This validator takes other validators as its constructor arguments. The first validator that is successful will be used. In place of a validator, you can use a list of validators (which all much succede). For instance, in an implausible example, you might have a field that can take either an integer ID, or an email address:

ValidateAny(AsInt(), ValidateEmail())

You may use the ifInvalid argument to ValidateAny, but not the ifEmpty.

ValidateList

The arguments to ValidateList are like a list of validators -- i.e., all of them must evaluate as true. The input to the validator should be a list of items (as returned by some fields), and the validators will be applied in turn to each item in the list.

Constant

Nominally useful, this takes a value argument, and converts all inputs to that value.

Normal Validators

If the validator takes any arguments, they are given first. Arguments are presented in order -- usually you do not need to use keyword arguments with validators. Messages are given at the end of the list, explained by presenting the default message.

MaxLength

maxLength:
The maximum length of the input.
Message: "tooLong"
Enter a value less than %(maxLength)i characters long

MinLength

minLength:
The minimum length of the input.
Message: "tooShort"
Enter a value more than %(minLength)i characters long

NotEmpty

Message: "empty"
Please enter a value

NotEmpty() rejects all empty values.

Empty

Message: "notEmpty"
You cannot enter a value here

Useful mostly with ValidateAny, since it rejects all interesting input.

Regex

regex:
A regular expression object, or a string which will be compiled into a regular expression object. The field must match.
strip:
Whether to strip whitespace off the front and back before matching (and return the stripped string). (default False)
Message: "invalid"
The input is not valid

PlainText

Checks that letters, numbers, underscore, and dash are the only characters in the text (i.e., no whitespace). Takes the strip argument and invalid message like Regex.

InList

l:
A list of items. The input must be one of the items in the list.
allowSublists:
Undocumented. I can't remember what this does.
hideList:
The error message can display the list of possibilities. If this argument is true, then a more cryptic, less helpful message will be used instead. (default False)
Message: "invalid"
The unhelpful, cryptic message, "Invalid valid"
Message: "notIn"
Value must be one of: %(items)s ("items" will be a string, with ``;`` used to split the items)

DictionaryConverter

dict:
This dictionary is used to convert values. The value given will be the key in the dictionary, and the value for that key will be returned.
Message: "invalid"
Choose something

IndexListConverter

l:
Like DictionaryConverter, this converts values. The value given is converted to an integer if necessary, and used as the index in this given list.
Message: "integer"
Must be an integer index
Message: "outOfRange"
Index out of range

DateValidator

This validator works on mxDateTime objects, so you should be sure to call DateConverter first to convert strings to mxDateTime objects.

earliestDate:
The earliest allowable date (inclusive). (default: no date is too early)
latestDate:
The latest allowable date (inclusive). (default: no date is too late)
Message: "after"
Date must be after %(date)s
Message: "before"
Date must be before %(date)s

AsInt

Message: "integer"
Please enter an integer value

Takes no arguments, just makes sure the value is an integer and converts the number to a Python integer.

AsNumber

Message: "number"
Please enter a number

Like AsInt, but converts to a float if necessary (but tries to convert to an int if possible).

AsList

In some cases, you may or may not get a list back from the cgi module. This makes sure it's always a list. Mostly used internally.

Email

resolveDomain:
If true, try to look up the domain name given in the email. An error will be given if there is no MX record for the domain. (default: False)
Message: "empty"
Please enter an email address
Message: "noAt"
An email address must contain an @
Message: "badUsername"
The username portion of the email address is invalid (the portion before the @: %(username)s)
Message: "badDomain"
The domain portion of the email address is invalid (the portion after the @: %(domain)s) (this is if the address is invalid, like not_a_domain.com -- not when the domain doesn't exist)
Message: "domainDoesNotExist"
The domain of the email address does not exist (the portion after the @: %(domain)s)

StateProvince

extraStates:
This validator already knows the codes for the USA states. If you want to add extra states, give a list here (Canadian provinces, for instance). If you want a different set of states, subclass StateProvince, and define a new _states class variable (nothing else has to be overridden). (default: no extra states)
Message: "empty"
Please enter a state code
Message: "wrongLength"
Please enter a state code with TWO letters
Message: "invalid"
That is not a valid state code

PhoneNumber

Message: "phoneFormat"
Please enter a number, with the area code, in the form ###-###-####, optionally with "ext.####"

DateConverter

acceptDay:
If you just want a month/year date (like for a credit card expiration date), then give true here. (default: False)
Message: "badFormat"
Please enter the date in the form dd/mm/yyyy
Message: "monthRange"
Please enter a month from 1 to 12
Message: "invalidDay"
Please enter a valid day
Message: "dayRange"
That month only has %(days)i days
Message: "invalidDay"
That is not a valid day (indicates that mxDateTime raised a ``DateTime.RangeError`` when trying to construct the date)
Message: "unknownMonthName"
Unknown month name: %(month)s
Message: "invalidYear"
Please enter a number for the year
Message: "fourDigitYear"
Please enter a four-digit year
Message: "wrongFormat"
Please enter a date in the form mm/yyyy

DateConverter tries its best to convert the date, including dates with dashes, and dates with month names or abbreviations of month names. The messages give a more strict view, but they only show up when there's a problem. If a two-digit year is given, it is assumed to be in the 1900's if it is after 50, and in the 2000's if it is before 20. Numbers from 21-49 are rejected, and the user asked to give a four-digit year. If four digits are given, any date is accepted (e.g., historical dates).

PostalCode

Message: "invalid"
Please enter a zip code (5 digits) (5+4 zips are also accepted)

Form Validators

Form validators work on the entire form, not just one field. If you want to enforce any relation between the fields, you must use a form validator. There are few stock form validators, you will probably need to create one on your own (see Creating a Validator).

Form validators are pass in the formValidators argument to the FormDefinition.

CreditCardValidator

I would suggest using CreditCardField, which will set this validator up for you.

FieldsMatch

You might want to use VerifyField instead. Otherwise:

fieldNames:
A list of the names of the fields in the form that should match.

Creating a Validator

While the stock validators can work for a number of situations, they don't work for all situations. It is common you will want to make your own validator. This is very easy!

The base class for validators is ValidatorConverter. There are two possible methods you may wish to override:

convert(value):
This attempts to convert the argument. You return the converted value. If anything goes wrong, you should raise Validator.InvalidField(message), which signals a failed validator (with message as the error message)
validate(value):
If the value is valid, return None. Otherwise, return the error message.

Creating Form Validators

Form validators work on a dictionary of values, all of which have gone through whatever earlier validators were attached to the individual fields. It's methods to override:

validate(fieldDict):
fieldDict is a dictionary of values, ready to be returned to the servlet (i.e., all other per-field validation has occurred). You can modify this dictionary to perform conversion. If there are no errors, return None. Otherwise return a string (which is the error message for the entire form) or a dictionary (which will contain per-field error messages, with the field name as the key). If you return a dictionary, the special key "form" can contain errors for the entire form.
validatePartialForm():
Normally, you only want to validate the form if all the values have been validated. If this method returns true then the form will be validated regardless, but validatePartial(fieldDict) will be called. It works like validate, except that some values may be missing from the dictionary (any fields where the per-field validators failed).
validatePartial(fieldDict):
Validate a form that isn't ready to be submitted because of other errors. See above.