1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Mechanism for evaluating intrinsic functions.
"""
from ..parser.exceptions import InvalidValueError
from ..parser.consumption import ConsumptionContext
from ..utils.collections import OrderedDict
from ..utils.type import full_type_name
from . import exceptions
class Function(object):
"""
Base class for intrinsic functions. Serves as a placeholder for a value that should eventually
be derived by "evaluating" (calling) the function.
Note that this base class is provided as a convenience and you do not have to inherit it: any
object with an ``__evaluate__`` method would be treated similarly.
"""
@property
def as_raw(self):
raise NotImplementedError
def __evaluate__(self, container_holder):
"""
Evaluates the function if possible.
:rtype: :class:`Evaluation` (or any object with ``value`` and ``final`` properties)
:raises CannotEvaluateFunctionException: if cannot be evaluated at this time (do *not* just
return ``None``)
"""
raise NotImplementedError
def __deepcopy__(self, memo):
# Circumvent cloning in order to maintain our state
return self
class Evaluation(object):
"""
An evaluated :class:`Function` return value.
:ivar value: evaluated value
:ivar final: whether the value is final
:vartype final: boolean
"""
def __init__(self, value, final=False):
self.value = value
self.final = final
def evaluate(value, container_holder, report_issues=False): # pylint: disable=too-many-branches
"""
Recursively attempts to call ``__evaluate__``. If an evaluation occurred will return an
:class:`Evaluation`, otherwise it will be ``None``. If any evaluation is non-final, then the
entire evaluation will also be non-final.
The ``container_holder`` argument should have three properties: ``container`` should return
the model that contains the value, ``service`` should return the containing
:class:`~aria.modeling.models.Service` model or None, and ``service_template`` should return the
containing :class:`~aria.modeling.models.ServiceTemplate` model or ``None``.
"""
evaluated = False
final = True
if hasattr(value, '__evaluate__'):
try:
evaluation = value.__evaluate__(container_holder)
# Verify evaluation structure
if (evaluation is None) \
or (not hasattr(evaluation, 'value')) \
or (not hasattr(evaluation, 'final')):
raise InvalidValueError('bad __evaluate__ implementation: {0}'
.format(full_type_name(value)))
evaluated = True
value = evaluation.value
final = evaluation.final
# The evaluated value might itself be evaluable
evaluation = evaluate(value, container_holder, report_issues)
if evaluation is not None:
value = evaluation.value
if not evaluation.final:
final = False
except exceptions.CannotEvaluateFunctionException:
pass
except InvalidValueError as e:
if report_issues:
context = ConsumptionContext.get_thread_local()
context.validation.report(e.issue)
elif isinstance(value, list):
evaluated_list = []
for v in value:
evaluation = evaluate(v, container_holder, report_issues)
if evaluation is not None:
evaluated_list.append(evaluation.value)
evaluated = True
if not evaluation.final:
final = False
else:
evaluated_list.append(v)
if evaluated:
value = evaluated_list
elif isinstance(value, dict):
evaluated_dict = OrderedDict()
for k, v in value.iteritems():
evaluation = evaluate(v, container_holder, report_issues)
if evaluation is not None:
evaluated_dict[k] = evaluation.value
evaluated = True
if not evaluation.final:
final = False
else:
evaluated_dict[k] = v
if evaluated:
value = evaluated_dict
return Evaluation(value, final) if evaluated else None
|