23
23
import binascii
24
24
25
25
26
+ def substitute_in_config_variables (field_value , config_values : dict ):
27
+ ''' Substitutes values that are config variables.
28
+
29
+ YAML values can contain a string of a configuration variable name. In these instances we
30
+ substitute the configuration variable name with the actual value.
31
+
32
+ For examples see unittest src/controller/python/test/unit_tests/test_yaml_format_converter.py
33
+
34
+ # TODO This should also substitue any saveAs values as well as perform any required
35
+ # evaluations.
36
+
37
+ Args:
38
+ 'field_value': Value as extracted from YAML.
39
+ 'config_values': Dictionary of global configuration variables.
40
+ Returns:
41
+ Value with all global configuration variables substituted with the real value.
42
+ '''
43
+ if isinstance (field_value , dict ):
44
+ return {key : substitute_in_config_variables (
45
+ field_value [key ], config_values ) for key in field_value }
46
+ if isinstance (field_value , list ):
47
+ return [substitute_in_config_variables (item , config_values ) for item in field_value ]
48
+ if isinstance (field_value , str ) and field_value in config_values :
49
+ config_value = config_values [field_value ]
50
+ if isinstance (config_value , dict ) and 'defaultValue' in config_value :
51
+ # TODO currently we don't validate that if config_value['type'] is provided
52
+ # that the type does in fact match our expectation.
53
+ return config_value ['defaultValue' ]
54
+ return config_values [field_value ]
55
+
56
+ return field_value
57
+
58
+
26
59
def convert_yaml_octet_string_to_bytes (s : str ) -> bytes :
27
- """Convert YAML octet string body to bytes, handling any c-style hex escapes (e.g. \x5a ) and hex: prefix"""
60
+ '''Convert YAML octet string body to bytes.
61
+
62
+ Included handling any c-style hex escapes (e.g. \x5a ) and 'hex:' prefix.
63
+ '''
28
64
# Step 1: handle explicit "hex:" prefix
29
65
if s .startswith ('hex:' ):
30
66
return binascii .unhexlify (s [4 :])
@@ -60,14 +96,21 @@ def convert_name_value_pair_to_dict(arg_values):
60
96
return ret_value
61
97
62
98
63
- def convert_yaml_type (field_value , field_type , use_from_dict = False ):
64
- ''' Converts yaml value to expected type.
99
+ def convert_yaml_type (field_value , field_type , inline_cast_dict_to_struct ):
100
+ ''' Converts yaml value to provided pythonic type.
101
+
102
+ The YAML representation when converted to a dictionary does not line up to
103
+ the python type data model for the various command/attribute/event object
104
+ types. This function converts 'field_value' to the appropriate provided
105
+ 'field_type'.
65
106
66
- The YAML representation when converted to a Python dictionary does not
67
- quite line up in terms of type (see each of the specific if branches
68
- below for the rationale for the necessary fix-ups). This function does
69
- a fix-up given a field value (as present in the YAML) and its matching
70
- cluster object type and returns it.
107
+ Args:
108
+ 'field_value': Value as extracted from yaml
109
+ 'field_type': Pythonic command/attribute/event object type that we
110
+ are converting value to.
111
+ 'inline_cast_dict_to_struct': If true, for any dictionary 'field_value'
112
+ types provided we will do a convertion to the corresponding data
113
+ model class in `field_type` by doing field_type.FromDict(...).
71
114
'''
72
115
origin = typing .get_origin (field_type )
73
116
@@ -110,8 +153,8 @@ def convert_yaml_type(field_value, field_type, use_from_dict=False):
110
153
f'Did not find field "{ item } " in { str (field_type )} ' ) from None
111
154
112
155
return_field_value [field_descriptor .Label ] = convert_yaml_type (
113
- field_value [item ], field_descriptor .Type , use_from_dict )
114
- if use_from_dict :
156
+ field_value [item ], field_descriptor .Type , inline_cast_dict_to_struct )
157
+ if inline_cast_dict_to_struct :
115
158
return field_type .FromDict (return_field_value )
116
159
return return_field_value
117
160
elif (type (field_value ) is float ):
@@ -122,7 +165,8 @@ def convert_yaml_type(field_value, field_type, use_from_dict=False):
122
165
123
166
# The field type passed in is the type of the list element and not list[T].
124
167
for idx , item in enumerate (field_value ):
125
- field_value [idx ] = convert_yaml_type (item , list_element_type , use_from_dict )
168
+ field_value [idx ] = convert_yaml_type (item , list_element_type ,
169
+ inline_cast_dict_to_struct )
126
170
return field_value
127
171
# YAML conversion treats all numbers as ints. Convert to a uint type if the schema
128
172
# type indicates so.
@@ -139,3 +183,25 @@ def convert_yaml_type(field_value, field_type, use_from_dict=False):
139
183
# By default, just return the field_value casted to field_type.
140
184
else :
141
185
return field_type (field_value )
186
+
187
+
188
+ def parse_and_convert_yaml_value (field_value , field_type , config_values : dict ,
189
+ inline_cast_dict_to_struct : bool = False ):
190
+ ''' Parse and converts YAML type
191
+
192
+ Parsing the YAML value means performing required substitutions and evaluations. Parsing is
193
+ then followed by converting from the YAML type done using yaml.safe_load() to the type used in
194
+ the various command/attribute/event object data model types.
195
+
196
+ Args:
197
+ 'field_value': Value as extracted from yaml to be parsed
198
+ 'field_type': Pythonic command/attribute/event object type that we
199
+ are converting value to.
200
+ 'config_values': Dictionary of global configuration variables.
201
+ 'inline_cast_dict_to_struct': If true, for any dictionary 'field_value'
202
+ types provided we will do an inline convertion to the corresponding
203
+ struct in `field_type` by doing field_type.FromDict(...).
204
+ '''
205
+ field_value_with_config_variables = substitute_in_config_variables (field_value , config_values )
206
+ return convert_yaml_type (field_value_with_config_variables , field_type ,
207
+ inline_cast_dict_to_struct )
0 commit comments