FormEncode
FormEncode is a Python library for HTML form validation, generation, and data conversion. It handles complex, nested data structures and provides a declarative way to define validation schemas. Currently at version 2.1.1, released on January 31, 2025, the library maintains an active release cadence with several updates per year, focusing on Python 3 compatibility and modern development practices.
Common errors
-
formencode.Invalid: ...
cause When a Schema or Validator fails, it raises an `Invalid` exception. Directly printing `e` might not give a user-friendly or complete error message, especially for schemas with multiple field errors.fixCatch the `Invalid` exception and use `e.unpack_errors()` to get a dictionary of field-specific errors. This dictionary is ideal for displaying errors next to their respective form fields. -
KeyError: 'field_name'
cause A `Schema` by default expects all fields defined within it to be present in the input dictionary. If a field is missing, it will raise an error.fixTo make a field optional, pass `if_missing=None` (or another default value) to the validator definition within your `Schema` class. Alternatively, set `allow_extra_fields=True` on the `Schema` itself if you want to permit fields not explicitly defined.
Warnings
- breaking FormEncode 2.0.0 and later are not compatible with Python 2.x. Version 2.0.0 itself dropped support for Python 2.6 and Python 3.2-3.5.
- deprecated FormEncode 2.1.1 is the last version to officially support Python 3.7 and 3.8. Future versions will drop compatibility with these Python versions.
- gotcha Older repository locations (SourceForge CVS, svn.colorstudy.com Subversion, Bitbucket Mercurial) are outdated and no longer maintained.
- gotcha When using `htmlfill`, if an input field needs a CSS class, you must use `class_` as the attribute name instead of `class` because `class` is a Python reserved keyword.
Install
-
pip install formencode
Imports
- Schema
from formencode import Schema
- Invalid
from formencode import Invalid
- validators
from formencode import validators
- htmlfill
from formencode import htmlfill
Quickstart
from formencode import Schema, Invalid
from formencode import validators
from formencode import htmlfill
# 1. Define a Schema
class RegistrationSchema(Schema):
username = validators.String(not_empty=True, min=3, max=20)
email = validators.Email(resolve_domain=False)
age = validators.Int(min=18, max=99)
password = validators.String(not_empty=True, min=6)
password_confirm = validators.String(not_empty=True)
chained_validators = [validators.FieldsMatch('password', 'password_confirm')]
# 2. Example usage: validate form data
form_data_valid = {
'username': 'testuser',
'email': 'test@example.com',
'age': '25',
'password': 'securepassword',
'password_confirm': 'securepassword'
}
form_data_invalid = {
'username': 'tu',
'email': 'invalid-email',
'age': '16',
'password': 'short',
'password_confirm': 'mismatch'
}
validator = RegistrationSchema()
print('--- Valid Data ---')
try:
validated_data = validator.to_python(form_data_valid)
print('Validation successful:', validated_data)
except Invalid as e:
print('Validation failed:', e.unpack_errors())
print('\n--- Invalid Data ---')
errors_for_html = {}
try:
validated_data = validator.to_python(form_data_invalid)
print('Validation successful (should not happen):', validated_data)
except Invalid as e:
print('Validation failed:')
errors_for_html = e.unpack_errors()
for field, msg in errors_for_html.items():
print(f' {field}: {msg}')
# 3. Example htmlfill usage (if you have an HTML template)
html_template = '''
<form>
Username: <input type="text" name="username"><br>
Email: <input type="text" name="email"><br>
Age: <input type="text" name="age"><br>
Password: <input type="password" name="password"><br>
Confirm Password: <input type="password" name="password_confirm"><br>
<form:error name="username"/>
<form:error name="email"/>
<form:error name="age"/>
<form:error name="password"/>
<form:error name="password_confirm"/>
<form:error name="form"/>
</form>
'''
print('\n--- HTML Fill with Errors ---')
filled_html = htmlfill.render(html_template, form_data_invalid, errors_for_html)
print(filled_html)