~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/parser/text_csv.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mfrom: (0.9.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080622211713-fpo2zrq3s5dfecxg
Tags: 1.7.0-3
Simplify /etc/moin/wikilist format: "USER URL" (drop unneeded middle
CONFIG_DIR that was wrongly advertised as DATA_DIR).  Make
moin-mass-migrate handle both formats and warn about deprecation of
the old one.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    MoinMoin - Parser for CSV data
 
4
 
 
5
    This parser uses the databrowser widget to display the data.
 
6
 
 
7
    It supports the following parser arguments:
 
8
 
 
9
     * delimiter/separator: the delimiter to use instead of ;
 
10
     * quotechar: quoting character, default off, must be ascii!
 
11
     * show: comma-separated list of columns to show only
 
12
     * hide: comma-separated list of columns to hide
 
13
     * autofilter: comma-separated list of columns to equip with
 
14
                   auto-filter drop down
 
15
     * name: name of the dataset
 
16
     * link: comma separated list of columns that take links, separate
 
17
             the link and the description with a space
 
18
     * static_cols: comma-separated list of columns that are static
 
19
                    and present in each row
 
20
     * static_vals: comma-separated list of values for those static
 
21
                    columns
 
22
 
 
23
    The static column feature is only really useful if the dataset
 
24
    postprocessed by some other plugin collecting data from multiple
 
25
    wiki pages.
 
26
 
 
27
    @copyright: 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
 
28
    @license: GNU GPL, see COPYING for details.
 
29
"""
 
30
 
 
31
from csv import reader, QUOTE_NONE, QUOTE_MINIMAL, Sniffer
 
32
from _csv import Error
 
33
 
 
34
from MoinMoin.util.dataset import TupleDataset, Column
 
35
from MoinMoin.widget.browser import DataBrowserWidget
 
36
from MoinMoin.wikiutil import escape
 
37
 
 
38
 
 
39
Dependencies = ['time']
 
40
 
 
41
class Parser:
 
42
    extensions = ['.csv']
 
43
    Dependencies = []
 
44
 
 
45
    def _read_rows(self, r):
 
46
        if self._first_row is not None:
 
47
            yield self._first_row
 
48
        for row in r:
 
49
            yield row
 
50
 
 
51
    def __init__(self, raw, request, **kw):
 
52
        self.request = request
 
53
        self._first_row = None
 
54
        formatter = request.formatter
 
55
 
 
56
        # workaround csv.reader deficiency by encoding to utf-8
 
57
        # removes empty lines in front of the csv table
 
58
        data = raw.encode('utf-8').lstrip('\n').split('\n')
 
59
 
 
60
        delimiter = ';'
 
61
        # Previous versions of this parser have used only the delimiter ";" (by default).
 
62
        # This version now tries to sniff the delimiter from the list preferred_delimiters
 
63
        # Although the Python csv sniffer had quite some changes from py 2.3 to 2.5.1, we try
 
64
        # to avoid problems for the case it does not find a delimiter in some given data.
 
65
        # Newer versions of the sniffer do raise an _csv.Error while older versions do
 
66
        # return a whitespace as delimiter.
 
67
        if data[0]:
 
68
            try:
 
69
                preferred_delimiters = [',', '\t', ';', ' ', ':']
 
70
                delimiter = Sniffer().sniff(data[0], preferred_delimiters).delimiter or ';'
 
71
            except Error:
 
72
                pass
 
73
 
 
74
        visible = None
 
75
        hiddenindexes = []
 
76
        hiddencols = []
 
77
        autofiltercols = []
 
78
        staticcols = []
 
79
        staticvals = []
 
80
        linkcols = []
 
81
        quotechar = '\x00' # can't be entered
 
82
        quoting = QUOTE_NONE
 
83
        name = None
 
84
        hdr = reader([kw.get('format_args', '').strip().encode('utf-8')], delimiter=" ")
 
85
        args = hdr.next()
 
86
 
 
87
        for arg in args:
 
88
            arg = arg.decode('utf-8')
 
89
            try:
 
90
                key, val = arg.split('=', 1)
 
91
            except:
 
92
                # handle compatibility with original 'csv' parser
 
93
                if arg.startswith('-'):
 
94
                    try:
 
95
                        hiddenindexes.append(int(arg[1:]) - 1)
 
96
                    except ValueError:
 
97
                        pass
 
98
                else:
 
99
                    delimiter = arg.encode('utf-8')
 
100
                continue
 
101
            if key == 'separator' or key == 'delimiter':
 
102
                delimiter = val.encode('utf-8')
 
103
            if key == 'quotechar':
 
104
                if val == val.encode('utf-8'):
 
105
                    quotechar = val.encode('utf-8')
 
106
                    quoting = QUOTE_MINIMAL
 
107
            elif key == 'show':
 
108
                visible = val.split(',')
 
109
            elif key == 'hide':
 
110
                hiddencols = val.split(',')
 
111
            elif key == 'autofilter':
 
112
                autofiltercols = val.split(',')
 
113
            elif key == 'name':
 
114
                name = val
 
115
            elif key == 'static_cols':
 
116
                staticcols = val.split(',')
 
117
            elif key == 'static_vals':
 
118
                staticvals = val.split(',')
 
119
            elif key == 'link':
 
120
                linkcols = val.split(',')
 
121
 
 
122
        if len(staticcols) > len(staticvals):
 
123
            staticvals.extend([''] * (len(staticcols)-len(staticvals)))
 
124
        elif len(staticcols) < len(staticvals):
 
125
            staticvals = staticvals[:len(staticcols)]
 
126
 
 
127
        r = reader(data, delimiter=delimiter, quotechar=quotechar, quoting=quoting)
 
128
        cols = map(lambda x: x.decode('utf-8'), r.next()) + staticcols
 
129
 
 
130
        self._show_header = True
 
131
 
 
132
        if cols == staticcols:
 
133
            try:
 
134
                self._first_row = map(lambda x: x.decode('utf-8'), r.next())
 
135
                cols = [None] * len(self._first_row) + staticcols
 
136
                self._show_header = False
 
137
            except StopIteration:
 
138
                pass
 
139
 
 
140
        num_entry_cols = len(cols) - len(staticcols)
 
141
 
 
142
        if not visible is None:
 
143
            for col in cols:
 
144
                if not col in visible:
 
145
                    hiddencols.append(col)
 
146
 
 
147
        linkparse = [False] * len(cols)
 
148
 
 
149
        data = TupleDataset(name)
 
150
        for colidx in range(len(cols)):
 
151
            col = cols[colidx]
 
152
            autofilter = col in autofiltercols
 
153
            hidden = col in hiddencols or colidx in hiddenindexes
 
154
            data.columns.append(Column(col, autofilter=autofilter, hidden=hidden))
 
155
 
 
156
            linkparse[colidx] = col in linkcols
 
157
 
 
158
        for row in self._read_rows(r):
 
159
            row = map(lambda x: x.decode('utf-8'), row)
 
160
            if len(row) > num_entry_cols:
 
161
                row = row[:num_entry_cols]
 
162
            elif len(row) < num_entry_cols:
 
163
                row.extend([''] * (num_entry_cols-len(row)))
 
164
            row += staticvals
 
165
            for colidx in range(len(row)):
 
166
                item = row[colidx]
 
167
                if linkparse[colidx]:
 
168
                    try:
 
169
                        url, item = item.split(' ', 1)
 
170
                        if url == '':
 
171
                            display = escape(item)
 
172
                        else:
 
173
                            display = ''.join([
 
174
                                formatter.url(1, url=url),
 
175
                                formatter.text(item),
 
176
                                formatter.url(0)])
 
177
                    except ValueError:
 
178
                        display = escape(item)
 
179
                else:
 
180
                    display = escape(item)
 
181
                row[colidx] = (display, item)
 
182
            data.addRow(tuple(row))
 
183
        self.data = data
 
184
 
 
185
    def format(self, formatter):
 
186
        browser = DataBrowserWidget(self.request, show_header=self._show_header)
 
187
        browser.setData(self.data)
 
188
        self.request.write(browser.format())