[Zope3-checkins] SVN: Zope3/branches/jhauser-filefieldwidget/src/zope/ Prepare for implement proposal.

Roger Ineichen roger at projekt01.ch
Wed Jan 19 09:23:48 EST 2005


Log message for revision 28871:
  Prepare for implement proposal.
  I moved the file widget part to a own file for bigger changes like descriped
  in the proposal.
  o Added PROPOSAL.txt in zope.app.file
  o Move file based widget part form zope.app.form.browser.textwidgets
    to zope.app.form.browser.filewidgets
  o Fix imports from the moving described above
  o Inherit MimeWidget and FileWidget form SimpleInputWidget instead form TextWidget
    (will be changed later, see proposal) 
  o Remove old test_mimefield.py
  
  Next step:
  Prepare classes that we can start to implement the MimeWidget for IMime field as 
  a ObjectWidget like view. This IMime widget(view) uses the schema fields of 
  IMime for displaying the subwidget.

Changed:
  A   Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/PROPOSAL.txt
  U   Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/interfaces.py
  D   Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/tests/test_mimefield.py
  U   Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/__init__.py
  A   Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/filewidgets.py
  U   Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/ftests/test_filewidget.py
  U   Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/textwidgets.py
  U   Zope3/branches/jhauser-filefieldwidget/src/zope/schema/_field.py

-=-
Added: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/PROPOSAL.txt
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/PROPOSAL.txt	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/PROPOSAL.txt	2005-01-19 14:23:47 UTC (rev 28871)
@@ -0,0 +1,127 @@
+IFile refactoring
+
+  Status
+
+    IsProposal
+
+  Author
+
+    Roger Ineichen
+
+  Problem/Proposal
+
+    Constraints of field data in IFile does'nt fit. The interface field Bytes
+    ignores the possible FileChunk as value we get on bigger values.
+    
+    We allready added a branch called for the refactoring. The branch is
+    called jhauser-filefieldwidget.
+
+  Goals
+
+    - Fix constraints in data schema field (Bytes), we could have FileChunk 
+      objects as values.
+
+    - Handle fileupload via session. The widget should read the file upload 
+      information from the session.
+    
+    - Make Refresh method in edit form working. Now the value of the file 
+      upload field (input type=file) get lost on refresh.
+
+  Proposed Solution
+
+    Refactoring, extend and/or add different parts
+
+    IFile interface::
+      
+      class IFile(Interface):
+      
+          contents = Mime(
+              title = _(u'The mime data'),
+              description = _(u'The mime data, which can be read as a file.'),
+              default='',
+              missing_value='',
+              required=False,
+              )
+      
+          data = ... for backward compatibility
+      
+    IMime interface::
+      
+      class IMime(Interface):
+      
+          contentType = MimeType(
+              title = _(u'Content Type'),
+              description=_(u'The content type identifies the type of data.'),
+              default='',
+              required=False,
+              missing_value=''
+              )
+      
+          encoding = MimeDataEncoding(
+              title = _(u'Encoding type'),
+              description=_(u'The encoding of the data if it is text.'),
+              default='',
+              required=False,
+              missing_value=''
+              )
+      
+          data = MimeData(
+              title=_(u'Data'),
+              description=_(u'The actual content of the object.'),
+              default='',
+              missing_value='',
+              required=False,
+              )
+      
+    IFile/contents/Mime field - MimeInputWidget:
+    
+      The input widget is like a object widget which renders it's information 
+      from the schema IMime. The widget is used for the field contents in the 
+      interface IFile. It's more a view the a widget like to object widget 
+      implementation.
+      
+      This widget directly handles:
+      
+        - extract information about the fileupload to the session
+        
+      The subwidgets of the schema IMime are not simply widgets like
+      TextLine etc, they have to support session reading:
+
+    IMime/contentType/MimeType - MimeTypeWidget:
+      
+      - set the contentType (mime-type) via session formation
+      
+
+    IMime/encoding/MimeDataEncoding - MimeDataEncodingWidget:
+      
+      - set the encoding if given and type is a text format
+      
+    IMime/data/MimeData - MimeDataWidget:
+ 
+      - render input field of type=file
+    
+      - store fileupload to the field data
+    
+      - don't override data value if upload is empty
+    
+    IMime/data/MimeData - MimeDataWidget (IInputWidget):
+    
+      The widget is used in the IMime schema on the data field
+      The interface field is called MimeData
+    
+      - stores FileChunk or str to the value
+    
+    IMime/data/MimeData - MimeDataDisplayWidget (IDisplayWidget):
+    
+      We need different widgets for displaying files. The different usecases 
+      are:
+    
+        - render 'a href' links
+        
+        - render 'img' images tags
+
+        - render text content
+
+  Risks
+
+    Backward compatiblility


