Commits

Olemis Lang committed 388efe9

GViz QL: Prototype for FORMAT clause. Test cases for bool patterns and no PyICU ... [ok]

Comments (0)

Files changed (2)

trac-dev/gviz/tracgviz/gvizql.py

   _PROPS = {'idx_syntax' : 9, 'idx_eval': 8, 'keyw' : 'format'}
   KEYWORDS = ('format',)
 
+  @property
+  def PyICU(self):
+    r"""Load PyICU module. Dynamically detect if installed at run time.
+    """
+    try:
+      return __import__('PyICU')
+    except ImportError:
+      return None
+
   def __init__(self, seq):
     r"""Initialize this clause with a sequence of formatting expressions
     """
       seq = Sequence([seq])
     self.fmt = seq
 
+  @staticmethod
+  def format_value(value, coltype, pattern):
+    r"""Format value of given data type according to some formatting pattern.
+    """
+    if coltype == 'boolean':
+      idx = 0 if bool(value) else 1
+      return pattern[idx]
+    elif coltype in ('date', 'timeofday', 'datetime'):
+      # FIXME: ICU SimpleDateFormat
+      return str(value)
+    elif coltype == 'number':
+      # FIXME: ICU DecimalFormat
+      return str(value)
+    else:
+      raise GVizRuntimeError("Format not supported for %s type" % (coltype,))
+
   def transform(self, schema, data):
-    r"""Annotate result set with formatted values.
+    r"""Annotate result set with formatted values. In practice this means
+    to transform data set into (value, formatted_value) tuples.
     """
-    self.unsupported()
+    patterns = dict(self.fmt)
+
+    # Special step for boolean patterns
+    for col in schema:
+      if col[0] in patterns:
+        if col[1] == 'boolean':
+          p = patterns[col[0]].rsplit(':', 1)
+          if len(p) != 2:
+            raise GVizRuntimeError("Invalid formatting pattern '%s'" % (p,))
+          else:
+            patterns[col[0]] = p
+        elif col[1] in ('number', 'date', 'timeofday', 'datetime'):
+          if self.PyICU is None:
+            raise GVizRuntimeError("PyICU needed to format '%s' '%s'" % col[:2])
+        else:
+          raise GVizRuntimeError("Format not supported for %s type" % (col[1],))
+
+    #raise ValueError('\n'.join([str(patterns), str(schema), str(list(data))]))
+    new_data = ([val if val is None or col[0] not in patterns else \
+                        (val, self.format_value(val, col[1], patterns[col[0]]))\
+                    for val, col in izip(row, schema)] for row in data)
+    return schema, new_data
 
 class GVizOptionsClause(GVizQLClauseHandler):
   _PROPS = {'idx_syntax' : 10, 'idx_eval': 9, 'keyw' : 'options'}

trac-dev/gviz/tracgviz/testing/test_gvizql.py

          upper(dept) = MARKETING
 
       """,
