blob: 6de93f38acddbb698fb5742f5b6925636eb15252 [file] [log] [blame]
Michael Walshced4eb02017-09-19 16:49:13 -05001#!/usr/bin/env python
2
3r"""
4Define variable manipulation functions.
5"""
6
7import os
Michael Walsh05c68d92017-09-20 16:36:37 -05008import re
Michael Walshced4eb02017-09-19 16:49:13 -05009
10try:
11 from robot.utils import DotDict
12except ImportError:
13 pass
14
15import collections
16
17import gen_print as gp
18import gen_misc as gm
19
20
21def create_var_dict(*args):
22
23 r"""
24 Create a dictionary whose keys/values are the arg names/arg values passed
25 to it and return it to the caller.
26
27 Note: The resulting dictionary will be ordered.
28
29 Description of argument(s):
30 *args An unlimited number of arguments to be processed.
31
32 Example use:
33
34 first_name = 'Steve'
35 last_name = 'Smith'
36 var_dict = create_var_dict(first_name, last_name)
37
38 gp.print_var(var_dict)
39
40 The print-out of the resulting var dictionary is:
41 var_dict:
42 var_dict[first_name]: Steve
43 var_dict[last_name]: Smith
44 """
45
46 try:
47 result_dict = collections.OrderedDict()
48 except AttributeError:
49 result_dict = DotDict()
50
51 arg_num = 1
52 for arg in args:
53 arg_name = gp.get_arg_name(None, arg_num, stack_frame_ix=2)
54 result_dict[arg_name] = arg
55 arg_num += 1
56
57 return result_dict
58
59
60default_record_delim = ':'
61default_key_val_delim = '.'
62
63
64def join_dict(dict,
65 record_delim=default_record_delim,
66 key_val_delim=default_key_val_delim):
67
68 r"""
69 Join a dictionary's keys and values into a string and return the string.
70
71 Description of argument(s):
72 dict The dictionary whose keys and values are
73 to be joined.
74 record_delim The delimiter to be used to separate
75 dictionary pairs in the resulting string.
76 key_val_delim The delimiter to be used to separate keys
77 from values in the resulting string.
78
79 Example use:
80
81 gp.print_var(var_dict)
82 str1 = join_dict(var_dict)
83 gp.pvar(str1)
84
85 Program output.
86 var_dict:
87 var_dict[first_name]: Steve
88 var_dict[last_name]: Smith
89 str1:
90 first_name.Steve:last_name.Smith
91 """
92
93 format_str = '%s' + key_val_delim + '%s'
94 return record_delim.join([format_str % (key, value) for (key, value) in
95 dict.items()])
96
97
98def split_to_dict(string,
99 record_delim=default_record_delim,
100 key_val_delim=default_key_val_delim):
101
102 r"""
103 Split a string into a dictionary and return it.
104
105 This function is the complement to join_dict.
106
107 Description of argument(s):
108 string The string to be split into a dictionary.
109 The string must have the proper delimiters
110 in it. A string created by join_dict
111 would qualify.
112 record_delim The delimiter to be used to separate
113 dictionary pairs in the input string.
114 key_val_delim The delimiter to be used to separate
115 keys/values in the input string.
116
117 Example use:
118
119 gp.print_var(str1)
120 new_dict = split_to_dict(str1)
121 gp.print_var(new_dict)
122
123
124 Program output.
125 str1:
126 first_name.Steve:last_name.Smith
127 new_dict:
128 new_dict[first_name]: Steve
129 new_dict[last_name]: Smith
130 """
131
132 try:
133 result_dict = collections.OrderedDict()
134 except AttributeError:
135 result_dict = DotDict()
136
137 raw_keys_values = string.split(record_delim)
138 for key_value in raw_keys_values:
139 key_value_list = key_value.split(key_val_delim)
140 try:
141 result_dict[key_value_list[0]] = key_value_list[1]
142 except IndexError:
143 result_dict[key_value_list[0]] = ""
144
145 return result_dict
146
147
148def create_file_path(file_name_dict,
149 dir_path="/tmp/",
150 file_suffix=""):
151
152 r"""
153 Create a file path using the given parameters and return it.
154
155 Description of argument(s):
156 file_name_dict A dictionary with keys/values which are to
157 appear as part of the file name.
158 dir_path The dir_path that is to appear as part of
159 the file name.
160 file_suffix A suffix to be included as part of the
161 file name.
162 """
163
164 dir_path = gm.add_trailing_slash(dir_path)
165 return dir_path + join_dict(file_name_dict) + file_suffix
166
167
168def parse_file_path(file_path):
169
170 r"""
171 Parse a file path created by create_file_path and return the result as a
172 dictionary.
173
174 This function is the complement to create_file_path.
175
176 Description of argument(s):
177 file_path The file_path.
178
179 Example use:
180 gp.pvar(boot_results_file_path)
181 file_path_data = parse_file_path(boot_results_file_path)
182 gp.pvar(file_path_data)
183
184 Program output.
185
186 boot_results_file_path:
187 /tmp/pgm_name.obmc_boot_test:openbmc_nickname.beye6:master_pid.2039:boot_re
188 sults
189 file_path_data:
190 file_path_data[dir_path]: /tmp/
191 file_path_data[pgm_name]: obmc_boot_test
192 file_path_data[openbmc_nickname]: beye6
193 file_path_data[master_pid]: 2039
194 file_path_data[boot_results]:
195 """
196
197 try:
198 result_dict = collections.OrderedDict()
199 except AttributeError:
200 result_dict = DotDict()
201
202 dir_path = os.path.dirname(file_path) + os.sep
203 file_path = os.path.basename(file_path)
204
205 result_dict['dir_path'] = dir_path
206
207 result_dict.update(split_to_dict(file_path))
208
209 return result_dict
Michael Walsh05c68d92017-09-20 16:36:37 -0500210
211
212def parse_key_value(string,
213 delim=":",
214 strip=" ",
215 to_lower=1,
216 underscores=1):
217
218 r"""
219 Parse a key/value string and return as a key/value tuple.
220
221 This function is useful for parsing a line of program output or data that
222 is in the following form:
223 <key or variable name><delimiter><value>
224
225 An example of a key/value string would be as follows:
226
227 Current Limit State: No Active Power Limit
228
229 In the example shown, the delimiter is ":". The resulting key would be as
230 follows:
231 Current Limit State
232
233 Note: If one were to take the default values of to_lower=1 and
234 underscores=1, the resulting key would be as follows:
235 current_limit_state
236
237 The to_lower and underscores arguments are provided for those who wish to
238 have their key names have the look and feel of python variable names.
239
240 The resulting value for the example above would be as follows:
241 No Active Power Limit
242
243 Another example:
244 name=Mike
245
246 In this case, the delim would be "=", the key is "name" and the value is
247 "Mike".
248
249 Description of argument(s):
250 string The string to be parsed.
251 delim The delimiter which separates the key from
252 the value.
253 strip The characters (if any) to strip from the
254 beginning and end of both the key and the
255 value.
256 to_lower Change the key name to lower case.
257 underscores Change any blanks found in the key name to
258 underscores.
259 """
260
261 pair = string.split(delim)
262
263 key = pair[0].strip(strip)
264 if len(pair) == 0:
265 value = ""
266 else:
MICHAEL J. WALSH9509a0f2018-02-08 11:08:52 -0600267 value = delim.join(pair[1:]).strip(strip)
Michael Walsh05c68d92017-09-20 16:36:37 -0500268
269 if to_lower:
270 key = key.lower()
271 if underscores:
272 key = re.sub(r" ", "_", key)
273
274 return key, value
275
276
277def key_value_list_to_dict(list,
278 **args):
279
280 r"""
281 Convert a list containing key/value strings to a dictionary and return it.
282
283 See docstring of parse_key_value function for details on key/value strings.
284
285 Example usage:
286
287 For the following value of list:
288
289 list:
290 list[0]: Current Limit State: No Active Power Limit
291 list[1]: Exception actions: Hard Power Off & Log Event to SEL
292 list[2]: Power Limit: 0 Watts
293 list[3]: Correction time: 0 milliseconds
294 list[4]: Sampling period: 0 seconds
295
296 And the following call in python:
297
298 power_limit = key_value_outbuf_to_dict(list)
299
300 The resulting power_limit directory would look like this:
301
302 power_limit:
303 [current_limit_state]: No Active Power Limit
304 [exception_actions]: Hard Power Off & Log Event to SEL
305 [power_limit]: 0 Watts
306 [correction_time]: 0 milliseconds
307 [sampling_period]: 0 seconds
308
309 Description of argument(s):
310 list A list of key/value strings. (See
311 docstring of parse_key_value function for
312 details).
313 **args Arguments to be interpreted by
314 parse_key_value. (See docstring of
315 parse_key_value function for details).
316 """
317
318 try:
319 result_dict = collections.OrderedDict()
320 except AttributeError:
321 result_dict = DotDict()
322
323 for entry in list:
Michael Walshc1dfc782017-09-26 16:08:51 -0500324 key, value = parse_key_value(entry, **args)
Michael Walsh05c68d92017-09-20 16:36:37 -0500325 result_dict[key] = value
326
327 return result_dict
328
329
330def key_value_outbuf_to_dict(out_buf,
331 **args):
332
333 r"""
334 Convert a buffer with a key/value string on each line to a dictionary and
335 return it.
336
337 Each line in the out_buf should end with a \n.
338
339 See docstring of parse_key_value function for details on key/value strings.
340
341 Example usage:
342
343 For the following value of out_buf:
344
345 Current Limit State: No Active Power Limit
346 Exception actions: Hard Power Off & Log Event to SEL
347 Power Limit: 0 Watts
348 Correction time: 0 milliseconds
349 Sampling period: 0 seconds
350
351 And the following call in python:
352
353 power_limit = key_value_outbuf_to_dict(out_buf)
354
355 The resulting power_limit directory would look like this:
356
357 power_limit:
358 [current_limit_state]: No Active Power Limit
359 [exception_actions]: Hard Power Off & Log Event to SEL
360 [power_limit]: 0 Watts
361 [correction_time]: 0 milliseconds
362 [sampling_period]: 0 seconds
363
364 Description of argument(s):
365 out_buf A buffer with a key/value string on each
366 line. (See docstring of parse_key_value
367 function for details).
368 **args Arguments to be interpreted by
369 parse_key_value. (See docstring of
370 parse_key_value function for details).
371 """
372
373 # Create key_var_list and remove null entries.
374 key_var_list = list(filter(None, out_buf.split("\n")))
Michael Walshc1dfc782017-09-26 16:08:51 -0500375 return key_value_list_to_dict(key_var_list, **args)
Michael Walshdb560d42017-11-20 16:42:49 -0600376
377
378def list_to_report(report_list,
379 to_lower=1):
380
381 r"""
382 Convert a list containing report text lines to a report "object" and
383 return it.
384
385 The first entry in report_list must be a header line consisting of column
386 names delimited by white space. No column name may contain white space.
387 The remaining report_list entries should contain tabular data which
388 corresponds to the column names.
389
390 A report object is a list where each entry is a dictionary whose keys are
391 the field names from the first entry in report_list.
392
393 Example:
394 Given the following report_list as input:
395
396 rl:
397 rl[0]: Filesystem 1K-blocks Used Available Use% Mounted on
398 rl[1]: dev 247120 0 247120 0% /dev
399 rl[2]: tmpfs 248408 79792 168616 32% /run
400
401 This function will return a list of dictionaries as shown below:
402
403 df_report:
404 df_report[0]:
405 [filesystem]: dev
406 [1k-blocks]: 247120
407 [used]: 0
408 [available]: 247120
409 [use%]: 0%
410 [mounted]: /dev
411 df_report[1]:
412 [filesystem]: dev
413 [1k-blocks]: 247120
414 [used]: 0
415 [available]: 247120
416 [use%]: 0%
417 [mounted]: /dev
418
419 Notice that because "Mounted on" contains a space, "on" would be
420 considered the 7th field. In this case, there is never any data in field
421 7 so things work out nicely. A caller could do some pre-processing if
422 desired (e.g. change "Mounted on" to "Mounted_on").
423
424 Description of argument(s):
425 report_list A list where each entry is one line of
426 output from a report. The first entry
427 must be a header line which contains
428 column names. Column names may not
429 contain spaces.
430 to_lower Change the resulting key names to lower
431 case.
432 """
433
434 # Process header line.
435 header_line = report_list[0]
436 if to_lower:
437 header_line = header_line.lower()
438 columns = header_line.split()
439
440 report_obj = []
441 for report_line in report_list[1:]:
442 line = report_list[1].split()
443 try:
444 line_dict = collections.OrderedDict(zip(columns, line))
445 except AttributeError:
446 line_dict = DotDict(zip(columns, line))
447 report_obj.append(line_dict)
448
449 return report_obj
450
451
452def outbuf_to_report(out_buf,
453 **args):
454
455 r"""
456 Convert a text buffer containing report lines to a report "object" and
457 return it.
458
459 Refer to list_to_report (above) for more details.
460
461 Example:
462
463 Given the following out_buf:
464
465 Filesystem 1K-blocks Used Available Use% Mounted on
466 dev 247120 0 247120 0% /dev
467 tmpfs 248408 79792 168616 32% /run
468
469 This function will return a list of dictionaries as shown below:
470
471 df_report:
472 df_report[0]:
473 [filesystem]: dev
474 [1k-blocks]: 247120
475 [used]: 0
476 [available]: 247120
477 [use%]: 0%
478 [mounted]: /dev
479 df_report[1]:
480 [filesystem]: dev
481 [1k-blocks]: 247120
482 [used]: 0
483 [available]: 247120
484 [use%]: 0%
485 [mounted]: /dev
486
487 Other possible uses:
488 - Process the output of a ps command.
489 - Process the output of an ls command (the caller would need to supply
490 column names)
491
492 Description of argument(s):
493 out_buf A text report The first line must be a
494 header line which contains column names.
495 Column names may not contain spaces.
496 **args Arguments to be interpreted by
497 list_to_report. (See docstring of
498 list_to_report function for details).
499 """
500
501 report_list = filter(None, out_buf.split("\n"))
502 return list_to_report(report_list, **args)