PATCH: Provide a textual representation for SetField

Mark Mitchell mark at codesourcery.com
Mon Sep 8 06:51:47 UTC 2003


This patch implements ParseTextValue for SetField so that values can
be specified on the command line.

--
Mark Mitchell
CodeSourcery, LLC
mark at codesourcery.com

2003-09-07  Mark Mitchell  <mark at codesourcery.com>

	* qm/fields.py (cStringIO): Do not import.
	(StringIO): Import.
	(tokenize): Import.
	(Field.FormatValueAsText): Use StringIO.
	(Field.ParseTextValue): Improve documentation.
	(SetField.FormatValueAsText): Make output match format expected 
	by ...
	(SetField.ParseTextField): ... this new method.
	* qm/test/cmdline.py (QMTest.attribute_option_spec): Generalize
	help text.
	* share/diagnostics/common.txt (invalid set value): New message.

Index: qm/fields.py
===================================================================
RCS file: /home/sc/Repository/qm/qm/fields.py,v
retrieving revision 1.77
diff -c -5 -p -r1.77 fields.py
*** qm/fields.py	30 Jul 2003 21:25:30 -0000	1.77
--- qm/fields.py	8 Sep 2003 06:45:22 -0000
*************** of test names."""
*** 40,59 ****
  # imports
  ########################################################################
  
  import attachment
  import common
- import cStringIO
  import formatter
  import htmllib
  import os
  import re
  import qm
  import string
  import structured_text
  import sys
  import time
  import types
  import urllib
  import web
  import xml.dom
  import xmlutil
--- 40,60 ----
  # imports
  ########################################################################
  
  import attachment
  import common
  import formatter
  import htmllib
  import os
  import re
  import qm
  import string
+ import StringIO
  import structured_text
  import sys
  import time
+ import tokenize
  import types
  import urllib
  import web
  import xml.dom
  import xmlutil
*************** class Field(object):
*** 225,239 ****
          'columns' -- The maximum width of each line of text.
  
          returns -- A plain-text string representing 'value'."""
  
          # Create a file to hold the result.
!         text_file = cStringIO.StringIO()
          # Format the field as HTML.
!         html_file = cStringIO.StringIO(self.FormatValueAsHtml(None,
!                                                               value,
!                                                               "brief"))
  
          # Turn the HTML into plain text.
          parser = htmllib.HTMLParser(formatter.AbstractFormatter
                                      (formatter.DumbWriter(text_file,
                                                            maxcol = columns)))
--- 226,240 ----
          'columns' -- The maximum width of each line of text.
  
          returns -- A plain-text string representing 'value'."""
  
          # Create a file to hold the result.
!         text_file = StringIO.StringIO()
          # Format the field as HTML.
!         html_file = StringIO.StringIO(self.FormatValueAsHtml(None,
!                                                              value,
!                                                              "brief"))
  
          # Turn the HTML into plain text.
          parser = htmllib.HTMLParser(formatter.AbstractFormatter
                                      (formatter.DumbWriter(text_file,
                                                            maxcol = columns)))
*************** class Field(object):
*** 307,317 ****
      def ParseTextValue(self, value):
          """Parse a value represented as a string.
  
          'value' -- A string representing the value.
  
!         returns -- The corresponding field value."""
  
          raise NotImplemented
      
          
      def ParseFormValue(self, request, name, attachment_store):
--- 308,320 ----
      def ParseTextValue(self, value):
          """Parse a value represented as a string.
  
          'value' -- A string representing the value.
  
