Ticket #1105: improved-api-for-validate-dec.patch
| File improved-api-for-validate-dec.patch, 26.2 kB (added by bjourne, 2 years ago) |
|---|
-
turbogears/controllers.py
old new 94 94 class BadFormatError(Exception): 95 95 """Output-format exception.""" 96 96 97 def validate(form=None, validators=None, state_factory=None): 98 """Validate input. 97 def validate(validator, state_factory=None): 98 """ 99 Decorates a function with validation. 99 100 100 @param form form to validate input from 101 @param validators individual validators to use for parameters 102 @param state_factory callable which returns the initial state instance for 103 validation 101 A decorator that validates parameters to the decorated function 102 and converts them to Python types. Only the parameters that have 103 the same names as fields in the schema are validated. Other 104 parameters are left untouched. 105 106 Validation results in four attributes of cherrypy.request being 107 set. 108 109 validation_errors: A dictionary containing names of the parameters 110 that failed validation as keys and error messages for each failing 111 field as values. 112 113 input_values: A dictionary containing names of the parameters that 114 failed validation as keys and the fields values as values. 115 116 validated_entity: The validator that was passed to the validate 117 decorator. 118 119 validation_state: State of validation. 120 121 @param validator Usually a subclass of formencode.Schema, but any 122 object that has a to_python() method which raises 123 formencode.api.Invalid exceptions work. A factory 124 function or class that creates an instance with a 125 to_python() method also works. 126 127 @param state_factory Callable which returns the initial state 128 instance for validation 104 129 """ 105 130 def entangle(func): 106 131 recursion_guard = dict(func=func) 107 if callable( form) and not hasattr(form, "validate"):108 init_ form = lambda self: form(self)132 if callable(validator) and not hasattr(validator, "to_python"): 133 init_validator = lambda self: validator(self) 109 134 else: 110 init_ form = lambda self: form135 init_validator = lambda self: validator 111 136 112 137 def validate(func, *args, **kw): 113 138 if tg_util.call_on_stack("validate", recursion_guard, 4): 114 139 return func(*args, **kw) 115 form = init_form(args and args[0] or kw["self"])140 validator = init_validator(args and args[0] or kw["self"]) 116 141 args, kw = tg_util.to_kw(func, args, kw) 117 118 errors = {} 142 119 143 if state_factory is not None: 120 144 state = state_factory() 121 145 else: 122 146 state = None 123 147 124 if form: 125 value = kw.copy() 126 try: 127 kw.update(form.validate(value, state)) 128 except Invalid, e: 129 errors = e.unpack_errors() 130 cherrypy.request.validation_exception = e 131 cherrypy.request.validated_form = form 148 errors = {} 149 value = kw.copy() 150 try: 151 kw.update(validator.to_python(value, state)) 152 except Invalid, e: 153 errors = e.unpack_errors() 132 154 133 if validators:134 if isinstance(validators, dict):135 for field, validator in validators.iteritems():136 try:137 kw[field] = validator.to_python(138 kw.get(field, None), state139 )140 except Invalid, error:141 errors[field] = error142 else:143 try:144 value = kw.copy()145 kw.update(validators.to_python(value, state))146 except Invalid, e:147 errors = e.unpack_errors()148 cherrypy.request.validation_exception = e149 155 cherrypy.request.validation_errors = errors 156 cherrypy.request.tg_validator = validator 150 157 cherrypy.request.input_values = kw.copy() 151 158 cherrypy.request.validation_state = state 152 159 153 154 160 args, kw = tg_util.from_kw(func, args, kw) 155 161 return errorhandling.run_with_errors(errors, func, *args, **kw) 156 162 -
turbogears/tests/test_form_controllers.py
old new 33 33 self.name = name 34 34 self.age = age 35 35 self.date = date 36 testform = turbogears.validate( form=myform)(testform)36 testform = turbogears.validate(myform)(testform) 37 37 testform = turbogears.expose(html="turbogears.tests.othertemplate")( 38 38 testform) 39 39 … … 43 43 self.name = name 44 44 self.age = age 45 45 self.date = date 46 testform_new_style = turbogears.validate( form=myform)(testform_new_style)46 testform_new_style = turbogears.validate(myform)(testform_new_style) 47 47 testform_new_style = turbogears.expose()(testform_new_style) 48 48 49 49 … … 126 126 class TestValidationState(TestCase): 127 127 128 128 class Controller(controllers.RootController): 129 @turbogears.validate(validators=AddingNestedSchema(), 130 state_factory=State) 129 @turbogears.validate(AddingNestedSchema(), state_factory=State) 131 130 @turbogears.expose() 132 131 def validate(self, a, b, c): 133 132 return 'counter: %d' % cherrypy.request.validation_state.counter -
turbogears/tests/test_errorhandling.py
old new 7 7 from turbogears.failsafe import values_atom_continuation, map_errors_continuation, \ 8 8 defaults_continuation, values_dict_continuation 9 9 from turbogears.util import bind_args 10 from turbogears import validators10 from turbogears.validators import Email, Int, String, StringBoolean 11 11 from turbogears import testutil 12 from turbogears.testutil import simple_schema 12 13 13 14 14 15 def _errors_to_str(errors): … … 31 32 def defaulterror(self, bar=""): 32 33 return dict(title="Default error provider") 33 34 defaulterror = error_handler(defaulterrorhandler)(defaulterror) 34 defaulterror = validate( validators={"bar":validators.StringBoolean()})(35 defaulterror)35 defaulterror = validate(simple_schema(bar = StringBoolean()))( 36 defaulterror) 36 37 defaulterror = expose()(defaulterror) 37 38 38 39 def specialisederror(self, bar="", baz=""): … … 41 42 specialisederror) 42 43 specialisederror = error_handler(specialisederrorhandler, 43 44 "'baz' in tg_errors")(specialisederror) 44 specialisederror = validate(validators={"bar":validators.Int(), 45 "baz":validators.Email()})( 46 specialisederror) 45 specialisederror = validate(simple_schema(bar = Int(), baz = Email()))( 46 specialisederror) 47 47 specialisederror = expose()(specialisederror) 48 48 49 49 def exceptionerror(self): … … 62 62 else: 63 63 return dict(title="Recursive error provider") 64 64 recursiveerror = error_handler()(recursiveerror) 65 recursiveerror = validate(validators={"bar":validators.Int()})( 66 recursiveerror) 65 recursiveerror = validate(simple_schema(bar = Int()))(recursiveerror) 67 66 recursiveerror = expose()(recursiveerror) 68 67 69 68 def impliciterror(self, tg_errors=None, bar=""): … … 72 71 tg_errors=str(tg_errors)) 73 72 else: 74 73 return dict(title="Implicit error provider") 75 impliciterror = validate(validators={"bar":validators.Int()})( 76 impliciterror) 74 impliciterror = validate(simple_schema(bar = Int()))(impliciterror) 77 75 impliciterror = expose()(impliciterror) 78 76 79 77 def normalmethod(self): … … 83 81 def normalmethodcaller(self, bar=""): 84 82 return dict(title="Normal method caller") 85 83 normalmethodcaller = error_handler(normalmethod)(normalmethodcaller) 86 normalmethodcaller = validate(validators={ 87 "bar":validators.StringBoolean()})( 88 normalmethodcaller) 84 normalmethodcaller = validate(simple_schema(bar = StringBoolean()))( 85 normalmethodcaller) 89 86 normalmethodcaller = expose()(normalmethodcaller) 90 87 91 88 def infiniteloop(self): … … 105 102 args=args, bar=kw["bar"]) 106 103 positionalargs = error_handler(defaulterrorhandler)( 107 104 positionalargs) 108 positionalargs = validate(validators={"bar":validators.StringBoolean(), 109 "second":validators.Int()})( 110 positionalargs) 105 positionalargs = validate(simple_schema(bar = StringBoolean(), 106 second = Int()))(positionalargs) 111 107 positionalargs = expose()(positionalargs) 112 108 113 109 def missingargs(self, bar=""): 114 110 return dict(title="Missing args provider") 115 111 missingargs = error_handler(defaulterrorhandler)(missingargs) 116 missingargs = validate(validators={"bar":validators.Int(not_empty=True)})(missingargs) 112 missingargs = validate(simple_schema(bar = Int(not_empty = True)))( 113 missingargs) 117 114 missingargs = expose()(missingargs) 118 115 119 116 def nohandler2(self, bar=""): 120 117 return dict(title="No handler inner") 121 nohandler2 = validate( validators={"bar":validators.Int()})(nohandler2)118 nohandler2 = validate(simple_schema(bar = Int()))(nohandler2) 122 119 nohandler2 = expose()(nohandler2) 123 120 124 121 def nohandler(self): … … 136 133 def bindargs(self, bar=""): 137 134 return dict(title="Bind arguments to error handler") 138 135 bindargs = error_handler(bind_args(baz=123)(simpleerrorhandler))(bindargs) 139 bindargs = validate( validators={"bar":validators.Int(not_empty=True)})(bindargs)136 bindargs = validate(simple_schema(bar = Int(not_empty=True)))(bindargs) 140 137 bindargs = expose()(bindargs) 141 138 142 139 def notexposed(self, bar, tg_errors = None): … … 144 141 return dict(title="Not exposed error", bar=bar) 145 142 else: 146 143 return dict(title="Not exposed", bar=bar) 147 notexposed = validate( validators={"bar":validators.Int()})(notexposed)144 notexposed = validate(simple_schema(bar = Int()))(notexposed) 148 145 149 146 def notexposedcaller(self, foo="", bar="", baz=""): 150 147 return self.notexposed(bar) … … 157 154 def continuationcaller(self, bar=""): 158 155 return dict(title="Continuation caller") 159 156 continuationcaller = error_handler(continuation)(continuationcaller) 160 continuationcaller = validate( validators={"bar":validators.Int()})(161 continuationcaller)157 continuationcaller = validate(simple_schema(bar = Int()))( 158 continuationcaller) 162 159 continuationcaller = expose()(continuationcaller) 163 160 164 161 def nest(self, bar=""): 165 162 return dict(title="Nested") 166 163 nest = error_handler(defaulterrorhandler)(nest) 167 nest = validate( validators={"bar":validators.Int()})(nest)164 nest = validate(simple_schema(bar = Int()))(nest) 168 165 nest = expose()(nest) 169 166 170 167 def failsafevaluesdict(self, tg_errors=None, bar="", baz=""): 171 168 return dict(title="Failsafe values-dict", bar=bar, baz=baz) 172 169 failsafevaluesdict = error_handler(values_dict_continuation({"bar":1, "baz":2}))(failsafevaluesdict) 173 failsafevaluesdict = validate(validators={"bar":validators.Int(), 174 "baz":validators.Int()})(failsafevaluesdict) 170 failsafevaluesdict = validate(simple_schema(bar = Int(), 171 baz = Int()))( 172 failsafevaluesdict) 175 173 failsafevaluesdict = expose()(failsafevaluesdict) 176 174 177 175 def failsafevaluesatom(self, tg_errors=None, bar="", baz=""): 178 176 return dict(title="Failsafe values-atom", bar=bar, baz=baz) 179 177 failsafevaluesatom = error_handler(values_atom_continuation(13))(failsafevaluesatom) 180 failsafevaluesatom = validate( validators={"bar":validators.Int(),181 "baz":validators.Int()})(failsafevaluesatom)178 failsafevaluesatom = validate(simple_schema(bar = Int(), baz = Int()))( 179 failsafevaluesatom) 182 180 failsafevaluesatom = expose()(failsafevaluesatom) 183 181 184 182 def failsafemaperrors(self, tg_errors=None, bar="", baz=""): 185 183 return dict(title="Failsafe map errors", bar=str(bar), baz=str(baz)) 186 184 failsafemaperrors = error_handler(map_errors_continuation())(failsafemaperrors) 187 failsafemaperrors = validate( validators={"bar":validators.Int(),188 "baz":validators.Int()})(failsafemaperrors)185 failsafemaperrors = validate(simple_schema(bar = Int(), baz = Int()))( 186 failsafemaperrors) 189 187 failsafemaperrors = expose()(failsafemaperrors) 190 188 191 189 def failsafeformencode(self, tg_errors=None, bar="", baz=""): 192 190 return dict(title="Formencode if_invalid", bar=bar, baz=baz) 193 failsafeformencode = validate(validators={"bar":validators.Int( 194 if_invalid=1), "baz":validators.Int(if_invalid=2)})(failsafeformencode) 191 failsafeformencode = validate(simple_schema(bar = Int(if_invalid = 1), 192 baz = Int(if_invalid = 2)))( 193 failsafeformencode) 195 194 failsafeformencode = expose()(failsafeformencode) 196 195 197 196 def failsafedefaults(self, tg_errors=None, bar=1, baz=2): 198 197 return dict(title="Failsafe map defaults", bar=bar, baz=baz) 199 198 failsafedefaults = error_handler(defaults_continuation())(failsafedefaults) 200 failsafedefaults = validate( validators={"bar":validators.Int(),201 "baz":validators.Int()})(failsafedefaults)199 failsafedefaults = validate(simple_schema(bar = Int(), baz = Int()))( 200 failsafedefaults) 202 201 failsafedefaults = expose()(failsafedefaults) 203 202 204 203 class NestedController(Controller): … … 206 205 def nest(self, bar=""): 207 206 return dict(title="Nested") 208 207 nest = error_handler()(nest) 209 nest = validate( validators={"bar":validators.Int()})(nest)208 nest = validate(simple_schema(bar = Int()))(nest) 210 209 nest = expose()(nest) 211 210 212 211 … … 219 218 def test_defaultErrorHandler(self): 220 219 """ Default error handler. """ 221 220 testutil.createRequest("/defaulterror?bar=abc") 221 222 print cherrypy.response.body[0] 223 222 224 self.failUnless("Default error handler" in cherrypy.response.body[0]) 223 225 testutil.createRequest("/defaulterror?bar=true") 224 226 self.failUnless("Default error provider" in cherrypy.response.body[0]) -
turbogears/tests/test_controllers.py
old new 7 7 from turbogears import validators 8 8 from turbogears import database 9 9 from turbogears import testutil 10 from turbogears.testutil import simple_schema 10 11 import cherrypy 11 12 import formencode 12 13 import pkg_resources … … 72 73 self.value = value 73 74 return str(value) 74 75 istrue = turbogears.error_handler(validation_error_handler)(istrue) 75 istrue = turbogears.validate( validators={76 'value': validators.StringBoolean()})(istrue)76 istrue = turbogears.validate( 77 simple_schema(value = validators.StringBoolean))(istrue) 77 78 istrue = turbogears.expose()(istrue) 78 79 79 80 … … 109 110 self.fullname = "%s %s" % (self.firstname, self.lastname) 110 111 return self.fullname 111 112 save = turbogears.error_handler(validation_error_handler)(save) 112 save = turbogears.validate( validators={113 "firstname": validators.String(min=2, not_empty=True),114 "lastname": validators.String()})(save)113 save = turbogears.validate( 114 simple_schema(firstname = validators.String(min = 2, not_empty=True), 115 lastname = validators.String()))(save) 115 116 save = turbogears.expose()(save) 116 117 117 118 class Registration(formencode.Schema): … … 122 123 def save2(self, submit, firstname, lastname="Miller"): 123 124 return self.save(submit, firstname, lastname) 124 125 save2 = turbogears.error_handler(validation_error_handler)(save2) 125 save2 = turbogears.validate( validators=Registration())(save2)126 save2 = turbogears.validate(Registration())(save2) 126 127 save2 = turbogears.expose()(save2) 127 128 128 129 def useother(self): … … 311 312 testutil.createRequest("/save?submit=send&firstname=D&lastname=") 312 313 assert len(cherrypy.root.errors) == 1 313 314 assert cherrypy.root.errors.has_key("firstname") 314 assert "characters" in cherrypy.root.errors["firstname"].msg.lower() 315 316 print cherrypy.root.errors["firstname"] 317 318 assert "characters" in cherrypy.root.errors["firstname"].lower() 315 319 testutil.createRequest("/save?submit=send&firstname=&lastname=") 316 320 assert len(cherrypy.root.errors) == 1 317 321 assert cherrypy.root.errors.has_key("firstname") -
turbogears/testutil.py
old new 74 74 response = cherrypy.serving.response 75 75 return output, response 76 76 77 def simple_schema(**fields): 78 """ Non-declarative way of creating a FormEncode schema. """ 79 schema = validators.Schema() 80 for name, validator in fields.items(): 81 schema.fields[name] = validator 82 return schema 77 83 78 84 class DBTest(unittest.TestCase): 79 85 model = None … … 92 98 93 99 def tearDown(self): 94 100 database.rollback_all() 95 <<<<<<< .mine96 101 for item in self.model.__dict__.values(): 97 102 if inspect.isclass(item) and issubclass(item, 98 103 sqlobject.SQLObject) and item != sqlobject.SQLObject \ 99 104 and item != InheritableSQLObject: 100 item.dropTable()101 =======102 for item in self.model.__dict__.values():103 if inspect.isclass(item) and issubclass(item,104 sqlobject.SQLObject) and item != sqlobject.SQLObject \105 and item != InheritableSQLObject:106 105 item.dropTable(ifExists=True) 107 >>>>>>> .theirs108 106 109 107 def reset_cp(): 110 108 cherrypy.root = None … … 113 111 """ Catches and unpacks validation errors. For testing purposes. """ 114 112 errors = {} 115 113 try: 116 value = widget. validate(value)114 value = widget.to_python(value) 117 115 except validators.Invalid, e: 118 116 if hasattr(e, 'unpack_errors'): 119 117 errors = e.unpack_errors() -
turbogears/widgets/tests/test_nested_form_controllers.py
old new 21 21 self.has_errors = True 22 22 self.name = p_data['name'] 23 23 self.age = p_data['age'] 24 testform = turbogears.validate( form=myform)(testform)24 testform = turbogears.validate(myform)(testform) 25 25 testform = turbogears.expose(html="turbogears.tests.othertemplate")( 26 26 testform) 27 27 … … 31 31 def testform_new_style(self, p_data): 32 32 self.name = p_data['name'] 33 33 self.age = p_data['age'] 34 testform_new_style = turbogears.validate( form=myform)(testform_new_style)34 testform_new_style = turbogears.validate(myform)(testform_new_style) 35 35 testform_new_style = turbogears.error_handler(set_errors)(testform_new_style) 36 36 testform_new_style = turbogears.expose()(testform_new_style) 37 37 -
turbogears/widgets/tests/test_new_validation.py
old new 61 61 form = SimpleForm() 62 62 value = dict(age="22", phone="5555555") 63 63 64 value = form. validate(value)64 value = form.to_python(value) 65 65 print value 66 66 assert value == dict(age=22, phone=5555555) 67 67 … … 94 94 form = SimpleForm(validator=NotSoSimpleSchema()) 95 95 value = dict(age="22", phone="5555555") 96 96 97 value = form. validate(value)97 value = form.to_python(value) 98 98 print value 99 99 assert value == dict(phoneage=5555577) 100 100 … … 106 106 value = dict(age="22", phone="5555555", 107 107 fs=dict(age="22", phone="5555555")) 108 108 109 value = form. validate(value)109 value = form.to_python(value) 110 110 print value 111 111 assert value == dict(age=22, phone=5555555, 112 112 fs=dict(age=22, phone=5555555)) -
turbogears/widgets/tests/test_forms.py
old new 36 36 widgets.TextField("age", validator=validators.Int())], 37 37 submit_text="Submit") 38 38 values = dict(name="ed", age="15") 39 values = form. validate(values)39 values = form.to_python(values) 40 40 assert values["name"] == "ed" 41 41 assert values["age"] == 15 42 42 assert not values.has_key("submit") … … 175 175 def checkform(self, foo): 176 176 self.foo = foo 177 177 checkform = expose()(checkform) 178 checkform = validate( form=nestedform)(checkform)178 checkform = validate(nestedform)(checkform) 179 179 180 180 def test_nested_variables(): 181 181 cherrypy.request = oldrequest -
turbogears/widgets/tests/test_request_related_features.py
old new 51 51 def test(self): 52 52 return dict(form1=form1, form2=form2) 53 53 test = turbogears.expose(template=".two_forms")(test) 54 test = turbogears.validate(form =form1)(test)54 test = turbogears.validate(form1)(test) 55 55 test = turbogears.error_handler(test)(test) 56 56 57 57 def test2(self): 58 58 return dict(form=form2) 59 59 test2 = turbogears.expose(template=".form")(test2) 60 test2 = turbogears.validate(form =form2)(test2)60 test2 = turbogears.validate(form2)(test2) 61 61 test2 = turbogears.error_handler(test2)(test2) 62 62 63 63 def test3(self): 64 64 return dict(form=form1) 65 65 test3 = turbogears.expose(template=".form")(test3) 66 test3 = turbogears.validate(form =form2)(test3)66 test3 = turbogears.validate(form2)(test3) 67 67 test3 = turbogears.error_handler(test3)(test3) 68 68 69 69 cherrypy.root = MyRoot() … … 71 71 output = cherrypy.response.body[0].lower() 72 72 iv = cherrypy.request.input_values 73 73 validation_errors = cherrypy.request.validation_errors 74 validated_form = cherrypy.request.validated_form74 tg_validator = cherrypy.request.tg_validator 75 75 76 76 print output 77 77 print iv 78 78 print validation_errors 79 print validated_form80 assert form1 is validated_form79 print tg_validator 80 assert form1 is tg_validator 81 81 assert form1.is_validated 82 assert form2 is not validated_form82 assert form2 is not tg_validator 83 83 assert not form2.is_validated 84 84 value_p = 'value="foo"' 85 85 id_p = 'id="form1_age"' … … 97 97 output = cherrypy.response.body[0].lower() 98 98 iv = cherrypy.request.input_values 99 99 validation_errors = cherrypy.request.validation_errors 100 validated_form = cherrypy.request.validated_form100 tg_validator = cherrypy.request.tg_validator 101 101 102 102 print output 103 103 print iv 104 104 print validation_errors 105 print validated_form106 assert form1 is not validated_form105 print tg_validator 106 assert form1 is not tg_validator 107 107 assert not form1.is_validated 108 assert form2 is validated_form108 assert form2 is tg_validator 109 109 assert form2.is_validated 110 110 assert 'value="foo"' in output 111 111 assert '>bar<' in output … … 116 116 output = cherrypy.response.body[0].lower() 117 117 iv = cherrypy.request.input_values 118 118 validation_errors = cherrypy.request.validation_errors 119 validated_form = cherrypy.request.validated_form119 tg_validator = cherrypy.request.tg_validator 120 120 121 121 print output 122 122 print iv 123 123 print validation_errors 124 print validated_form125 assert form1 is not validated_form124 print tg_validator 125 assert form1 is not tg_validator 126 126 assert not form1.is_validated 127 assert form2 is validated_form127 assert form2 is tg_validator 128 128 assert form2.is_validated 129 129 assert 'value="foo"' not in output 130 130 assert '>bar<' not in output … … 155 155 def test_validation(self): 156 156 return dict(form=form) 157 157 test_validation = turbogears.expose(template=".form")(test_validation) 158 test_validation = turbogears.validate(form =form)(test_validation)158 test_validation = turbogears.validate(form)(test_validation) 159 159 test_validation = turbogears.error_handler(test_validation)(test_validation) 160 160 161 161 cherrypy.root = MyRoot() -
turbogears/widgets/forms.py
old new 158 158 159 159 def _get_is_validated(self): 160 160 if self.path: 161 validated_form = getattr(request, "validated_form", None)161 tg_validator = getattr(request, "tg_validator", None) 162 162 form = self.path[0].widget 163 if form is validated_form:163 if form is tg_validator: 164 164 return True 165 165 else: 166 166 return False … … 1068 1068 if self.file_upload: 1069 1069 d["form_attrs"]['enctype'] = "multipart/form-data" 1070 1070 1071 def validate(self, value, state=None):1071 def to_python(self, value, state=None): 1072 1072 if self.validator: 1073 1073 return self.validator.to_python(value, state) 1074 1074