Property changes on: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/PROPOSAL.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/interfaces.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/interfaces.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/interfaces.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -51,8 +51,12 @@
         """Return the byte-size of the data of the object."""
 
     def open(mode='r'):
-        """Return a file like object for reading or updating."""
-    
+        """Return a file like object for reading or updating.
+        
+        Default is set to readonly, use mode='w' for write mode.
+        """
+
+
 class IFile(Interface):
 
     contents = Mime(

Deleted: Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/tests/test_mimefield.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/tests/test_mimefield.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/file/tests/test_mimefield.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -1,27 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Test file field implementation.
-
-$Id: $
-"""
-import unittest
-from zope.testing.doctestunit import DocTestSuite
-
-def test_suite():
-    return unittest.TestSuite((
-        DocTestSuite('zope.app.file.mimefield'),        
-        ))
-
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')

Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/__init__.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/__init__.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/__init__.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -21,15 +21,18 @@
 
 from zope.app.form.browser.textwidgets import TextWidget, BytesWidget
 from zope.app.form.browser.textwidgets import TextAreaWidget, BytesAreaWidget
-from zope.app.form.browser.textwidgets import PasswordWidget, FileWidget
+from zope.app.form.browser.textwidgets import PasswordWidget
 from zope.app.form.browser.textwidgets import ASCIIWidget
 from zope.app.form.browser.textwidgets import IntWidget, FloatWidget
 from zope.app.form.browser.textwidgets import DatetimeWidget, DateWidget
 from zope.app.form.browser.textwidgets import DatetimeDisplayWidget
 from zope.app.form.browser.textwidgets import DateDisplayWidget
 from zope.app.form.browser.textwidgets import BytesDisplayWidget
-from zope.app.form.browser.textwidgets import MimeDisplayWidget, MimeWidget
 
+# Widgets for file-based fields
+from zope.app.form.browser.filewidgets import FileWidget
+from zope.app.form.browser.filewidgets import MimeDisplayWidget, MimeWidget
+
 # Widgets for boolean fields
 from zope.app.form.browser.boolwidgets import CheckBoxWidget
 from zope.app.form.browser.boolwidgets import BooleanRadioWidget

Added: Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/filewidgets.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/filewidgets.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/filewidgets.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -0,0 +1,153 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Browser widgets with file-based input
+
+$Id:$
+"""
+__docformat__ = 'restructuredtext'
+
+
+from zope.interface import implements
+
+from zope.app.form.interfaces import IInputWidget, ConversionError
+from zope.app.form.browser.widget import SimpleInputWidget, renderElement
+from zope.app.form.browser.widget import DisplayWidget
+from zope.app.form.browser.textwidgets import escape
+
+
+
+class FileWidget(SimpleInputWidget):
+    """File Widget"""
+
+    type = 'file'
+
+    default = ''
+    displayWidth = 20
+    displayMaxWidth = ""
+    extra = ''
+    style = ''
+    convert_missing_value = True
+
+    def __call__(self):
+        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=self.displayWidth,
+                                 maxlength=displayMaxWidth,
+                                 extra=self.extra)
+        else:
+            return renderElement(self.tag,
+                                 type=self.type,
+                                 name=self.name,
+                                 id=self.name,
+                                 cssClass=self.cssClass,
+                                 size=self.displayWidth,
+                                 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:
+            seek(0)
+            data = read()
+            if data or getattr(input, 'filename', ''):
+                return data
+            else:
+                return self.context.missing_value
+
+
+class MimeWidget(SimpleInputWidget):
+    u"""Mime file upload widget"""
+
+    type = 'file'
+
+    default = ''
+    displayWidth = 20
+    displayMaxWidth = ""
+    extra = ''
+    style = ''
+    convert_missing_value = True
+
+    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 the FileUpload instance has no filename set, there is
+            # no upload.
+            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 MimeDisplayWidget(DisplayWidget):
+    """Mime data display widget."""
+    # There need to be probably some widget options to determine how
+    # the file is displayed, e.g. as a download link.
+
+    def __call__(self):
+        if self._renderedValueSet():
+            content = self._data
+        else:
+            content = self.context.default
+
+        show = u"Filename %s, size in bytes: %s" (content.filename,
+                                                  content.getSize())
+        return renderElement("span", contents=escape(show))


Property changes on: Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/filewidgets.py
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/ftests/test_filewidget.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/ftests/test_filewidget.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/ftests/test_filewidget.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -26,7 +26,7 @@
 from zope.schema.interfaces import IField
 from zope.schema import Field
 
-from zope.app.form.browser.textwidgets import FileWidget
+from zope.app.form.browser import FileWidget
 
 from support import *
 from zope.app.traversing.api import traverse

Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/textwidgets.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/textwidgets.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/app/form/browser/textwidgets.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -187,6 +187,7 @@
     'Bob'
     """
 
+
 class BytesDisplayWidget(DisplayWidget):
     """Bytes display widget"""
 
@@ -334,6 +335,7 @@
                              contents=self._getFormValue(),
                              extra=self.extra)
 
+
 class BytesAreaWidget(Bytes, TextAreaWidget):
     """BytesArea widget.
 
@@ -350,6 +352,7 @@
     'Hello\\nworld!'
     """
 
+
 class PasswordWidget(TextWidget):
     """Password Widget"""
 
@@ -383,116 +386,7 @@
         raise NotImplementedError(
             'Cannot get a hidden tag for a password field')
 
-class FileWidget(TextWidget):
-    """File Widget"""
 
-    type = 'file'
-
-    def __call__(self):
-        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=self.displayWidth,
-                                 maxlength=displayMaxWidth,
-                                 extra=self.extra)
-        else:
-            return renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 cssClass=self.cssClass,
-                                 size=self.displayWidth,
-                                 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:
-            seek(0)
-            data = read()
-            if data or getattr(input, 'filename', ''):
-                return data
-            else:
-                return self.context.missing_value
-
-class MimeWidget(TextWidget):
-    u"""Mime 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 the FileUpload instance has no filename set, there is
-            # no upload.
-            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 MimeDisplayWidget(DisplayWidget):
-    """Mime data display widget."""
-    # There need to be probably some widget options to determine how
-    # the file is displayed, e.g. as a download link.
-
-    def __call__(self):
-        if self._renderedValueSet():
-            content = self._data
-        else:
-            content = self.context.default
-
-        show = u"Filename %s, size in bytes: %s" (content.filename,
-                                                  content.getSize())
-        return renderElement("span", contents=escape(show))
-   
-    
 class IntWidget(TextWidget):
     displayWidth = 10
 

Modified: Zope3/branches/jhauser-filefieldwidget/src/zope/schema/_field.py
===================================================================
--- Zope3/branches/jhauser-filefieldwidget/src/zope/schema/_field.py	2005-01-18 23:41:26 UTC (rev 28870)
+++ Zope3/branches/jhauser-filefieldwidget/src/zope/schema/_field.py	2005-01-19 14:23:47 UTC (rev 28871)
@@ -67,11 +67,13 @@
 classImplements(Bool, IBool)
 classImplements(Int, IInt)
 
+
 class SourceText(Text):
     __doc__ = ISourceText.__doc__
     implements(ISourceText)
     _type = unicode
 
+
 class Bytes(MinMaxLen, Field):
     __doc__ = IBytes.__doc__
     implements(IBytes, IFromUnicode)
@@ -94,7 +96,8 @@
         self.validate(v)
         return v
 
-class Mime(Bytes):
+
+class Mime(Field):
     __doc__ = IMime.__doc__
     implements(IMime)
 
@@ -131,6 +134,13 @@
             return
         super(Bytes, self)._validate(value)
 
+    def _validate(self, value):
+        if self._type is not None and not isinstance(value, self._type):
+            raise WrongType(value, self._type)
+
+        if not self.constraint(value):
+            raise ConstraintNotSatisfied(value)
+
     def _extractFilename(self, data):
         # if it is a fileupload object
         if hasattr(data,'filename'):
@@ -143,6 +153,7 @@
         else:
             return ''
 
+
 class ASCII(Bytes):
     __doc__ = IASCII.__doc__
     implements(IASCII)
@@ -173,6 +184,7 @@
         if not max(map(ord, value)) < 128:
             raise InvalidValue
 
+
 class BytesLine(Bytes):
     """A Text field with no newlines."""
 
@@ -205,6 +217,7 @@
         self.validate(v)
         return v
 
+
 class Datetime(Orderable, Field):
     __doc__ = IDatetime.__doc__
     implements(IDatetime)
@@ -213,11 +226,13 @@
     def __init__(self, *args, **kw):
         super(Datetime, self).__init__(*args, **kw)
 
+
 class Date(Orderable, Field):
     __doc__ = IDate.__doc__
     implements(IDate)
     _type = date
 
+
 class Choice(Field):
     """Choice fields can have a value found in a constant or dynamic set of
     values given by the field definition.
@@ -301,6 +316,7 @@
         if value not in vocabulary:
             raise ConstraintNotSatisfied, value
 
+
 class InterfaceField(Field):
     __doc__ = IInterfaceField.__doc__
     implements(IInterfaceField)
@@ -310,6 +326,7 @@
         if not IInterface.providedBy(value):
             raise WrongType("An interface is required")
 
+
 def _validate_sequence(value_type, value, errors=None):
     """Validates a sequence value.
     
@@ -351,6 +368,7 @@
             errors.append(error)
     return errors
 
+
 def _validate_uniqueness(value):
     temp_values = []
     for item in value:
@@ -359,6 +377,7 @@
 
         temp_values.append(item)
 
+
 class AbstractCollection(MinMaxLen, Iterable, Field):
     value_type = None
     unique = False
@@ -388,16 +407,19 @@
         if self.unique:
             _validate_uniqueness(value)
 
+
 class Tuple(AbstractCollection):
     """A field representing a Tuple."""
     implements(ITuple)
     _type = tuple
 
+
 class List(AbstractCollection):
     """A field representing a List."""
     implements(IList)
     _type = list
 
+
 class Set(AbstractCollection):
     """A field representing a set."""
     implements(ISet)
@@ -408,6 +430,7 @@
                 "__init__() got an unexpected keyword argument 'unique'")
         super(Set, self).__init__(unique=True, **kw)
 
+
 def _validate_fields(schema, value, errors=None):
     if errors is None:
         errors = []  
@@ -487,6 +510,8 @@
     r"[a-zA-z0-9+.-]+:"   # scheme
     r"\S*$"               # non space (should be pickier)
     ).match
+
+
 class URI(BytesLine):
     """URI schema field
     """
@@ -535,6 +560,7 @@
     r"$" # use the whole line
     ).match
 
+
 class Id(BytesLine):
     """Id field
 



More information about the Zope3-Checkins mailing list