[Checkins] SVN: z3c.sessionwidget/trunk/src/ This is a widget that interfaces with a session to manage the input

Stephan Richter srichter at cosmos.phy.tufts.edu
Tue Sep 19 13:01:35 EDT 2006


Log message for revision 70231:
  This is a widget that interfaces with a session to manage the input 
  data. This is ideal for any objects that require multiple steps to 
  assemble themselves, such as files, complex lists, etc. I will provide 
  an image widget based on this code in a moment.
  
  --This line, and those below, will 
  be ignored--
  
  A    .
  

Changed:
  A   z3c.sessionwidget/trunk/src/README.txt
  A   z3c.sessionwidget/trunk/src/SETUP.cfg
  A   z3c.sessionwidget/trunk/src/__init__.py
  A   z3c.sessionwidget/trunk/src/configure.zcml
  A   z3c.sessionwidget/trunk/src/interfaces.py
  A   z3c.sessionwidget/trunk/src/namespace.py
  A   z3c.sessionwidget/trunk/src/tests.py
  A   z3c.sessionwidget/trunk/src/widget.py
  A   z3c.sessionwidget/trunk/src/z3c.sessionwidget-configure.zcml

-=-
Added: z3c.sessionwidget/trunk/src/README.txt
===================================================================
--- z3c.sessionwidget/trunk/src/README.txt	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/README.txt	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,158 @@
+========================
+The Session Input Widget
+========================
+
+Sometimes fields do not describe just simple data types, but complex data
+structures. In those scenarios, widgets of the field do not represent a simple
+text input or a small set of input elements, but more complex
+combinations. Until now, those scenarios were solved using either sub-forms or
+a fairly complicated widget for the object field.
+
+While a sub-form is an acceptable solution, it often writes the data to the
+object before the form's save button is pressed. This is, for example, the
+case when uploading images and displaying them right away as visual
+feedback. The object widget has the same problem when constructing sequences
+qith complex sub-items. In general it is up to the developer to decide when to
+present a new form or use the widget, but at least s/he should have the
+choice.
+
+To solve this problem, this package provides a widget that is only responsible
+for relaying the data of interest to a session. A sub-form or any other
+componentcan then use this session data and provide new data, if desired. The
+session data will also be publically available via a URL, so that the objects
+can also be displayed, such as images. This has the advantage that the data is
+*not* stored on the content until the overall form is submitted.
+
+The session has two data fields:
+
+1. data --> The data object of interest as it will be stored in the content
+            object.
+
+2. changed --> A boolean saying whether the data has changed.
+
+Usually, sub-forms work with those two data fields and update the new data. To
+demonstrate this we first need to create a schema for the object and the
+content containing the object,
+
+  >>> import zope.interface
+  >>> import zope.schema
+
+  >>> class IObject(zope.interface.Interface):
+  ...     '''An object in the content.'''
+
+  >>> class IContent(zope.interface.Interface):
+  ...     obj = zope.schema.Object(
+  ...         title=u'Object',
+  ...         schema=IObject)
+
+implement those interfaces,
+
+  >>> class Object(object):
+  ...     zope.interface.implements(IObject)
+  ...     def __init__(self, id):
+  ...         self.id = id
+  ...     def __repr__(self):
+  ...         return '<%s %s>' %(self.__class__.__name__, self.id)
+
+  >>> class Content(object):
+  ...     zope.interface.implements(IContent)
+  ...     obj = zope.schema.fieldproperty.FieldProperty(IContent['obj'])
+
+and finally instantiate the content:
+
+  >>> content = Content()
+
+After creating a request,
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+we can now initialize the widget:
+
+  >>> from z3c.sessionwidget import widget
+  >>> objWidget = widget.SessionInputWidget(IContent['obj'], request)
+
+The widget can directly access the session:
+
+  >>> objWidget.session
+  <zope.app.session.session.SessionPkgData object at ...>
+  >>> objWidget.session.get('data', 'nothing')
+  'nothing'
+  >>> objWidget.session.get('changed', 'nothing')
+  'nothing'
+
+Initially, the widget has no data:
+
+  >>> objWidget.hasInput()
+  False
+
+Once we set the rendered value, we have soem input:
+
+  >>> objWidget.setRenderedValue(Object('1'))
+  >>> objWidget.hasInput()
+  True
+
+Of course, you can now retrieve that value:
+
+  >>> objWidget.getInputValue()
+  <Object 1>
+
+Let's now say that some arbitrary form creates a new object.
+
+  >>> objWidget.session['data'] = Object('2')
+
+This form is also responsible for setting the changed flag:
+
+  >>> objWidget.session['changed'] = True
+
+Now the input value is different:
+
+  >>> objWidget.getInputValue()
+  <Object 2>
+
+Also, setting the rendered value is now ineffective:
+
+  >>> objWidget.setRenderedValue(Object('1'))
+  >>> objWidget.getInputValue()
+  <Object 2>
+
+When applying the changes, the method only looks at the changed flag to decide
+whether the data changed:
+
+  >>> content.obj
+
+  >>> objWidget.applyChanges(content)
+  True
+
+  >>> content.obj
+  <Object 2>
+
+Note that calling thos method also resets the session:
+
+  >>> objWidget.session['data']
+  >>> objWidget.session['changed']
+
+Note that hidden always renders empty:
+
+  >>> objWidget.hidden()
+  ''
+
+Let's now set a new object value again, but changing the changed flag. No
+changes will be applied:
+
+  >>> objWidget.session['data'] = Object('3')
+  >>> objWidget.session['changed'] = False
+
+  >>> content.obj
+  <Object 2>
+  >>> objWidget.applyChanges(content)
+  False
+  >>> content.obj
+  <Object 2>
+
+
+TO DO:
+------
+
+The id identifying the session data is not unique enough; we need some better
+mechanism for this later.


