Permalink
Browse files

Add Flask-WTF

  • Loading branch information...
1 parent 2dddae2 commit 46ac4568530bc0fa2f797343e0dcdce4242f0f1c @georgevreilly committed Feb 2, 2013
Showing with 5,910 additions and 0 deletions.
  1. +67 −0 flask_wtf/__init__.py
  2. +72 −0 flask_wtf/file.py
  3. +124 −0 flask_wtf/form.py
  4. +125 −0 flask_wtf/html5.py
  5. +5 −0 flask_wtf/recaptcha/__init__.py
  6. +17 −0 flask_wtf/recaptcha/fields.py
  7. +73 −0 flask_wtf/recaptcha/validators.py
  8. +82 −0 flask_wtf/recaptcha/widgets.py
  9. +16 −0 wtforms/__init__.py
  10. +19 −0 wtforms/compat.py
  11. 0 wtforms/ext/__init__.py
  12. +1 −0 wtforms/ext/appengine/__init__.py
  13. +460 −0 wtforms/ext/appengine/db.py
  14. +120 −0 wtforms/ext/appengine/fields.py
  15. +1 −0 wtforms/ext/csrf/__init__.py
  16. +18 −0 wtforms/ext/csrf/fields.py
  17. +53 −0 wtforms/ext/csrf/form.py
  18. +70 −0 wtforms/ext/csrf/session.py
  19. 0 wtforms/ext/dateutil/__init__.py
  20. +76 −0 wtforms/ext/dateutil/fields.py
  21. 0 wtforms/ext/django/__init__.py
  22. +98 −0 wtforms/ext/django/fields.py
  23. +23 −0 wtforms/ext/django/i18n.py
  24. +172 −0 wtforms/ext/django/orm.py
  25. 0 wtforms/ext/django/templatetags/__init__.py
  26. +78 −0 wtforms/ext/django/templatetags/wtforms.py
  27. +1 −0 wtforms/ext/i18n/__init__.py
  28. +28 −0 wtforms/ext/i18n/form.py
  29. +173 −0 wtforms/ext/i18n/messages/en/LC_MESSAGES/wtforms.po
  30. +175 −0 wtforms/ext/i18n/messages/es/LC_MESSAGES/wtforms.po
  31. +171 −0 wtforms/ext/i18n/messages/fa/LC_MESSAGES/wtforms.po
  32. +173 −0 wtforms/ext/i18n/messages/fr/LC_MESSAGES/wtforms.po
  33. +173 −0 wtforms/ext/i18n/messages/it/LC_MESSAGES/wtforms.po
  34. +176 −0 wtforms/ext/i18n/messages/pl/LC_MESSAGES/wtforms.po
  35. +178 −0 wtforms/ext/i18n/messages/ru/LC_MESSAGES/wtforms.po
  36. +172 −0 wtforms/ext/i18n/messages/wtforms.pot
  37. +173 −0 wtforms/ext/i18n/messages/zh/LC_MESSAGES/wtforms.po
  38. +49 −0 wtforms/ext/i18n/utils.py
  39. 0 wtforms/ext/sqlalchemy/__init__.py
  40. +188 −0 wtforms/ext/sqlalchemy/fields.py
  41. +297 −0 wtforms/ext/sqlalchemy/orm.py
  42. +36 −0 wtforms/ext/sqlalchemy/validators.py
  43. +6 −0 wtforms/fields/__init__.py
  44. +890 −0 wtforms/fields/core.py
  45. +54 −0 wtforms/fields/simple.py
  46. +295 −0 wtforms/form.py
  47. +460 −0 wtforms/validators.py
  48. +4 −0 wtforms/widgets/__init__.py
  49. +268 −0 wtforms/widgets/core.py
