[Zope3-checkins]
SVN: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/
After a wrong start, the basic structure is now in place. Also added
Janko Hauser
jhauser at zscout.de
Sun Jan 16 17:36:49 EST 2005
Log message for revision 28851:
After a wrong start, the basic structure is now in place. Also added
a simple first widget, which deals with the handling of a FileUpload
instance.
Changed:
U Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/configure.zcml
U Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/mimefield.py
-=-
Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/configure.zcml
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/configure.zcml 2005-01-16 19:59:10 UTC (rev 28850)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/configure.zcml 2005-01-16 22:36:48 UTC (rev 28851)
@@ -95,7 +95,16 @@
permission="zope.ManageContent"
/>
+ <!-- define another widget for the mimefield -->
+ <view
+ type="zope.publisher.interfaces.browser.IBrowserRequest"
+ for=".mimefield.IFileData"
+ provides="zope.app.form.interfaces.IInputWidget"
+ factory=".mimefield.FileDataWidget"
+ permission="zope.Public"
+ />
+
<!-- include browser package -->
<include package=".browser" />
Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/mimefield.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/mimefield.py 2005-01-16 19:59:10 UTC (rev 28850)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/mimefield.py 2005-01-16 22:36:48 UTC (rev 28851)
@@ -27,6 +27,10 @@
from zope.schema._field import Bytes
from zope.app.file.file import File
+# import for the FileDataWidget
+from zope.app.form.browser import FileWidget
+from zope.app.form.browser.widget import renderElement
+
from zope.i18nmessageid import MessageIDFactory
_ = MessageIDFactory("zope")
@@ -57,111 +61,41 @@
description=_(u"The Filename of the uploaded file"),
required=False)
-# The field implementation
-class FileData(Bytes, File):
- """A field implementation for uploaded files.
+# The field implementation, does currently assume to handle file-like data
+class FileData(Bytes):
+ u"""A field implementation for uploaded files. """
- Let's test the constructor:
+ implements(IFileData)
- >>> file = FileData()
- >>> file.contentType
- ''
- >>> file.data
- ''
+ def set(self, obj, value):
+ """
+ Do a two phase save, first create an empty file object, make it persistent
+ than read the data into it in chunks, to reduce memory consumption.
- >>> file = FileData('Foobar')
- >>> file.contentType
- ''
- >>> file.data
- 'Foobar'
+ 'value' is a FileUpload object.
+ """
+ if self.readonly:
+ raise TypeError("Can't set values on read-only fields "
+ "(name=%s, class=%s.%s)"
+ % (self.__name__,
+ obj.__class__.__module__,
+ obj.__class__.__name__))
+ # now create an empty file object and store it at the persistent object
+ setattr(obj, self.__name__, FileDataValue())
+ file = getattr(obj, self.__name__)
+ # now do the upload in chunks
+ file.data = value
+ filename = self._extractFilename(value)
+ file.filename = filename
- >>> file = FileData('Foobar', 'text/plain')
- >>> file.contentType
- 'text/plain'
- >>> file.data
- 'Foobar'
+ def _validate(self, value):
+ # just test for the seek method of FileUpload instances.
+ if value and not getattr(value, 'seek',''):
+ raise WrongType(value, self._type)
- >>> file = FileData(data='Foobar', contentType='text/plain')
- >>> file.contentType
- 'text/plain'
- >>> file.data
- 'Foobar'
-
-
- Let's test the mutators:
-
- >>> file = FileData()
- >>> file.contentType = 'text/plain'
- >>> file.contentType
- 'text/plain'
-
- >>> file.data = 'Foobar'
- >>> file.data
- 'Foobar'
-
- >>> file.data = None
- Traceback (most recent call last):
- ...
- TypeError: Cannot set None data on a file.
-
-
- Let's test large data input:
-
- >>> file = FileData()
-
- Insert as string:
-
- >>> file.data = 'Foobar'*60000
- >>> file.getSize()
- 360000
- >>> file.data == 'Foobar'*60000
- True
-
- Insert data as FileChunk:
- >>> from zope.app.file.file import FileChunk
- >>> fc = FileChunk('Foobar'*4000)
- >>> file.data = fc
- >>> file.getSize()
- 24000
- >>> file.data == 'Foobar'*4000
- True
-
- Insert data from file object:
-
- >>> import cStringIO
- >>> sio = cStringIO.StringIO()
- >>> sio.write('Foobar'*100000)
- >>> sio.seek(0)
- >>> file.data = sio
- >>> file.getSize()
- 600000
- >>> file.data == 'Foobar'*100000
- True
-
- Test handling of filename
-
- >>> file.filename == ''
- True
-
- Last, but not least, verify the interface:
-
- >>> from zope.interface.verify import verifyClass
- >>> IFile.implementedBy(FileData)
- True
- >>> verifyClass(IFile, FileData)
- True
- """
-
- implements(IFileData, IFile)
-
- def _setdata(self, data):
- File._setdata(data)
- print 'setting data', type(data)
- self.filename = self._extractFilename(data)
- self.contentType = self._extractContentType(data)
-
def _extractContentType(self, data):
u"""Extract the content type for the given data"""
+ # XXX Need to call some function here
return 'application/octet-stream'
def _extractFilename(self, data):
@@ -177,3 +111,61 @@
else:
return ''
+class FileDataWidget(FileWidget):
+ u"""a simple file upload widget"""
+
+ type = 'file'
+
+ def __call__(self):
+ # XXX set the width to 40 to be sure to recognize this widget
+ displayMaxWidth = self.displayMaxWidth or 0
+ if displayMaxWidth > 0:
+ return renderElement(self.tag,
+ type=self.type,
+ name=self.name,
+ id=self.name,
+ cssClass=self.cssClass,
+ size=40,
+ maxlength=40,
+ extra=self.extra)
+ else:
+ return renderElement(self.tag,
+ type=self.type,
+ name=self.name,
+ id=self.name,
+ cssClass=self.cssClass,
+ size=40,
+ extra=self.extra)
+
+ def _toFieldValue(self, input):
+ if input == '':
+ return self.context.missing_value
+ try:
+ seek = input.seek
+ read = input.read
+ except AttributeError, e:
+ raise ConversionError('Form input is not a file object', e)
+ else:
+ if getattr(input, 'filename', ''):
+ return input
+ else:
+ return self.context.missing_value
+
+ def applyChanges(self, content):
+ field = self.context
+ value = self.getInputValue()
+ # need to test for value, as an empty field is not an error, but
+ # the current file should not be replaced.
+ if value and (field.query(content, self) != value):
+ field.set(content, value)
+ return True
+ else:
+ return False
+
+class FileDataValue(File):
+ u"""Inherit a normal file content object."""
+
+ def __init__(self, *args):
+ super(File, self).__init__(*args)
+ self.filename = ''
+
More information about the Zope3-Checkins
mailing list