Property changes on: z3c.sessionwidget/trunk/src/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.sessionwidget/trunk/src/SETUP.cfg
===================================================================
--- z3c.sessionwidget/trunk/src/SETUP.cfg	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/SETUP.cfg	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+  z3c.sessionwidget-*.zcml
+</data-files>

Added: z3c.sessionwidget/trunk/src/__init__.py
===================================================================
--- z3c.sessionwidget/trunk/src/__init__.py	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/__init__.py	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,3 @@
+# Make a package.
+
+from z3c.sessionwidget.widget import SessionInputWidget


Property changes on: z3c.sessionwidget/trunk/src/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.sessionwidget/trunk/src/configure.zcml
===================================================================
--- z3c.sessionwidget/trunk/src/configure.zcml	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/configure.zcml	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,19 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+  <view
+      name="session" type="*"
+      provides="zope.traversing.interfaces.ITraversable" for="*"
+      factory=".namespace.sessionNamespace"
+      />
+
+  <view
+      for="zope.app.session.session.SessionPkgData"
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
+      provides="zope.publisher.interfaces.browser.IBrowserPublisher"
+      factory="zope.app.container.traversal.ItemTraverser"
+      permission="zope.Public"
+      allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
+      />
+
+</configure>


Property changes on: z3c.sessionwidget/trunk/src/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.sessionwidget/trunk/src/interfaces.py
===================================================================
--- z3c.sessionwidget/trunk/src/interfaces.py	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/interfaces.py	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Session Widget Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.interface
+from zope.app.form import interfaces
+
+class ISessionWidget(interfaces.IWidget):
+    """A widget that communicates its data via a session."""
+
+    session = zope.interface.Attribute(
+        '''The session object that holds all information necessary for the
+        session widget to implement the IWidget API. Two fields are declared:
+
+        ``data`` -- Holds the data object that is to be stored. It can be any
+                    arbitrary Python object.
+
+        ``changed`` -- a flag (boolean) describing whether the object has been
+                       changed since the widget was originally initialized.
+        ''')


Property changes on: z3c.sessionwidget/trunk/src/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.sessionwidget/trunk/src/namespace.py
===================================================================
--- z3c.sessionwidget/trunk/src/namespace.py	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/namespace.py	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Session Namespace
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from zope.app.session.interfaces import ISession
+from z3c.sessionwidget import widget
+
+class sessionNamespace(object):
+    """Used to traverse to a session."""
+
+    def __init__(self, ob, request=None):
+        self.context = ob
+        self.request = request
+
+    def traverse(self, name, ignore):
+        return ISession(self.request)[name]


