8a7b2cef50
Most of assignment expressions involving indexation operator except for the most trivial one fail. For example the following failed: $myDict[$keyName]: value $myDict['A']['B']: value (even if $myDict['A'] is a dictionary) $myList[2 + 2]: value $myList[$index]: value This commit adds support for sub-expressions within LHS-expressions Change-Id: I4b72e85b5f9bda04c6156d5c8b07eb8f5358643d Closes-Bug: #1358545
145 lines
5.5 KiB
Python
145 lines
5.5 KiB
Python
# Copyright (c) 2014 Mirantis, Inc.
|
|
#
|
|
# Licensed 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.
|
|
|
|
import types
|
|
|
|
import yaql
|
|
import yaql.context
|
|
import yaql.expressions
|
|
|
|
import murano.dsl.murano_object as murano_object
|
|
import murano.dsl.type_scheme as type_scheme
|
|
import murano.dsl.yaql_expression as yaql_expression
|
|
|
|
|
|
class LhsExpression(object):
|
|
class Property(object):
|
|
def __init__(self, getter, setter):
|
|
self._getter = getter
|
|
self._setter = setter
|
|
|
|
def get(self):
|
|
return self._getter()
|
|
|
|
def set(self, value):
|
|
self._setter(value)
|
|
|
|
def __init__(self, expression):
|
|
if isinstance(expression, (yaql_expression.YaqlExpression,
|
|
yaql.expressions.Expression)):
|
|
self._expression = expression
|
|
else:
|
|
self._expression = yaql.parse(str(expression))
|
|
self._current_obj = None
|
|
self._current_obj_name = None
|
|
|
|
def _create_context(self, root_context, murano_class):
|
|
def _evaluate(thing):
|
|
if isinstance(thing, yaql.expressions.Expression.Callable):
|
|
thing.yaql_context = root_context
|
|
thing = thing()
|
|
return thing
|
|
|
|
def _get_value(src, key):
|
|
key = _evaluate(key)
|
|
if isinstance(src, types.DictionaryType):
|
|
return src.get(key)
|
|
elif isinstance(src, types.ListType) and isinstance(
|
|
key, types.IntType):
|
|
return src[key]
|
|
elif isinstance(src, murano_object.MuranoObject) and isinstance(
|
|
key, types.StringTypes):
|
|
self._current_obj = src
|
|
self._current_obj_name = key
|
|
return src.get_property(key, murano_class)
|
|
else:
|
|
raise TypeError()
|
|
|
|
def _set_value(src, key, value):
|
|
key = _evaluate(key)
|
|
if isinstance(src, types.DictionaryType):
|
|
old_value = src.get(key, type_scheme.NoValue)
|
|
src[key] = value
|
|
if self._current_obj is not None:
|
|
try:
|
|
p_value = self._current_obj.get_property(
|
|
self._current_obj_name, murano_class)
|
|
self._current_obj.set_property(
|
|
self._current_obj_name, p_value, murano_class)
|
|
except Exception as e:
|
|
if old_value is not type_scheme.NoValue:
|
|
src[key] = old_value
|
|
else:
|
|
src.pop(key, None)
|
|
raise e
|
|
elif isinstance(src, types.ListType) and isinstance(
|
|
key, types.IntType):
|
|
old_value = src[key]
|
|
src[key] = value
|
|
if self._current_obj is not None:
|
|
try:
|
|
p_value = self._current_obj.get_property(
|
|
self._current_obj_name, murano_class)
|
|
self._current_obj.set_property(
|
|
self._current_obj_name, p_value, murano_class)
|
|
except Exception as e:
|
|
src[key] = old_value
|
|
raise e
|
|
|
|
elif isinstance(src, murano_object.MuranoObject) and isinstance(
|
|
key, types.StringTypes):
|
|
src.set_property(key, value, murano_class)
|
|
else:
|
|
raise TypeError()
|
|
|
|
def get_context_data(path):
|
|
path = path()
|
|
|
|
def set_data(value):
|
|
if not path or path == '$' or path == '$this':
|
|
raise ValueError()
|
|
root_context.set_data(value, path)
|
|
|
|
return LhsExpression.Property(
|
|
lambda: root_context.get_data(path), set_data)
|
|
|
|
@yaql.context.EvalArg('this', arg_type=LhsExpression.Property)
|
|
def attribution(this, arg_name):
|
|
arg_name = arg_name()
|
|
return LhsExpression.Property(
|
|
lambda: _get_value(this.get(), arg_name),
|
|
lambda value: _set_value(this.get(), arg_name, value))
|
|
|
|
@yaql.context.EvalArg("this", LhsExpression.Property)
|
|
def indexation(this, index):
|
|
index = _evaluate(index)
|
|
|
|
return LhsExpression.Property(
|
|
lambda: _get_value(this.get(), index),
|
|
lambda value: _set_value(this.get(), index, value))
|
|
|
|
context = yaql.context.Context()
|
|
context.register_function(get_context_data, '#get_context_data')
|
|
context.register_function(attribution, '#operator_.')
|
|
context.register_function(indexation, "where")
|
|
return context
|
|
|
|
def __call__(self, value, context, murano_class):
|
|
new_context = self._create_context(context, murano_class)
|
|
new_context.set_data(context.get_data('$'))
|
|
self._current_obj = None
|
|
self._current_obj_name = None
|
|
property = self._expression.evaluate(context=new_context)
|
|
property.set(value)
|