1 # -*- coding: utf-8 -*-
5 from itertools import izip
30 for prop in pass_throughs:
31 globals()[prop] = getattr(csv, prop)
34 def _stringify(s, encoding, errors):
37 if isinstance(s, unicode):
38 return s.encode(encoding, errors)
39 elif isinstance(s, numbers.Number):
40 pass # let csv.QUOTE_NONNUMERIC do its thing.
41 elif not isinstance(s, str):
46 def _stringify_list(l, encoding, errors='strict'):
48 return [_stringify(s, encoding, errors) for s in iter(l)]
49 except TypeError as e:
50 raise csv.Error(str(e))
53 def _unicodify(s, encoding):
56 if isinstance(s, (unicode, int, float)):
58 elif isinstance(s, str):
59 return s.decode(encoding)
63 class UnicodeWriter(object):
66 >>> from cStringIO import StringIO
68 >>> w = unicodecsv.writer(f, encoding='utf-8')
69 >>> w.writerow((u'é', u'ñ'))
71 >>> r = unicodecsv.reader(f, encoding='utf-8')
78 def __init__(self, f, dialect=csv.excel, encoding='utf-8', errors='strict',
80 self.encoding = encoding
81 self.writer = csv.writer(f, dialect, *args, **kwds)
82 self.encoding_errors = errors
84 def writerow(self, row):
85 return self.writer.writerow(
86 _stringify_list(row, self.encoding, self.encoding_errors))
88 def writerows(self, rows):
94 return self.writer.dialect
95 writer = UnicodeWriter
98 class UnicodeReader(object):
99 def __init__(self, f, dialect=None, encoding='utf-8', errors='strict',
102 format_params = ['delimiter', 'doublequote', 'escapechar',
103 'lineterminator', 'quotechar', 'quoting',
107 if not any([kwd_name in format_params
108 for kwd_name in kwds.keys()]):
110 self.reader = csv.reader(f, dialect, **kwds)
111 self.encoding = encoding
112 self.encoding_errors = errors
113 self._parse_numerics = bool(
114 self.dialect.quoting & csv.QUOTE_NONNUMERIC)
117 row = self.reader.next()
118 encoding = self.encoding
119 encoding_errors = self.encoding_errors
121 if self._parse_numerics:
123 return [(value if isinstance(value, float_) else
124 unicode_(value, encoding, encoding_errors))
127 return [unicode_(value, encoding, encoding_errors)
135 return self.reader.dialect
139 return self.reader.line_num
140 reader = UnicodeReader
143 class DictWriter(csv.DictWriter):
145 >>> from cStringIO import StringIO
147 >>> w = DictWriter(f, ['a', u'ñ', 'b'], restval=u'î')
148 >>> w.writerow({'a':'1', u'ñ':'2'})
149 >>> w.writerow({'a':'1', u'ñ':'2', 'b':u'ø'})
150 >>> w.writerow({'a':u'é', u'ñ':'2'})
152 >>> r = DictReader(f, fieldnames=['a', u'ñ'], restkey='r')
153 >>> r.next() == {'a': u'1', u'ñ':'2', 'r': [u'î']}
155 >>> r.next() == {'a': u'1', u'ñ':'2', 'r': [u'\xc3\xb8']}
157 >>> r.next() == {'a': u'\xc3\xa9', u'ñ':'2', 'r': [u'\xc3\xae']}
160 def __init__(self, csvfile, fieldnames, restval='',
161 extrasaction='raise', dialect='excel', encoding='utf-8',
162 errors='strict', *args, **kwds):
163 self.encoding = encoding
164 csv.DictWriter.__init__(self, csvfile, fieldnames, restval,
165 extrasaction, dialect, *args, **kwds)
166 self.writer = UnicodeWriter(csvfile, dialect, encoding=encoding,
167 errors=errors, *args, **kwds)
168 self.encoding_errors = errors
170 def writeheader(self):
171 header = dict(zip(self.fieldnames, self.fieldnames))
172 self.writerow(header)
175 class DictReader(csv.DictReader):
177 >>> from cStringIO import StringIO
179 >>> w = DictWriter(f, fieldnames=['name', 'place'])
180 >>> w.writerow({'name': 'Cary Grant', 'place': 'hollywood'})
181 >>> w.writerow({'name': 'Nathan Brillstone', 'place': u'øLand'})
182 >>> w.writerow({'name': u'Will ø. Unicoder', 'place': u'éSpandland'})
184 >>> r = DictReader(f, fieldnames=['name', 'place'])
185 >>> print r.next() == {'name': 'Cary Grant', 'place': 'hollywood'}
187 >>> print r.next() == {'name': 'Nathan Brillstone', 'place': u'øLand'}
189 >>> print r.next() == {'name': u'Will ø. Unicoder', 'place': u'éSpandland'}
192 def __init__(self, csvfile, fieldnames=None, restkey=None, restval=None,
193 dialect='excel', encoding='utf-8', errors='strict', *args,
195 if fieldnames is not None:
196 fieldnames = _stringify_list(fieldnames, encoding)
197 csv.DictReader.__init__(self, csvfile, fieldnames, restkey, restval,
198 dialect, *args, **kwds)
199 self.reader = UnicodeReader(csvfile, dialect, encoding=encoding,
200 errors=errors, *args, **kwds)
201 if fieldnames is None and not hasattr(csv.DictReader, 'fieldnames'):
202 # Python 2.5 fieldnames workaround.
203 # See http://bugs.python.org/issue3436
204 reader = UnicodeReader(csvfile, dialect, encoding=encoding,
206 self.fieldnames = _stringify_list(reader.next(), reader.encoding)
208 if self.fieldnames is not None:
209 self.unicode_fieldnames = [_unicodify(f, encoding) for f in
212 self.unicode_fieldnames = []
214 self.unicode_restkey = _unicodify(restkey, encoding)
217 row = csv.DictReader.next(self)
218 result = dict((uni_key, row[str_key]) for (str_key, uni_key) in
219 izip(self.fieldnames, self.unicode_fieldnames))
220 rest = row.get(self.restkey)
222 result[self.unicode_restkey] = rest