!         returns -- The corresponding field value.  The value returned
!         should be processed by 'Validate' to ensure that it is valid
!         before it is returned."""
  
          raise NotImplemented
      
          
      def ParseFormValue(self, request, name, attachment_store):
*************** class SetField(Field):
*** 868,879 ****
          # comma-separated list. 
          contained_field = self.GetContainedField()
          formatted_items = []
          for item in value:
              formatted_item = contained_field.FormatValueAsText(item, columns)
!             formatted_items.append(formatted_item)
!         result = string.join(formatted_items, ", ")
          return qm.common.wrap_lines(result, columns)
  
  
      def FormatValueAsHtml(self, server, value, style, name=None):
          # Use default value if requested.
--- 871,882 ----
          # comma-separated list. 
          contained_field = self.GetContainedField()
          formatted_items = []
          for item in value:
              formatted_item = contained_field.FormatValueAsText(item, columns)
!             formatted_items.append(repr(formatted_item))
!         result = "[ " + string.join(formatted_items, ", ") + " ]"
          return qm.common.wrap_lines(result, columns)
  
  
      def FormatValueAsHtml(self, server, value, style, name=None):
          # Use default value if requested.
*************** class SetField(Field):
*** 979,988 ****
--- 982,1044 ----
          # validating each element in the contained field.
          return map(lambda v: self.__contained.Validate(v),
                     value)
  
  
+     def ParseTextValue(self, value):
+ 
+         def invalid(tok):
+             """Raise an exception indicating a problem with 'value'.
+             
+             'tok' -- A token indicating the position of the problem.
+ 
+             This function does not return; instead, it raises an
+             appropriate exception."""
+ 
+             raise qm.QMException, \
+                   qm.error("invalid set value", start = value[tok[2][1]:])
+             
+         # Use the Python parser to handle the elements of the set.
+         s = StringIO.StringIO(value)
+         g = tokenize.generate_tokens(s.readline)
+         
+         # Read the opening square bracket.
+         tok = g.next()
+         if tok[0] != tokenize.OP or tok[1] != "[":
+             invalid(tok)
+ 
+         # There are no elements yet.
+         elements = []
+ 
+         # Keep going until we find the closing bracket.
+         while 1:
+             # If we've reached the closing bracket, the set is
+             # complete.
+             tok = g.next()
+             if tok[0] == tokenize.OP and tok[1] == "]":
+                 break
+             # If this is not the first element of the set, there should
+             # be a comma before the next element.
+             if elements:
+                 if tok[0] != tokenize.OP or tok[1] != ",":
+                     invalid(tok)
+                 tok = g.next()
+             # The next token should be a string constant.
+             if tok[0] != tokenize.STRING:
+                 invalid(tok)
+             # Parse the string constant.
+             v = eval(tok[1])
+             elements.append(self.GetContainedField().ParseTextValue(v))
+ 
+         # There should not be any tokens left over.
+         tok = g.next()
+         if not tokenize.ISEOF(tok[0]):
+             invalid(tok)
+ 
+         return self.Validate(elements)
+         
+                        
      def ParseFormValue(self, request, name, attachment_store):
  
          values = []
  
          contained_field = self.GetContainedField()
Index: qm/test/cmdline.py
===================================================================
RCS file: /home/sc/Repository/qm/qm/test/cmdline.py,v
retrieving revision 1.95
diff -c -5 -p -r1.95 cmdline.py
*** qm/test/cmdline.py	20 Aug 2003 19:43:28 -0000	1.95
--- qm/test/cmdline.py	8 Sep 2003 06:45:23 -0000
*************** class QMTest:
*** 274,284 ****
  
      attribute_option_spec = (
          "a",
          "attribute",
          "KEY=VALUE",
!         "Set a database attribute."
          )
  
      extension_kind_option_spec = (
          "k",
          "kind",
--- 274,284 ----
  
      attribute_option_spec = (
          "a",
          "attribute",
          "KEY=VALUE",
!         "Set an attribute of the extension class."
          )
  
      extension_kind_option_spec = (
          "k",
          "kind",
Index: share/diagnostics/common.txt
===================================================================
RCS file: /home/sc/Repository/qm/share/diagnostics/common.txt,v
retrieving revision 1.21
diff -c -5 -p -r1.21 common.txt
*** share/diagnostics/common.txt	14 Apr 2003 06:06:40 -0000	1.21
--- share/diagnostics/common.txt	8 Sep 2003 06:45:23 -0000
*************** The user name or password you entered is
*** 79,88 ****
--- 79,94 ----
  
  @ invalid property
  The property '%(error)s' is invalid.  Use the form 'NAME=VALUE' to
  specify properties.  
  
+ @ invalid set value
+ The set value provided could not be parsed.  The invalid part of the
+ value is "%(start)s".
+ 
+ A valid set value has the form "[ 'value1', 'value2', ... ]".
+ 
  @ missing command
  Specify a command.
  
  @ sendmail error
  Could not execute your mail transport agent, `%(sendmail_path)s'.



More information about the qmtest mailing list