2

I want to nest my custom validators within my schema, like this:

MySchema(Schema):
    class MyValidator(validators.FancyValidator):
        def _to_python(self, value, state):
            ...
    class MyOtherValidator(validators.FancyValidator):
        def _to_python(self, value, state):
            ...

    field_foo = All(validators.NotEmpty(),
                    MyValidator())
    field_bar = All(validators.NotEmpty(),
                    MyOtherValidator())

However, it seems to think that MyValidator and MyOtherValidator are fields b/c it's form_errors contain:

{ 
  'MyValidator': 'Missing value',
  'MyOtherValidator': 'Missing value'
}

If I don't nest them, they seem fine. What am I missing?

skaffman
  • 398,947
  • 96
  • 818
  • 769
steve
  • 423
  • 6
  • 16

2 Answers2

2

My advice is: you should move the FancyValidator subclass definitions to global scope, either (1) in the same module just before the definition of the Schema in which they're used, or (2) in a separate module for greater reuse. Unless there is a specific reason why nesting is required, a few extra class names in the module namespace shouldn't hurt.

For example:

from formencode import All, FancyValidator, Schema, validators

class MyValidator(FancyValidator):
    def _to_python(self, value, state):
        return value + '_foo'

class MyOtherValidator(FancyValidator):
    def _to_python(self, value, state):
        return value + '_bar'

class MySchema(Schema):
    field_foo = All(validators.NotEmpty(), MyValidator())
    field_bar = All(validators.NotEmpty(), MyOtherValidator())

print MySchema().to_python({'field_foo': 'x', 'field_bar': 'y'}, None)

Result:

{'field_foo': 'x_foo', 'field_bar': 'y_bar'}
samplebias
  • 37,113
  • 6
  • 107
  • 103
  • it's more of a preference to not to pollute the global space since these validators are specific to this schema. – steve May 19 '11 at 21:11
  • @steve OK. The symbols defined in the module are local to the module -- for example `from formencode import All` pulls `All` into the module scope. You can define `__all__` to control the visible symbols if someone imports your module using `from X import *`. In any case, the limitations of formencode may prevent nesting. – samplebias May 19 '11 at 22:28
0

In python, anything that you define in your class is a field. Be it static variables, variables set with self, methods or classes. If you want to "hide" the classes, or make them "less public", as is probably the right wording in the python dictionary, you should start their names with __.

>>> dir(X())
['A', '_B', '_X__C', '__doc__', '__module__']
>>> class X:
...     class A: pass
...     class __B: pass
...     c = 0
...     __d = 1
... 
>>> dir(X())
['A', '_X__B', '_X__d', '__doc__', '__module__', 'c']

As you can see, there is a loophole for this kind of privacy, but most automatic tools will recognize that you are trying to make something private.

Thomas Ahle
  • 30,774
  • 21
  • 92
  • 114
  • tried both _ and __ beforehand. somehow, formencode's schema class would still process them. – steve May 19 '11 at 21:11