Commits

James Crasta committed f8059a0 Merge

Merged ext.sqlalchemy improvements from jeanphix/wtforms

Comments (0)

Files changed (13)

 eab645ef8ca1dee6fd39ea28f93a1a37a4cb2347 0.6.1
 8e5a93665d108cc8977936e6ab54706ebc05587a 0.6.2
 6a6954927a13911fae6941fd0aac13b8d6372a42 0.6.3
+643ce2169fb4359f8b541102e7db22fed4871215 1.0
+b83e12f59ac1be690533141025d17f7cd0bc1467 1.0.1
 WTForms Changelog
 =================
 
+Version 1.0.1
+-------------
+Released February 29, 2012
 
-Version 0.6.4dev
-----------------
-Not yet released
+- Fixed issues related to building for python 3 and python pre-releases.
+
+- Add object_data to fields to get at the originally passed data.
+
+Version 1.0
+-----------
+Released February 28, 2012
 
 - Output HTML5 compact syntax by default.
 
 
 - Add localization support for WTForms built-in messages
 
+- Python 3 support (via 2to3)
+
 - Minor changes/fixes:
   * An empty label string can be specified on fields if desired
   * Option widget can now take kwargs customization
 # All configuration values have a default value; values that are commented out
 # serve to show the default value.
 
-import sys, os
+def _fix_import_path():
+    """
+    Don't want to pollute the config globals, so do path munging 
+    here in this function
+    """
+    import sys, os
 
-sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+    try:
+        import wtforms
+    except ImportError:
+        parent_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+        build_lib = os.path.join(parent_dir, 'build', 'lib')
+        if os.path.isdir(build_lib):
+            sys.path.insert(0, build_lib)
+        else:
+            sys.path.insert(0, parent_dir)
 
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-#sys.path.append(os.path.abspath('some/directory'))
+_fix_import_path()
 
 # General configuration
 # ---------------------
 # other places throughout the built documents.
 #
 # The short X.Y version.
-version = '0.6.4'
+version = '1.0.2'
 # The full version, including alpha/beta/rc tags.
-release = '0.6.4dev'
+release = '1.0.2dev'
 
 
 # There are two options for replacing |today|: either, you set today to some
 for your file input, even if the form is prefixed.
 
 
+Why does blank input not go back to the default value?
+------------------------------------------------------
+
+A key design decision of WTForms was that form data -always- takes precedence
+when there's a form submission. That is, if a field exists on a form, and a
+form was posted, but that field's value was missing, it will not revert to a
+default, but instead store an empty value (and in some cases cause a validation
+error.)
+
+This is for a number of reasons:
+
+1. Security. If a form reverted to defaults on missing data, then an evil user
+   could potentially cause problems by submitting a hand-coded form with key
+   missing fields.
+
+2. Bug-finding. If you omitted a field in your template, it might fall through
+   to the default and you'd possibly miss it.
+
+3. Consistency.
+
+See the following mailing list posts for more discussion on the topic:
+ - http://groups.google.com/group/wtforms/browse_frm/thread/6755a45a13878e9 
+ - http://groups.google.com/group/wtforms/msg/fa409c8c89b6f62d 
+
+
 How do I... [convoluted combination of libraries]
 -------------------------------------------------
 
         If form data is processed, is the valuelist given from the formdata
         wrapper. Otherwise, `raw_data` will be `None`.
 
+    .. attribute:: object_data
+
+        This is the data passed from an object or from kwargs to the field,
+        stored unmodified. This can be used by templates, widgets, validators
+        as needed (for comparison, for example)
+
     **Rendering**
 
     To render a field, simply call it, providing any values the widget expects

docs/validators.rst

 Built-in validators
 -------------------
 
+.. autoclass:: wtforms.validators.DataRequired
+
+   This also sets the ``required`` :attr:`flag <wtforms.fields.Field.flags>` on
+   fields it is used on.
+
 .. autoclass:: wtforms.validators.Email
 
 .. autoclass:: wtforms.validators.EqualTo
     passwords specified at all. Because Required stops the validation chain,
     EqualTo is not run in the case the password field is left empty.
 
+.. autoclass:: wtforms.validators.InputRequired
+
+   This also sets the ``required`` :attr:`flag <wtforms.fields.Field.flags>` on
+   fields it is used on.
+
 .. autoclass:: wtforms.validators.IPAddress
 
 .. autoclass:: wtforms.validators.Length
    This also sets the ``optional`` :attr:`flag <wtforms.fields.Field.flags>` on
    fields it is used on.
 
-.. autoclass:: wtforms.validators.Required
-
-   This also sets the ``required`` :attr:`flag <wtforms.fields.Field.flags>` on
-   fields it is used on.
 
 .. autoclass:: wtforms.validators.Regexp
 
     if not has_setuptools:
         raise Exception('Python3 support in WTForms requires distribute.')
     extra['use_2to3'] = True
