validationpyramidformencode

Formencode ignores if_missing on USPostalCode


I have a problem with FormEncode not acknowledging that a validator has if_missing set. It keeps returning a "Missing Error" error for the field.

I have a Schema that looks like this

class ABCSchema(Schema):

allow_extra_fields = True
filter_extra_fields = True

primary_surname = validators.UnicodeString(not_empty=True)
mailing_address_1 = validators.UnicodeString(not_empty=True)
mailing_address_2 = validators.UnicodeString()
mailing_city = validators.UnicodeString(not_empty=True)
mailing_state = national.USStateProvince(not_empty=True)
mailing_zip = national.USPostalCode(not_empty=True) 
billing_address_is_same_as_mailing = validators.StringBool(if_empty=False, not_empty=False)
billing_address_1 = validators.UnicodeString(if_missing=None)
billing_address_2 = validators.UnicodeString(if_missing=None)
billing_city = validators.UnicodeString(if_missing=None)
billing_state = national.USStateProvince(if_missing=None)
billing_zip = national.USPostalCode(if_empty=None, not_empty=False)
special_instructions = validators.UnicodeString()

The validator in question is billing_zip.

The idea is that a user may have the option to flip the billing_address_is_same_as_mailing flag. This will disable the billing address fields which prevents those fields from being submitted.

Upon form submission the request has the following values

NestedMultiDict([('primary_surname', 'Something'), ('mailing_address_1', '81 turnbull St'), ('mailing_address_2', ''), ('mailing_city', 'Tampa'), ('mailing_state', 'NE'), ('mailing_zip', '98754'), ('billing_address_is_same_as_mailing', 'True'), ('special_instructions', ''), ('submit', 'Submit')])

This is validate with the following data and error dicts.

{'special_instructions': '', 'billing_city': None, 'mailing_city': 'Budd Lake', 'primary_surname': 'Something', 'billing_address_is_same_as_mailing': 'True', 'billing_state': None, 'mailing_address_1': '81 turnbull St', 'billing_zip': None, 'mailing_zip': '07828', 'mailing_state': 'NE', 'billing_address_2': None, 'submit': 'Submit', 'billing_address_1': None, 'mailing_address_2': '8 Locust St'}
{'billing_zip': 'Missing value'}

I've tried if_empty, if_missing, and not_empty in various combinations, but I can't seem to get the validator to pass if the billing_zip is missing. However, it doesn't seem to complain about the other billing fields.

What am I missing?


Solution

  • USPostalCode really ignores if_missing option. It can be seen in source code (USPostalCode is implemented as Any compound validator that does not define if_missing unlike All compound validator). Also the next commands demonstrate it:

    >>> validators.Regex(r'^\d+$', not_empty=False, if_missing='').if_missing
    ''
    >>> national.USPostalCode(not_empty=False, if_missing='').if_missing
    <class 'formencode.api.NoDefault'>
    

    It should be a bug in formencode.

    As a possible workaround, if_missing may be defined manually for each validator:

    us_postal_code_validator = national.USPostalCode(if_empty=None, not_empty=False)
    us_postal_code_validator.if_missing = ''
    
    class ABCSchema(Schema):
        allow_extra_fields = True
        filter_extra_fields = True
        billing_zip = us_postal_code_validator
    

    Or if_key_missing may be defined for the entire schema (but be careful since it will affect all fields in that schema):

    class ABCSchema(Schema):
        if_key_missing = ''
        allow_extra_fields = True
        filter_extra_fields = True
        billing_zip = national.USPostalCode(if_empty=None, not_empty=False)