changeset 3309:4c14c613e275

new csv parser, uses data browser widget and supports much more, is backward compatible
author Johannes Berg <johannes AT sipsolutions DOT net>
date Tue, 18 Mar 2008 21:44:25 +0100
parents 6eb96b8664b0
children d67113dc5a89
files MoinMoin/parser/text_csv.py
diffstat 1 files changed, 136 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/parser/text_csv.py	Tue Mar 18 20:58:57 2008 +0100
+++ b/MoinMoin/parser/text_csv.py	Tue Mar 18 21:44:25 2008 +0100
@@ -1,74 +1,154 @@
-# -*- coding: iso-8859-1 -*-
+# -*- coding: utf-8 -*-
 """
     MoinMoin - Parser for CSV data
 
-    This parser lacks to flexibility to read arbitary csv dialects.
+    This parser uses the databrowser widget to display the data.
 
-    Perhaps this should be rewritten using another CSV lib
-    because the standard module csv does not support unicode.
+    It supports the following parser arguments:
 
-    @copyright: 2004 Oliver Graf <ograf@bitart.de>, Alexander Schremmer
+     * delimiter/separator: the delimiter to use instead of ;
+     * quotechar: quoting character, default off, must be ascii!
+     * show: comma-separated list of columns to show only
+     * hide: comma-separated list of columns to hide
+     * autofilter: comma-separated list of columns to equip with
+                   auto-filter drop down
+     * name: name of the dataset
+     * link: comma separated list of columns that take links, separate
+             the link and the description with a space
+     * static_cols: comma-separated list of columns that are static
+                    and present in each row
+     * static_vals: comma-separated list of values for those static
+                    columns
+
+    The static column feature is only really useful if the dataset
+    postprocessed by some other plugin collecting data from multiple
+    wiki pages.
+
+    @copyright: 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
     @license: GNU GPL, see COPYING for details.
 """
 
-Dependencies = []
+from csv import reader
+
+from MoinMoin.util.dataset import TupleDataset, Column
+from MoinMoin.widget.browser import DataBrowserWidget
+from MoinMoin.wikiutil import escape
+
+
+Dependencies = ['time']
 
 class Parser:
-    """ Format CSV data as table
-    """
-
-    extensions = ['.csv']
+    extensions = ['.csvdata']
     Dependencies = []
 
     def __init__(self, raw, request, **kw):
-        """ Store the source text.
-        """
-        self.raw = raw
         self.request = request
-        self.form = request.form
-        self._ = request.getText
+        formatter = request.formatter
 
-        # parse extra arguments for excludes
-        self.exclude = []
-        self.separator = ';'
-        for arg in kw.get('format_args', '').split():
-            if arg[0] == '-':
-                try:
-                    idx = int(arg[1:])
-                except ValueError:
-                    pass
+        # workaround csv.reader deficiency by encoding to utf-8
+        data = raw.encode('utf-8').split('\n')
+
+        visible = None
+        hiddenindexes = []
+        hiddencols = []
+        autofiltercols = []
+        staticcols = []
+        staticvals = []
+        linkcols = []
+        delimiter = ';'
+        quotechar = '\x00' # can't be entered
+        name = None
+        hdr = reader([kw.get('format_args', '').strip().encode('utf-8')], delimiter=" ")
+        args = hdr.next()
+
+        for arg in args:
+            arg = arg.decode('utf-8')
+            try:
+                key, val = arg.split('=', 1)
+            except:
+                # handle compatibility with original 'csv' parser
+                if arg.startswith('-'):
+                    try:
+                        hiddenindexes.append(int(arg[1:]) - 1)
+                    except ValueError:
+                        pass
                 else:
-                    self.exclude.append(idx-1)
-            else:
-                self.separator = arg
+                    delimiter = arg.encode('utf-8')
+                continue
+            if key == 'separator' or key == 'delimiter':
+                delimiter = val.encode('utf-8')
+            if key == 'quotechar':
+                if val == val.encode('utf-8'):
+                    quotechar = val.encode('utf-8')
+            elif key == 'show':
+                visible = val.split(',')
+            elif key == 'hide':
+                hiddencols = val.split(',')
+            elif key == 'autofilter':
+                autofiltercols = val.split(',')
+            elif key == 'name':
+                name = val
+            elif key == 'static_cols':
+                staticcols = val.split(',')
+            elif key == 'static_vals':
+                staticvals = val.split(',')
+            elif key == 'link':
+                linkcols = val.split(',')
+
+        if len(staticcols) > len(staticvals):
+            staticvals.extend([''] * (len(staticcols)-len(staticvals)))
+        elif len(staticcols) < len(staticvals):
+            staticvals = staticvals[:len(staticcols)]
+
+        r = reader(data, delimiter=delimiter, quotechar=quotechar)
+        cols = map(lambda x: x.decode('utf-8'), r.next()) + staticcols
+
+        num_entry_cols = len(cols) - len(staticcols)
+
+        if not visible is None:
+            for col in cols:
+                if not col in visible:
+                    hiddencols.append(col)
+
+        linkparse = [False] * len(cols)
+
+        data = TupleDataset(name)
+        for colidx in range(len(cols)):
+            col = cols[colidx]
+            autofilter = col in autofiltercols
+            hidden = col in hiddencols or colidx in hiddenindexes
+            data.columns.append(Column(col, autofilter=autofilter, hidden=hidden))
+
+            linkparse[colidx] = col in linkcols
+
+        for row in r:
+            row = map(lambda x: x.decode('utf-8'), row)
+            if len(row) > num_entry_cols:
+                row = row[:num_entry_cols]
+            elif len(row) < num_entry_cols:
+                row.extend([''] * (num_entry_cols-len(row)))
+            row += staticvals
+            for colidx in range(len(row)):
+                item = row[colidx]
+                if linkparse[colidx]:
+                    try:
+                        url, item = item.split(' ', 1)
+                        if url == '':
+                            display = escape(item)
+                        else:
+                            display = ''.join([
+                                formatter.url(1, url=url),
+                                formatter.text(item),
+                                formatter.url(0)])
+                    except ValueError:
+                        display = escape(item)
+                else:
+                    display = escape(item)
+                row[colidx] = (display, item)
+            data.addRow(tuple(row))
+        self.data = data
 
     def format(self, formatter):
-        """ Parse and send the table.
-        """
-        lines = self.raw.split('\n')
-        if lines[0]:
-            # expect column headers in first line
-            first = 1
-        else:
-            # empty first line, no bold headers
-            first = 0
-            del lines[0]
-
-        self.request.write(formatter.table(1))
-        for line in lines:
-            self.request.write(formatter.table_row(1))
-            cells = line.split(self.separator)
-            for idx in range(len(cells)):
-                if idx in self.exclude:
-                    continue
-                self.request.write(formatter.table_cell(1))
-                if first:
-                    self.request.write(formatter.strong(1))
-                self.request.write(formatter.text(cells[idx]))
-                if first:
-                    self.request.write(formatter.strong(0))
-                self.request.write(formatter.table_cell(0))
-            self.request.write(formatter.table_row(0))
-            first = 0
-        self.request.write(formatter.table(0))
-
+        browser = DataBrowserWidget(self.request)
+        browser.setData(self.data)
+        self.request.write(browser.format())