Property changes on: z3c.sessionwidget/trunk/src/namespace.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.sessionwidget/trunk/src/tests.py
===================================================================
--- z3c.sessionwidget/trunk/src/tests.py	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/tests.py	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,55 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Image Widgets Test
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import doctest
+import unittest
+import zope.component
+from zope.app.session import interfaces
+from zope.app.session import session
+from zope.app.testing import placelesssetup
+from zope.app.session.http import CookieClientIdManager
+from zope.publisher.interfaces import IRequest
+from zope.testing.doctestunit import DocFileSuite
+
+
+def setUp(test):
+    placelesssetup.setUp()
+    zope.component.provideAdapter(
+        session.ClientId, (IRequest,), interfaces.IClientId)
+    zope.component.provideAdapter(
+        session.Session, (IRequest,), interfaces.ISession)
+    zope.component.provideUtility(
+        CookieClientIdManager(), interfaces.IClientIdManager)
+    zope.component.provideUtility(
+        session.PersistentSessionDataContainer(),
+        interfaces.ISessionDataContainer)
+
+def tearDown(test):
+    placelesssetup.tearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     setUp=setUp, tearDown=tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3c.sessionwidget/trunk/src/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.sessionwidget/trunk/src/widget.py
===================================================================
--- z3c.sessionwidget/trunk/src/widget.py	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/widget.py	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Session Widget Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.interface
+import zope.location
+from zope.app import form
+from zope.app.form.browser import widget
+from zope.app.session.interfaces import ISession
+from zope.app.session.session import SessionPkgData
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.sessionwidget import interfaces
+
+SESSION_KEY = 'z3c.sessionwidget.SessionInputWidget'
+
+class SessionInputWidget(widget.BrowserWidget, form.InputWidget):
+    """Session Input Widget"""
+    zope.interface.implements(interfaces.ISessionWidget)
+
+    @property
+    def session(self):
+        """Get the session containing all data relevant for this widget."""
+        return ISession(self.request)[SESSION_KEY].setdefault(
+            self.name, SessionPkgData())
+
+    def setRenderedValue(self, value):
+        """See zope.app.form.interfaces.IWidget"""
+        if not self.session.get('changed', False):
+            self.session['data'] = value
+
+    def hidden(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        # Since the data is stored in a session, no data has to be passed here.
+        return ''
+
+    def hasInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        missing = self.context.missing_value
+        return self.session.get('data', missing) is not missing
+
+    def getInputValue(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        self._error = None
+        field = self.context
+
+        # form input is required, otherwise raise an error
+        if not self.hasInput():
+            raise MissingInputError(self.name, self.label, None)
+
+        # Get the value from the session
+        value = self.session['data']
+
+        # allow missing values only for non-required fields
+        if value == field.missing_value and not field.required:
+            return value
+
+        # value must be valid per the field constraints
+        try:
+            field.validate(value)
+        except ValidationError, v:
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, v)
+            raise self._error
+
+        return value
+
+    def applyChanges(self, content):
+        """See zope.app.form.interfaces.IInputWidget"""
+        field = self.context
+        value = self.getInputValue()
+        # Look into the session to see whether the data changed
+        if self.session['changed']:
+            zope.location.locate(value, content, field.getName())
+            field.set(content, value)
+            changed = True
+        else:
+            changed = False
+        # Cleanup the session, so that everything is reset for next time
+        self.session['changed'] = None
+        self.session['data'] = None
+        # Now return the result
+        return changed
+
+    def __call__(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        form = zope.component.getMultiAdapter(
+            (self, self.request), zope.interface.Interface,
+            'SessionInputWidget.form')
+        form.update()
+        return form.render()


Property changes on: z3c.sessionwidget/trunk/src/widget.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.sessionwidget/trunk/src/z3c.sessionwidget-configure.zcml
===================================================================
--- z3c.sessionwidget/trunk/src/z3c.sessionwidget-configure.zcml	2006-09-19 16:59:18 UTC (rev 70230)
+++ z3c.sessionwidget/trunk/src/z3c.sessionwidget-configure.zcml	2006-09-19 17:01:34 UTC (rev 70231)
@@ -0,0 +1 @@
+<include package="z3c.sessionwidget" />


Property changes on: z3c.sessionwidget/trunk/src/z3c.sessionwidget-configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list