1 |
1388
|
aaronmk
|
# CSV I/O
|
2 |
|
|
|
3 |
|
|
import csv
|
4 |
|
|
import StringIO
|
5 |
|
|
|
6 |
1444
|
aaronmk
|
import util
|
7 |
|
|
|
8 |
1442
|
aaronmk
|
delimiters = ',\t`'
|
9 |
|
|
|
10 |
1444
|
aaronmk
|
def stream_info(stream):
|
11 |
|
|
'''Automatically detects the dialect based on the header line
|
12 |
|
|
@return NamedTuple {header_line, dialect}'''
|
13 |
|
|
info = util.NamedTuple()
|
14 |
|
|
info.header_line = stream.readline()
|
15 |
|
|
sniffer = csv.Sniffer()
|
16 |
|
|
info.dialect = sniffer.sniff(info.header_line, delimiters)
|
17 |
|
|
info.dialect.doublequote = True # Sniffer doesn't turn this on by default
|
18 |
|
|
return info
|
19 |
|
|
|
20 |
1388
|
aaronmk
|
def reader_and_header(stream):
|
21 |
|
|
'''Automatically detects the dialect based on the header line
|
22 |
|
|
@return tuple (reader, header)'''
|
23 |
1444
|
aaronmk
|
info = stream_info(stream)
|
24 |
|
|
header = csv.reader(StringIO.StringIO(info.header_line),
|
25 |
|
|
info.dialect).next()
|
26 |
|
|
return (csv.reader(stream, info.dialect), header)
|
27 |
1446
|
aaronmk
|
|
28 |
|
|
##### csv modifications
|
29 |
|
|
|
30 |
|
|
# Note that these methods only work on *instances* of Dialect classes
|
31 |
|
|
csv.Dialect.__eq__ = lambda self, other: self.__dict__ == other.__dict__
|
32 |
|
|
csv.Dialect.__ne__ = lambda self, other: not (self == other)
|