11import csv
22from robot .api import logger
33from .version import VERSION
4+ import sys
5+
6+ if sys .version_info .major >= 3 :
7+ from io import StringIO as IO
8+ else :
9+ from io import BytesIO as IO
410
511__version__ = VERSION
612
@@ -11,36 +17,47 @@ class CSVLibrary(object):
1117 ROBOT_LIBRARY_SCOPE = 'GLOBAL'
1218
1319 @staticmethod
14- def _open_csv_file_for_read (filename , csv_reader = csv .reader , line_numbers = None , ** kwargs ):
20+ def _reader (to_read , csv_reader = csv .reader , line_numbers = None , ** kwargs ):
21+ reader = csv_reader (to_read , ** kwargs )
22+ try :
23+ for line_number , row in enumerate (reader ):
24+ if line_numbers is None :
25+ yield row
26+ elif isinstance (line_numbers , list ) and line_number in line_numbers :
27+ yield row
28+ line_numbers .remove (line_number )
29+ if len (line_numbers ) == 0 :
30+ break
31+ except csv .Error as e :
32+ logger .error ('line %d: %s' % (reader .line_num , e ))
33+
34+ def _read_csv (self , csv_handler , csv_reader = csv .reader , line_numbers = None , ** kwargs ):
1535 if line_numbers is not None and isinstance (line_numbers , list ):
16- line_numbers = map (int , line_numbers )
36+ line_numbers = list (map (int , line_numbers ))
37+
38+ return [row for row in self ._reader (csv_handler , csv_reader , line_numbers , ** kwargs )]
39+
40+ def _open_csv_file_for_read (self , filename , csv_reader = csv .reader , line_numbers = None , ** kwargs ):
1741 with open (filename , 'r' ) as csv_handler :
18- reader = csv_reader (csv_handler , ** kwargs )
19- try :
20- for line_number , row in enumerate (reader ):
21- if line_numbers is None :
22- yield row
23- elif isinstance (line_numbers , list ):
24- if line_number in line_numbers :
25- yield row
26- line_numbers .remove (line_number )
27- if len (line_numbers ) == 0 :
28- break
29- except csv .Error as e :
30- logger .error ('file %s, line %d: %s' % (filename , reader .line_num , e ))
42+ return self ._read_csv (csv_handler , csv_reader , line_numbers , ** kwargs )
3143
3244 @staticmethod
33- def _open_csv_file_for_write (filename , data , csv_writer = csv .writer , ** kwargs ):
34- with open (filename , 'ab' ) as csv_handler :
35- writer = csv_writer (csv_handler , ** kwargs )
36- try :
37- if isinstance (writer , csv .DictWriter ) and 'fieldnames' in kwargs .keys ():
38- csv_handler .truncate ()
39- writer .writeheader ()
40-
41- writer .writerows (data )
42- except csv .Error as e :
43- logger .error ('file %s, line %d: %s' % (filename , writer .line_num , e ))
45+ def _write_csv (csv_handler , data , csv_writer = csv .writer , ** kwargs ):
46+ if 'fieldnames' not in kwargs .keys () and isinstance (data [0 ], dict ):
47+ kwargs ['fieldnames' ] = data [0 ].keys ()
48+
49+ writer = csv_writer (csv_handler , ** kwargs )
50+ try :
51+ if isinstance (writer , csv .DictWriter ) and csv_handler .tell () == 0 :
52+ writer .writeheader ()
53+
54+ writer .writerows (data )
55+ except csv .Error as e :
56+ logger .error ('%s' % e )
57+
58+ def _open_csv_file_for_write (self , filename , data , csv_writer = csv .writer , ** kwargs ):
59+ with open (filename , 'a' ) as csv_handler :
60+ self ._write_csv (csv_handler , data , csv_writer , ** kwargs )
4461
4562 @staticmethod
4663 def empty_csv_file (filename ):
@@ -69,7 +86,31 @@ def read_csv_file_to_list(self, filename, delimiter=',', **kwargs):
6986 delimiter = str (delimiter ),
7087 ** kwargs
7188 )
72- return [tuple (row ) for row in csv_list ]
89+ return csv_list
90+
91+ def read_csv_string_to_list (self , csv_string , delimiter = ',' , ** kwargs ):
92+ """Read CSV string and return its content as a Python list of tuples.
93+
94+ - ``csv_string``: name of csv file
95+ - ``delimiter``: Default: `,`
96+ - ``line_numbers``: List of linenumbers to read. Default None
97+ - ``quoting`` (int):
98+ _0_: QUOTE_MINIMAL
99+ _1_: QUOTE_ALL
100+ _2_: QUOTE_NONNUMERIC
101+ _3_: QUOTE_NONE
102+ """
103+ if sys .version_info .major < 3 :
104+ csv_string = csv_string .encode ("utf-8" )
105+
106+ with IO (csv_string ) as csv_handler :
107+ csv_list = self ._read_csv (
108+ csv_handler ,
109+ csv_reader = csv .reader ,
110+ delimiter = str (delimiter ),
111+ ** kwargs
112+ )
113+ return csv_list
73114
74115 def read_csv_file_to_associative (self , filename , delimiter = ',' , fieldnames = None , ** kwargs ):
75116 """Read CSV file and return its content as a Python list of dictionaries.
@@ -84,14 +125,40 @@ def read_csv_file_to_associative(self, filename, delimiter=',', fieldnames=None,
84125 _2_: QUOTE_NONNUMERIC
85126 _3_: QUOTE_NONE
86127 """
128+ kwargs ['fieldnames' ] = fieldnames
87129 csv_dict = self ._open_csv_file_for_read (
88130 filename ,
89131 csv_reader = csv .DictReader ,
90132 delimiter = str (delimiter ),
91- fieldnames = fieldnames ,
92133 ** kwargs
93134 )
94- return [item for item in csv_dict ]
135+ return csv_dict
136+
137+ def read_csv_string_to_associative (self , csv_string , delimiter = ',' , fieldnames = None , ** kwargs ):
138+ """Read CSV from string and return its content as a Python list of dictionaries.
139+
140+ - ``csv_string``: csv formatted string
141+ - ``delimiter``: Default: `,`
142+ - ``fieldnames``: list of column names
143+ - ``line_numbers``: List of linenumbers to read. Default None
144+ - ``quoting`` (int):
145+ _0_: QUOTE_MINIMAL
146+ _1_: QUOTE_ALL
147+ _2_: QUOTE_NONNUMERIC
148+ _3_: QUOTE_NONE
149+ """
150+ if sys .version_info .major < 3 :
151+ csv_string = csv_string .encode ("utf-8" )
152+
153+ with IO (csv_string ) as csv_handler :
154+ csv_dict = self ._read_csv (
155+ csv_handler ,
156+ csv_reader = csv .DictReader ,
157+ delimiter = str (delimiter ),
158+ fieldnames = fieldnames ,
159+ ** kwargs
160+ )
161+ return csv_dict
95162
96163 def append_to_csv_file (self , filename , data , ** kwargs ):
97164 """This keyword will append data to a new or existing CSV file.
@@ -104,9 +171,56 @@ def append_to_csv_file(self, filename, data, **kwargs):
104171 _2_: QUOTE_NONNUMERIC
105172 _3_: QUOTE_NONE
106173 """
107- if isinstance (data [0 ], dict ):
108- data = map (lambda row : row .items (), data )
109- self ._open_csv_file_for_write (filename , data = data , csv_writer = csv .writer , ** kwargs )
174+
175+ if isinstance (data , dict ):
176+ data = [data ]
177+
178+ fieldnames = self ._open_csv_file_for_read (
179+ filename ,
180+ csv_reader = csv .reader ,
181+ line_numbers = [0 ],
182+ ** kwargs
183+ )[0 ]
184+
185+ self ._open_csv_file_for_write (
186+ filename ,
187+ data = data ,
188+ csv_writer = csv .DictWriter ,
189+ fieldnames = fieldnames ,
190+ ** kwargs
191+ )
192+
193+ def append_to_csv_string (self , csv_string , data , ** kwargs ):
194+ """This keyword will append data to a new or existing CSV string.
195+
196+ - ``csv_string``: csv formatted string
197+ - ``data``: iterable(e.g. list or tuple) data.
198+ - ``quoting`` (int):
199+ _0_: QUOTE_MINIMAL
200+ _1_: QUOTE_ALL
201+ _2_: QUOTE_NONNUMERIC
202+ _3_: QUOTE_NONE
203+ """
204+ if isinstance (data , dict ):
205+ data = [data ]
206+
207+ if 'lineterminator' not in kwargs .keys ():
208+ kwargs ['lineterminator' ] = '\n '
209+
210+ if sys .version_info .major < 3 :
211+ csv_string = csv_string .encode ("utf-8" )
212+
213+ with IO (csv_string ) as csv_handler :
214+ fieldnames = self ._read_csv (
215+ csv_handler ,
216+ csv_reader = csv .reader ,
217+ ** kwargs
218+ )[0 ]
219+
220+ kwargs ['fieldnames' ] = fieldnames
221+
222+ self ._write_csv (csv_handler , data , csv_writer = csv .DictWriter , ** kwargs )
223+ return csv_handler .getvalue ()
110224
111225 def csv_file_from_associative (self , filename , data , fieldnames = None , delimiter = ',' , ** kwargs ):
112226 """This keyword will create new file
@@ -121,12 +235,36 @@ def csv_file_from_associative(self, filename, data, fieldnames=None, delimiter='
121235 _2_: QUOTE_NONNUMERIC
122236 _3_: QUOTE_NONE
123237 """
124- fieldnames = fieldnames or data [0 ].keys ()
238+ kwargs ['fieldnames' ] = fieldnames or data [0 ].keys ()
239+
125240 self ._open_csv_file_for_write (
126241 filename ,
127242 data = data ,
128243 csv_writer = csv .DictWriter ,
129244 delimiter = str (delimiter ),
130- fieldnames = fieldnames ,
131245 ** kwargs
132246 )
247+
248+ def csv_string_from_associative (self , data , fieldnames = None , delimiter = ',' , ** kwargs ):
249+ """This keyword will create new file
250+
251+ - ``data``: iterable(e.g. list or tuple) data.
252+ - ``fieldnames``: list of column names
253+ - ``delimiter``: Default: `,`
254+ - ``quoting`` (int):
255+ _0_: QUOTE_MINIMAL
256+ _1_: QUOTE_ALL
257+ _2_: QUOTE_NONNUMERIC
258+ _3_: QUOTE_NONE
259+ """
260+ if isinstance (data , dict ):
261+ data = [data ]
262+
263+ kwargs ['fieldnames' ] = fieldnames or data [0 ].keys ()
264+ if 'lineterminator' not in kwargs .keys ():
265+ kwargs ['lineterminator' ] = '\n '
266+ kwargs ['delimiter' ] = delimiter
267+
268+ with IO () as csv_handler :
269+ self ._write_csv (csv_handler , data , csv_writer = csv .DictWriter , ** kwargs )
270+ return csv_handler .getvalue ()
0 commit comments