[Checkins] SVN: z3c.quickentry/trunk/src/z3c/quickentry/
Implemented better error handling and reporting,
so that user interfaces
Stephan Richter
srichter at cosmos.phy.tufts.edu
Tue Feb 13 04:31:56 EST 2007
Log message for revision 72509:
Implemented better error handling and reporting, so that user interfaces
can be more informative.
Changed:
U z3c.quickentry/trunk/src/z3c/quickentry/README.txt
U z3c.quickentry/trunk/src/z3c/quickentry/interfaces.py
U z3c.quickentry/trunk/src/z3c/quickentry/plugin.py
U z3c.quickentry/trunk/src/z3c/quickentry/processor.py
-=-
Modified: z3c.quickentry/trunk/src/z3c/quickentry/README.txt
===================================================================
--- z3c.quickentry/trunk/src/z3c/quickentry/README.txt 2007-02-12 22:11:59 UTC (rev 72508)
+++ z3c.quickentry/trunk/src/z3c/quickentry/README.txt 2007-02-13 09:31:51 UTC (rev 72509)
@@ -28,12 +28,16 @@
... shortName = 'nm'
... varName = 'name'
-Any plugin is instantiated using an initial text:
+Any plugin is instantiated using an initial text and optionally a position
+that is used during error reporting:
>>> name = NamePlugin('nm=Stephan')
>>> name
<NamePlugin shortName='nm', varName='name'>
+ >>> NamePlugin('nm=Stephan', 35)
+ <NamePlugin shortName='nm', varName='name'>
+
You can now ask the plugin, whether it can process this text:
>>> name.canProcess()
@@ -83,18 +87,22 @@
>>> phone.process(None)
{'phone': u'978-555-5300'}
-If the text changes, so that the plugin cannot parse the text anymore, a value
-error is raised:
+If the text changes, so that the plugin cannot parse the text anymore, a
+process error is raised:
>>> phone.text += ' (ext. 2134)'
>>> phone.process(None)
Traceback (most recent call last):
...
- ValueError: The regex did match anymore. ...
+ ProcessError: The regex did match anymore. Probably some text was added
+ later that disrupted the pattern. (Position 0)
+
Finally let's have a look at a more advanced example. We would like to be able
to handle the string "<age><gender>" and parse it into 2 variables:
+ >>> from z3c.quickentry import interfaces
+
>>> class AgeGenderPlugin(plugin.BasePlugin):
... regex = re.compile('([0-9]{1,3})([FM])')
...
@@ -103,6 +111,8 @@
...
... def process(self, context):
... match = self.regex.match(self.text)
+ ... if match is None:
+ ... raise interfaces.ProcessError(self.position, u'Error here.')
... return {'age': int(match.groups()[0]),
... 'gender': unicode(match.groups()[1])}
@@ -130,6 +140,14 @@
>>> pprint(AgeGenderPlugin('101F').process(None))
{'age': 101, 'gender': u'F'}
+When an error occurs at any point during the processing, a process error must
+be raised:
+
+ >>> pprint(AgeGenderPlugin('27N').process(None))
+ Traceback (most recent call last):
+ ...
+ ProcessError: Error here. (Position 0)
+
The plugin above used the ``BasePlugin`` class to minimize the
boilerplate. The base plugin requires you to implement the ``canProcess()``
and ``process()``:
@@ -226,7 +244,14 @@
>>> pprint(info.process('nm=Stephan Richter,27M', context=object()))
{'age': 27, 'gender': u'M', 'name': u'Stephan Richter'}
+But what happens, if no plugin can be found. Then a process error is raised:
+ >>> info.process('err=Value', context=object())
+ Traceback (most recent call last):
+ ...
+ ProcessError: No matching plugin found. (Position 0)
+
+
Executing Processors
--------------------
Modified: z3c.quickentry/trunk/src/z3c/quickentry/interfaces.py
===================================================================
--- z3c.quickentry/trunk/src/z3c/quickentry/interfaces.py 2007-02-12 22:11:59 UTC (rev 72508)
+++ z3c.quickentry/trunk/src/z3c/quickentry/interfaces.py 2007-02-13 09:31:51 UTC (rev 72509)
@@ -17,7 +17,35 @@
"""
__docformat__ = "reStructuredText"
import zope.interface
+import zope.schema
+class IProcessError(zope.interface.Interface):
+
+ position = zope.schema.Int(
+ title=u'Position',
+ description=u'The position at which the error occured.',
+ required=True)
+
+ reason = zope.schema.Text(
+ title=u'Reason',
+ description=u'The reason for the parse error.',
+ required=True)
+
+class ProcessError(Exception):
+ zope.interface.implements(IProcessError)
+
+ def __init__(self, position, reason):
+ self.position = position
+ self.reason = reason
+
+ def __repr__(self):
+ return '<%s at pos %r: %r>' %(
+ self.__class__.__name__, self.position, self.reason)
+
+ def __str__(self):
+ return self.reason + u' (Position %i)' %self.position
+
+
class IProcessor(zope.interface.Interface):
"""A processor for a quick entry text."""
@@ -55,6 +83,12 @@
'The text that is going to be converted into values. '
'The processor will fill this attribute after the initial text is set.')
+ position = zope.schema.Int(
+ title=u'Position',
+ description=u'The position at which the text started',
+ default=0,
+ required=True)
+
def canProcess():
"""Determine whether the plugin can handle the text.
Modified: z3c.quickentry/trunk/src/z3c/quickentry/plugin.py
===================================================================
--- z3c.quickentry/trunk/src/z3c/quickentry/plugin.py 2007-02-12 22:11:59 UTC (rev 72508)
+++ z3c.quickentry/trunk/src/z3c/quickentry/plugin.py 2007-02-13 09:31:51 UTC (rev 72509)
@@ -24,8 +24,9 @@
"""An abstract base plugin."""
zope.interface.implements(interfaces.IPlugin)
- def __init__(self, initialText):
+ def __init__(self, initialText, position=0):
self.text = initialText
+ self.position = position
def canProcess(self):
"""See interfaces.IPlugin"""
@@ -73,8 +74,10 @@
def process(self, context):
"""See interfaces.IPlugin"""
if self.regex.match(self.text) is None:
- raise ValueError('The regex did match anymore. Probably some text '
- 'was added later that disrupted the pattern.')
+ raise interfaces.ProcessError(
+ self.position,
+ (u'The regex did match anymore. Probably some text '
+ u'was added later that disrupted the pattern.'))
return {self.varName: unicode(self.text)}
def __repr__(self):
Modified: z3c.quickentry/trunk/src/z3c/quickentry/processor.py
===================================================================
--- z3c.quickentry/trunk/src/z3c/quickentry/processor.py 2007-02-12 22:11:59 UTC (rev 72508)
+++ z3c.quickentry/trunk/src/z3c/quickentry/processor.py 2007-02-13 09:31:51 UTC (rev 72509)
@@ -29,6 +29,7 @@
plugins = ()
def parse(self, text):
+ position = 0
# Step 0: Get the sequence of all plugins; we store the result
# locally, since the lookup might be expensive.
plugins = self.plugins
@@ -49,8 +50,14 @@
# Step 2.3: If no plugin can handle the piece, it is simply added
# to the text of the last plugin's test.
else:
+ if len(result) == 0:
+ raise interfaces.ProcessError(
+ position, u'No matching plugin found.')
result[-1].text += self.separationCharacter
result[-1].text += piece
+ # Step 2.4: Update the position
+ # (add one for the separation character)
+ position += len(piece) + 1
return result
def process(self, text, context=None):
More information about the Checkins
mailing list