blob: a3ea4e20a6369226ad8bfd74351a4d1f37d5e69d [file] [log] [blame]
Skip Montanarob4a04172003-03-20 23:29:12 +00001from _csv import Error, __version__, writer, reader, register_dialect, \
2 unregister_dialect, get_dialect, list_dialects, \
3 QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \
4 __doc__
5
6__all__ = [ "QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
7 "Error", "Dialect", "excel", "excel_tab", "reader", "writer",
8 "register_dialect", "get_dialect", "list_dialects",
9 "unregister_dialect", "__version__", "DictReader", "DictWriter" ]
10
11class Dialect:
12 _name = ""
13 _valid = False
14 # placeholders
15 delimiter = None
16 quotechar = None
17 escapechar = None
18 doublequote = None
19 skipinitialspace = None
20 lineterminator = None
21 quoting = None
22
23 def __init__(self):
24 if self.__class__ != Dialect:
25 self._valid = True
26 errors = self._validate()
27 if errors != []:
28 raise Error, "Dialect did not validate: %s" % ", ".join(errors)
29
30 def _validate(self):
31 errors = []
32 if not self._valid:
33 errors.append("can't directly instantiate Dialect class")
34
35 if self.delimiter is None:
36 errors.append("delimiter character not set")
37 elif (not isinstance(self.delimiter, str) or
38 len(self.delimiter) > 1):
39 errors.append("delimiter must be one-character string")
40
41 if self.quotechar is None:
42 if self.quoting != QUOTE_NONE:
43 errors.append("quotechar not set")
44 elif (not isinstance(self.quotechar, str) or
45 len(self.quotechar) > 1):
46 errors.append("quotechar must be one-character string")
47
48 if self.lineterminator is None:
49 errors.append("lineterminator not set")
50 elif not isinstance(self.lineterminator, str):
51 errors.append("lineterminator must be a string")
52
53 if self.doublequote not in (True, False):
54 errors.append("doublequote parameter must be True or False")
55
56 if self.skipinitialspace not in (True, False):
57 errors.append("skipinitialspace parameter must be True or False")
58
59 if self.quoting is None:
60 errors.append("quoting parameter not set")
61
62 if self.quoting is QUOTE_NONE:
63 if (not isinstance(self.escapechar, (unicode, str)) or
64 len(self.escapechar) > 1):
65 errors.append("escapechar must be a one-character string or unicode object")
66
67 return errors
68
69class excel(Dialect):
70 delimiter = ','
71 quotechar = '"'
72 doublequote = True
73 skipinitialspace = False
74 lineterminator = '\r\n'
75 quoting = QUOTE_MINIMAL
76register_dialect("excel", excel)
77
78class excel_tab(excel):
79 delimiter = '\t'
80register_dialect("excel-tab", excel_tab)
81
82
83class DictReader:
84 def __init__(self, f, fieldnames, restkey=None, restval=None,
85 dialect="excel", *args):
86 self.fieldnames = fieldnames # list of keys for the dict
87 self.restkey = restkey # key to catch long rows
88 self.restval = restval # default value for short rows
89 self.reader = reader(f, dialect, *args)
90
91 def __iter__(self):
92 return self
93
94 def next(self):
95 row = self.reader.next()
96 # unlike the basic reader, we prefer not to return blanks,
97 # because we will typically wind up with a dict full of None
98 # values
99 while row == []:
100 row = self.reader.next()
101 d = dict(zip(self.fieldnames, row))
102 lf = len(self.fieldnames)
103 lr = len(row)
104 if lf < lr:
105 d[self.restkey] = row[lf:]
106 elif lf > lr:
107 for key in self.fieldnames[lr:]:
108 d[key] = self.restval
109 return d
110
111
112class DictWriter:
113 def __init__(self, f, fieldnames, restval="", extrasaction="raise",
114 dialect="excel", *args):
115 self.fieldnames = fieldnames # list of keys for the dict
116 self.restval = restval # for writing short dicts
117 if extrasaction.lower() not in ("raise", "ignore"):
118 raise ValueError, \
119 ("extrasaction (%s) must be 'raise' or 'ignore'" %
120 extrasaction)
121 self.extrasaction = extrasaction
122 self.writer = writer(f, dialect, *args)
123
124 def _dict_to_list(self, rowdict):
125 if self.extrasaction == "raise":
126 for k in rowdict.keys():
127 if k not in self.fieldnames:
128 raise ValueError, "dict contains fields not in fieldnames"
129 return [rowdict.get(key, self.restval) for key in self.fieldnames]
130
131 def writerow(self, rowdict):
132 return self.writer.writerow(self._dict_to_list(rowdict))
133
134 def writerows(self, rowdicts):
135 rows = []
136 for rowdict in rowdicts:
137 rows.append(self._dict_to_list(rowdict))
138 return self.writer.writerows(rows)