<?xml version="1.0"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>CKAN: Ticket #926: Pick a simpler form framework</title>
    <link>http://localhost/ticket/926</link>
    <description>&lt;p&gt;
The current formalchemy setup conflates view, controller and model code in a way that makes it hard to debug and customise.
&lt;/p&gt;
&lt;p&gt;
Review existing (and potentially non-existing) frameworks with a view to porting forms over to something more explicit and lightweight.
&lt;/p&gt;
&lt;p&gt;
Implement the current Package forms as an example of how this would work.
&lt;/p&gt;
&lt;p&gt;
Document and circulate.
&lt;/p&gt;
</description>
    <language>en-us</language>
    <image>
      <title>CKAN</title>
      <url>http://assets.okfn.org/p/ckan/img/ckan_logo_shortname.png</url>
      <link>http://localhost/ticket/926</link>
    </image>
    <generator>Trac 0.12.3</generator>
    <item>
      
        <dc:creator>rgrp</dc:creator>

      <pubDate>Wed, 02 Feb 2011 09:12:07 GMT</pubDate>
      <title>priority changed; milestone set</title>
      <link>http://localhost/ticket/926#comment:1</link>
      <guid isPermaLink="false">http://localhost/ticket/926#comment:1</guid>
      <description>
          &lt;ul&gt;
            &lt;li&gt;&lt;strong&gt;priority&lt;/strong&gt;
                changed from &lt;em&gt;awaiting triage&lt;/em&gt; to &lt;em&gt;critical&lt;/em&gt;
            &lt;/li&gt;
            &lt;li&gt;&lt;strong&gt;milestone&lt;/strong&gt;
                set to &lt;em&gt;ckan-v1.4-sprint-1&lt;/em&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;p&gt;
Comments from RP - &lt;a class="ext-link" href="http://lists.okfn.org/pipermail/ckan-dev/2011-January/000181.html"&gt;&lt;span class="icon"&gt;​&lt;/span&gt;http://lists.okfn.org/pipermail/ckan-dev/2011-January/000181.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Libraries I have used: &lt;a class="missing wiki"&gt;FormEncode?&lt;/a&gt;, &lt;a class="missing wiki"&gt;FormAlchemy?&lt;/a&gt; (what we are currently
using, before that formencode).
&lt;/p&gt;
&lt;p&gt;
Neither seemed perfect but I think the form issue is a 'hard' problem
(perhaps with no perfect answer) &lt;a class="missing changeset" title="No default repository defined"&gt;[1]&lt;/a&gt;. &lt;a class="missing wiki"&gt;FormAlchemy?&lt;/a&gt;, in retrospect, was
probably a mistake as it merges too much model/validation/form
generation into one thing.
&lt;/p&gt;
&lt;p&gt;
At least 3 functions involved:
&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Generating (or just filling) a form template with 'form data' (and errors)
&lt;/li&gt;&lt;li&gt;Converting model data to form data (also happens for APIs in fact) -- let's call this 'dict-ization'
&lt;/li&gt;&lt;li&gt;Converting form data to model data (and validating) (inverse of
&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;
previous step)
&lt;/p&gt;
&lt;p&gt;
I think one can and should separate 1 from 2+3 (and one of problems
with formalchemy is it doesn't -- the attraction being you don't
repeat yourself as forms get generated from model but I think this is
actually a false economy in medium-term).
&lt;/p&gt;
&lt;p&gt;
I'm not specifically recommending the following as I haven't used them
but I've looked through docs, they are active and reasonably mature:
&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Flatland: &lt;a class="ext-link" href="http://discorporate.us/projects/flatland/docs/tip/"&gt;&lt;span class="icon"&gt;​&lt;/span&gt;http://discorporate.us/projects/flatland/docs/tip/&lt;/a&gt;
&lt;ul&gt;&lt;li&gt;Only does 2+3 which is a good thing IMO
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ol start="2"&gt;&lt;li&gt;WTForms: &lt;a class="ext-link" href="http://wtforms.simplecodes.com/"&gt;&lt;span class="icon"&gt;​&lt;/span&gt;http://wtforms.simplecodes.com/&lt;/a&gt;
&lt;ul&gt;&lt;li&gt;Used in standard flask docs: &amp;lt;&lt;a class="ext-link" href="http://flask.pocoo.org/docs/patterns/wtforms/"&gt;&lt;span class="icon"&gt;​&lt;/span&gt;http://flask.pocoo.org/docs/patterns/wtforms/&lt;/a&gt;&amp;gt;
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;
      </description>
      <category>Ticket</category>
    </item><item>
      
        <dc:creator>rgrp</dc:creator>

      <pubDate>Mon, 07 Feb 2011 09:11:24 GMT</pubDate>
      <title>description changed</title>
      <link>http://localhost/ticket/926#comment:2</link>
      <guid isPermaLink="false">http://localhost/ticket/926#comment:2</guid>
      <description>
          &lt;ul&gt;
            &lt;li&gt;&lt;strong&gt;description&lt;/strong&gt;
              modified (&lt;a href="/ticket/926?action=diff&amp;amp;version=2"&gt;diff&lt;/a&gt;)
            &lt;/li&gt;
          &lt;/ul&gt;
      </description>
      <category>Ticket</category>
    </item><item>
      
        <dc:creator>rgrp</dc:creator>

      <pubDate>Wed, 23 Feb 2011 19:31:57 GMT</pubDate>
      <title></title>
      <link>http://localhost/ticket/926#comment:3</link>
      <guid isPermaLink="false">http://localhost/ticket/926#comment:3</guid>
      <description>
        &lt;p&gt;
