PATCH: documentation on how to verify one date is before another

"Matthew Wilson" <[email protected]> Tue, 25 Nov 2008 16:50:49 -0500
Newsgroups gmane.comp.python.formencode
Message-ID <[email protected]>
NOTE: I am sending this again, because I'm not sure my first attempt
made it.  The first attempt had an attachment.  In this case, the
patch is inline.

I wrote a blog post today with a description on how to verify one date
field is before another.  This patch contains the text of that blog
post along with a new "Examples" section to the bottom of
Validator.txt.

There is some weirdness going on with the headings in the new examples
section.  I tried to use toctree but couldn't figure it out, so
hopefully somebody else can tweak this so it is more useful.

Matt

PATCH

Index: docs/schema_validator_example.rst
===================================================================
--- docs/schema_validator_example.rst	(revision 0)
+++ docs/schema_validator_example.rst	(revision 0)
@@ -0,0 +1,110 @@
+++++++++++++++++++++++++++++++++++++++++++++++++++
+Use FormEncode to verify one date precedes another
+++++++++++++++++++++++++++++++++++++++++++++++++++
+
+I have a form on my site that lets people choose a start date and a stop
+date. Then I show statistics for that date range. I wrote a FormEncode
+schema to verify that the start date is before the stop date.
+
+Here's the code
+===============
+
+::
+
+    # This is in a file named formencodefun.py
+    from formencode import Schema
+    from formencode.validators import DateConverter, FancyValidator, Invalid
+
+    class DateCompare(FancyValidator):
+        messages = dict(invalid="Start date must be before stop date")
+
+        def validate_python(self, field_dict, state):
+
+            start_date = field_dict['start_date']
+            stop_date = field_dict['stop_date']
+
+            if start_date > stop_date:
+                msg = self.message('invalid', state)
+
+                raise Invalid(msg, field_dict, state,
+                    error_dict=dict(stop_date=msg))
+
+    class MySchema(Schema):
+        start_date = DateConverter()
+        stop_date = DateConverter()
+
+        chained_validators = [DateCompare()]
+
+Usage
+=====
+
+::
+
+    >>> from formencodefun import MySchema
+    >>> s = MySchema()
+    >>> d1 = {'start_date':'11-02-2008', 'stop_date':'11-15-2008'}
+    >>> d2 = {'start_date':'11-15-2008', 'stop_date':'11-02-2008'}
+    >>> s.to_python(d1)
+    {'stop_date': datetime.date(2008, 11, 15), 'start_date':
+    datetime.date(2008, 11, 2)}
+    >>> s.to_python(d2)
+    ------------------------------------------------------------
+    Traceback (most recent call last):
+      File "<ipython console>", line 1, in <module>
+      File
+    "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py",
+    line 400, in to_python
+        value = tp(value, state)
+      File
+    "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/schema.py",
+    line 200, in _to_python
+        new = validator.to_python(new, state)
+      File
+    "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py",
+    line 403, in to_python
+        vp(value, state)
+      File "formencodefun.py", line 18, in validate_python
+        error_dict=dict(stop_date=msg))
+    Invalid: Start date must be before stop date
+
+How it works
+============
+
+Notice when I run s.to_python(d1), I get a dictionary back with the the
+values for start_date and stop_date replaced with datetime.date objects.
+
+Then when I run my schema on d2, where the start_date is after the
+stop_date, my schema raises an Invalid exception. In a web framework
+like TurboGears, there is some exception handler that will catch that
+exception and take that error dictionary and redraw the form and print
+my error message.
+
+Notice that the DateConverters first take my strings and turn them into
+datetime.date objects before the test in DateCompare. FormEncode runs
+the chained validators after it runs the individual validators.
+
+In this case, I just want to make sure that the start date precedes the
+stop date. I have written other validators that add extra keys into the
+field dict or change the values, but I want to keep this example simple.
+
+If the first DateConverters fail, then the chained validators never
+run::
+
+    >>> s.to_python({'start_date':'UNPARSEABLE', 'stop_date':'11-20-2008'})
+    ------------------------------------------------------------
+    Traceback (most recent call last):
+      File "<ipython console>", line 1, in <module>
+      File
+    "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/api.py",
+    line 400, in to_python
+        value = tp(value, state)
+      File
+    "/home/matt/virtualenvs/scratch/lib/python2.5/site-packages/FormEncode-1.1-py2.5.egg/formencode/schema.py",
+    line 197, in _to_python
+        error_dict=errors)
+    Invalid: start_date: Please enter the date in the form mm/dd/yyyy
+
+When my DateCompare validator is run, I can be confident that the
+objects with the keys start_date and stop_date in the field_dict have
+already been converted to datetime.date objects.
+
Index: docs/Validator.txt
===================================================================
--- docs/Validator.txt	(revision 3696)
+++ docs/Validator.txt	(working copy)
@@ -637,3 +637,9 @@
 is hard to access the ``'action'`` key in the example; storing the
 options (action.option and action.confirm) under another key would be
 preferable.
+
+
+Examples
+========
+
+.. include:: schema_validator_example.rst



END



-- 
Matthew Wilson
[email protected]
http://tplus1.com

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/