-    extra['use_2to3_exclude_fixers'] = ['lib2to3.fixes.filter']
+    extra['use_2to3_exclude_fixers'] = ['lib2to3.fixes.fix_filter', 'lib2to3.fixes.filter']
 
 setup(
     name='WTForms',
-    version='0.6.4dev',
+    version='1.0.2',
     url='http://wtforms.simplecodes.com/',
     license='BSD',
     author='Thomas Johansson, James Crasta',
 #!/usr/bin/env python
-import platform
+import sys
 
 from datetime import date, datetime
 from decimal import Decimal, ROUND_UP, ROUND_DOWN
 from wtforms.form import Form
 
 
-PYTHON_VERSION = tuple(int(x) for x in platform.python_version_tuple())
+PYTHON_VERSION = sys.version_info 
 
 class DummyPostData(dict):
     def getlist(self, key):
         self.assertEqual(label().__html__(), expected)
         self.assertEqual(label(u'hello'), u"""<label for="test">hello</label>""")
         self.assertEqual(TextField(u'hi').bind(Form(), 'a').label.text, u'hi')
-        if PYTHON_VERSION < (3, 0, 0):
+        if PYTHON_VERSION < (3, ):
             self.assertEqual(repr(label), "Label('test', u'Caption')") 
         else:
             self.assertEqual(repr(label), "Label('test', 'Caption')") 
         self.assert_(u'not match format' in form.a.errors[0])
 
     def test_microseconds(self):
-        if PYTHON_VERSION < (2, 6, 0):
+        if PYTHON_VERSION < (2, 6):
             return # Microsecond formatting support was only added in 2.6
 
         d = datetime(2011, 5, 7, 3, 23, 14, 424200)

wtforms/__init__.py

 from wtforms.form import Form
 from wtforms.validators import ValidationError
 
-__version__ = '0.6.4dev'
+__version__ = '1.0.2dev'

wtforms/ext/i18n/form.py

 class Form(form.Form):
     """
     Base form for a simple localized WTForms form.
-   
+
     This will use the stdlib gettext library to retrieve an appropriate
     translations object for the language, by default using the locale
     information from the environment.
 
     If the LANGUAGES class variable is overridden and set to a sequence of
     strings, this will be a list of languages by priority to use instead, e.g::
+
         LANGUAGES = ['en_GB', 'en']
 
     Translations objects are cached to prevent having to get a new one for the

wtforms/ext/i18n/messages/wtforms.pot

 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: WTForms 0.6.4dev\n"
+"Project-Id-Version: WTForms 1.0\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
 "POT-Creation-Date: 2012-01-31 12:58-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

wtforms/fields/core.py

                 data = self.default()
             except TypeError:
                 data = self.default
+
+        self.object_data = data
+
         try:
             self.process_data(data)
         except ValueError, e:
             self.data = u''
 
     def _value(self):
-        return self.data is not None and unicode(self.data) or u''
+        return unicode(self.data) if self.data is not None else u''
 
 
 class IntegerField(Field):
                 data = self.default
             self._obj = data
 
+        self.object_data = data
+
         prefix = self.name + self.separator
         if isinstance(data, dict):
             self.form = self.form_class(formdata=formdata, prefix=prefix, **data)
             except TypeError:
                 data = self.default
 
+        self.object_data = data
+
         if formdata:
             indices = sorted(set(self._extract_indices(self.name, formdata)))
             if self.max_entries:

wtforms/validators.py

             raise StopValidation()
 
 
-class Required(object):
+class DataRequired(object):
     """
     Validates that the field contains data. This validator will stop the
     validation chain on error.
             raise StopValidation(self.message)
 
 
+class Required(DataRequired):
+    """
+    Legacy alias for DataRequired.
+
+    This is needed over simple aliasing for those who require that the
+    class-name of required be 'Required.'
+
+    This class will start throwing deprecation warnings in WTForms 1.1 and be removed by 1.2.
+    """
+
+
+class InputRequired(object):
+    """
+    Validates that input was provided for this field. 
+
+    Note there is a distinction between this and DataRequired in that
+    InputRequired looks that form-input data was provided, and DataRequired
+    looks at the post-coercion data.
+    """
+    field_flags = ('required', )
+
+    def __init__(self, message=None):
+        self.message = message
+
+    def __call__(self, form, field):
+        if not field.raw_data or not field.raw_data[0]:
+            if self.message is None:
+                self.message = field.gettext(u'This field is required.')
+
+            field.errors[:] = []
+            raise StopValidation(self.message)
+
+
 class Regexp(object):
     """
     Validates the field against a user provided regexp.
 number_range = NumberRange
 optional = Optional
 required = Required
+input_required = InputRequired
+data_required = DataRequired
 regexp = Regexp
 url = URL
 any_of = AnyOf