@Seb: I believe this is now decided following discussion last week. Please could you detail results and close :)
&lt;/p&gt;
      </description>
      <category>Ticket</category>
    </item><item>
      
        <dc:creator>anonymous</dc:creator>

      <pubDate>Thu, 24 Feb 2011 09:59:57 GMT</pubDate>
      <title>status changed; resolution set</title>
      <link>http://localhost/ticket/926#comment:4</link>
      <guid isPermaLink="false">http://localhost/ticket/926#comment:4</guid>
      <description>
          &lt;ul&gt;
            &lt;li&gt;&lt;strong&gt;status&lt;/strong&gt;
                changed from &lt;em&gt;new&lt;/em&gt; to &lt;em&gt;closed&lt;/em&gt;
            &lt;/li&gt;
            &lt;li&gt;&lt;strong&gt;resolution&lt;/strong&gt;
                set to &lt;em&gt;fixed&lt;/em&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;p&gt;
Goals:
&lt;/p&gt;
&lt;p&gt;
We want the interface for updating an object to be loosely coupled to
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
the method for updating it.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
We might update a Package from:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;HTML forms
&lt;/li&gt;&lt;li&gt;a REST API (using JSON)
&lt;/li&gt;&lt;li&gt;a CLI (potentially using command line arguments, YaML, XML or ini files)
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
Right now, data is validated using a form framework, even if we're not
using forms.  Data is written to the object as part of the forms
framework (using the "sync()" method), making the process hard to
customise and hard to discover.
&lt;/p&gt;
&lt;p&gt;
Instead, there should be a standard chain for:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;deserialising untyped data (such as that received from an HTTP POST
or parsed from a YaML file) into valid data
&lt;/li&gt;&lt;li&gt;returning structured errors suitable for displaying to the user
&lt;/li&gt;&lt;li&gt;saving the validated, deserialised data
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
Ideally, it would look something like:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
schema = &lt;a class="missing wiki"&gt;MySchemaDefinition?&lt;/a&gt;()
raw_data = open("raw.csv", "r").read()
structured_data = to_python(raw_data, schema)
try:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
validated = validate(python_data)
myobject.update_from_dict(validated)
return "Updated OK"
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
except &lt;a class="missing wiki"&gt;ValidationError?&lt;/a&gt;, e:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
return "Error: %s" % e.to_dict()
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;
The inverse would be something like:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
structured_data = myobject.render_to_dict()
raw_data.write(to_csv(structured_data, schema)
print "Wrote CSV %s" % to_logformat(serialized_data, schema)
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
The question of how to generate and display forms should be completely
decoupled from this.  It should be easy to write forms by hand, which
means it should be simple to flatten the serialized data to key, value
pairs, and match up any validation errors to each key.
&lt;/p&gt;
&lt;p&gt;
Optionally, a form widget generation framework is a nice-to-have, but
not essential, as it is expected that, given enough time, the majority
of forms will require manual coding to accomodate edge conditions.
&lt;/p&gt;
&lt;p&gt;
A form widget generation framework should be reasonably complete if
it's worth trying at all, which means it should support things like:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;nested fields (at least repeating, multi-value fieldsets)
&lt;/li&gt;&lt;li&gt;widgets for dates and file uploads
&lt;/li&gt;&lt;li&gt;internationalisation
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
...but note I'd settle for *no* widget generation
&lt;/p&gt;
&lt;p&gt;
Components of a serialisation / validation framework:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;a simple, obvious way to define a schema
&lt;/li&gt;&lt;li&gt;a lightweight validation implementation
&lt;ul&gt;&lt;li&gt;simple interface for validators
&lt;/li&gt;&lt;li&gt;easy to match validation errors to data structure items
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
Overall, I'd like to see:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;loose coupling, no framework dependencies
&lt;/li&gt;&lt;li&gt;maximal test coverage
&lt;/li&gt;&lt;li&gt;extensive documentation with readily available examples
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
## Findings
&lt;/p&gt;
&lt;p&gt;
I looked at flatland, formencode, &lt;a class="missing wiki"&gt;FormAlchemy?&lt;/a&gt;, formish, WTForms, Django, web2py, deform/colander, formconvert and web.py
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;web2py&lt;/strong&gt; just helps build HTML from python, so isn't what I'm after at all
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;web.py&lt;/strong&gt; has rudimentary validation which is only aimed at HTML forms and is hence tightly coupled with them.
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Django&lt;/strong&gt;'s forms are again tightly coupled to HTML forms (and their generation)
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;a class="missing wiki"&gt;FormAlchemy?&lt;/a&gt;&lt;/strong&gt; similarly couples validation to forms, and is focussed on inferring a schema from a data model SQLAlchemy.
&lt;/li&gt;&lt;li&gt;&lt;strong&gt;WTForms&lt;/strong&gt; again focuses on Form generation and don't make itx easy to deserialise arbitrary data
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;
This leaves us with Flatland, Formencode, Formish, &lt;a class="missing wiki"&gt;Colander/Peppercorn/Deform?&lt;/a&gt;, and &lt;a class="missing wiki"&gt;FormConvert?&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Having reviewed all of these, I rejected Formencode on the basis of its patchy documentation and relatively low unit test coverage.  I also found it mixed concerns a bit much for my taste.
&lt;/p&gt;
&lt;p&gt;
Formish felt similarly sparsely documented.
&lt;/p&gt;
&lt;p&gt;
Of the remainder, I'd be happy using any of them, but opted for Colander in the end as it has the most exhaustive documentation and unit tests and has been used in production for a long time.  &lt;a class="missing wiki"&gt;FormConvert?&lt;/a&gt; has a nice design but is a bit of a moving target at the moment -- worth revisiting in the future.
&lt;/p&gt;
      </description>
      <category>Ticket</category>
    </item>
 </channel>
</rss>