[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