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.
17 Mechanism for evaluating intrinsic functions.
19 from ..parser.exceptions import InvalidValueError
20 from ..parser.consumption import ConsumptionContext
21 from ..utils.collections import OrderedDict
22 from ..utils.type import full_type_name
23 from . import exceptions
26 class Function(object):
28 Base class for intrinsic functions. Serves as a placeholder for a value that should eventually
29 be derived by "evaluating" (calling) the function.
31 Note that this base class is provided as a convenience and you do not have to inherit it: any
32 object with an ``__evaluate__`` method would be treated similarly.
37 raise NotImplementedError
39 def __evaluate__(self, container_holder):
41 Evaluates the function if possible.
43 :rtype: :class:`Evaluation` (or any object with ``value`` and ``final`` properties)
44 :raises CannotEvaluateFunctionException: if cannot be evaluated at this time (do *not* just
48 raise NotImplementedError
50 def __deepcopy__(self, memo):
51 # Circumvent cloning in order to maintain our state
55 class Evaluation(object):
57 An evaluated :class:`Function` return value.
59 :ivar value: evaluated value
60 :ivar final: whether the value is final
61 :vartype final: boolean
64 def __init__(self, value, final=False):
69 def evaluate(value, container_holder, report_issues=False): # pylint: disable=too-many-branches
71 Recursively attempts to call ``__evaluate__``. If an evaluation occurred will return an
72 :class:`Evaluation`, otherwise it will be ``None``. If any evaluation is non-final, then the
73 entire evaluation will also be non-final.
75 The ``container_holder`` argument should have three properties: ``container`` should return
76 the model that contains the value, ``service`` should return the containing
77 :class:`~aria.modeling.models.Service` model or None, and ``service_template`` should return the
78 containing :class:`~aria.modeling.models.ServiceTemplate` model or ``None``.
84 if hasattr(value, '__evaluate__'):
86 evaluation = value.__evaluate__(container_holder)
88 # Verify evaluation structure
89 if (evaluation is None) \
90 or (not hasattr(evaluation, 'value')) \
91 or (not hasattr(evaluation, 'final')):
92 raise InvalidValueError('bad __evaluate__ implementation: {0}'
93 .format(full_type_name(value)))
96 value = evaluation.value
97 final = evaluation.final
99 # The evaluated value might itself be evaluable
100 evaluation = evaluate(value, container_holder, report_issues)
101 if evaluation is not None:
102 value = evaluation.value
103 if not evaluation.final:
105 except exceptions.CannotEvaluateFunctionException:
107 except InvalidValueError as e:
109 context = ConsumptionContext.get_thread_local()
110 context.validation.report(e.issue)
112 elif isinstance(value, list):
115 evaluation = evaluate(v, container_holder, report_issues)
116 if evaluation is not None:
117 evaluated_list.append(evaluation.value)
119 if not evaluation.final:
122 evaluated_list.append(v)
124 value = evaluated_list
126 elif isinstance(value, dict):
127 evaluated_dict = OrderedDict()
128 for k, v in value.iteritems():
129 evaluation = evaluate(v, container_holder, report_issues)
130 if evaluation is not None:
131 evaluated_dict[k] = evaluation.value
133 if not evaluation.final:
136 evaluated_dict[k] = v
138 value = evaluated_dict
140 return Evaluation(value, final) if evaluated else None