[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