1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 from aria.utils.collections import (merge, deepcopy_with_locators, OrderedDict)
17 from aria.utils.formatting import pluralize
18 from aria.parser.presentation import Value
19 from aria.parser.validation import Issue
21 from .data_types import (coerce_value, get_primitive_data_type)
22 from ..presentation.types import get_type_by_name
26 # ArtifactType, DataType, CapabilityType, RelationshipType, NodeType, GroupType, PolicyType
29 def get_inherited_parameter_definitions(context, presentation, field_name, for_presentation=None):
31 Returns our parameter definitions added on top of those of our parent, if we have one
34 Allows overriding all aspects of parent properties except data type.
37 if for_presentation is None:
38 for_presentation = presentation
40 # Get definitions from parent
41 # If we inherit from a primitive, it does not have a parent:
42 parent = presentation._get_parent(context) if hasattr(presentation, '_get_parent') else None
43 definitions = get_inherited_parameter_definitions(context, parent, field_name,
45 if parent is not None else OrderedDict()
47 # Add/merge our definitions
48 # If we inherit from a primitive, it does not have our field
49 our_definitions = getattr(presentation, field_name, None)
51 our_definitions_clone = OrderedDict()
52 for name, our_definition in our_definitions.iteritems():
53 our_definitions_clone[name] = our_definition._clone(for_presentation)
54 our_definitions = our_definitions_clone
55 merge_parameter_definitions(context, presentation, definitions, our_definitions, field_name)
57 for definition in definitions.itervalues():
58 definition._reset_method_cache()
64 # NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate
67 def get_assigned_and_defined_parameter_values(context, presentation, field_name):
69 Returns the assigned parameter values while making sure they are defined in our type.
71 The parameter definition's default value, if available, will be used if we did not assign it.
73 Makes sure that required parameters indeed end up with a value.
76 values = OrderedDict()
78 the_type = presentation._get_type(context)
79 field_name_plural = pluralize(field_name)
80 assignments = getattr(presentation, field_name_plural)
81 get_fn_name = '_get_{0}'.format(field_name_plural)
82 definitions = getattr(the_type, get_fn_name)(context) if the_type is not None else None
84 # Fill in our assignments, but make sure they are defined
86 for name, value in assignments.iteritems():
87 if (definitions is not None) and (name in definitions):
88 definition = definitions[name]
89 values[name] = coerce_parameter_value(context, value, definition, value.value)
91 context.validation.report('assignment to undefined {0} "{1}" in "{2}"'
92 .format(field_name, name, presentation._fullname),
93 locator=value._locator, level=Issue.BETWEEN_TYPES)
95 # Fill in defaults from the definitions
97 for name, definition in definitions.iteritems():
98 # Note: attributes will always have a default value, even if it's None
99 if (name not in values) and \
100 (('default' in definition._raw) or (field_name == 'attribute')):
101 values[name] = coerce_parameter_value(context, presentation, definition,
104 validate_required_values(context, presentation, values, definitions)
106 # Fill in nulls for missing values that are *not* required
108 for name, definition in definitions.iteritems():
109 if (name not in values) and not getattr(definition, 'required', False):
110 values[name] = coerce_parameter_value(context, presentation, definition, None)
119 def get_parameter_values(context, presentation, field_name):
120 values = OrderedDict()
122 parameters = getattr(presentation, field_name)
124 # Fill in defaults and values
126 for name, parameter in parameters.iteritems():
127 if values.get(name) is None:
128 if hasattr(parameter, 'value') and (parameter.value is not None):
129 # For parameters only:
130 values[name] = coerce_parameter_value(context, presentation, parameter,
133 default = parameter.default if hasattr(parameter, 'default') else None
134 values[name] = coerce_parameter_value(context, presentation, parameter, default)
143 def validate_required_values(context, presentation, values, definitions):
145 Check if required properties have not been assigned.
150 for name, definition in definitions.iteritems():
151 if getattr(definition, 'required', False) and \
152 ((values is None) or (values.get(name) is None)):
153 context.validation.report('required property "%s" is not assigned a value in "%s"'
154 % (name, presentation._fullname),
155 locator=presentation._get_child_locator('properties'),
156 level=Issue.BETWEEN_TYPES)
159 def merge_raw_parameter_definition(context, presentation, raw_property_definition,
160 our_property_definition, field_name, property_name):
161 # Check if we changed the parameter type
162 type1_name = raw_property_definition.get('type')
163 type1 = get_type_by_name(context, type1_name, 'data_types')
165 type1 = get_primitive_data_type(type1_name)
166 our_property_definition._reset_method_cache()
167 type2 = our_property_definition._get_type(context)
170 if not hasattr(type1, '_is_descendant') or not type1._is_descendant(context, type2):
171 context.validation.report(
172 'property definition type "{0}" is not a descendant of overridden '
173 'property definition type "{1}"' \
174 .format(type1_name, type2._name),
175 locator=presentation._get_child_locator(field_name, property_name),
176 level=Issue.BETWEEN_TYPES)
178 merge(raw_property_definition, our_property_definition._raw)
181 def merge_raw_parameter_definitions(context, presentation, raw_property_definitions,
182 our_property_definitions, field_name):
183 if not our_property_definitions:
185 for property_name, our_property_definition in our_property_definitions.iteritems():
186 if property_name in raw_property_definitions:
187 raw_property_definition = raw_property_definitions[property_name]
188 merge_raw_parameter_definition(context, presentation, raw_property_definition,
189 our_property_definition, field_name, property_name)
191 raw_property_definitions[property_name] = \
192 deepcopy_with_locators(our_property_definition._raw)
195 def merge_parameter_definitions(context, presentation, property_definitions,
196 our_property_definitions, field_name):
197 if not our_property_definitions:
199 for property_name, our_property_definition in our_property_definitions.iteritems():
200 if property_name in property_definitions:
201 property_definition = property_definitions[property_name]
202 merge_raw_parameter_definition(context, presentation, property_definition._raw,
203 our_property_definition, field_name, property_name)
205 property_definitions[property_name] = our_property_definition
208 # Works on properties, inputs, and parameters
209 def coerce_parameter_value(context, presentation, definition, value, aspect=None):
210 the_type = definition._get_type(context) if definition is not None else None
211 entry_schema = definition.entry_schema if definition is not None else None
212 constraints = definition._get_constraints(context) \
213 if ((definition is not None) and hasattr(definition, '_get_constraints')) else None
214 value = coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect)
215 if (the_type is not None) and hasattr(the_type, '_name'):
216 type_name = the_type._name
218 type_name = getattr(definition, 'type', None)
219 description = getattr(definition, 'description', None)
220 description = description.value if description is not None else None
221 required = getattr(definition, 'required', None)
222 return Value(type_name, value, description, required)
225 def convert_parameter_definitions_to_values(context, definitions):
226 values = OrderedDict()
227 for name, definition in definitions.iteritems():
228 default = definition.default
229 values[name] = coerce_parameter_value(context, definition, definition, default)