Skip to content
Browse files

WTForms validation for Tornado

This is a very thin wrapper that allows you to use WTForms to validate
user input with the RequestHandler.
  • Loading branch information...
1 parent 1f3030e commit c7d91b53061d39ad23131f2a8b2751fc22902dd6 Daniel Truemper committed Aug 1, 2011
Showing with 161 additions and 0 deletions.
  1. +52 −0 tornadotools/forms.py
  2. +109 −0 vows/forms_vows.py
View
52 tornadotools/forms.py
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2008 Daniel Truemper truemped@googlemail.com
+#
+# forms.py 31-Jul-2011
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# under the License.
+#
+#
+from wtforms import Form
+
+
+class TornadoInputWrapper(object):
+
+ def __init__(self, handler):
+ self._handler = handler
+
+ def __iter__(self):
+ return iter(self._handler.request.arguments)
+
+ def __len__(self):
+ return len(self._handler.request.arguments)
+
+ def __contains__(self, name):
+ return (name in self._handler.request.arguments)
+
+ def getlist(self, name):
+ return self._handler.request.arguments[name]
+
+
+class Form(Form):
+ """
+ `WTForms` wrapper for Tornado.
+ """
+
+ def __init__(self, formdata=None, obj=None, prefix='', **kwargs):
+ """
+ Wrap the `formdata` with the `TornadoInputWrapper` and call the base
+ constuctor.
+ """
+ super(Form, self).__init__(TornadoInputWrapper(formdata),
+ obj=obj, prefix=prefix, **kwargs)
View
109 vows/forms_vows.py
@@ -0,0 +1,109 @@
+#
+# Copyright (c) 2008 Daniel Truemper truemped@googlemail.com
+#
+# forms_vows.py 01-Aug-2011
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# under the License.
+#
+#
+import urllib
+
+from tornado.web import Application, RequestHandler
+from wtforms import TextField, validators
+
+from tornadotools.route import Route
+from tornadotools.forms import Form
+
+from pyvows import Vows, expect
+from tornado_pyvows.context import TornadoContext, TornadoSubContext
+
+
+class SampleForm(Form):
+
+ user = TextField('Username', [
+ validators.Length(min=4,
+ message="Username should have at least 4 characters!")
+ ])
+
+ email = TextField('Email', [
+ validators.Length(min=5,
+ message="Email should have a least 5 characters!"),
+ validators.Email(
+ message="This is not a valid email address")
+ ])
+
+
+@Route(r'/forms/')
+class SampleFormHandler(RequestHandler):
+
+ def get(self):
+ form = SampleForm(self)
+ if form.validate():
+ self.finish({'ok': 'true'})
+ else:
+ self.set_status(400)
+ resp = {'error': 'notvalidating'}
+ if form.user.errors:
+ resp['user.errors'] = form.user.errors
+ if form.email.errors:
+ resp['email.errors'] = form.email.errors
+ self.finish(resp)
+
+
+@Vows.batch
+class Forms(TornadoContext):
+
+ def _get_app(self):
+ return Application(Route.routes())
+
+ class WithAMissingParameter(TornadoSubContext):
+
+ def topic(self):
+ return self._get('/forms/?%s' % urllib.urlencode([('user', 'test')]))
+
+ def codeShouldEqual400(self, topic):
+ expect(topic.code).to_equal(400)
+
+ def bodyShouldBe(self, topic):
+ expect(topic.body).to_equal('{"email.errors": ["Email should ' \
+ + 'have a least 5 characters!", "This is not a valid email ' \
+ + 'address"], "error": "notvalidating"}')
+
+ class WithAWrongParameter(WithAMissingParameter):
+
+ def topic(self):
+ return self._get('/forms/?%s' % urllib.urlencode([
+ ('user', 'test'),
+ ('email', 'notanemail')
+ ]))
+
+ def bodyShouldBe(self, topic):
+ expect(topic.body).to_equal('{"email.errors": ["This is not a ' \
+ + 'valid email address"], "error": "notvalidating"}')
+
+ class WithACorrectInput(TornadoSubContext):
+
+ def topic(self):
+ return self._get('/forms/?%s' %
+ urllib.urlencode([
+ ('user', 'test'),
+ ('email', 'email@web.de')
+ ])
+ )
+
+ def shouldBeSuccessful(self, topic):
+ expect(topic.code).to_equal(200)
+
+ def bodyShouldBe(self, topic):
+ expect(topic.body).to_equal('{"ok": "true"}')

0 comments on commit c7d91b5

Please sign in to comment.
Something went wrong with that request. Please try again.