[Checkins] SVN: z3c.form/trunk/src/z3c/form/ - Implemented support
for FileUpload in FileWidget
Roger Ineichen
roger at projekt01.ch
Thu May 31 19:16:01 EDT 2007
Log message for revision 76065:
- Implemented support for FileUpload in FileWidget
- Added helper for handling FileUpload. You can find this helpers in
z3c.form.util
Changed:
A z3c.form/trunk/src/z3c/form/CHANGES.txt
U z3c.form/trunk/src/z3c/form/TODO.txt
U z3c.form/trunk/src/z3c/form/browser/file.py
U z3c.form/trunk/src/z3c/form/browser/file.txt
U z3c.form/trunk/src/z3c/form/configure.zcml
U z3c.form/trunk/src/z3c/form/converter.py
U z3c.form/trunk/src/z3c/form/converter.txt
U z3c.form/trunk/src/z3c/form/util.py
-=-
Added: z3c.form/trunk/src/z3c/form/CHANGES.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/CHANGES.txt (rev 0)
+++ z3c.form/trunk/src/z3c/form/CHANGES.txt 2007-05-31 23:16:01 UTC (rev 76065)
@@ -0,0 +1,20 @@
+=======
+CHANGES
+=======
+
+- Added named vocabulary lookup in ChoiceTerms and CollectionTerms
+
+- Implemented support for FileUpload in FileWidget
+
+- Added helper for handling FileUpload. You can find this helpers in
+ z3c.form.util:
+
+ def extractContentType(form, id):
+ """Knows how to extract a filename if a IBytes/IFileWidget was used."""
+
+ def extractFileName(form, id, cleanup=True):
+ """Knows how to extract a filename if a IBytes/IFileWidget was used.
+
+ Uploads from win/IE need some cleanup because the filename includes also
+ the path. cleanUp=True will do this for you.
+ """
Modified: z3c.form/trunk/src/z3c/form/TODO.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/TODO.txt 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/TODO.txt 2007-05-31 23:16:01 UTC (rev 76065)
@@ -27,3 +27,6 @@
Notes from Roger
----------------
+
+- Define all widget attributes for the different widgets in the interfaces
+ as fields
Modified: z3c.form/trunk/src/z3c/form/browser/file.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/file.py 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/browser/file.py 2007-05-31 23:16:01 UTC (rev 76065)
@@ -28,6 +28,10 @@
"""Input type text widget implementation."""
zope.interface.implementsOnly(interfaces.IFileWidget)
+ # filename and headers attribute get set by IDataConverter to the widget
+ # providedy form the FileUpload
+ headers = None
+ filename = None
css = u'fileWidget'
@zope.component.adapter(zope.schema.interfaces.IBytes, interfaces.IFormLayer)
Modified: z3c.form/trunk/src/z3c/form/browser/file.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/file.txt 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/browser/file.txt 2007-05-31 23:16:01 UTC (rev 76065)
@@ -63,3 +63,33 @@
>>> widget.update()
>>> widget.extract()
<NOVALUE>
+
+Make also sure that we can handle FileUpload objects given form a file upload.
+
+ >>> import cStringIO
+ >>> from zope.publisher.browser import FileUpload
+
+Let's define a FieldStorage stub:
+
+ >>> class FieldStorageStub:
+ ... def __init__(self, file):
+ ... self.file = file
+ ... self.headers = {}
+ ... self.filename = 'foo.bar'
+
+Now build a FileUpload:
+
+ >>> myfile = cStringIO.StringIO('File upload contents.')
+ >>> aFieldStorage = FieldStorageStub(myfile)
+ >>> myUpload = FileUpload(aFieldStorage)
+
+ >>> widget.request = TestRequest(form={'widget.name': myUpload})
+ >>> widget.update()
+ >>> widget.extract()
+ <zope.publisher.browser.FileUpload object at ...>
+
+If we render them, we get a regular file upload widget:
+
+ >>> print widget.render()
+ <input type="file" id="widget.id" name="widget.name"
+ class="fileWidget" />
Modified: z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/configure.zcml 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/configure.zcml 2007-05-31 23:16:01 UTC (rev 76065)
@@ -46,6 +46,9 @@
factory=".converter.TimedeltaDataConverter"
/>
<adapter
+ factory=".converter.BytesDataConverter"
+ />
+ <adapter
factory=".converter.SequenceDataConverter"
/>
<adapter
Modified: z3c.form/trunk/src/z3c/form/converter.py
===================================================================
--- z3c.form/trunk/src/z3c/form/converter.py 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/converter.py 2007-05-31 23:16:01 UTC (rev 76065)
@@ -20,7 +20,9 @@
import zope.interface
import zope.component
import zope.schema
+import zope.publisher.browser
+from z3c.form.i18n import MessageFactory as _
from z3c.form import interfaces
@@ -104,6 +106,44 @@
return datetime.timedelta(days, sum(seconds))
+class BytesDataConverter(FieldDataConverter):
+ """A special data converter for bytes, supporting also FileUpload.
+
+ Since IBytes represents a file upload too, this converter can handle
+ zope.publisher.browser.FileUpload object as given value.
+ """
+ zope.component.adapts(
+ zope.schema.interfaces.IBytes, interfaces.IWidget)
+
+ def toFieldValue(self, value):
+ """See interfaces.IDataConverter"""
+ if value is None or value == '':
+ return self.context.missing_value
+
+ if isinstance(value, zope.publisher.browser.FileUpload):
+ # By default a IBytes field is used for get a file upload widget.
+ # But interfaces extending IBytes do not use file upload widgets.
+ # Any way if we get a FileUpload object, we'll convert it.
+ # We also store the additional FileUpload values on the widget
+ # before we loose them.
+ self.widget.headers = value.headers
+ self.widget.filename = value.filename
+ try:
+ seek = value.seek
+ read = value.read
+ except AttributeError, e:
+ raise ValueError(_('Bytes data is not a file object'), e)
+ else:
+ seek(0)
+ data = read()
+ if data or getattr(value, 'filename', ''):
+ return data
+ else:
+ return self.context.missing_value
+ else:
+ return unicode(value)
+
+
class SequenceDataConverter(FieldDataConverter):
"""Basic data converter for ISequenceWidget."""
Modified: z3c.form/trunk/src/z3c/form/converter.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/converter.txt 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/converter.txt 2007-05-31 23:16:01 UTC (rev 76065)
@@ -198,6 +198,48 @@
datetime.timedelta(1, 3661)
+Bytes Data Converter
+--------------------
+
+Since the ``Bytes`` field can contain a FileUpload object, we have to make
+sure we can convert FileUpload objects to bytes too.
+
+ >>> bytes = zope.schema.Bytes()
+
+ >>> bdc = converter.BytesDataConverter(bytes, text)
+ >>> bdc
+ <DataConverter from Bytes to Widget>
+
+Bytes are converted to unicode:
+
+ >>> simple = 'foobar'
+ >>> bdc.toFieldValue(simple)
+ u'foobar'
+
+The converter can also convert FileUpload objects. Setup a fields storage
+stub...
+
+ >>> class FieldStorageStub:
+ ... def __init__(self, file):
+ ... self.file = file
+ ... self.headers = {}
+ ... self.filename = 'foo.bar'
+
+build a FileUpload...
+
+ >>> import cStringIO
+ >>> from zope.publisher.browser import FileUpload
+ >>> myfile = cStringIO.StringIO('File upload contents.')
+ >>> aFieldStorage = FieldStorageStub(myfile)
+ >>> myUpload = FileUpload(aFieldStorage)
+
+and try to convert:
+
+ >>> bdc.toFieldValue(myUpload)
+ 'File upload contents.'
+
+
+
Sequence Data Converter
-----------------------
Modified: z3c.form/trunk/src/z3c/form/util.py
===================================================================
--- z3c.form/trunk/src/z3c/form/util.py 2007-05-31 21:09:58 UTC (rev 76064)
+++ z3c.form/trunk/src/z3c/form/util.py 2007-05-31 23:16:01 UTC (rev 76065)
@@ -19,6 +19,7 @@
import re
import types
import zope.interface
+import zope.contenttype
from z3c.form import interfaces
@@ -77,6 +78,34 @@
return form.widgets.get(shortName, None)
+def extractContentType(form, id):
+ """Knows how to extract a filename if a IBytes/IFileWidget was used."""
+ widget = getWidgetById(form, id)
+ return zope.contenttype.guess_content_type(widget.filename)[0]
+
+
+def extractFileName(form, id, cleanup=True):
+ """Knows how to extract a filename if a IBytes/IFileWidget was used.
+
+ Uploads from win/IE need some cleanup because the filename includes also
+ the path. cleanUp=True will do this for you.
+ """
+ widget = getWidgetById(form, id)
+ if cleanup:
+ # we try to use a better file name. Uploads from win/IE need some
+ # cleanup because the filename includes also the path.
+ path = widget.filename.split('.')
+ if len(path) > 1:
+ postfix = path.pop(-1)
+ # now remove the rest of the path
+ pathStr = path.pop(-1)
+ cleanFileName = pathStr.split('\\')[-1]
+ cleanFileName = cleanFileName.split('/')[-1]
+ filename = cleanFileName +'.'+ postfix
+ return filename
+ return widget.filename
+
+
class Manager(object):
"""Non-persistent IManager implementation."""
zope.interface.implements(interfaces.IManager)
More information about the Checkins
mailing list