+  'Parsing FORMAT (no ICU)' : r"""
+
+      Hack to ensure PyICU won't be imported
+      >>> import sys
+      >>> sys.modules['PyICU'] = None
+
+      Boolean format patterns should still work
+      >>> parse("format isSenior 'Yes!:Not yet'", 'fmt')
+      *****
+      * Tokens
+      *****
+      Token.Keyword.Reserved format
+      Token.Name.Variable isSenior
+      Token.Literal.String.Single 'Yes!:Not yet'
+      *****
+      * Parsing
+      *****
+      [('isSenior', 'Yes!:Not yet')]
+      *****
+      * Result
+      *****
+      = Columns =
+      name string
+      dept string
+      lunchTime timeofday
+      salary number
+      hireDate date
+      age number
+      isSenior boolean
+      seniorityStartTime datetime
+      = Row =
+         name = John
+         dept = Eng
+         lunchTime = 12:00:00
+         salary = 1000
+         hireDate = 2005-03-19
+         age = 35
+         isSenior = (True, 'Yes!')
+         seniorityStartTime = 2007-12-02 15:56:00
+      = Row =
+         name = Dave
+         dept = Eng
+         lunchTime = 12:00:00
+         salary = 500
+         hireDate = 2006-04-19
+         age = 27
+         isSenior = (False, 'Not yet')
+         seniorityStartTime = None
+      = Row =
+         name = Sally
+         dept = Eng
+         lunchTime = 13:00:00
+         salary = 600
+         hireDate = 2005-10-10
+         age = 30
+         isSenior = (False, 'Not yet')
+         seniorityStartTime = None
+      = Row =
+         name = Ben
+         dept = Sales
+         lunchTime = 12:00:00
+         salary = 400
+         hireDate = 2002-10-10
+         age = 32
+         isSenior = (True, 'Yes!')
+         seniorityStartTime = 2005-03-09 12:30:00
+      = Row =
+         name = Dana
+         dept = Sales
+         lunchTime = 12:00:00
+         salary = 350
+         hireDate = 2004-09-08
+         age = 25
+         isSenior = (False, 'Not yet')
+         seniorityStartTime = None
+      = Row =
+         name = Mike
+         dept = Marketing
+         lunchTime = 13:00:00
+         salary = 800
+         hireDate = 2005-01-10
+         age = 24
+         isSenior = (True, 'Yes!')
+         seniorityStartTime = 2007-12-30 14:40:00
+
+      Number format patterns require PyICU
+      >>> parse("  format  salary   '#,##0.00' ", 'fmt')
+      *****
+      * Tokens
+      *****
+      Token.Keyword.Reserved format
+      Token.Name.Variable salary
+      Token.Literal.String.Single '#,##0.00'
+      *****
+      * Parsing
+      *****
+      [('salary', '#,##0.00')]
+      *****
+      * Result
+      *****
+      GVizRuntimeError  :  PyICU needed to format 'salary' 'number'
+
+      Date format patterns require PyICU
+      >>> parse(r'''format hireDate "EEE, MMM d, ''yy" ''', 'fmt')
+      *****
+      * Tokens
+      *****
+      Token.Keyword.Reserved format
+      Token.Name.Variable hireDate
+      Token.Literal.String.Double "EEE, MMM d, ''yy"
+      *****
+      * Parsing
+      *****
+      [('hireDate', "EEE, MMM d, ''yy")]
+      *****
+      * Result
+      *****
+      GVizRuntimeError  :  PyICU needed to format 'hireDate' 'date'
+
+      Datetime format patterns require PyICU
+      >>> parse(r'''format seniorityStartTime "yyyy.MM.dd G 'at' HH:mm:ss" ''',
+      ...       'fmt')
+      *****
+      * Tokens
+      *****
+      Token.Keyword.Reserved format
+      Token.Name.Variable seniorityStartTime
+      Token.Literal.String.Double "yyyy.MM.dd G 'at' HH:mm:ss"
+      *****
+      * Parsing
+      *****
+      [('seniorityStartTime', "yyyy.MM.dd G 'at' HH:mm:ss")]
+      *****
+      * Result
+      *****
+      GVizRuntimeError  :  PyICU needed to format 'seniorityStartTime' 'datetime'
+
+      Time format patterns require PyICU
+      >>> parse("  format lunchTime 'K:mm a' ", 'fmt')
+      *****
+      * Tokens
+      *****
+      Token.Keyword.Reserved format
+      Token.Name.Variable lunchTime
+      Token.Literal.String.Single 'K:mm a'
+      *****
+      * Parsing
+      *****
+      [('lunchTime', 'K:mm a')]
+      *****
+      * Result
+      *****
+      GVizRuntimeError  :  PyICU needed to format 'lunchTime' 'timeofday'
+
+      Import hack not needed any more . Back to normal
+      >>> del sys.modules['PyICU']
+      """,
   'Parsing FORMAT (simple)' : r"""
       >>> parse("  format  salary   '#,##0.00' ", 'fmt')
       *****
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.