diff --git a/composer/schema/field.py b/composer/schema/field.py
index 379e51c..86d0dee 100644
--- a/composer/schema/field.py
+++ b/composer/schema/field.py
@@ -33,7 +33,7 @@ from zope.i18n.locales import locales
from cybertools.composer.base import Component
from cybertools.composer.schema.interfaces import IField, IFieldInstance
-from cybertools.composer.schema.interfaces import fieldTypes
+from cybertools.composer.schema.interfaces import fieldTypes, undefined
from cybertools.composer.schema.schema import formErrors
from cybertools.util.format import toStr, toUnicode
@@ -61,7 +61,8 @@ class Field(Component):
def __init__(self, name, title=None, fieldType='textline', **kw):
assert name
self.__name__ = name
- title = title or u''
+ #title = title or u''
+ title = title or name
self.fieldType = fieldType
super(Field, self).__init__(title, __name__=name, **kw)
self.title = title
@@ -127,6 +128,7 @@ class FieldInstance(object):
adapts(IField)
clientInstance = None
+ value = undefined
def __init__(self, context):
self.context = context
diff --git a/composer/schema/instance.py b/composer/schema/instance.py
index 8caf2cd..812aa34 100644
--- a/composer/schema/instance.py
+++ b/composer/schema/instance.py
@@ -39,6 +39,7 @@ class Instance(BaseInstance):
aspect = 'schema.editor.default'
template = None
+ view = None
def applyTemplate(self, *args, **kw):
#result = dict(__name__=self.context.__name__)
diff --git a/composer/schema/interfaces.py b/composer/schema/interfaces.py
index 9fd64c5..24f3499 100644
--- a/composer/schema/interfaces.py
+++ b/composer/schema/interfaces.py
@@ -192,6 +192,8 @@ class IField(IComponent):
'field instance.')
+undefined = object() # A marker for a field instance value not set.
+
class IFieldInstance(Interface):
""" An adapter for checking and converting data values coming
from or being displayed on an external system (like a browser form).
@@ -201,18 +203,28 @@ class IFieldInstance(Interface):
name = Attribute('Field name.')
change = Attribute('A tuple ``(oldValue, newValue)`` or None.')
errors = Attribute('A sequence of error infos.')
- severity = Attribute("An integer giving a state or error "
- "code, 0 meaning 'OK'.")
+ severity = Attribute('An integer giving a state or error '
+ 'code, 0 meaning OK.')
+ clientInstance = Attribute('An optional adapter to a client object that '
+ 'provides or receives data processed by this field instance.')
+ value = Attribute ('May contain the current value of the field '
+ 'for later reuse. Default is ``undefined``. '
+ 'If the ``change`` attribute is set ``value`` should '
+ 'be equal to ``change[1]``.')
def getRawValue(data, key, default=None):
""" Extract a raw value for the field from the data given
using the key; if no corresponding value is found return
- the default.
+ the default. The value returned may then be turned
+ byt self.unmarshall() to the real (internal) value.
"""
def marshall(value):
""" Return a string (possibly unicode) representation of the
- value given that may be used for editing.
+ value given that may be used for editing. In case of complex
+ or structured fields (list, mapping, object fields) the return
+ value may also be a structured object (typically a list or
+ mapping) built up form string (unicode) values.
"""
def display(value):
@@ -220,9 +232,9 @@ class IFieldInstance(Interface):
value given that may be used for presentation.
"""
- def unmarshall(rawValue):
+ def unmarshall(inputValue):
""" Return the internal (real) value corresponding to the
- raw value given.
+ input (external, raw) value given.
"""
def validate(value, data=None):
diff --git a/reporter/README.txt b/reporter/README.txt
index 5f5bc12..f63074e 100644
--- a/reporter/README.txt
+++ b/reporter/README.txt
@@ -7,15 +7,12 @@ A Basic API for Reports and Listings
TO DO...
>>> from zope import component
- >>> from zope.interface import directlyProvides
Listings
========
>>> from cybertools.reporter.data import DataSource
- >>> from cybertools.reporter.resultset import ResultSet
- >>> from cybertools.reporter.interfaces import IResultSet
Let's start with the Person class from the cybertools.organize package - we will
then provide a listing of persons...
@@ -29,38 +26,42 @@ then provide a listing of persons...
>>> persons = DataSource([Person(f, s, date(*[int(d) for d in b.split('-')]))
... for f, s, b in pdata])
+ >>> from cybertools.reporter.resultset import ResultSet, ContentRow
+ >>> from cybertools.reporter.interfaces import IResultSet, IRow
>>> component.provideAdapter(ResultSet)
- >>> rset = IResultSet(persons)
-
- >>> len(list(rset.rows))
- 3
-
-As we have not yet provided a schema for the result set the rows are
-empty.
-
- >>> r1 = rset.rows.next()
- >>> list(r1.cells)
- []
-
-So let's assign a schema to the result set.
+ >>> component.provideAdapter(ContentRow, provides=IRow)
>>> from cybertools.composer.schema.schema import Schema
>>> from cybertools.composer.schema.field import Field
- >>> rset.schema = Schema(Field(u'firstName'), Field(u'lastName'), Field(u'birthDate'))
- >>> r1 = rset.rows.next()
- >>> [c.text for c in r1.cells]
- [u'Smith', u'John', u'1956-08-01']
+ >>> from cybertools.composer.schema.field import FieldInstance, DateFieldInstance
+ >>> component.provideAdapter(FieldInstance)
+ >>> component.provideAdapter(DateFieldInstance, name='date')
+
+ >>> rset = IResultSet(persons)
+ >>> rset.schema = Schema(Field(u'firstName'), Field(u'lastName'),
+ ... Field(u'birthDate', fieldType='date'))
+
+ >>> rows = list(rset.getRows())
+ >>> len(rows)
+ 3
+
+ >>> for r in rows:
+ ... print r.applyTemplate()
+ {u'lastName': u'John', u'birthDate': '1956-08-01', u'firstName': u'Smith'}
+ {u'lastName': u'David', u'birthDate': '1972-12-24', u'firstName': u'Waters'}
+ {u'lastName': u'Carla', u'birthDate': '1981-10-11', u'firstName': u'Myers'}
For the browser presentation we can also use a browser view providing
the result set with extended attributes:
- >>> #rsView = component.getMultiAdapter((context, TestRequest()), IBrowserView)
+ >>> #rsView = component.getMultiAdapter((rset, TestRequest()), IBrowserView)
+
The reporter package also includes facilities for sorting the rows in a
result set and splitting a result into batches.
Sorting
--------
+=======
Batching
diff --git a/reporter/configure.zcml b/reporter/configure.zcml
index f820e5f..a6f9a1a 100644
--- a/reporter/configure.zcml
+++ b/reporter/configure.zcml
@@ -5,6 +5,11 @@
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="zope">
+
+
diff --git a/reporter/interfaces.py b/reporter/interfaces.py
index 7c9db16..e20a647 100644
--- a/reporter/interfaces.py
+++ b/reporter/interfaces.py
@@ -55,6 +55,7 @@ class IRow(Interface):
class ICell(Interface):
""" A single cell of a listing or table.
"""
+ # TODO: replace Cell by FieldInstance
field = Attribute(u'The schema field the cell belongs to.')
diff --git a/reporter/resultset.py b/reporter/resultset.py
index 573ee6c..4e10586 100644
--- a/reporter/resultset.py
+++ b/reporter/resultset.py
@@ -25,15 +25,18 @@ $Id$
# TODO: move the generic stuff to cybertools.reporter.result
+from zope.cachedescriptors.property import Lazy
from zope.component import adapts
-from zope.interface import implements
+from zope.interface import Interface, implements
-from cybertools.composer.schema.schema import Schema
+from cybertools.composer.schema import Schema
+from cybertools.composer.schema.instance import Instance
from cybertools.reporter.interfaces import IDataSource
from cybertools.reporter.interfaces import IResultSet, IRow, ICell
class Cell(object):
+ # TODO: replace Cell by FieldInstance
implements(ICell)
@@ -61,7 +64,7 @@ class Cell(object):
url = urlTitle = u''
-class Row(object):
+class Row(Instance):
implements(IRow)
@@ -69,17 +72,33 @@ class Row(object):
self.context = context
self.resultSet = resultSet
- @property
+ @Lazy
def schema(self):
return self.resultSet.schema
+ @Lazy
+ def fields(self):
+ return self.schema.fields
+
@property
def cells(self):
- for f in self.resultSet.schema.fields:
+ for f in self.schema.fields:
rf = f.renderFactory or Cell
yield rf(f, getattr(self.context, f.name), self)
+class ContentRow(Instance):
+ """ A row adapter for standard content objects.
+ """
+
+ implements(IRow)
+ adapts(Interface)
+
+ @Lazy
+ def fields(self):
+ return self.template.fields
+
+
class ResultSet(object):
implements(IResultSet)
@@ -96,3 +115,9 @@ class ResultSet(object):
for o in iter(self.context):
yield Row(o, self)
+ def getRows(self):
+ for o in iter(self.context):
+ row = IRow(o)
+ row.resultSet = self
+ row.template = self.schema
+ yield row