1#!/usr/bin/env python3
2
3r"""
4This module provides validation functions like valid_value(), valid_integer(), etc. for robot programs.
5"""
6
7import re
8import gen_print as gp
9import gen_valid as gv
10import func_args as fa
11
12from robot.libraries.BuiltIn import BuiltIn
13
14
15def valid_var_name(var_name):
16    r"""
17    Validate the robot variable name and return its value.
18
19    If the variable is undefined, this function will print an error message and call BuiltIn().fail().
20
21    Description of arguments():
22    var_name                        The name of the robot variable (e.g. "var1").  Do not include "${}" (e.g.
23                                    "${var1}".  Just provide the simple name of the variable.
24    """
25
26    # Note: get_variable_value() seems to have no trouble with local variables.
27    var_value = BuiltIn().get_variable_value("${" + var_name + "}")
28    if var_value is None:
29        var_value = "<undefined>"
30        error_message = gv.valid_value(var_value, invalid_values=[var_value],
31                                       var_name=var_name)
32        BuiltIn().fail(error_message)
33
34    return var_value
35
36
37def valid_init(var_name, *args, **kwargs):
38    r"""
39    Do initialization for variable validation and return var_name, args and kwargs.
40
41    This function is to be called by all of the various validation functions in this module.
42
43    This function is designed solely for use by other functions in this file.
44
45    Description of argument(s):
46    var_name                        The name of the variable to be validated.
47    args                            The positional arguments to be passed to a validation function.
48    kwargs                          The keyword arguments to be passed to a validation function.
49    """
50
51    var_value = valid_var_name(var_name)
52    # Convert python string object definitions to objects (useful for robot callers).
53    args = fa.args_to_objects(args)
54    kwargs = fa.args_to_objects(kwargs)
55    return var_value, args, kwargs
56
57
58def process_error_message(error_message):
59    r"""
60    Process an error message.
61
62    If error_message is non-blank, fail.  Otherwise, do nothing.
63
64    This function is designed solely for use by other functions in this file.
65
66    Description of argument(s):
67    error_message                   The error message to be processed.
68    """
69
70    if error_message:
71        error_message = gp.sprint_error_report(error_message)
72        BuiltIn().fail(error_message)
73
74
75# The docstring header will be pre-pended to each validation function's existing docstring.
76docstring_header = \
77    r"""
78    Fail if the variable named by var_name is invalid.
79    """
80
81
82def customize_doc_string(doc_string):
83    r"""
84    Customize a gen_valid function docstring and return the result.
85
86    This function is designed solely for use by other functions in this file.
87
88    The caller should pass a docstring from a gen_valid.py validation function.  This docstring will be
89    changed to make a suitable docstring for this module's corresponding validation function.
90
91    For example:
92
93    Let's suppose that gen_valid.py has a function called "valid_value()".  This module could make the
94    following call to essentially copy gen_valid's "valid_value()" function, modify it and then assign it to
95    the local version of the valid_value() function.
96
97    valid.__doc__ = customize_doc_string(gv.valid.__doc__)
98
99    Description of argument(s):
100    doc_string                      The docstring to be customized.
101    """
102
103    doc_string = docstring_header + doc_string
104    doc_string = doc_string.split("\n")
105
106    start_ix = 0
107    # Find the "var_value" line.
108    start_ix = next((index for index, value in
109                     enumerate(doc_string[start_ix:], start_ix)
110                     if re.match("[ ]+var_value  ", value)), None)
111    # Replace the "var_value" line with our "var_name" line.
112    doc_string[start_ix] = "    var_name                        " \
113        + "The name of the variable to be validated."
114
115    return "\n".join(doc_string)
116
117
118# All of the following functions are robot wrappers for the equivalent functions defined in gen_valid.py.
119# Note that the only difference between any two of these locally defined functions is the function name and
120# the gv.<function name> which they call.  Also, note that the docstring for each is created by modifying the
121# docstring from the supporting gen_valid.py function.
122
123def valid_type(var_name, *args, **kwargs):
124
125    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
126    error_message = \
127        gv.valid_type(var_value, *args, var_name=var_name, **kwargs)
128    process_error_message(error_message)
129
130
131def valid_value(var_name, *args, **kwargs):
132
133    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
134    error_message = \
135        gv.valid_value(var_value, *args, var_name=var_name, **kwargs)
136    process_error_message(error_message)
137
138
139def valid_range(var_name, *args, **kwargs):
140
141    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
142    error_message = \
143        gv.valid_range(var_value, *args, var_name=var_name, **kwargs)
144    process_error_message(error_message)
145
146
147def valid_integer(var_name, *args, **kwargs):
148
149    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
150    error_message = \
151        gv.valid_integer(var_value, *args, var_name=var_name, **kwargs)
152    process_error_message(error_message)
153
154
155def valid_float(var_name, *args, **kwargs):
156
157    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
158    error_message = \
159        gv.valid_float(var_value, *args, var_name=var_name, **kwargs)
160    process_error_message(error_message)
161
162
163def valid_date_time(var_name, *args, **kwargs):
164
165    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
166    error_message = \
167        gv.valid_date_time(var_value, *args, var_name=var_name, **kwargs)
168    process_error_message(error_message)
169
170
171def valid_dir_path(var_name, *args, **kwargs):
172
173    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
174    error_message = \
175        gv.valid_dir_path(var_value, *args, var_name=var_name, **kwargs)
176    process_error_message(error_message)
177
178
179def valid_file_path(var_name, *args, **kwargs):
180
181    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
182    error_message = \
183        gv.valid_file_path(var_value, *args, var_name=var_name, **kwargs)
184    process_error_message(error_message)
185
186
187def valid_path(var_name, *args, **kwargs):
188
189    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
190    error_message = \
191        gv.valid_path(var_value, *args, var_name=var_name, **kwargs)
192    process_error_message(error_message)
193
194
195def valid_list(var_name, *args, **kwargs):
196
197    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
198    error_message = \
199        gv.valid_list(var_value, *args, var_name=var_name, **kwargs)
200    process_error_message(error_message)
201
202
203def valid_dict(var_name, *args, **kwargs):
204
205    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
206    error_message = \
207        gv.valid_dict(var_value, *args, var_name=var_name, **kwargs)
208    process_error_message(error_message)
209
210
211def valid_program(var_name, *args, **kwargs):
212
213    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
214    error_message = \
215        gv.valid_program(var_value, *args, var_name=var_name, **kwargs)
216    process_error_message(error_message)
217
218
219def valid_length(var_name, *args, **kwargs):
220
221    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
222    error_message = \
223        gv.valid_length(var_value, *args, var_name=var_name, **kwargs)
224    process_error_message(error_message)
225
226
227# Modify the validation function docstrings by calling customize_doc_string for each function in the
228# func_names list.
229func_names = [
230    "valid_type", "valid_value", "valid_range", "valid_integer",
231    "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
232    "valid_dict", "valid_program", "valid_length", "valid_float",
233    "valid_date_time"
234]
235
236for func_name in func_names:
237    cmd_buf = func_name \
238        + ".__doc__ = customize_doc_string(gv.raw_doc_strings['" \
239        + func_name + "'])"
240    exec(cmd_buf)
241