View
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+"""
+ flask.ext.wtf
+ ~~~~~~~~~~~~
+
+ Flask-WTF extension
+
+ :copyright: (c) 2010 by Dan Jacob.
+ :license: BSD, see LICENSE for more details.
+"""
+
+try:
+ import sqlalchemy
+ _is_sqlalchemy = True
+except ImportError:
+ _is_sqlalchemy = False
+
+from wtforms import fields, widgets, validators
+from wtforms.fields import *
+from wtforms.validators import *
+from wtforms.widgets import *
+from wtforms import ValidationError
+
+from . import html5
+from .form import Form
+from . import recaptcha
+
+from .recaptcha.fields import RecaptchaField
+from .recaptcha.widgets import RecaptchaWidget
+from .recaptcha.validators import Recaptcha
+
+fields.RecaptchaField = RecaptchaField
+widgets.RecaptchaWidget = RecaptchaWidget
+validators.Recaptcha = Recaptcha
+
+from .file import FileField
+from .file import FileAllowed, FileRequired, file_allowed, file_required
+
+fields.FileField = FileField
+
+validators.file_allowed = file_allowed
+validators.file_required = file_required
+validators.FileAllowed = FileAllowed
+validators.FileRequired = FileRequired
+
+
+__all__ = ['Form', 'ValidationError', 'fields', 'validators', 'widgets', 'html5']
+
+__all__ += [str(v) for v in validators.__all__ ]
+__all__ += [str(v) for v in (fields.__all__ if hasattr(fields, '__all__') else
+ fields.core.__all__) ]
+
+__all__ += [str(v) for v in (widgets.__all__ if hasattr(widgets, '__all__') else
+ widgets.core.__all__)]
+__all__ += recaptcha.__all__
+
+if _is_sqlalchemy:
+ from wtforms.ext.sqlalchemy.fields import QuerySelectField, \
+ QuerySelectMultipleField
+
+ __all__ += ['QuerySelectField',
+ 'QuerySelectMultipleField']
+
+ for field in (QuerySelectField,
+ QuerySelectMultipleField):
+
+ setattr(fields, field.__name__, field)
View
@@ -0,0 +1,72 @@
+from werkzeug import FileStorage
+from wtforms import FileField as _FileField
+from wtforms import ValidationError
+
+class FileField(_FileField):
+ """
+ Werkzeug-aware subclass of **wtforms.FileField**
+
+ Provides a `has_file()` method to check if its data is a FileStorage
+ instance with an actual file.
+ """
+ @property
+ def file(self):
+ """
+ :deprecated: synonym for **data**
+ """
+ return self.data
+
+ def has_file(self):
+ '''Return True iff self.data is a FileStorage with file data'''
+ if not isinstance(self.data, FileStorage):
+ return False
+ # filename == None => the field was present but no file was entered
+ # filename == '<fdopen>' is for a werkzeug hack:
+ # large file uploads will get stored in a temporary file on disk and
+ # show up as an extra FileStorage with name '<fdopen>'
+ return self.data.filename not in [None, '', '<fdopen>']
+
+
+class FileRequired(object):
+ """
+ Validates that field has a file.
+
+ `message` : error message
+
+ You can also use the synonym **file_required**.
+ """
+
+ def __init__(self, message=None):
+ self.message=message
+
+ def __call__(self, form, field):
+ if not field.has_file():
+ raise ValidationError, self.message
+
+file_required = FileRequired
+
+
+class FileAllowed(object):
+ """
+ Validates that the uploaded file is allowed by the given
+ Flask-Uploads UploadSet.
+
+ `upload_set` : instance of **flask.ext.uploads.UploadSet**
+
+ `message` : error message
+
+ You can also use the synonym **file_allowed**.
+ """
+
+ def __init__(self, upload_set, message=None):
+ self.upload_set = upload_set
+ self.message = message
+
+ def __call__(self, form, field):
+ if not field.has_file():
+ return
+ if not self.upload_set.file_allowed(field.data, field.data.filename):
+ raise ValidationError, self.message
+
+file_allowed = FileAllowed
+
View
@@ -0,0 +1,124 @@
+import werkzeug.datastructures
+
+from jinja2 import Markup
+from flask import request, session, current_app
+from wtforms.fields import HiddenField
+from wtforms.ext.csrf.session import SessionSecureForm
+
+class _Auto():
+ '''Placeholder for unspecified variables that should be set to defaults.
+
+ Used when None is a valid option and should not be replaced by a default.
+ '''
+ pass
+
+class Form(SessionSecureForm):
+
+ """
+ Flask-specific subclass of WTForms **SessionSecureForm** class.
+
+ Flask-specific behaviors:
+ If formdata is not specified, this will use flask.request.form. Explicitly
+ pass formdata = None to prevent this.
+
+ csrf_context - a session or dict-like object to use when making CSRF tokens.
+ Default: flask.session.
+
+ secret_key - a secret key for building CSRF tokens. If this isn't specified,
+ the form will take the first of these that is defined:
+ * the SECRET_KEY attribute on this class
+ * the value of flask.current_app.config["SECRET_KEY"]
+ * the session's secret_key
+ If none of these are set, raise an exception.
+
+ csrf_enabled - whether to use CSRF protection. If False, all csrf behavior
+ is suppressed. Default: check app.config for CSRF_ENABLED, else True
+
+ """
+ def __init__(self, formdata=_Auto, obj=None, prefix='', csrf_context=None,
+ secret_key=None, csrf_enabled=None, *args, **kwargs):
+
+ if csrf_enabled is None:
+ csrf_enabled = current_app.config.get('CSRF_ENABLED', True)
+ self.csrf_enabled = csrf_enabled
+
+ if formdata is _Auto:
+ if self.is_submitted():
+ formdata = request.form
+ if request.files:
+ formdata = formdata.copy()
+ formdata.update(request.files)
+ elif request.json:
+ formdata = werkzeug.datastructures.MultiDict(request.json);
+ else:
+ formdata = None
+ if self.csrf_enabled:
+ if csrf_context is None:
+ csrf_context = session
+ if secret_key is None:
+ # It wasn't passed in, check if the class has a SECRET_KEY set
+ secret_key = getattr(self, "SECRET_KEY", None)
+ if secret_key is None:
+ # It wasn't on the class, check the application config
+ secret_key = current_app.config.get("SECRET_KEY")
+ if secret_key is None and session:
+ # It's not there either! Is there a session secret key if we can
+ secret_key = session.secret_key
+ if secret_key is None:
+ # It wasn't anywhere. This is an error.
+ raise Exception('Must provide secret_key to use csrf.')
+
+ self.SECRET_KEY = secret_key
+ else:
+ csrf_context = {}
+ self.SECRET_KEY = ""
+ super(Form, self).__init__(formdata, obj, prefix, csrf_context=csrf_context, *args, **kwargs)
+
+ def generate_csrf_token(self, csrf_context=None):
+ if not self.csrf_enabled:
+ return None
+ return super(Form, self).generate_csrf_token(csrf_context)
+
+ def validate_csrf_token(self, field):
+ if not self.csrf_enabled:
+ return
+ super(Form, self).validate_csrf_token(field)
+
+ def is_submitted(self):
+ """
+ Checks if form has been submitted. The default case is if the HTTP
+ method is **PUT** or **POST**.
+ """
+
+ return request and request.method in ("PUT", "POST")
+
+ def hidden_tag(self, *fields):
+ """
+ Wraps hidden fields in a hidden DIV tag, in order to keep XHTML
+ compliance.
+
+ .. versionadded:: 0.3
+
+ :param fields: list of hidden field names. If not provided will render
+ all hidden fields, including the CSRF field.
+ """
+
+ if not fields:
+ fields = [f for f in self if isinstance(f, HiddenField)]
+
+ rv = [u'<div style="display:none;">']
+ for field in fields:
+ if isinstance(field, basestring):
+ field = getattr(self, field)
+ rv.append(unicode(field))
+ rv.append(u"</div>")
+
+ return Markup(u"".join(rv))
+
+ def validate_on_submit(self):
+ """
+ Checks if form has been submitted and if so runs validate. This is
+ a shortcut, equivalent to ``form.is_submitted() and form.validate()``
+ """
+ return self.is_submitted() and self.validate()
+
View
@@ -0,0 +1,125 @@
+from wtforms import TextField
+from wtforms import IntegerField as _IntegerField
+from wtforms import DecimalField as _DecimalField
+from wtforms import DateField as _DateField
+from wtforms.widgets import Input
+
+class DateInput(Input):
+ """
+ Creates `<input type=date>` widget
+ """
+ input_type = "date"
+
+
+class NumberInput(Input):
+ """
+ Creates `<input type=number>` widget
+ """
+ input_type="number"
+
+
+class RangeInput(Input):
+ """
+ Creates `<input type=range>` widget
+ """
+ input_type="range"
+
+
+class URLInput(Input):
+ """
+ Creates `<input type=url>` widget
+ """
+ input_type = "url"
+
+
+class EmailInput(Input):
+ """
+ Creates `<input type=email>` widget
+ """
+
+ input_type = "email"
+
+
+class SearchInput(Input):
+ """
+ Creates `<input type=search>` widget
+ """
+
+ input_type = "search"
+
+class TelInput(Input):
+ """
+ Creates `<input type=tel>` widget
+ """
+
+ input_type = "tel"
+
+
+class SearchField(TextField):
+ """
+ **TextField** using **SearchInput** by default
+ """
+ widget = SearchInput()
+
+
+class DateField(_DateField):
+ """
+ **DateField** using **DateInput** by default
+ """
+
+ widget = DateInput()
+
+
+class URLField(TextField):
+ """
+ **TextField** using **URLInput** by default
+ """
+
+ widget = URLInput()
+
+
+class EmailField(TextField):
+ """
+ **TextField** using **EmailInput** by default
+ """
+
+ widget = EmailInput()
+
+class TelField(TextField):
+ """
+ **TextField** using **TelInput** by default
+ """
+
+ widget = TelInput()
+
+
+class IntegerField(_IntegerField):
+ """
+ **IntegerField** using **NumberInput** by default
+ """
+
+ widget = NumberInput()
+
+
+class DecimalField(_DecimalField):
+ """
+ **DecimalField** using **NumberInput** by default
+ """
+
+ widget = NumberInput()
+
+
+class IntegerRangeField(_IntegerField):
+ """
+ **IntegerField** using **RangeInput** by default
+ """
+
+ widget = RangeInput()
+
+
+class DecimalRangeField(_DecimalField):
+ """
+ **DecimalField** using **RangeInput** by default
+ """
+
+ widget = RangeInput()
@@ -0,0 +1,5 @@
+from . import fields
+from . import validators
+from . import widgets
+
+__all__ = fields.__all__ + validators.__all__ + widgets.__all__
Oops, something went wrong.

0 comments on commit 46ac456

Please sign in to comment.