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 deepcopy_with_locators, OrderedDict
17 from aria.parser.validation import Issue
19 from .parameters import (convert_parameter_definitions_to_values, merge_raw_parameter_definitions,
20 get_assigned_and_defined_parameter_values)
27 def get_inherited_valid_source_types(context, presentation):
29 If we haven't set the ``valid_source_types`` fields, uses that value from our parent, if we have
33 valid_source_types = presentation.valid_source_types
35 if valid_source_types is None:
36 parent = presentation._get_parent(context)
37 valid_source_types = get_inherited_valid_source_types(context, parent) \
38 if parent is not None else None
40 return valid_source_types
47 def get_inherited_capability_definitions(context, presentation, for_presentation=None):
49 Returns our capability capability definitions added on top of those of our parent, if we have
52 Allows overriding all aspects of parent capability properties except data type.
55 if for_presentation is None:
56 for_presentation = presentation
58 # Get capability definitions from parent
59 parent = presentation._get_parent(context)
60 capability_definitions = get_inherited_capability_definitions(
61 context, parent, for_presentation) if parent is not None else OrderedDict()
63 # Add/merge our capability definitions
64 our_capability_definitions = presentation.capabilities
65 if our_capability_definitions:
66 for capability_name, our_capability_definition in our_capability_definitions.iteritems():
67 if capability_name in capability_definitions:
68 capability_definition = capability_definitions[capability_name]
70 # Check if we changed the type
71 type1 = capability_definition._get_type(context)
72 type2 = our_capability_definition._get_type(context)
74 if not type1._is_descendant(context, type2):
75 context.validation.report(
76 'capability definition type "{0}" is not a descendant of overridden '
77 'capability definition type "{1}"' \
78 .format(type1._name, type2._name),
79 locator=our_capability_definition._locator, level=Issue.BETWEEN_TYPES)
81 merge_capability_definition(context, presentation, capability_definition,
82 our_capability_definition)
84 capability_definition = our_capability_definition._clone(for_presentation)
85 if isinstance(capability_definition._raw, basestring):
86 # Make sure we have a dict
87 the_type = capability_definition._raw
88 capability_definition._raw = OrderedDict()
89 capability_definition._raw['type'] = the_type
90 capability_definitions[capability_name] = capability_definition
92 merge_capability_definition_from_type(context, presentation, capability_definition)
94 for capability_definition in capability_definitions.itervalues():
95 capability_definition._reset_method_cache()
97 return capability_definitions
104 def get_template_capabilities(context, presentation):
106 Returns the node type's capabilities with our assignments to properties and attributes merged
109 Capability properties' default values, if available, will be used if we did not assign them.
111 Makes sure that required properties indeed end up with a value.
114 capability_assignments = OrderedDict()
116 the_type = presentation._get_type(context) # NodeType
117 capability_definitions = the_type._get_capabilities(context) if the_type is not None else None
119 # Copy over capability definitions from the type (will initialize properties with default
121 if capability_definitions:
122 for capability_name, capability_definition in capability_definitions.iteritems():
123 capability_assignments[capability_name] = \
124 convert_capability_from_definition_to_assignment(context, capability_definition,
127 # Fill in our capability assignments
128 our_capability_assignments = presentation.capabilities
129 if our_capability_assignments:
130 for capability_name, our_capability_assignment in our_capability_assignments.iteritems():
131 if capability_name in capability_assignments:
132 capability_assignment = capability_assignments[capability_name]
135 values = get_assigned_and_defined_parameter_values(context,
136 our_capability_assignment,
140 capability_assignment._raw['properties'] = values
141 capability_assignment._reset_method_cache()
143 context.validation.report(
144 'capability "{0}" not declared at node type "{1}" in "{2}"'
145 .format(capability_name, presentation.type, presentation._fullname),
146 locator=our_capability_assignment._locator, level=Issue.BETWEEN_TYPES)
148 return capability_assignments
155 def convert_capability_from_definition_to_assignment(context, presentation, container):
156 from ..assignments import CapabilityAssignment
160 properties = presentation.properties
161 if properties is not None:
162 raw['properties'] = convert_parameter_definitions_to_values(context, properties)
166 return CapabilityAssignment(name=presentation._name, raw=raw, container=container)
169 def merge_capability_definition(context, presentation, capability_definition,
170 from_capability_definition):
171 raw_properties = OrderedDict()
173 capability_definition._raw['type'] = from_capability_definition.type
175 # Merge properties from type
176 from_property_defintions = from_capability_definition.properties
177 merge_raw_parameter_definitions(context, presentation, raw_properties, from_property_defintions,
180 # Merge our properties
181 merge_raw_parameter_definitions(context, presentation, raw_properties,
182 capability_definition.properties, 'properties')
185 capability_definition._raw['properties'] = raw_properties
186 capability_definition._reset_method_cache()
189 occurrences = from_capability_definition._raw.get('occurrences')
190 if (occurrences is not None) and (capability_definition._raw.get('occurrences') is None):
191 capability_definition._raw['occurrences'] = \
192 deepcopy_with_locators(occurrences)
195 def merge_capability_definition_from_type(context, presentation, capability_definition):
197 Merge ``properties`` and ``valid_source_types`` from the node type's capability definition
198 over those taken from the parent node type.
200 raw_properties = OrderedDict()
202 # Merge properties from parent
203 the_type = capability_definition._get_type(context)
204 type_property_defintions = the_type._get_properties(context)
205 merge_raw_parameter_definitions(context, presentation, raw_properties, type_property_defintions,
208 # Merge our properties (might override definitions in parent)
209 merge_raw_parameter_definitions(context, presentation, raw_properties,
210 capability_definition.properties, 'properties')
213 capability_definition._raw['properties'] = raw_properties
215 # Override valid_source_types
216 if capability_definition._raw.get('valid_source_types') is None:
217 valid_source_types = the_type._get_valid_source_types(context)
218 if valid_source_types is not None:
219 capability_definition._raw['valid_source_types'] = \
220 deepcopy_with_locators(valid_source_types)