Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Various updates to prepare for 0.8 public release

Updated the documentation and added an example custom widget
Tweaked docstrings
Updated requirements in seutp.py
  • Loading branch information...
commit 7a6aa29aea3e91bd011273215ca89d12c84f0d89 1 parent b15a3a8
Tim Parkin authored
View
91 CHANGELOG
@@ -2,22 +2,104 @@
Changlelog
==========
+0.8
+---
+
+ * Added 'readonly' attribute to widget that does not put data on the form.
+ This allows the creation of forms based on parts of a schema (i.e. mark the
+ rest of the schema widgets as 'readonly')
+
+ * Allow sparse request data (missing request data is now interpreted as the
+ default value for that widget (see default_value class attribute)
+
+ * Refactored the CachedTempFilestores api to only specify the cache tag and
+ headers.
+
+ * CachedTempFilestore now has a FileSystemHeaderedFilestore backend (by
+ default).
+
+ * Improved FileResource store initialisation and handling
+
+ - FileResource is now configured using a single filestore or dict of
+ filestores where the dict keys are the filestore's name. Filestores now
+ need no name attribute. The filestore with a None key is considered
+ unnamed, and is the default application filestore.
+ - The name of the filestore is now encoded in the URL and is used to select
+ the exact filestore to use.
+ - FileUpload widget now specifies the exact filestore (unnamed or 'tmp') to
+ use to display a preview.
+ - formish.util has some functions to help encode/decode FileResource paths
+
+ * Added formish.js and formish.css to the module
+
+ * Add min_start_fields, min_empty_start_fields to SequenceDefault widget. This
+ allows a sequence to always show a spare or only show a spare when no data
+ entered or to show many spares.
+
+ * Added batch_add_count which specifies how many empty fields to add when
+ 'add' is clicked
+
+ * Added empty_checker to SequenceDefault so that it can throw away excess
+ fields left because of min_start_fields (for instance).
+
+ * Changed the FileResource initialiser to assume nothing about where the
+ contents of the cache are stored (defaults could cause a security problem if
+ file cache and other caches collided). It now needs explicit filestores.
+ However a quickstart class method has been added that should provide handy
+ testing fileresources.
+
+ * Changed widget from and to request data methods to actively call child
+ fields methods. Widgets are now soleley in charge of managing the return of
+ request data/data from themselves and their children.
+
+ * Changed to use the new, vastly simplified, dottedish module. The old
+ dottedish module should no longer be used.
+
+ * Charset field can now be disabled. Names on action fields are optional. Form
+ name is optional.
+
+ * A check_form_name keyword argument can be passed to the validate function to
+ disable form name checking
+
+API CHANGES:
+
+ - FileResource and FileUpload filestores now handled differently
+ - to_request_data, form_request_data and pre_process_incoming_request now take
+ field instead of attr and explicitly call their child field's methods and
+ also return data (i.e. Widgets are now soleley in charge of managing the
+ return of request data/data from themselves and their children).
+
+BUG FIXES:
+
+ - bug in CheckBox repr
+ - added missing error_list block to the form (form level errors were not
+ shown)
+ - added styling to ensure all blocks with error class are #900 (dk red)
+ - generated files now use 0660 as base permissions
+ - problem with convertor_options.delimiter not being correctly handled
+ - replaced 'for each' instances with 'for' in formish.js
+ - SelectChoice selected method failed for complex sub-schemas
+
+
0.7.1
-----
API CHANGES:
- * Action init argument changes and add_action argument changes. Also, a default form now has an action in form.actions
+ * Action init argument changes and add_action argument changes. Also, a
+ default form now has an action in form.actions
A form now has a 'add_default_action' keyword argument that defaults to True.
Action init now takes (name, value=None, callback=None).
The default action on a form has a value of 'Submit' and a name of 'submit'.
- You can manage the list of actions explicitly. A value of None removes the value html attribute.
+ You can manage the list of actions explicitly. A value of None removes the
+ value html attribute.
0.7e
----
-Relase didn't include any template files (caused by missing gitlsfiles when building)
+Relase didn't include any template files (caused by missing gitlsfiles when
+building)
0.7d
----
@@ -66,7 +148,8 @@ BUG FIX: There were some errors in the previous file upload system but the
0.6.6 (2009-01-29)
------------------
- * Added the errors property to allow a user to get hold of the full list of errors (including the original validator settings)
+ * Added the errors property to allow a user to get hold of the full list of
+ errors (including the original validator settings)
0.6.5 (2009-01-23)
----------------
View
12 TODO
@@ -9,15 +9,3 @@ Adding additional templating languages
* Jinja would be a good start
-Widgets
--------
-
-* Select with other widget
-
-Tests
------
-
-* Add tests for checkedpassword widget
-
-
-
View
1  docs-build/index.rst
@@ -15,6 +15,7 @@ Contents:
restish
future
modules
+ recaptcha
Indices and tables
==================
View
108 docs-build/introduction.rst
@@ -541,33 +541,57 @@ The filestore uses a headered file format which is similar to an email format wi
.. code-block:: python
- class CachedTempFilestore(FileSystemHeaderedFilestore):
-
- def __init__(self, root_dir=None, name=None):
- if root_dir is None:
- self._root_dir = tempfile.gettempdir()
- else:
- self._root_dir = root_dir
- if name is None:
- self.name = ''
- else:
- self.name = name
+ class FileSystemHeaderedFilestore(object):
+ """
+ A general purpose readable and writable file store useful for storing data
+ along with additional metadata (simple key-value pairs).
+
+ This can be used to implement temporary file stores, local caches, etc.
+ XXX file ownership?
+ """
+
+ def __init__(self, root_dir, mode=0660):
+ """
+ Create a new storage space.
+
+ :arg root_dir: directory for stored files to be written to.
+ :arg mode: initial mode of created files, defaults to 0660. See os.open
+ for details.
+ """
+ self._root_dir = root_dir
+ self._mode = mode
+
+ class CachedTempFilestore(object):
+
+ def __init__(self, backend=None):
+ if backend is None:
+ backend = FileSystemHeaderedFilestore(tempfile.gettempdir())
+ self.backend = backend
def get(self, key, cache_tag=None):
- headers, f = FileSystemHeaderedFilestore.get(self, key)
- headers = dict(headers)
- if not cache_tag and headers['Cache-Tag'] == cache_tag:
- f.close()
- return (headers['Cache-Tag'], None, None)
- return (headers['Cache-Tag'],headers['Content-Type'], f)
+ """
+ Get the file stored for the given key.
+
+ :arg key: unique key that identifies the file.
+ :arg cache_tag: opaque value that is used to validate cache freshness
+ (similar to an HTTP etag).
+ :returns: tuple of (header, f) where headers is a list of (name, value)
+ pairs and f is a readable file-like object. f will be None if
+ the cache_tag was valid. f must be closed by the caller.
+ :raises KeyError: not found
+ """
+ def put(self, key, src, cache_tag, headers=None):
+ """
+ Add a file to the store, overwriting an existing file with the same key.
- def put(self, key, src, cache_tag, content_type, headers=None):
- if headers is None:
- headers = {}
- headers['Cache-Tag'] = cache_tag
- headers['Content-Type'] = content_type
- FileSystemHeaderedFilestore.put(self, key, headers, src)
+ :arg key: unique key that identifies the file.
+ :arg cache_tag: opaque value that is later used to validate cache
+ freshness (similar to an HTTP etag).
+ :arg headers: list of (name, value) pairs that will be associated with
+ the file.
+ :arg src: readable file-like object
+ """
@@ -580,6 +604,8 @@ So here is a simple FileUpload widget
.. code-block:: python
+ from formish import filestore
+
schema = schemaish.Structure()
schema.add( 'myFile', schemaish.File() )
@@ -590,26 +616,50 @@ So here is a simple FileUpload widget
show_image_thumbnail=True
)
+ schema = schemaish.Structure()
+ schema.add('myFile', schemaish.File())
+ form = formish.Form(schema, 'form')
+ form['myFile'].widget = formish.FileUpload(
+ filestore=CachedTempFilestore()
+ )
+ return form
+
+
+and a more complex example for images
+
+.. code-block:: python
+
+ schema = schemaish.Structure()
+ schema.add('myImage', schemaish.File())
+ form = formish.Form(schema, 'form')
+ form['myImage'].widget = formish.FileUpload(
+ filestore=CachedTempFilestore(),
+ show_image_thumbnail=True,
+ image_thumbnail_default='/images/nouploadyet.png',
+ show_download_link=True
+ )
+ return form
+
-To set up a file resource handler at /filehandler, you could use the following (if you are using restish)
+To set up a file resource handler at /filehandler, you could use the following (if you are using restish). This example serves stored files from a couchdb store and has a cache for temporary files.
.. code-block:: python
@resource.child()
def filehandler(self, request, segments):
- tempfilestore = formish.filestore.CachedTempFilestore(name='tmp')
- filestore = couchish.filestore.CouchDBAttachmentSource(couchish_store,name='cdb')
- return FileResource(filestores=[filestore, tempfilestore])
+ cdbfilestore = CouchDBAttachmentSource(request.environ['couchish'])
+ cache = CachedTempFilestore(FileSystemHeaderedFilestore(root_dir='cache'))
+ return FileResource(filestores=cdbfilestore,cache=cache)
-This looks a little more complicated, and is. This resource needs to serve files that are already in your application's persistent storage (the filestore here) and also provide a way of accessing temporary files that have been uploaded as the form is being possibly posted repeatedly before finally succeeding. Don't worry though, if you're happy with using temporary file storage for a while, your resource could look like this
+If you only need to set up some temporary filestore for testing or are happy with this for deployment.
.. code-block:: python
@resource.child()
def filehandler(self, request, segments):
- return FileResource()
+ return fileresource.FileResource.quickstart('store', 'cache'), segments[1:]
Then at some point when you get your storage implemented, you could add your own custom fileaccessor.
View
110 docs-build/recaptcha.rst
@@ -0,0 +1,110 @@
+ReCAPTCHA and Formish Custom Widgets
+====================================
+
+Someone posted a comment in my last blog entry about 'why another form library?' (as predicted I suppose). My personal opinion is that it's about easy of use but that is a difficult thing to describe. So I thought I'd challenge myself to port a Tosca Widget widget to see what it would look like in formish. I decided to include the ReCAPTCHA widget to make it a little more interesting.
+
+First thing was to write the Widget python code which went roughly as follows. First we set up the widget header with some constants..
+
+.. code-block:: python
+
+ import urllib, urllib2
+ from validatish import ConvertError
+ from convertish.convert import string_converter
+
+ class ReCAPTCHA(widgets.Input):
+
+ template = 'field.ReCAPTCHA'
+
+ API_SSL_SERVER="https://api-secure.recaptcha.net"
+ API_SERVER="http://api.recaptcha.net"
+ VERIFY_SERVER="api-verify.recaptcha.net"
+ USER_AGENT = "reCAPTCHA Formish"
+
+ def __init__(self, publickey, privatekey, environ, **k):
+ self.use_ssl = k.pop('use_ssl', False)
+ widgets.Input.__init__(self, **k)
+ self.publickey = publickey
+ self.privatekey = privatekey
+ self.remoteip = environ.get('REMOTE_ADDR', '127.0.0.1')
+
+
+
+This was the easy bit.. next we need to add the recaptcha code..
+
+
+.. code-block:: python
+
+ def from_request_data(self, field, data):
+ print 'in from ',data
+ params = urllib.urlencode({
+ 'privatekey': self.privatekey,
+ 'remoteip' : self.remoteip,
+ 'challenge': data['recaptcha_challenge_field'][0],
+ 'response' : data['recaptcha_response_field'][0],
+ })
+ request = urllib2.Request (
+ url = "http://%s/verify"%self.VERIFY_SERVER,
+ data = params,
+ headers = {
+ "Content-type": "application/x-www-form-urlencoded",
+ "User-agent": self.USER_AGENT
+ }
+ )
+ response = urllib2.urlopen(request)
+ return_values = response.read().splitlines()
+ response.close()
+ return_code = return_values[0]
+ if (return_code == "true"):
+ return string_converter(field.attr).to_type('True')
+ else:
+ raise ConvertError('reCAPTCHA failed')
+
+This code just prepares a request to make to the captcha server and reads the result. Now this would be it for the python code but unfortunately captcha widgets don't let you define your own name for the fields. This is just what the ``pre_parse_request`` method is for. It lets you munge some code up front if needed. In this case we move the captcha data into the right request field names.
+
+.. code-block:: python
+
+ def pre_parse_incoming_request_data(self, field, request_data):
+ """ reCaptcha won't let you use your own field names so we move them """
+ full_request_data = field.form.request_data
+ print 'full_request_data',full_request_data
+ return {'recaptcha_challenge_field': full_request_data['recaptcha_challenge_field'],
+ 'recaptcha_response_field': full_request_data['recaptcha_response_field'],}
+
+Finally we need a template
+
+.. code-block:: mako
+
+ <%page args="field" />
+ <%
+ if field.error:
+ args = "k=%s&amp;error=incorrect-captcha-sol"%field.widget.publickey
+ else:
+ args = "k=%s"%field.widget.publickey
+ if field.widget.use_ssl:
+ apiserver = field.widget.API_SSL_SERVER
+ else:
+ apiserver = field.widget.API_SERVER
+ %>
+ <script type="text/javascript" src="${apiserver}/challenge?${args|n}"></script>
+ <noscript>
+ <iframe src="${apiserver}/noscript?${args|n}" height="300" width="500" frameborder="0"></iframe><br />
+ <textarea name="${field.name}.recaptcha_challenge_field" rows="3" cols="40"></textarea>
+ <input type="hidden" name="${field.name}.recaptcha_response_field" value="manual_challenge" />
+ </noscript>
+
+So the widget just works out if there is an error and prepares the appropriate args and also plans for ssl if needed.
+
+And using the widget is as simple as .. (ReCAPTCHA isn't in the current release as I only wrote it tonight)
+
+.. code-block:: python
+
+ import schemaish, formish
+ schema = schemaish.Structure()
+ schema.add('recaptcha', schemaish.Boolean())
+ form = formish.Form(schema, 'form')
+ publickey = '6LcSqgQAAAAAAA1A6MJZXGpY35ZsdvwxvsEq0KQD'
+ privatekey = '6LcSqgQAA....................7ugn72Hi2va'
+ form['recaptcha'].widget = formish.ReCAPTCHA(publickey, privatekey, request.environ)
+
+Have a look at the widget in action at `http://ish.io:8891/ReCAPTCHA <http://ish.io:8891/ReCAPTCHA>`_ .
+
View
1  docs/html/_sources/index.txt
@@ -15,6 +15,7 @@ Contents:
restish
future
modules
+ recaptcha
Indices and tables
==================
View
108 docs/html/_sources/introduction.txt
@@ -541,33 +541,57 @@ The filestore uses a headered file format which is similar to an email format wi
.. code-block:: python
- class CachedTempFilestore(FileSystemHeaderedFilestore):
-
- def __init__(self, root_dir=None, name=None):
- if root_dir is None:
- self._root_dir = tempfile.gettempdir()
- else:
- self._root_dir = root_dir
- if name is None:
- self.name = ''
- else:
- self.name = name
+ class FileSystemHeaderedFilestore(object):
+ """
+ A general purpose readable and writable file store useful for storing data
+ along with additional metadata (simple key-value pairs).
+
+ This can be used to implement temporary file stores, local caches, etc.
+ XXX file ownership?
+ """
+
+ def __init__(self, root_dir, mode=0660):
+ """
+ Create a new storage space.
+
+ :arg root_dir: directory for stored files to be written to.
+ :arg mode: initial mode of created files, defaults to 0660. See os.open
+ for details.
+ """
+ self._root_dir = root_dir
+ self._mode = mode
+
+ class CachedTempFilestore(object):
+
+ def __init__(self, backend=None):
+ if backend is None:
+ backend = FileSystemHeaderedFilestore(tempfile.gettempdir())
+ self.backend = backend
def get(self, key, cache_tag=None):
- headers, f = FileSystemHeaderedFilestore.get(self, key)
- headers = dict(headers)
- if not cache_tag and headers['Cache-Tag'] == cache_tag:
- f.close()
- return (headers['Cache-Tag'], None, None)
- return (headers['Cache-Tag'],headers['Content-Type'], f)
+ """
+ Get the file stored for the given key.
+
+ :arg key: unique key that identifies the file.
+ :arg cache_tag: opaque value that is used to validate cache freshness
+ (similar to an HTTP etag).
+ :returns: tuple of (header, f) where headers is a list of (name, value)
+ pairs and f is a readable file-like object. f will be None if
+ the cache_tag was valid. f must be closed by the caller.
+ :raises KeyError: not found
+ """
+ def put(self, key, src, cache_tag, headers=None):
+ """
+ Add a file to the store, overwriting an existing file with the same key.
- def put(self, key, src, cache_tag, content_type, headers=None):
- if headers is None:
- headers = {}
- headers['Cache-Tag'] = cache_tag
- headers['Content-Type'] = content_type
- FileSystemHeaderedFilestore.put(self, key, headers, src)
+ :arg key: unique key that identifies the file.
+ :arg cache_tag: opaque value that is later used to validate cache
+ freshness (similar to an HTTP etag).
+ :arg headers: list of (name, value) pairs that will be associated with
+ the file.
+ :arg src: readable file-like object
+ """
@@ -580,6 +604,8 @@ So here is a simple FileUpload widget
.. code-block:: python
+ from formish import filestore
+
schema = schemaish.Structure()
schema.add( 'myFile', schemaish.File() )
@@ -590,26 +616,50 @@ So here is a simple FileUpload widget
show_image_thumbnail=True
)
+ schema = schemaish.Structure()
+ schema.add('myFile', schemaish.File())
+ form = formish.Form(schema, 'form')
+ form['myFile'].widget = formish.FileUpload(
+ filestore=CachedTempFilestore()
+ )
+ return form
+
+
+and a more complex example for images
+
+.. code-block:: python
+
+ schema = schemaish.Structure()
+ schema.add('myImage', schemaish.File())
+ form = formish.Form(schema, 'form')
+ form['myImage'].widget = formish.FileUpload(
+ filestore=CachedTempFilestore(),
+ show_image_thumbnail=True,
+ image_thumbnail_default='/images/nouploadyet.png',
+ show_download_link=True
+ )
+ return form
+
-To set up a file resource handler at /filehandler, you could use the following (if you are using restish)
+To set up a file resource handler at /filehandler, you could use the following (if you are using restish). This example serves stored files from a couchdb store and has a cache for temporary files.
.. code-block:: python
@resource.child()
def filehandler(self, request, segments):
- tempfilestore = formish.filestore.CachedTempFilestore(name='tmp')
- filestore = couchish.filestore.CouchDBAttachmentSource(couchish_store,name='cdb')
- return FileResource(filestores=[filestore, tempfilestore])
+ cdbfilestore = CouchDBAttachmentSource(request.environ['couchish'])
+ cache = CachedTempFilestore(FileSystemHeaderedFilestore(root_dir='cache'))
+ return FileResource(filestores=cdbfilestore,cache=cache)
-This looks a little more complicated, and is. This resource needs to serve files that are already in your application's persistent storage (the filestore here) and also provide a way of accessing temporary files that have been uploaded as the form is being possibly posted repeatedly before finally succeeding. Don't worry though, if you're happy with using temporary file storage for a while, your resource could look like this
+If you only need to set up some temporary filestore for testing or are happy with this for deployment.
.. code-block:: python
@resource.child()
def filehandler(self, request, segments):
- return FileResource()
+ return fileresource.FileResource.quickstart('store', 'cache'), segments[1:]
Then at some point when you get your storage implemented, you could add your own custom fileaccessor.
View
110 docs/html/_sources/recaptcha.txt
@@ -0,0 +1,110 @@
+ReCAPTCHA and Formish Custom Widgets
+====================================
+
+Someone posted a comment in my last blog entry about 'why another form library?' (as predicted I suppose). My personal opinion is that it's about easy of use but that is a difficult thing to describe. So I thought I'd challenge myself to port a Tosca Widget widget to see what it would look like in formish. I decided to include the ReCAPTCHA widget to make it a little more interesting.
+
+First thing was to write the Widget python code which went roughly as follows. First we set up the widget header with some constants..
+
+.. code-block:: python
+
+ import urllib, urllib2
+ from validatish import ConvertError
+ from convertish.convert import string_converter
+
+ class ReCAPTCHA(widgets.Input):
+
+ template = 'field.ReCAPTCHA'
+
+ API_SSL_SERVER="https://api-secure.recaptcha.net"
+ API_SERVER="http://api.recaptcha.net"
+ VERIFY_SERVER="api-verify.recaptcha.net"
+ USER_AGENT = "reCAPTCHA Formish"
+
+ def __init__(self, publickey, privatekey, environ, **k):
+ self.use_ssl = k.pop('use_ssl', False)
+ widgets.Input.__init__(self, **k)
+ self.publickey = publickey
+ self.privatekey = privatekey
+ self.remoteip = environ.get('REMOTE_ADDR', '127.0.0.1')
+
+
+
+This was the easy bit.. next we need to add the recaptcha code..
+
+
+.. code-block:: python
+
+ def from_request_data(self, field, data):
+ print 'in from ',data
+ params = urllib.urlencode({
+ 'privatekey': self.privatekey,
+ 'remoteip' : self.remoteip,
+ 'challenge': data['recaptcha_challenge_field'][0],
+ 'response' : data['recaptcha_response_field'][0],
+ })
+ request = urllib2.Request (
+ url = "http://%s/verify"%self.VERIFY_SERVER,
+ data = params,
+ headers = {
+ "Content-type": "application/x-www-form-urlencoded",
+ "User-agent": self.USER_AGENT
+ }
+ )
+ response = urllib2.urlopen(request)
+ return_values = response.read().splitlines()
+ response.close()
+ return_code = return_values[0]
+ if (return_code == "true"):
+ return string_converter(field.attr).to_type('True')
+ else:
+ raise ConvertError('reCAPTCHA failed')
+
+This code just prepares a request to make to the captcha server and reads the result. Now this would be it for the python code but unfortunately captcha widgets don't let you define your own name for the fields. This is just what the ``pre_parse_request`` method is for. It lets you munge some code up front if needed. In this case we move the captcha data into the right request field names.
+
+.. code-block:: python
+
+ def pre_parse_incoming_request_data(self, field, request_data):
+ """ reCaptcha won't let you use your own field names so we move them """
+ full_request_data = field.form.request_data
+ print 'full_request_data',full_request_data
+ return {'recaptcha_challenge_field': full_request_data['recaptcha_challenge_field'],
+ 'recaptcha_response_field': full_request_data['recaptcha_response_field'],}
+
+Finally we need a template
+
+.. code-block:: mako
+
+ <%page args="field" />
+ <%
+ if field.error:
+ args = "k=%s&amp;error=incorrect-captcha-sol"%field.widget.publickey
+ else:
+ args = "k=%s"%field.widget.publickey
+ if field.widget.use_ssl:
+ apiserver = field.widget.API_SSL_SERVER
+ else:
+ apiserver = field.widget.API_SERVER
+ %>
+ <script type="text/javascript" src="${apiserver}/challenge?${args|n}"></script>
+ <noscript>
+ <iframe src="${apiserver}/noscript?${args|n}" height="300" width="500" frameborder="0"></iframe><br />
+ <textarea name="${field.name}.recaptcha_challenge_field" rows="3" cols="40"></textarea>
+ <input type="hidden" name="${field.name}.recaptcha_response_field" value="manual_challenge" />
+ </noscript>
+
+So the widget just works out if there is an error and prepares the appropriate args and also plans for ssl if needed.
+
+And using the widget is as simple as .. (ReCAPTCHA isn't in the current release as I only wrote it tonight)
+
+.. code-block:: python
+
+ import schemaish, formish
+ schema = schemaish.Structure()
+ schema.add('recaptcha', schemaish.Boolean())
+ form = formish.Form(schema, 'form')
+ publickey = '6LcSqgQAAAAAAA1A6MJZXGpY35ZsdvwxvsEq0KQD'
+ privatekey = '6LcSqgQAA....................7ugn72Hi2va'
+ form['recaptcha'].widget = formish.ReCAPTCHA(publickey, privatekey, request.environ)
+
+Have a look at the widget in action at `http://ish.io:8891/ReCAPTCHA <http://ish.io:8891/ReCAPTCHA>`_ .
+
View
160 docs/html/_sources/walkthrough.txt
@@ -696,14 +696,14 @@ Formish tries to ensure that fields are 'symmetric'. i.e. what goes in comes bac
.. code-block:: python
- class FileHandlerMinimal(object):
+ class MinimalFilestore(object):
""" Example of File handler for formish file upload support. """
- def store_file(self, fs):
- """ Method to store a file """
+ def get(self, key, cache_tag=None):
+ pass
- def get_path_for_file(self, filename):
- """ Method to get a path for a file on disk """
+ def put(self, key, src, cache_tag, content_type, headers=None):
+ pass
As you can see, the two important things are a method to store the file and a method to get the file back off disk given the filename.
@@ -711,69 +711,145 @@ Our tempfile handler implements this as follows.
.. code-block:: python
- class TempFileHandler(FileHandlerMinimal):
- """
- File handler using python tempfile module to store file
- """
+ class CachedTempFilestore(object):
- def store_file(self, fs):
- fileno, filename = tempfile.mkstemp(suffix='%s-%s'%(uuid.uuid4().hex,fs.filename))
- fp = os.fdopen(fileno, 'wb')
- fp.write(fs.value)
- fp.close()
- prefix = tempfile.gettempprefix()
- tempdir = tempfile.gettempdir()
- filename = ''.join( filename[(len(tempdir)+len(prefix)+1):] )
- return filename
+ def __init__(self, root_dir=None, name=None):
+ if root_dir is None:
+ self._root_dir = tempfile.gettempdir()
+ else:
+ self._root_dir = root_dir
+ if name is None:
+ self.name = ''
+ else:
+ self.name = name
+
+ def get(self, key, cache_tag=None):
+ headers, f = FileSystemHeaderedFilestore.get(self, key)
+ headers = dict(headers)
+ if cache_tag and headers.get('Cache-Tag') == cache_tag:
+ f.close()
+ return (cache_tag, None, None)
+ return (headers.get('Cache-Tag'), headers.get('Content-Type'), f)
+
+ def put(self, key, src, cache_tag, content_type, headers=None):
+ if headers is None:
+ headers = {}
+ else:
+ headers = dict(headers)
+ if cache_tag:
+ headers['Cache-Tag'] = cache_tag
+ if content_type:
+ headers['Content-Type'] = content_type
+ FileSystemHeaderedFilestore.put(self, key, headers, src)
- def get_path_for_file(self, filename):
- prefix = tempfile.gettempprefix()
- tempdir = tempfile.gettempdir()
- return '%s/%s%s'%(tempdir,prefix,filename)
-.. note:: We also implement a ``get_mimetype`` method that helps in building the schemaish.type.File
-We typically want to access the file again from our widget however (especially in the case of image uploads!). Formish extends the TempFileHandler with a get_url_for_file method as follows..
+We typically want to access the file again from our widget however (especially in the case of image uploads!). A fileresource is available within formish that should return an appropriate image. The fileresource needs to be able to serve images from either the main image store (database? filesystem?) or from the temporary store if the form is in the middle of being processed (i.e. after a submission that fails through validation and needs to be redisplayed).
.. code-block:: python
- class TempFileHandlerWeb(TempFileHandler):
- def __init__(self, default_url=None,
- resource_root='/filehandler',urlfactory=None):
- self.default_url = default_url
- self.resource_root = resource_root
- self.urlfactory = urlfactory
+ class FileResource(resource.Resource):
+ """ A simple file serving utility """
- def get_url_for_file(self, object):
- if self.urlfactory is not None:
- return self.urlfactory(object)
- if id is None:
- return self.default_url.replace(' ','+')
- else:
- return '%s/%s'%(self.resource_root,object)
+ def __init__(self, filestores=None, filestore=None, segments=None, cache=None):
+ pass
-This needs configuring with a resource root (where to find files), a default_url (if we have no file, what to use - useful to showing missing images) and a urlfactory (how to convert a object into a url representation).
+ @resource.child(resource.any)
+ def child(self, request, segments):
+ return FileResource(filestores=self.filestores, segments=segments, cache=self.cache), []
+ def __call__(self, request):
+ """ Find the appropriate image to return including cacheing and resizing """
+
+
+ def get_file(self, request, filestore, filename, etag):
+ """ get the file through the cache and possibly resizing """
+
So what happens when a file is uploaded?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-If we're using the TempFileHandlerWeb handler the following steps take place.
+If we're using the CachedTempFilestore the following steps take place.
.. note:: we'll presume that the first form submit has a missing field and so the form gets redisplayed.
-The first time a file is uploaded, formish takes the FieldStorage object and copies the contents of the file to a tempfile using it's ``store_file`` method.
+The first time a file is uploaded, formish takes the FieldStorage object and copies the contents of the file to a tempfile using it's ``put`` method. It will generate a cachetag using uuid.uuid4().hex (the cache tag is used as an ETAG for cacheing purposes).
-When the form page is redisplayed, the widget uses the handlers ``get_url_for_file``` method to work out a url for the file. The file can then be displayed.
+When the form page is redisplayed, the widget uses its ``urlfactory``` method to work out a url for the file. The urlfactory either uses the ``url_ident_factory`` attribute (which can be supplied when a FileUpload widget is created) or, if there is a temporary file currently used, it uses its own internal method. This means you can customise the urlfactory for your own storage but temporary filestorage during widget use is handled separately.
.. note:: We're not covering how the file is actually displayed. This is framework specific but we'll give an example for restish after this section.
-When the users completes the corrections to the form and resubmits, formish processes the file. It first checks to see if the file is new (the widget stores a reference to the old file so it can check) and if it isn't new, it returns a schema.type.File object with None for all of the attributes.
+When the users completes the corrections to the form and resubmits, formish processes the file. It first checks to see if the a new file has been uploaded (the widget stores a reference to the old file so it can check) and if it isn't new, it returns a schema.type.File object with None for all of the attributes (i.e. an empty Schema.type.File object indicates an unchanged file.
If there is no file (i.e. no file was submitted on a clean form or a file was removed using the checkbox) then a None is returned.
If the file is new or has changed, formish generates the schemaish.type.File object from the data stored in the temporary file.
+There is a default urlfactory on the FileUpload widget
+
+What happens if I want to use my own tempfile storage and main storage?
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The first thing you would look at doing is writing your own Filestore. You can use the CachedTempFilestore as a model but you will replace the FileSystemHeaderedFilestore with your own class. The FileSystemHeaderedFilestore looks as follows.
+
+.. code-block:: python
+
+ class FileSystemHeaderedFilestore(object):
+ """
+ A general purpose readable and writable file store useful for storing data
+ along with additional metadata (simple key-value pairs).
+
+ This can be used to implement temporary file stores, local caches, etc.
+ XXX file ownership?
+ """
+
+ def __init__(self, root_dir):
+ self._root_dir = root_dir
+
+ def get(self, key):
+ try:
+ f = open(os.path.join(self._root_dir, safefilename.encode(key)), 'rb')
+ except IOError, AttributeError:
+ raise KeyError(key)
+ headers = []
+ while True:
+ line = f.readline().strip()
+ if not line:
+ break
+ name, value = line.split(': ', 1)
+ headers.append((name, value.decode('utf-8')))
+ return headers, f
+
+ def put(self, key, headers, src):
+ # XXX We should only allow strings as headers keys and values.
+ dest = file(os.path.join(self._root_dir, safefilename.encode(key)), 'wb')
+ try:
+ if isinstance(headers, dict):
+ headers = headers.items()
+ for name, value in headers:
+ if isinstance(value, unicode):
+ value = value.encode('utf-8')
+ dest.write('%s: %s\n' % (name, value))
+ dest.write('\n')
+ _copyfile.copyfileobj(src, dest)
+ finally:
+ dest.close()
+
+ def delete(self, key, glob=False):
+ # if glob is true will delete all with filename prefix
+ if glob == True:
+ for f in os.listdir(self._root_dir):
+ if f.startswith(safefilename.encode(key)):
+ os.remove(os.path.join(self._root_dir,f))
+ else:
+ os.remove( os.path.join(self._root_dir, safefilename.encode(key)))
+
+The get method simply returns a file and some headers based on a key. The only heads that the system is interested in are 'Cache-Tag' and 'Content-Type'. Cache-Tag is just a unique id which will be used to work out if a file has changed or not. Content-Type is fairly obvious (i.e. 'image/jpeg' or 'text/html').
+
+The put method supplies a key, some headers (as above) and src, which is an open filehandle. We've added a delete method too which isn't used within formish at the moment but may be in the future.
+
+Once you have implemented this store, you can replicate the code in CachedTempFilestore but with your own instantiation of your store in place of the tempfile instantiation.
+
What else can I configure?
^^^^^^^^^^^^^^^^^^^^^^^^^^
View
367 docs/html/formish.forms.html
@@ -38,9 +38,6 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
- <li class="right" >
- <a href="modindex.html" title="Global Module Index"
- accesskey="M">modules</a> |</li>
<li><a href="index.html">Formish v1 documentation</a> &raquo;</li>
</ul>
</div>
@@ -56,365 +53,8 @@
<div class="bodywrapper">
<div class="body">
- <div class="section" id="module-formish.forms">
-<h1>formish.forms<a class="headerlink" href="#module-formish.forms" title="Permalink to this headline">¶</a></h1>
-<p>The form module contains the main form, field, group and sequence classes</p>
-<dl class="class">
-<dt id="formish.forms.Form">
-<em class="property">
-class </em><tt class="descclassname">formish.forms.</tt><tt class="descname">Form</tt><big>(</big><em>structure</em>, <em>name=None</em>, <em>defaults=None</em>, <em>errors=None</em>, <em>action_url=None</em>, <em>renderer=None</em>, <em>method='POST'</em><big>)</big><a class="headerlink" href="#formish.forms.Form" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="(in Python v2.7)" class="reference external" href="http://docs.python.org/dev/library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a></p>
-<p>The definition of a form</p>
-<p>The Form type is the container for all the information a form needs to
-render and validate data.</p>
-<p>Create a new form instance</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>structure</em> (schemaish.Structure) &#8211; Schema Structure attribute to bind to the the form</li>
-<li><em>name</em> (str &#8220;valid html id&#8221;) &#8211; Optional form name used to identify multiple forms on the same page</li>
-<li><em>defaults</em> (dict) &#8211; Default values for the form</li>
-<li><em>errors</em> (dict) &#8211; Errors to store on the form for redisplay</li>
-<li><em>action_url</em> (string &#8220;url or path&#8221;) &#8211; Use if you don&#8217;t want the form to post to itself</li>
-<li><em>renderer</em> (callable) &#8211; Something that returns a form serialization when called</li>
-<li><em>method</em> (string) &#8211; Option method, default POST</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.forms.Form.action">
-<tt class="descname">action</tt><big>(</big><em>request</em>, <em>*args</em><big>)</big><a class="headerlink" href="#formish.forms.Form.action" title="Permalink to this definition">¶</a></dt>
-<dd><p>Find and call the action callback for the action found in the request</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>request</em> (webob.Request) &#8211; request which is used to find the action and also passed through to
-the callback</li>
-<li><em>args</em> &#8211; list of arguments Pass through to the callback</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.actions">
-<tt class="descname">actions</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Form.actions" title="Permalink to this definition">¶</a></dt>
-<dd>Return just the actions part of the template</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.add_action">
-<tt class="descname">add_action</tt><big>(</big><em>callback</em>, <em>name='submit'</em>, <em>label=None</em><big>)</big><a class="headerlink" href="#formish.forms.Form.add_action" title="Permalink to this definition">¶</a></dt>
-<dd><p>Add an action callable to the form</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>callback</em> (callable) &#8211; A function to call if this action is triggered</li>
-<li><em>name</em> (string) &#8211; The identifier for this action</li>
-<li><em>label</em> (string) &#8211; Use this label instead of the form.name for the value of
-the action (for buttons, the value is used as the text on the button)</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Form.defaults">
-<tt class="descname">defaults</tt><a class="headerlink" href="#formish.forms.Form.defaults" title="Permalink to this definition">¶</a></dt>
-<dd>Get the raw default data</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Form.element_name">
-<tt class="descname">element_name</tt><a class="headerlink" href="#formish.forms.Form.element_name" title="Permalink to this definition">¶</a></dt>
-<dd>Set the element name</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Form.fields">
-<tt class="descname">fields</tt><a class="headerlink" href="#formish.forms.Form.fields" title="Permalink to this definition">¶</a></dt>
-<dd>Return a generator that yields all of the fields at the top level of
-the form (e.g. if a field is a subsection or sequence, it will be up to
-the application to iterate that field&#8217;s fields.</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.footer">
-<tt class="descname">footer</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Form.footer" title="Permalink to this definition">¶</a></dt>
-<dd>Return just the footer part of the template</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.get_field">
-<tt class="descname">get_field</tt><big>(</big><em>name</em><big>)</big><a class="headerlink" href="#formish.forms.Form.get_field" title="Permalink to this definition">¶</a></dt>
-<dd><p>Get a field by dotted field name</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameter:</th><td class="field-body"><em>name</em> &#8211; Dotted name e.g. names.0.firstname</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.get_item_data">
-<tt class="descname">get_item_data</tt><big>(</big><em>key</em>, <em>name</em>, <em>default=&lt;object object at 0x40205908&gt;</em><big>)</big><a class="headerlink" href="#formish.forms.Form.get_item_data" title="Permalink to this definition">¶</a></dt>
-<dd>Access item data associates with a field key and an attribute name
-(e.g. title, widget, description&#8217;)</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.get_item_data_values">
-<tt class="descname">get_item_data_values</tt><big>(</big><em>name=None</em><big>)</big><a class="headerlink" href="#formish.forms.Form.get_item_data_values" title="Permalink to this definition">¶</a></dt>
-<dd>get all of the item data values</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.get_unvalidated_data">
-<tt class="descname">get_unvalidated_data</tt><big>(</big><em>request_data</em>, <em>raise_exceptions=True</em><big>)</big><a class="headerlink" href="#formish.forms.Form.get_unvalidated_data" title="Permalink to this definition">¶</a></dt>
-<dd><p>Convert the request object into a nested dict in the correct structure
-of the schema but without applying the schema&#8217;s validation.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>request_data</em> &#8211; Webob style request data</li>
-<li><em>raise_exceptions</em> &#8211; Whether to raise exceptions or return errors</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.header">
-<tt class="descname">header</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Form.header" title="Permalink to this definition">¶</a></dt>
-<dd>Return just the header part of the template</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.metadata">
-<tt class="descname">metadata</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Form.metadata" title="Permalink to this definition">¶</a></dt>
-<dd>Return just the metada part of the template</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Form.name">
-<tt class="descname">name</tt><a class="headerlink" href="#formish.forms.Form.name" title="Permalink to this definition">¶</a></dt>
-<dd>Get the name of the form, default to <cite>formish</cite></dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Form.request_data">
-<tt class="descname">request_data</tt><a class="headerlink" href="#formish.forms.Form.request_data" title="Permalink to this definition">¶</a></dt>
-<dd>Retrieve previously set request_data or return the defaults in
-request_data format.</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.set_item_data">
-<tt class="descname">set_item_data</tt><big>(</big><em>key</em>, <em>name</em>, <em>value</em><big>)</big><a class="headerlink" href="#formish.forms.Form.set_item_data" title="Permalink to this definition">¶</a></dt>
-<dd>Allow the setting os certain attributes on item_data, a dictionary used
-to associates data with fields.</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Form.validate">
-<tt class="descname">validate</tt><big>(</big><em>request</em>, <em>failure_callable=None</em>, <em>success_callable=None</em><big>)</big><a class="headerlink" href="#formish.forms.Form.validate" title="Permalink to this definition">¶</a></dt>
-<dd><p>Validate the form data in the request.</p>
-<p>By default, this method returns either a dict of data or raises an
-exception if validation fails. However, if either success_callable or
-failure_callable are provided then the approriate callback will be
-called, and the callback&#8217;s result will be returned instead.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
-<li><em>request</em> (webob.Request) &#8211; the HTTP request</li>
-<li><em>failure_callable</em> &#8211; Optional callback to call on failure.</li>
-<li><em>success_callable</em> &#8211; Optional callback to call on success.</li>
-</ul>
-</td>
-</tr>
-<tr class="field"><th class="field-name">Returns:</th><td class="field-body"><p class="first">Python dict of converted and validated data.</p>
-</td>
-</tr>
-<tr class="field"><th class="field-name">Raises:</th><td class="field-body"><p class="first last">formish.FormError, raised on validation failure.</p>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.forms.Action">
-<em class="property">
-class </em><tt class="descclassname">formish.forms.</tt><tt class="descname">Action</tt><big>(</big><em>callback</em>, <em>name</em>, <em>label</em><big>)</big><a class="headerlink" href="#formish.forms.Action" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="(in Python v2.7)" class="reference external" href="http://docs.python.org/dev/library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a></p>
-<p>An action that that can added to a form.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>callback</em> &#8211; A callable with the signature (request, form, <a href="#id1"><span class="problematic" id="id2">*</span></a>args)</li>
-<li><em>name</em> &#8211; an valid html id used to lookup an action</li>
-<li><em>label</em> &#8211; The &#8216;value&#8217; of the submit button and hence the text that people see</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.forms.Field">
-<em class="property">
-class </em><tt class="descclassname">formish.forms.</tt><tt class="descname">Field</tt><big>(</big><em>name</em>, <em>attr</em>, <em>form</em><big>)</big><a class="headerlink" href="#formish.forms.Field" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="(in Python v2.7)" class="reference external" href="http://docs.python.org/dev/library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a></p>
-<p>A wrapper for a schema field type that includes form information.</p>
-<p>The Schema Type Atribute does not have any bindings to the form library, it can be
-used on it&#8217;s own. We bind the Schema Attribute to a Field in order to include form
-related information.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name" colspan="2">Method __call__:</th></tr>
-<tr><td>&nbsp;</td><td class="field-body"><p class="first">returns a serialisation for this field using the form&#8217;s renderer - read only</p>
-</td>
-</tr>
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>name</em> &#8211; Name for the field</li>
-<li><em>attr</em> (schemaish.attr.*) &#8211; Schema attr to bind to the field</li>
-<li><em>form</em> (formish.Form instance.) &#8211; The form the field belongs to.</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="attribute">
-<dt id="formish.forms.Field.classes">
-<tt class="descname">classes</tt><a class="headerlink" href="#formish.forms.Field.classes" title="Permalink to this definition">¶</a></dt>
-<dd>Works out a list of classes that should be applied to the field</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.cssname">
-<tt class="descname">cssname</tt><a class="headerlink" href="#formish.forms.Field.cssname" title="Permalink to this definition">¶</a></dt>
-<dd>cssname identifier for the field</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.defaults">
-<tt class="descname">defaults</tt><a class="headerlink" href="#formish.forms.Field.defaults" title="Permalink to this definition">¶</a></dt>
-<dd>Get the defaults from the form.</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.description">
-<tt class="descname">description</tt><a class="headerlink" href="#formish.forms.Field.description" title="Permalink to this definition">¶</a></dt>
-<dd>The Field schema&#8217;s description</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.error">
-<tt class="descname">error</tt><a class="headerlink" href="#formish.forms.Field.error" title="Permalink to this definition">¶</a></dt>
-<dd>Lazily get the error from the form.errors when needed</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.errors">
-<tt class="descname">errors</tt><a class="headerlink" href="#formish.forms.Field.errors" title="Permalink to this definition">¶</a></dt>
-<dd>Lazily get the error from the form.errors when needed</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Field.inputs">
-<tt class="descname">inputs</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Field.inputs" title="Permalink to this definition">¶</a></dt>
-<dd>returns the templated widget</dd></dl>
-
-<dl class="method">
-<dt id="formish.forms.Field.label">
-<tt class="descname">label</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Field.label" title="Permalink to this definition">¶</a></dt>
-<dd>returns the templated title</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.required">
-<tt class="descname">required</tt><a class="headerlink" href="#formish.forms.Field.required" title="Permalink to this definition">¶</a></dt>
-<dd>Does this field have a Not Empty validator of some sort</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.title">
-<tt class="descname">title</tt><a class="headerlink" href="#formish.forms.Field.title" title="Permalink to this definition">¶</a></dt>
-<dd>The Field schema&#8217;s title</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.value">
-<tt class="descname">value</tt><a class="headerlink" href="#formish.forms.Field.value" title="Permalink to this definition">¶</a></dt>
-<dd>Convert the request_data to a value object for the form or None.</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Field.widget">
-<tt class="descname">widget</tt><a class="headerlink" href="#formish.forms.Field.widget" title="Permalink to this definition">¶</a></dt>
-<dd>return the fields widget bound with extra params.</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.forms.Group">
-<em class="property">
-class </em><tt class="descclassname">formish.forms.</tt><tt class="descname">Group</tt><big>(</big><em>name</em>, <em>attr</em>, <em>form</em><big>)</big><a class="headerlink" href="#formish.forms.Group" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.forms.Collection</span></tt></p>
-<p>A group is a basic collection with a different template</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>name</em> &#8211; Name for the Collection</li>
-<li><em>attr</em> (schemaish.attr.*) &#8211; Schema attr to bind to the field</li>
-<li><em>form</em> (formish.Form instance.) &#8211; The form the field belongs to.</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.forms.Sequence">
-<em class="property">
-class </em><tt class="descclassname">formish.forms.</tt><tt class="descname">Sequence</tt><big>(</big><em>name</em>, <em>attr</em>, <em>form</em><big>)</big><a class="headerlink" href="#formish.forms.Sequence" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.forms.Collection</span></tt></p>
-<p>A sequence is a collection with a variable number of fields depending on request data, data or min/max values</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>name</em> &#8211; Name for the Collection</li>
-<li><em>attr</em> (schemaish.attr.*) &#8211; Schema attr to bind to the field</li>
-<li><em>form</em> (formish.Form instance.) &#8211; The form the field belongs to.</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.forms.Sequence.collection_fields">
-<tt class="descname">collection_fields</tt><big>(</big><big>)</big><a class="headerlink" href="#formish.forms.Sequence.collection_fields" title="Permalink to this definition">¶</a></dt>
-<dd>For sequences we check to see if the name is numeric. As names cannot be numeric normally, the first iteration loops
-on a fields values and spits out a</dd></dl>
-
-<dl class="attribute">
-<dt id="formish.forms.Sequence.template">
-<tt class="descname">template</tt><a class="headerlink" href="#formish.forms.Sequence.template" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-</dd></dl>
-
+ <div class="section" id="formish-forms">
+<h1>formish.forms<a class="headerlink" href="#formish-forms" title="Permalink to this headline">¶</a></h1>
</div>
@@ -443,9 +83,6 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
- <li class="right" >
- <a href="modindex.html" title="Global Module Index"
- accesskey="M">modules</a> |</li>
<li><a href="index.html">Formish v1 documentation</a> &raquo;</li>
</ul>
</div>
View
367 docs/html/formish.widgets.html
@@ -38,9 +38,6 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
- <li class="right" >
- <a href="modindex.html" title="Global Module Index"
- accesskey="M">modules</a> |</li>
<li><a href="index.html">Formish v1 documentation</a> &raquo;</li>
</ul>
</div>
@@ -56,365 +53,8 @@
<div class="bodywrapper">
<div class="body">
- <div class="section" id="module-formish.widgets">
-<h1>formish.widgets<a class="headerlink" href="#module-formish.widgets" title="Permalink to this headline">¶</a></h1>
-<p>Commonly needed form widgets.</p>
-<dl class="class">
-<dt id="formish.widgets.Input">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">Input</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.Input" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Basic input widget type, used for text input</p>
-<dl class="method">
-<dt id="formish.widgets.Input.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.Input.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Default to stripping whitespace</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.Password">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">Password</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.Password" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.Input" class="reference internal" href="#formish.widgets.Input"><tt class="xref docutils literal"><span class="pre">formish.widgets.Input</span></tt></a></p>
-<p>Password widget is a basic input type but using password html input type</p>
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.CheckedPassword">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">CheckedPassword</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckedPassword" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.Input" class="reference internal" href="#formish.widgets.Input"><tt class="xref docutils literal"><span class="pre">formish.widgets.Input</span></tt></a></p>
-<p>Checked Password ensures that the password has been entered twice</p>
-<dl class="method">
-<dt id="formish.widgets.CheckedPassword.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckedPassword.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Check the password and confirm match (when stripped)</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.CheckedPassword.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckedPassword.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>Extract both the password and confirm fields</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.Hidden">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">Hidden</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.Hidden" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.Input" class="reference internal" href="#formish.widgets.Input"><tt class="xref docutils literal"><span class="pre">formish.widgets.Input</span></tt></a></p>
-<p>Basic input but using a hidden html input field</p>
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.TextArea">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">TextArea</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.TextArea" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.Input" class="reference internal" href="#formish.widgets.Input"><tt class="xref docutils literal"><span class="pre">formish.widgets.Input</span></tt></a></p>
-<p>Textarea input field</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>cols</em> &#8211; set the cols attr on the textarea element</li>
-<li><em>rows</em> &#8211; set the cols attr on the textarea element</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.widgets.TextArea.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.TextArea.convert" title="Permalink to this definition">¶</a></dt>
-<dd>We&#8217;re using the converter options to allow processing sequence data
-using the csv module</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.TextArea.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.TextArea.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>We&#8217;re using the converter options to allow processing sequence data
-using the csv module</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.Checkbox">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">Checkbox</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.Checkbox" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Checkbox widget, defaults to True or False</p>
-<dl class="method">
-<dt id="formish.widgets.Checkbox.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.Checkbox.convert" title="Permalink to this definition">¶</a></dt>
-<dd>If the request data exists, then we treat this as True</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.DateParts">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">DateParts</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.DateParts" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Simple three part date entry form</p>
-<dl class="method">
-<dt id="formish.widgets.DateParts.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.DateParts.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Pull out the parts and convert</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.DateParts.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.DateParts.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>Convert to date parts</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.FileUpload">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">FileUpload</tt><big>(</big><em>filestore</em>, <em>show_file_preview=True</em>, <em>show_download_link=False</em>, <em>show_image_thumbnail=False</em>, <em>url_base=None</em>, <em>css_class=None</em>, <em>image_thumbnail_default=None</em>, <em>url_ident_factory=None</em><big>)</big><a class="headerlink" href="#formish.widgets.FileUpload" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>File upload widget.</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>filestore</em> &#8211; <p>filestore is any object with the following methods:</p>
-<dl class="docutils">
-<dt>storeFile(self, f)</dt>
-<dd>where f is a file instance</dd>
-</dl>
-</li>
-<li><em>show_image_thumbnail</em> &#8211; a boolean that, if set, will include an image
-thumbnail with the widget</li>
-<li><em>css_class</em> &#8211; extra css classes to apply to the widget</li>
-<li><em>image_thumbnail_default</em> &#8211; a default url to</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<p>XXX image_thumbnail_default -&gt; default_image
-XXX allow_clear -&gt; allow_delete
-XXX url_ident_factory -&gt; filestore_key_factory</p>
-<dl class="method">
-<dt id="formish.widgets.FileUpload.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.FileUpload.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Creates a File object if possible</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.FileUpload.pre_parse_request">
-<tt class="descname">pre_parse_request</tt><big>(</big><em>schema_type</em>, <em>data</em>, <em>full_request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.FileUpload.pre_parse_request" title="Permalink to this definition">¶</a></dt>
-<dd>File uploads are wierd; in out case this means assymetric. We store the
-file in a temporary location and just store an identifier in the field.
-This at least makes the file look symmetric.</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.FileUpload.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.FileUpload.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>We use the url factory to get an identifier for the file which we use
-as the name. We also store it in the &#8216;default&#8217; field so we can check if
-something has been uploaded (the identifier doesn&#8217;t match the name)</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.FileUpload.urlfactory">
-<tt class="descname">urlfactory</tt><big>(</big><em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.FileUpload.urlfactory" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.SelectChoice">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">SelectChoice</tt><big>(</big><em>options</em>, <em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectChoice" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Html Select element</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>options</em> &#8211; either a list of values <tt class="docutils literal"><span class="pre">[value,]</span></tt> where value is used for the label or a list of tuples of the form <tt class="docutils literal"><span class="pre">[(value,</span> <span class="pre">label),]</span></tt></li>
-<li><em>none_option</em> &#8211; a tuple of <tt class="docutils literal"><span class="pre">(value,</span> <span class="pre">label)</span></tt> to use as the unselected option</li>
-<li><em>css_class</em> &#8211; a css class to apply to the field</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.widgets.SelectChoice.get_none_option_value">
-<tt class="descname">get_none_option_value</tt><big>(</big><em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectChoice.get_none_option_value" title="Permalink to this definition">¶</a></dt>
-<dd>Get the default option (the &#8216;unselected&#8217; option)</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.SelectChoice.get_options">
-<tt class="descname">get_options</tt><big>(</big><em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectChoice.get_options" title="Permalink to this definition">¶</a></dt>
-<dd>Return all of the options for the widget</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.SelectChoice.selected">
-<tt class="descname">selected</tt><big>(</big><em>option</em>, <em>value</em>, <em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectChoice.selected" title="Permalink to this definition">¶</a></dt>
-<dd>Check the value passed matches the actual value</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.SelectWithOtherChoice">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">SelectWithOtherChoice</tt><big>(</big><em>options</em>, <em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectWithOtherChoice" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.SelectChoice" class="reference internal" href="#formish.widgets.SelectChoice"><tt class="xref docutils literal"><span class="pre">formish.widgets.SelectChoice</span></tt></a></p>
-<p>Html Select element</p>
-<dl class="method">
-<dt id="formish.widgets.SelectWithOtherChoice.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectWithOtherChoice.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Check to see if we need to use the &#8216;other&#8217; value</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.SelectWithOtherChoice.get_other_option">
-<tt class="descname">get_other_option</tt><big>(</big><em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectWithOtherChoice.get_other_option" title="Permalink to this definition">¶</a></dt>
-<dd>Get the other option</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.SelectWithOtherChoice.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectWithOtherChoice.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>populate the other choice if needed</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.SelectWithOtherChoice.selected">
-<tt class="descname">selected</tt><big>(</big><em>option</em>, <em>value</em>, <em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.SelectWithOtherChoice.selected" title="Permalink to this definition">¶</a></dt>
-<dd>Check the value passed matches the actual value</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.RadioChoice">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">RadioChoice</tt><big>(</big><em>options</em>, <em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.RadioChoice" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.SelectChoice" class="reference internal" href="#formish.widgets.SelectChoice"><tt class="xref docutils literal"><span class="pre">formish.widgets.SelectChoice</span></tt></a></p>
-<p>Radio choice html element</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>options</em> &#8211; either a list of values <tt class="docutils literal"><span class="pre">[value,]</span></tt> where value is used for the label or a list of tuples of the form <tt class="docutils literal"><span class="pre">[(value,</span> <span class="pre">label),]</span></tt></li>
-<li><em>none_option</em> &#8211; a tuple of <tt class="docutils literal"><span class="pre">(value,</span> <span class="pre">label)</span></tt> to use as the unselected option</li>
-<li><em>css_class</em> &#8211; a css class to apply to the field</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.widgets.RadioChoice.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.RadioChoice.convert" title="Permalink to this definition">¶</a></dt>
-<dd>If we don&#8217;t have a choice, set a blank value</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.RadioChoice.get_none_option_value">
-<tt class="descname">get_none_option_value</tt><big>(</big><em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.RadioChoice.get_none_option_value" title="Permalink to this definition">¶</a></dt>
-<dd>Get the default option (the &#8216;unselected&#8217; option)</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.RadioChoice.selected">
-<tt class="descname">selected</tt><big>(</big><em>option</em>, <em>value</em>, <em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.RadioChoice.selected" title="Permalink to this definition">¶</a></dt>
-<dd>Check if the currently rendering input is the same as the value</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.CheckboxMultiChoice">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">CheckboxMultiChoice</tt><big>(</big><em>options</em>, <em>css_class=None</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoice" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Checkbox multi choice is a set of checkboxes that for a sequence of data</p>
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoice.checked">
-<tt class="descname">checked</tt><big>(</big><em>option</em>, <em>values</em>, <em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoice.checked" title="Permalink to this definition">¶</a></dt>
-<dd>For each value, convert it and check to see if it matches the input data</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoice.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoice.convert" title="Permalink to this definition">¶</a></dt>
-<dd>Iterating to convert back to the source data</dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoice.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoice.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>Iterate over the data, converting each one</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.SequenceDefault">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">SequenceDefault</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.SequenceDefault" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>Sequence handling widget - used by default for schema sequences</p>
-<table class="docutils field-list" frame="void" rules="none">
-<col class="field-name" />
-<col class="field-body" />
-<tbody valign="top">
-<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><em>min</em> &#8211; minimum number of sequence items to show</li>
-<li><em>max</em> &#8211; maximum number of sequence items to show</li>
-<li><em>addremove</em> &#8211; boolean whether to show the addremove buttons (jquery
-activated)</li>
-</ul>
-</td>
-</tr>
-</tbody>
-</table>
-<dl class="method">
-<dt id="formish.widgets.SequenceDefault.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.SequenceDefault.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd>Short circuits the usual pre_render</dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.CheckboxMultiChoiceTree">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">CheckboxMultiChoiceTree</tt><big>(</big><em>options</em>, <em>cssClass=None</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoiceTree" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <tt class="xref docutils literal"><span class="pre">formish.widgets.Widget</span></tt></p>
-<p>A more complicated checkbox select that</p>
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoiceTree.checked">
-<tt class="descname">checked</tt><big>(</big><em>option</em>, <em>values</em>, <em>schema_type</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoiceTree.checked" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoiceTree.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoiceTree.convert" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.CheckboxMultiChoiceTree.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.CheckboxMultiChoiceTree.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-</dd></dl>
-
-<dl class="class">
-<dt id="formish.widgets.Grid">
-<em class="property">
-class </em><tt class="descclassname">formish.widgets.</tt><tt class="descname">Grid</tt><big>(</big><em>**k</em><big>)</big><a class="headerlink" href="#formish.widgets.Grid" title="Permalink to this definition">¶</a></dt>
-<dd><p>Bases: <a title="formish.widgets.Input" class="reference internal" href="#formish.widgets.Input"><tt class="xref docutils literal"><span class="pre">formish.widgets.Input</span></tt></a></p>
-<p>Grid input field</p>
-<dl class="method">
-<dt id="formish.widgets.Grid.convert">
-<tt class="descname">convert</tt><big>(</big><em>schema_type</em>, <em>request_data</em><big>)</big><a class="headerlink" href="#formish.widgets.Grid.convert" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-<dl class="method">
-<dt id="formish.widgets.Grid.pre_render">
-<tt class="descname">pre_render</tt><big>(</big><em>schema_type</em>, <em>data</em><big>)</big><a class="headerlink" href="#formish.widgets.Grid.pre_render" title="Permalink to this definition">¶</a></dt>
-<dd></dd></dl>
-
-</dd></dl>
-
+ <div class="section" id="formish-widgets">
+<h1>formish.widgets<a class="headerlink" href="#formish-widgets" title="Permalink to this headline">¶</a></h1>
</div>
@@ -443,9 +83,6 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
- <li class="right" >
- <a href="modindex.html" title="Global Module Index"
- accesskey="M">modules</a> |</li>
<li><a href="index.html">Formish v1 documentation</a> &raquo;</li>
</ul>
</div>
View
223 docs/html/genindex.html
@@ -38,9 +38,6 @@
<li class="right" style="margin-right: 10px">
<a href="" title="General Index"
accesskey="I">index</a></li>
- <li class="right" >
- <a href="modindex.html" title="Global Module Index"
- accesskey="M">modules</a> |</li>
<li><a href="index.html">Formish v1 documentation</a> &raquo;</li>
</ul>
</div>
@@ -59,226 +56,11 @@
<h1 id="index">Index</h1>
- <a href="#_"><strong>_</strong></a> | <a href="#A"><strong>A</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#D"><strong>D</strong></a> | <a href="#E"><strong>E</strong></a> | <a href="#F"><strong>F</strong></a> | <a href="#G"><strong>G</strong></a> | <a href="#H"><strong>H</strong></a> | <a href="#I"><strong>I</strong></a> | <a href="#L"><strong>L</strong></a> | <a href="#M"><strong>M</strong></a> | <a href="#N"><strong>N</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> | <a href="#T"><strong>T</strong></a> | <a href="#U"><strong>U</strong></a> | <a href="#V"><strong>V</strong></a> | <a href="#W"><strong>W</strong></a>
+
<hr />
-<h2 id="_">_</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="walkthrough.html#formish.forms.Field.__call__">__call__() (formish.forms.Field method)</a></dt>
- <dd><dl>
- <dt><a href="walkthrough.html#formish.forms.Form.__call__">(formish.forms.Form method)</a></dt>
- </dl></dd></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="walkthrough.html#formish.widgets.FileUpload.__init__">__init__() (formish.widgets.FileUpload method)</a></dt>
-</dl></td></tr></table>
-
-<h2 id="A">A</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Action">Action (class in formish.forms)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.action">action() (formish.forms.Form method)</a>, <a href="walkthrough.html#formish.forms.Form.action">[1]</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.actions">actions() (formish.forms.Form method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Form.add_action">add_action() (formish.forms.Form method)</a>, <a href="walkthrough.html#formish.forms.Form.add_action">[1]</a></dt>
-</dl></td></tr></table>
-
-<h2 id="C">C</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.Checkbox">Checkbox (class in formish.widgets)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoice">CheckboxMultiChoice (class in formish.widgets)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoiceTree">CheckboxMultiChoiceTree (class in formish.widgets)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoice.checked">checked() (formish.widgets.CheckboxMultiChoice method)</a></dt>
- <dd><dl>
- <dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoiceTree.checked">(formish.widgets.CheckboxMultiChoiceTree method)</a></dt>
- </dl></dd>
-<dt><a href="formish.widgets.html#formish.widgets.CheckedPassword">CheckedPassword (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Field.classes">classes (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.classes">[1]</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Sequence.collection_fields">collection_fields() (formish.forms.Sequence method)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.Checkbox.convert">convert() (formish.widgets.Checkbox method)</a></dt>
- <dd><dl>
- <dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoice.convert">(formish.widgets.CheckboxMultiChoice method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoiceTree.convert">(formish.widgets.CheckboxMultiChoiceTree method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.CheckedPassword.convert">(formish.widgets.CheckedPassword method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.DateParts.convert">(formish.widgets.DateParts method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.FileUpload.convert">(formish.widgets.FileUpload method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.Grid.convert">(formish.widgets.Grid method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.Input.convert">(formish.widgets.Input method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.RadioChoice.convert">(formish.widgets.RadioChoice method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.SelectWithOtherChoice.convert">(formish.widgets.SelectWithOtherChoice method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.TextArea.convert">(formish.widgets.TextArea method)</a></dt>
- </dl></dd></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Field.cssname">cssname (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.cssname">[1]</a></dt>
-</dl></td></tr></table>
-
-<h2 id="D">D</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.DateParts">DateParts (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Field.defaults">defaults (formish.forms.Field attribute)</a></dt>
- <dd><dl>
- <dt><a href="formish.forms.html#formish.forms.Form.defaults">(formish.forms.Form attribute)</a></dt>
- </dl></dd></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Field.description">description (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.description">[1]</a></dt>
-</dl></td></tr></table>
-
-<h2 id="E">E</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.element_name">element_name (formish.forms.Form attribute)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Field.error">error (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.error">[1]</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Field.errors">errors (formish.forms.Field attribute)</a></dt>
-</dl></td></tr></table>
-
-<h2 id="F">F</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Field">Field (class in formish.forms)</a>, <a href="walkthrough.html#formish.forms.Field">[1]</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.fields">fields (formish.forms.Form attribute)</a>, <a href="walkthrough.html#formish.forms.Form.fields">[1]</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.FileUpload">FileUpload (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.footer">footer() (formish.forms.Form method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Form">Form (class in formish.forms)</a>, <a href="walkthrough.html#formish.forms.Form">[1]</a></dt>
-<dt><a href="formish.forms.html#module-formish.forms">formish.forms (module)</a></dt>
-<dt><a href="formish.widgets.html#module-formish.widgets">formish.widgets (module)</a></dt>
-</dl></td></tr></table>
-
-<h2 id="G">G</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.get_field">get_field() (formish.forms.Form method)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.get_item_data">get_item_data() (formish.forms.Form method)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.get_item_data_values">get_item_data_values() (formish.forms.Form method)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.RadioChoice.get_none_option_value">get_none_option_value() (formish.widgets.RadioChoice method)</a></dt>
- <dd><dl>
- <dt><a href="formish.widgets.html#formish.widgets.SelectChoice.get_none_option_value">(formish.widgets.SelectChoice method)</a></dt>
- </dl></dd>
-<dt><a href="formish.widgets.html#formish.widgets.SelectChoice.get_options">get_options() (formish.widgets.SelectChoice method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.widgets.html#formish.widgets.SelectWithOtherChoice.get_other_option">get_other_option() (formish.widgets.SelectWithOtherChoice method)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.get_unvalidated_data">get_unvalidated_data() (formish.forms.Form method)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.Grid">Grid (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Group">Group (class in formish.forms)</a></dt>
-</dl></td></tr></table>
-
-<h2 id="H">H</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.header">header() (formish.forms.Form method)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.Hidden">Hidden (class in formish.widgets)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="I">I</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.Input">Input (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Field.inputs">inputs() (formish.forms.Field method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="L">L</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Field.label">label() (formish.forms.Field method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="M">M</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.metadata">metadata() (formish.forms.Form method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="N">N</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.name">name (formish.forms.Form attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="P">P</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.Password">Password (class in formish.widgets)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.FileUpload.pre_parse_request">pre_parse_request() (formish.widgets.FileUpload method)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoice.pre_render">pre_render() (formish.widgets.CheckboxMultiChoice method)</a></dt>
- <dd><dl>
- <dt><a href="formish.widgets.html#formish.widgets.CheckboxMultiChoiceTree.pre_render">(formish.widgets.CheckboxMultiChoiceTree method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.CheckedPassword.pre_render">(formish.widgets.CheckedPassword method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.DateParts.pre_render">(formish.widgets.DateParts method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.FileUpload.pre_render">(formish.widgets.FileUpload method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.Grid.pre_render">(formish.widgets.Grid method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.SelectWithOtherChoice.pre_render">(formish.widgets.SelectWithOtherChoice method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.SequenceDefault.pre_render">(formish.widgets.SequenceDefault method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.TextArea.pre_render">(formish.widgets.TextArea method)</a></dt>
- </dl></dd></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="R">R</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.RadioChoice">RadioChoice (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.request_data">request_data (formish.forms.Form attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Field.required">required (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.required">[1]</a></dt>
-</dl></td></tr></table>
-
-<h2 id="S">S</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.SelectChoice">SelectChoice (class in formish.widgets)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.RadioChoice.selected">selected() (formish.widgets.RadioChoice method)</a></dt>
- <dd><dl>
- <dt><a href="formish.widgets.html#formish.widgets.SelectChoice.selected">(formish.widgets.SelectChoice method)</a></dt>
- <dt><a href="formish.widgets.html#formish.widgets.SelectWithOtherChoice.selected">(formish.widgets.SelectWithOtherChoice method)</a></dt>
- </dl></dd>
-<dt><a href="formish.widgets.html#formish.widgets.SelectWithOtherChoice">SelectWithOtherChoice (class in formish.widgets)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Sequence">Sequence (class in formish.forms)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.SequenceDefault">SequenceDefault (class in formish.widgets)</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Form.set_item_data">set_item_data() (formish.forms.Form method)</a></dt>
-</dl></td></tr></table>
-
-<h2 id="T">T</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Sequence.template">template (formish.forms.Sequence attribute)</a></dt>
-<dt><a href="formish.widgets.html#formish.widgets.TextArea">TextArea (class in formish.widgets)</a></dt></dl></td><td width="33%" valign="top"><dl>
-<dt><a href="formish.forms.html#formish.forms.Field.title">title (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.title">[1]</a></dt>
-</dl></td></tr></table>
-
-<h2 id="U">U</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.widgets.html#formish.widgets.FileUpload.urlfactory">urlfactory() (formish.widgets.FileUpload method)</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="V">V</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Form.validate">validate() (formish.forms.Form method)</a>, <a href="walkthrough.html#formish.forms.Form.validate">[1]</a></dt>
-<dt><a href="formish.forms.html#formish.forms.Field.value">value (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.value">[1]</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
-<h2 id="W">W</h2>
-<table width="100%" class="indextable"><tr><td width="33%" valign="top">
-<dl>
-
-<dt><a href="formish.forms.html#formish.forms.Field.widget">widget (formish.forms.Field attribute)</a>, <a href="walkthrough.html#formish.forms.Field.widget">[1]</a></dt></dl></td><td width="33%" valign="top"><dl>
-</dl></td></tr></table>
-
</div>
@@ -305,9 +87,6 @@ <h2 id="W">W</h2>
<li class="right" style="margin-right: 10px">
<a href="" title="General Index"