yaql context versioning

This commit reworks mechanism how context chain
is built at each point. The goal was to make
entire chain be dependent on format version
number. This would allow for example to use
yaql 1.0 legacy mode context for MuranoPL/1.0
and not to use it for 2.0.

Not the entire chain is built on demand up to the
root instead of attaching to existed parent context
as it was before. DSL host (engine) is no more
required to have custom MuranoDslExecutor implementation
but a new ContextManager interface that is used
to control contexts on each layer. Engine uses
this interface to register system classes and
engine level yaql functions. Also a ContextManager
is a foundation for method mocking because now
all MuranoPL methods are yaql functions stored
in context and with ContextManager it is possible
to inject/replace function in each scope (
global, package, class, object)

Partially implements: blueprint murano-versioning

Change-Id: I0a553e8044061fe780a83bc04d70b8f80580988f
This commit is contained in:
Stan Lagun 2015-08-29 13:16:18 +03:00 committed by Victor Ryzhenkin
parent b1fc727e73
commit 16030aeec8
23 changed files with 491 additions and 291 deletions

View File

@ -28,7 +28,6 @@ from murano import version
from murano.common.i18n import _, _LE
from murano.common import config
from murano.common import engine
from murano.dsl import constants
from murano.dsl import exceptions
from murano.dsl import executor
from murano.dsl import helpers
@ -122,13 +121,10 @@ def _get_all_test_methods(exc, package):
"""
class_to_obj = {}
class_to_methods = {}
child_context = exc.object_store.context.create_child_context()
child_context[constants.CTX_ALLOW_PROPERTY_WRITES] = True
for pkg_class_name in package.classes:
class_obj = package.find_class(pkg_class_name, False)
obj = class_obj.new(None, exc.object_store, child_context)()
obj = class_obj.new(None, exc.object_store)(None)
if not helpers.is_instance_of(obj, BASE_CLASS, '*'):
LOG.debug('Class {0} is not inherited from {1}. '
'Skipping it.'.format(pkg_class_name, BASE_CLASS))
@ -212,7 +208,8 @@ def run_tests(args):
with package_loader.CombinedPackageLoader(
murano_client_factory, client.tenant_id) as pkg_loader:
engine.get_plugin_loader().register_in_loader(pkg_loader)
exc = executor.MuranoDslExecutor(pkg_loader, test_env)
exc = executor.MuranoDslExecutor(
pkg_loader, engine.ContextManager(), test_env)
package = _load_package(pkg_loader, provided_pkg_name)
class_to_methods, class_to_obj = _get_all_test_methods(exc, package)

View File

@ -28,12 +28,15 @@ from murano.common import auth_utils
from murano.common.helpers import token_sanitizer
from murano.common import plugin_loader
from murano.common import rpc
from murano.dsl import context_manager
from murano.dsl import dsl_exception
from murano.dsl import executor as dsl_executor
from murano.dsl import linked_context
from murano.dsl import serializer
from murano.engine import environment
from murano.engine import executor as engine_executor
from murano.engine import package_loader
from murano.engine.system import status_reporter
from murano.engine.system import yaql_functions
from murano.common.i18n import _LI, _LE, _LW
from murano.policy import model_policy_enforcer as enforcer
@ -71,6 +74,14 @@ def get_plugin_loader():
return PLUGIN_LOADER
class ContextManager(context_manager.ContextManager):
def create_root_context(self, runtime_version):
root_context = super(ContextManager, self).create_root_context(
runtime_version)
return linked_context.link(
root_context, yaql_functions.get_context(runtime_version))
class TaskProcessingEndpoint(object):
@classmethod
def handle_task(cls, context, task):
@ -149,8 +160,8 @@ class TaskExecutor(object):
def _execute(self, pkg_loader):
get_plugin_loader().register_in_loader(pkg_loader)
executor = engine_executor.Executor(
pkg_loader, self.environment)
executor = dsl_executor.MuranoDslExecutor(
pkg_loader, ContextManager(), self.environment)
try:
obj = executor.load(self.model)
except Exception as e:

View File

@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import semantic_version
EXPRESSION_MEMORY_QUOTA = 512 * 1024
ITERATORS_LIMIT = 2000
@ -25,11 +27,11 @@ CTX_CURRENT_EXCEPTION = '$?currentException'
CTX_CURRENT_METHOD = '$?currentMethod'
CTX_ENVIRONMENT = '$?environment'
CTX_EXECUTOR = '$?executor'
CTX_OBJECT_STORE = '$?objectStore'
CTX_PACKAGE_LOADER = '$?packageLoader'
CTX_SKIP_FRAME = '$?skipFrame'
CTX_THIS = '$?this'
CTX_TYPE = '$?type'
CTX_YAQL_ENGINE = '$?yaqlEngine'
DM_OBJECTS = 'Objects'
DM_OBJECTS_COPY = 'ObjectsCopy'
@ -39,3 +41,6 @@ META_NO_TRACE = '?noTrace'
CORE_LIBRARY = 'io.murano'
CORE_LIBRARY_OBJECT = 'io.murano.Object'
RUNTIME_VERSION_1_0 = semantic_version.Version('1.0.0')
RUNTIME_VERSION_2_0 = semantic_version.Version('2.0.0')

View File

@ -0,0 +1,37 @@
# Copyright (c) 2015 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.
from murano.dsl import yaql_integration
# noinspection PyMethodMayBeStatic
class ContextManager(object):
"""Context manager for the MuranoDslExecutor.
DSL hosting project should subclass this and override methods in order
to insert yaql function at various scopes. For example it may override
create_root_context to register its own global yaql functions.
"""
def create_root_context(self, runtime_version):
return yaql_integration.create_context(runtime_version)
def create_package_context(self, package):
return package.context
def create_class_context(self, murano_class):
return murano_class.context
def create_object_context(self, obj):
return None

View File

@ -64,7 +64,7 @@ class MuranoType(yaqltypes.PythonType):
result = super(MuranoType, self).convert(
value, sender, context, function_spec, engine, *args, **kwargs)
if isinstance(result, dsl_types.MuranoObject):
return MuranoObjectInterface(result, engine)
return MuranoObjectInterface(result)
return result
@ -76,7 +76,7 @@ class ThisParameterType(yaqltypes.HiddenParameterType, yaqltypes.SmartType):
*args, **kwargs):
this = helpers.get_this(context)
executor = helpers.get_executor(context)
return MuranoObjectInterface(this, engine, executor)
return MuranoObjectInterface(this, executor)
class InterfacesParameterType(yaqltypes.HiddenParameterType,
@ -87,7 +87,7 @@ class InterfacesParameterType(yaqltypes.HiddenParameterType,
def convert(self, value, sender, context, function_spec, engine,
*args, **kwargs):
this = helpers.get_this(context)
return Interfaces(engine, this)
return Interfaces(this)
class MuranoTypeName(yaqltypes.LazyParameterType, yaqltypes.PythonType):
@ -151,10 +151,9 @@ class MuranoObjectInterface(dsl_types.MuranoObjectInterface):
context[constants.CTX_CURRENT_INSTRUCTION] = NativeInstruction(
frame[4][0].strip(), location)
def __init__(self, mpl_object, engine, executor=None):
def __init__(self, mpl_object, executor=None):
self.__object = mpl_object
self.__executor = executor
self.__engine = engine
@property
def object(self):
@ -188,7 +187,7 @@ class MuranoObjectInterface(dsl_types.MuranoObjectInterface):
helpers.cast(
self.__object, murano_class,
version_spec or helpers.get_type()),
self.__engine, self.__executor)
self.__executor)
def is_instance_of(self, murano_class, version_spec=None):
return helpers.is_instance_of(
@ -201,7 +200,8 @@ class MuranoObjectInterface(dsl_types.MuranoObjectInterface):
def __getitem__(self, item):
context = helpers.get_context()
return to_mutable(
self.__object.get_property(item, context), self.__engine)
self.__object.get_property(item, context),
helpers.get_yaql_engine(context))
def __setitem__(self, key, value):
context = helpers.get_context()
@ -217,28 +217,27 @@ class MuranoObjectInterface(dsl_types.MuranoObjectInterface):
class YaqlInterface(object):
def __init__(self, engine, sender=utils.NO_VALUE):
self.__engine = engine
def __init__(self, sender=utils.NO_VALUE):
self.__sender = sender
@property
def context(self):
return self.__context
return helpers.get_context()
@property
def engine(self):
return self.__engine
return helpers.get_yaql_engine(self.context)
@property
def sender(self):
return self.__sender
def on(self, sender):
return YaqlInterface(self.engine, sender)
return YaqlInterface(sender)
def __getattr__(self, item):
def stub(*args, **kwargs):
context = helpers.get_context()
context = self.context
args = tuple(helpers.evaluate(arg, context) for arg in args)
kwargs = dict((key, helpers.evaluate(value, context))
for key, value in kwargs.iteritems())
@ -265,12 +264,11 @@ class YaqlInterface(object):
class Interfaces(object):
def __init__(self, engine, mpl_object):
self.__engine = engine
def __init__(self, mpl_object):
self.__object = mpl_object
def yaql(self, sender=utils.NO_VALUE):
return YaqlInterface(self.__engine, sender)
return YaqlInterface(sender)
def this(self):
return self.methods(self.__object)
@ -278,7 +276,7 @@ class Interfaces(object):
def methods(self, mpl_object):
if mpl_object is None:
return None
return MuranoObjectInterface(mpl_object, self.__engine)
return MuranoObjectInterface(mpl_object)
@property
def environment(self):
@ -292,7 +290,7 @@ class Interfaces(object):
caller = helpers.get_this(caller_context)
if caller is None:
return None
return MuranoObjectInterface(caller, self.__engine)
return MuranoObjectInterface(caller)
@property
def attributes(self):
@ -321,7 +319,7 @@ class NativeInstruction(object):
def to_mutable(obj, yaql_engine):
def converter(value, limit_func, engine, rec):
if isinstance(value, dsl_types.MuranoObject):
return MuranoObjectInterface(value, engine)
return MuranoObjectInterface(value)
else:
return utils.convert_output_data(value, limit_func, engine, rec)

View File

@ -28,29 +28,24 @@ from murano.dsl import attribute_store
from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import helpers
from murano.dsl import linked_context
from murano.dsl import murano_method
from murano.dsl import object_store
from murano.dsl.principal_objects import stack_trace
from murano.dsl import yaql_functions
from murano.dsl import yaql_integration
LOG = logging.getLogger(__name__)
class MuranoDslExecutor(object):
def __init__(self, package_loader, environment=None):
def __init__(self, package_loader, context_manager, environment=None):
self._package_loader = package_loader
self._context_manager = context_manager
self._environment = environment
self._attribute_store = attribute_store.AttributeStore()
self._root_context = \
self.create_root_context().create_child_context()
self._root_context[constants.CTX_EXECUTOR] = weakref.proxy(self)
self._root_context[
constants.CTX_PACKAGE_LOADER] = weakref.proxy(self._package_loader)
self._root_context[constants.CTX_ENVIRONMENT] = environment
self._root_context[constants.CTX_ATTRIBUTE_STORE] = weakref.proxy(
self._attribute_store)
self._object_store = object_store.ObjectStore(self._root_context)
self._object_store = object_store.ObjectStore(self)
self._locks = {}
self._root_context_cache = {}
@property
def object_store(self):
@ -64,24 +59,32 @@ class MuranoDslExecutor(object):
def package_loader(self):
return self._package_loader
@property
def context_manager(self):
return self._context_manager
def invoke_method(self, method, this, context, args, kwargs,
skip_stub=False):
if isinstance(this, dsl.MuranoObjectInterface):
this = this.object
kwargs = yaql_integration.filter_parameters_dict(kwargs)
kwargs = helpers.filter_parameters_dict(kwargs)
runtime_version = method.murano_class.package.runtime_version
yaql_engine = yaql_integration.choose_yaql_engine(runtime_version)
if context is None or not skip_stub:
actions_only = context is None and not method.name.startswith('.')
method_context = self._create_method_context(
this, method, context, actions_only, skip_frame=True)
method_context = self.create_method_context(
self.create_object_context(this, context), method)
method_context[constants.CTX_SKIP_FRAME] = True
method_context[constants.CTX_ACTIONS_ONLY] = actions_only
return method.yaql_function_definition(
yaql_integration.ENGINE, method_context, this.real_this)(
*args, **kwargs)
yaql_engine, method_context, this.real_this)(*args, **kwargs)
if (context[constants.CTX_ACTIONS_ONLY] and method.usage !=
murano_method.MethodUsages.Action):
raise Exception('{0} is not an action'.format(method.name))
context = self._create_method_context(this, method, context)
context = self.create_method_context(
self.create_object_context(this, context), method)
this = this.real_this
if method.arguments_scheme is not None:
@ -99,8 +102,7 @@ class MuranoDslExecutor(object):
native_this = this.cast(
method.murano_class).extension
return method.body(
yaql_integration.ENGINE, context, native_this)(
*args, **kwargs)
yaql_engine, context, native_this)(*args, **kwargs)
else:
return (None if method.body is None
else method.body.execute(context))
@ -171,30 +173,12 @@ class MuranoDslExecutor(object):
@staticmethod
def _canonize_parameters(arguments_scheme, args, kwargs):
arg_names = arguments_scheme.keys()
parameter_values = yaql_integration.filter_parameters_dict(kwargs)
parameter_values = helpers.filter_parameters_dict(kwargs)
for i, arg in enumerate(args):
name = arg_names[i]
parameter_values[name] = arg
return tuple(), parameter_values
def _create_method_context(self, this, method, context=None,
actions_only=False, skip_frame=False):
new_context = self.create_local_context(
parent_context=this.context,
murano_class=this.type)
caller = context
while caller is not None and caller[constants.CTX_SKIP_FRAME]:
caller = caller[constants.CTX_CALLER_CONTEXT]
new_context[constants.CTX_CALLER_CONTEXT] = caller
new_context[constants.CTX_CURRENT_METHOD] = method
new_context[constants.CTX_ACTIONS_ONLY] = actions_only
new_context[constants.CTX_SKIP_FRAME] = skip_frame
if context is not None:
new_context[constants.CTX_ALLOW_PROPERTY_WRITES] = context[
constants.CTX_ALLOW_PROPERTY_WRITES]
return new_context
def load(self, data):
if not isinstance(data, types.DictionaryType):
raise TypeError()
@ -202,14 +186,13 @@ class MuranoDslExecutor(object):
result = self._object_store.load(data.get(constants.DM_OBJECTS), None)
if result is None:
return None
return dsl.MuranoObjectInterface(
result, yaql_integration.ENGINE, executor=self)
return dsl.MuranoObjectInterface(result, executor=self)
def cleanup(self, data):
objects_copy = data.get(constants.DM_OBJECTS_COPY)
if not objects_copy:
return
gc_object_store = object_store.ObjectStore(self._root_context)
gc_object_store = object_store.ObjectStore(self)
gc_object_store.load(objects_copy, None)
objects_to_clean = []
for object_id in self._list_potential_object_ids(objects_copy):
@ -244,12 +227,57 @@ class MuranoDslExecutor(object):
for res in self._list_potential_object_ids(val):
yield res
# noinspection PyMethodMayBeStatic
def create_local_context(self, parent_context, murano_class):
return parent_context.create_child_context()
# noinspection PyMethodMayBeStatic
def create_root_context(self):
context = yaql_integration.create_context()
yaql_functions.register(context)
def create_root_context(self, runtime_version):
context = self._root_context_cache.get(runtime_version)
if not context:
context = self.context_manager.create_root_context(runtime_version)
context = context.create_child_context()
context[constants.CTX_EXECUTOR] = weakref.ref(self)
context[constants.CTX_PACKAGE_LOADER] = weakref.ref(
self._package_loader)
context[constants.CTX_ENVIRONMENT] = self._environment
context[constants.CTX_ATTRIBUTE_STORE] = weakref.ref(
self._attribute_store)
self._root_context_cache[runtime_version] = context
return context
def create_package_context(self, package):
root_context = self.create_root_context(package.runtime_version)
context = linked_context.link(
root_context,
self.context_manager.create_package_context(package))
return context
def create_class_context(self, murano_class):
package_context = self.create_package_context(
murano_class.package)
context = linked_context.link(
package_context,
self.context_manager.create_class_context(
murano_class)).create_child_context()
context[constants.CTX_TYPE] = murano_class
return context
def create_object_context(self, obj, caller_context=None):
class_context = self.create_class_context(obj.type)
context = linked_context.link(
class_context, self.context_manager.create_object_context(
obj)).create_child_context()
context[constants.CTX_THIS] = obj.real_this
context['this'] = obj.real_this
context[''] = obj.real_this
if caller_context is not None:
caller = caller_context
while caller is not None and caller[constants.CTX_SKIP_FRAME]:
caller = caller[constants.CTX_CALLER_CONTEXT]
context[constants.CTX_CALLER_CONTEXT] = caller
context[constants.CTX_ALLOW_PROPERTY_WRITES] = caller_context[
constants.CTX_ALLOW_PROPERTY_WRITES]
return context
@staticmethod
def create_method_context(object_context, method):
context = object_context.create_child_context()
context[constants.CTX_CURRENT_METHOD] = method
return context

View File

@ -14,6 +14,7 @@
import collections
import contextlib
import functools
import re
import string
import sys
@ -135,7 +136,8 @@ def get_context():
def get_executor(context=None):
context = context or get_context()
return context[constants.CTX_EXECUTOR]
result = context[constants.CTX_EXECUTOR]
return None if not result else result()
def get_type(context=None):
@ -150,12 +152,13 @@ def get_environment(context=None):
def get_object_store(context=None):
context = context or get_context()
return context[constants.CTX_OBJECT_STORE]
return context[constants.CTX_THIS].object_store
def get_package_loader(context=None):
context = context or get_context()
return context[constants.CTX_PACKAGE_LOADER]
result = context[constants.CTX_PACKAGE_LOADER]
return None if not result else result()
def get_this(context=None):
@ -170,7 +173,8 @@ def get_caller_context(context=None):
def get_attribute_store(context=None):
context = context or get_context()
return context[constants.CTX_ATTRIBUTE_STORE]
store = context[constants.CTX_ATTRIBUTE_STORE]
return None if not store else store()
def get_current_instruction(context=None):
@ -183,6 +187,11 @@ def get_current_method(context=None):
return context[constants.CTX_CURRENT_METHOD]
def get_yaql_engine(context=None):
context = context or get_context()
return context[constants.CTX_YAQL_ENGINE]
def get_current_exception(context=None):
context = context or get_context()
return context[constants.CTX_CURRENT_EXCEPTION]
@ -316,3 +325,25 @@ def is_instance_of(obj, class_name, pov_or_version_spec=None):
return True
except (exceptions.NoClassFound, exceptions.AmbiguousClassName):
return False
def filter_parameters_dict(parameters):
parameters = parameters.copy()
for name in parameters.keys():
if not is_keyword(name):
del parameters[name]
return parameters
def memoize(func):
cache = {}
@functools.wraps(func)
def wrap(*args):
if args not in cache:
result = func(*args)
cache[args] = result
return result
else:
return cache[args]
return wrap

View File

@ -0,0 +1,69 @@
# Copyright (c) 2015 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.
from yaql.language import contexts
from yaql.language import utils
class LinkedContext(contexts.ContextBase):
"""Context that is as a proxy to another context but has its own parent."""
def __init__(self, parent_context, linked_context, convention=None):
self.linked_context = linked_context
if linked_context.parent:
super(LinkedContext, self).__init__(
LinkedContext(parent_context, linked_context.parent,
convention), convention)
else:
super(LinkedContext, self).__init__(parent_context, convention)
def register_function(self, spec, *args, **kwargs):
return self.linked_context.register_function(spec, *args, **kwargs)
def keys(self):
return self.linked_context.keys()
def get_data(self, name, default=None, ask_parent=True):
result = self.linked_context.get_data(
name, default=utils.NO_VALUE, ask_parent=False)
if result is utils.NO_VALUE:
if not ask_parent or not self.parent:
return default
return self.parent.get_data(name, default=default, ask_parent=True)
return result
def get_functions(self, name, predicate=None, use_convention=False):
return self.linked_context.get_functions(
name, predicate=predicate, use_convention=use_convention)
def delete_function(self, spec):
return self.linked_context.delete_function(spec)
def __contains__(self, item):
return item in self.linked_context
def __delitem__(self, name):
del self.linked_context[name]
def __setitem__(self, name, value):
self.linked_context[name] = value
def create_child_context(self):
return type(self.linked_context)(self)
def link(parent_context, context):
if not context:
return parent_context
return LinkedContext(parent_context, context)

View File

@ -16,6 +16,7 @@ import collections
import weakref
import semantic_version
from yaql.language import utils
from murano.dsl import constants
from murano.dsl import dsl
@ -24,16 +25,16 @@ from murano.dsl import exceptions
from murano.dsl import helpers
from murano.dsl import murano_method
from murano.dsl import murano_object
from murano.dsl import namespace_resolver
from murano.dsl import typespec
from murano.dsl import yaql_integration
class MuranoClass(dsl_types.MuranoClass):
def __init__(self, namespace_resolver, name, package,
parents=None):
def __init__(self, ns_resolver, name, package, parents=None):
self._package = weakref.ref(package)
self._methods = {}
self._namespace_resolver = namespace_resolver
self._namespace_resolver = ns_resolver
self._name = name
self._properties = {}
self._config = {}
@ -42,9 +43,46 @@ class MuranoClass(dsl_types.MuranoClass):
else:
self._parents = parents or [
package.find_class(constants.CORE_LIBRARY_OBJECT)]
self._unique_methods = None
self._context = None
self._parent_mappings = self._build_parent_remappings()
@classmethod
def create(cls, data, package, name=None):
namespaces = data.get('Namespaces') or {}
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
if not name:
name = ns_resolver.resolve_name(data['Name'])
parent_class_names = data.get('Extends')
parent_classes = []
if parent_class_names:
if not utils.is_sequence(parent_class_names):
parent_class_names = [parent_class_names]
for parent_name in parent_class_names:
full_name = ns_resolver.resolve_name(parent_name)
parent_classes.append(package.find_class(full_name))
type_obj = cls(ns_resolver, name, package, parent_classes)
properties = data.get('Properties') or {}
for property_name, property_spec in properties.iteritems():
spec = typespec.PropertySpec(property_spec, type_obj)
type_obj.add_property(property_name, spec)
methods = data.get('Methods') or data.get('Workflow') or {}
method_mappings = {
'initialize': '.init',
'destroy': '.destroy'
}
for method_name, payload in methods.iteritems():
type_obj.add_method(
method_mappings.get(method_name, method_name), payload)
return type_obj
@property
def name(self):
return self._name
@ -70,34 +108,22 @@ class MuranoClass(dsl_types.MuranoClass):
return self._parent_mappings
def extend_with_class(self, cls):
ctor = yaql_integration.get_class_factory_definition(cls)
ctor = yaql_integration.get_class_factory_definition(cls, self)
self.add_method('__init__', ctor)
@property
def unique_methods(self):
if self._unique_methods is None:
self._unique_methods = list(self._iterate_unique_methods())
return self._unique_methods
def get_method(self, name):
return self._methods.get(name)
def add_method(self, name, payload):
method = murano_method.MuranoMethod(self, name, payload)
self._methods[name] = method
self._unique_methods = None
self._context = None
return method
@property
def properties(self):
return self._properties.keys()
def register_methods(self, context):
for method in self.unique_methods:
context.register_function(
method.yaql_function_definition,
name=method.yaql_function_definition.name)
def add_property(self, name, property_typespec):
if not isinstance(property_typespec, typespec.PropertySpec):
raise TypeError('property_typespec')
@ -161,7 +187,12 @@ class MuranoClass(dsl_types.MuranoClass):
for c in self.ancestors():
names.update(c.methods.keys())
for name in names:
yield self.find_single_method(name)
try:
yield self.find_single_method(name)
except exceptions.AmbiguousMethodName as e:
def func(*args, **kwargs):
raise e
yield murano_method.MuranoMethod(self, name, func)
def find_property(self, name):
result = []
@ -197,14 +228,13 @@ class MuranoClass(dsl_types.MuranoClass):
obj = obj.type
return any(cls is self for cls in obj.ancestors())
def new(self, owner, object_store, context=None, **kwargs):
if context is None:
context = object_store.context
obj = murano_object.MuranoObject(
self, owner, object_store.context, **kwargs)
def new(self, owner, object_store, **kwargs):
obj = murano_object.MuranoObject(self, owner, object_store, **kwargs)
def initializer(**params):
init_context = context.create_child_context()
def initializer(__context, **params):
if __context is None:
__context = object_store.executor.create_object_context(obj)
init_context = __context.create_child_context()
init_context[constants.CTX_ALLOW_PROPERTY_WRITES] = True
obj.initialize(init_context, object_store, params)
return obj
@ -304,3 +334,13 @@ class MuranoClass(dsl_types.MuranoClass):
def ancestors(self):
for c in helpers.traverse(self, lambda t: t.parents(self)):
yield c
@property
def context(self):
if not self._context:
self._context = yaql_integration.create_empty_context()
for m in self._iterate_unique_methods():
self._context.register_function(
m.yaql_function_definition,
name=m.yaql_function_definition.name)
return self._context

View File

@ -14,6 +14,7 @@
import collections
import types
import weakref
from yaql.language import specs
@ -38,7 +39,7 @@ class MethodUsages(object):
class MuranoMethod(dsl_types.MuranoMethod):
def __init__(self, murano_class, name, payload):
self._name = name
self._murano_class = murano_class
self._murano_class = weakref.ref(murano_class)
if callable(payload):
if isinstance(payload, specs.FunctionDefinition):
@ -78,7 +79,7 @@ class MuranoMethod(dsl_types.MuranoMethod):
@property
def murano_class(self):
return self._murano_class
return self._murano_class()
@property
def arguments_scheme(self):

View File

@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import weakref
from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import dsl_types
@ -22,7 +24,7 @@ from murano.dsl import yaql_integration
class MuranoObject(dsl_types.MuranoObject):
def __init__(self, murano_class, owner, context, object_id=None,
def __init__(self, murano_class, owner, object_store, object_id=None,
name=None, known_classes=None, defaults=None, this=None):
if known_classes is None:
known_classes = {}
@ -35,8 +37,7 @@ class MuranoObject(dsl_types.MuranoObject):
self.__this = this
self.__name = name
self.__extension = None
self.__context = self.__setup_context(context)
object_store = helpers.get_object_store(context)
self.__object_store = weakref.ref(object_store)
self.__config = murano_class.package.get_class_config(
murano_class.name)
if not isinstance(self.__config, dict):
@ -46,28 +47,15 @@ class MuranoObject(dsl_types.MuranoObject):
name = parent_class.name
if name not in known_classes:
obj = parent_class.new(
owner, object_store, context,
object_id=self.__object_id,
known_classes=known_classes,
defaults=defaults, this=self.real_this).object
owner, object_store, object_id=self.__object_id,
known_classes=known_classes, defaults=defaults,
this=self.real_this).object
self.__parents[name] = known_classes[name] = obj
else:
self.__parents[name] = known_classes[name]
self.__initialized = False
def __setup_context(self, context):
context = context.create_child_context()
context[constants.CTX_THIS] = self.real_this
context[constants.CTX_TYPE] = self.type
context['this'] = self.real_this
context[''] = self.real_this
return context
@property
def context(self):
return self.__context
@property
def extension(self):
return self.__extension
@ -80,6 +68,10 @@ class MuranoObject(dsl_types.MuranoObject):
def extension(self, value):
self.__extension = value
@property
def object_store(self):
return self.__object_store()
def initialize(self, context, object_store, params):
if self.__initialized:
return
@ -153,9 +145,8 @@ class MuranoObject(dsl_types.MuranoObject):
parent.initialize(context, object_store, params)
if not object_store.initializing and init:
init_context = context.create_child_context()
init_context[constants.CTX_ARGUMENT_OWNER] = self.real_this
init.invoke(executor, self.real_this, (), init_args, init_context)
context[constants.CTX_ARGUMENT_OWNER] = self.real_this
init.invoke(executor, self.real_this, (), init_args, context)
self.__initialized = True
@property
@ -203,6 +194,8 @@ class MuranoObject(dsl_types.MuranoObject):
if caller_class is not None and caller_class.is_compatible(self):
start_type, derived = caller_class, True
declared_properties = start_type.find_property(name)
if context is None:
context = self.object_store.executor.create_object_context(self)
if len(declared_properties) > 0:
declared_properties = self.type.find_property(name)
values_to_assign = []
@ -216,7 +209,7 @@ class MuranoObject(dsl_types.MuranoObject):
default = self.__config.get(name, spec.default)
default = self.__defaults.get(name, default)
default = helpers.evaluate(default, context or self.context)
default = helpers.evaluate(default, context)
obj = self.cast(mc)
values_to_assign.append((obj, spec.validate(

View File

@ -16,7 +16,6 @@ import inspect
import weakref
import semantic_version
from yaql.language import utils
from murano.dsl import constants
from murano.dsl import dsl_types
@ -24,9 +23,7 @@ from murano.dsl import exceptions
from murano.dsl import helpers
from murano.dsl import murano_class
from murano.dsl import murano_object
from murano.dsl import namespace_resolver
from murano.dsl import principal_objects
from murano.dsl import typespec
from murano.dsl import yaql_integration
@ -88,41 +85,10 @@ class MuranoPackage(dsl_types.MuranoPackage):
return {}
def _register_mpl_class(self, data, name=None):
if name in self._classes:
return self._classes[name]
namespaces = data.get('Namespaces') or {}
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
parent_class_names = data.get('Extends')
parent_classes = []
if parent_class_names:
if not utils.is_sequence(parent_class_names):
parent_class_names = [parent_class_names]
for parent_name in parent_class_names:
full_name = ns_resolver.resolve_name(parent_name)
parent_classes.append(self.find_class(full_name))
type_obj = murano_class.MuranoClass(
ns_resolver, name, self, parent_classes)
properties = data.get('Properties') or {}
for property_name, property_spec in properties.iteritems():
spec = typespec.PropertySpec(property_spec, type_obj)
type_obj.add_property(property_name, spec)
methods = data.get('Methods') or data.get('Workflow') or {}
method_mappings = {
'initialize': '.init',
'destroy': '.destroy'
}
for method_name, payload in methods.iteritems():
type_obj.add_method(
method_mappings.get(method_name, method_name), payload)
self._classes[name] = type_obj
type_obj = self._classes.get(name)
if not type_obj:
type_obj = murano_class.MuranoClass.create(data, self, name)
self._classes[name] = type_obj
return type_obj
def _register_native_class(self, cls, name):
@ -153,6 +119,8 @@ class MuranoPackage(dsl_types.MuranoPackage):
if inspect.isclass(cls):
name = name or getattr(cls, '__murano_name', None) or cls.__name__
self._native_load_queue[name] = cls
elif isinstance(cls, murano_class.MuranoClass):
self._classes[cls.name] = cls
else:
self._load_queue[name] = cls
@ -182,3 +150,7 @@ class MuranoPackage(dsl_types.MuranoPackage):
except exceptions.NoClassFound:
continue
raise exceptions.NoClassFound(name)
@property
def context(self):
return None

View File

@ -12,19 +12,19 @@
# License for the specific language governing permissions and limitations
# under the License.
from murano.dsl import constants
import weakref
from murano.dsl import dsl_types
from murano.dsl import helpers
class ObjectStore(object):
def __init__(self, context, parent_store=None):
self._context = context.create_child_context()
self._package_loader = helpers.get_package_loader(context)
self._context[constants.CTX_OBJECT_STORE] = self
def __init__(self, executor, parent_store=None):
self._parent_store = parent_store
self._store = {}
self._designer_attributes_store = {}
self._executor = weakref.ref(executor)
self._initializing = False
@property
@ -32,8 +32,8 @@ class ObjectStore(object):
return self._initializing
@property
def context(self):
return self._context
def executor(self):
return self._executor()
def get(self, object_id):
if object_id in self._store:
@ -51,7 +51,7 @@ class ObjectStore(object):
def put(self, murano_object):
self._store[murano_object.object_id] = murano_object
def load(self, value, owner, defaults=None):
def load(self, value, owner, context=None, defaults=None):
if value is None:
return None
if '?' not in value or 'type' not in value['?']:
@ -63,10 +63,10 @@ class ObjectStore(object):
system_key.get('classVersion'))
if 'package' not in system_key:
package = self._package_loader.load_class_package(
package = self.executor.package_loader.load_class_package(
obj_type, version_spec)
else:
package = self._package_loader.load_package(
package = self.executor.package_loader.load_package(
system_key['package'], version_spec)
class_obj = package.find_class(obj_type, False)
@ -80,19 +80,21 @@ class ObjectStore(object):
return factory
else:
factory = class_obj.new(
owner, self, context=self.context,
owner, self,
name=system_key.get('name'),
object_id=object_id, defaults=defaults)
self._store[object_id] = factory
system_value = ObjectStore._get_designer_attributes(system_key)
self._designer_attributes_store[object_id] = system_value
obj = factory(**value)
init_context = self.executor.create_object_context(
factory.object, context)
obj = factory(init_context, **value)
if not self._initializing:
self._store[object_id] = obj
if owner is None:
self._initializing = False
self._store[object_id] = factory(**value)
self._store[object_id] = factory(init_context, **value)
finally:
if owner is None:
self._initializing = False

View File

@ -107,4 +107,4 @@ def create_stack_trace(context, include_native_frames=True):
includeNativeFrames=include_native_frames)
executor = helpers.get_executor(context)
return dsl.MuranoObjectInterface(
stacktrace, yaql_integration.ENGINE, executor)
stacktrace, executor)

View File

@ -24,7 +24,6 @@ from murano.dsl import dsl
from murano.dsl import dsl_types
from murano.dsl import exceptions
from murano.dsl import helpers
from murano.dsl import yaql_integration
class TypeScheme(object):
@ -151,7 +150,7 @@ class TypeScheme(object):
@specs.parameter('version_spec', yaqltypes.String(True))
@specs.method
def class_(value, name, default_name=None, version_spec=None):
object_store = helpers.get_object_store(root_context)
object_store = this.object_store
if not default_name:
default_name = name
murano_class = name.murano_class
@ -171,7 +170,8 @@ class TypeScheme(object):
new_value.update(value)
value = new_value
obj = object_store.load(value, owner, defaults=default)
obj = object_store.load(
value, owner, root_context, defaults=default)
elif isinstance(value, types.StringTypes):
obj = object_store.get(value)
if obj is None:
@ -191,7 +191,7 @@ class TypeScheme(object):
'requested type {1}'.format(obj.type.name, name))
return obj
context = yaql_integration.create_context()
context = root_context.create_child_context()
context.register_function(int_)
context.register_function(string)
context.register_function(bool_)

View File

@ -45,7 +45,8 @@ class Spec(object):
if default is None:
default = self.default
return self._contract(
value, this.cast(self._container_class()).context,
value, this.object_store.executor.create_object_context(
this.cast(self._container_class())),
this, owner, default)
@property

View File

@ -19,14 +19,14 @@ from yaql.language import specs
from yaql.language import utils
from yaql.language import yaqltypes
from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import dsl_types
from murano.dsl import helpers
from murano.dsl import yaql_integration
from murano.dsl import linked_context
@specs.parameter('value', dsl_types.MuranoObject)
@specs.extension_method
def id_(value):
return value.object_id
@ -34,7 +34,6 @@ def id_(value):
@specs.parameter('value', dsl_types.MuranoObject)
@specs.parameter('type__', dsl.MuranoTypeName())
@specs.parameter('version_spec', yaqltypes.String(True))
@specs.extension_method
def cast(context, value, type__, version_spec=None):
return helpers.cast(
value, type__.murano_class.name,
@ -53,7 +52,7 @@ def new(__context, __type_name, __owner=None, __object_name=None, __extra=None,
if helpers.is_keyword(key):
new_context[key] = value
return __type_name.murano_class.new(
__owner, object_store, new_context, name=__object_name)(**parameters)
__owner, object_store, name=__object_name)(new_context, **parameters)
@specs.parameter('type_name', dsl.MuranoTypeName())
@ -65,12 +64,11 @@ def new(__context, __type_name, __owner=None, __object_name=None, __extra=None,
def new_from_dict(type_name, context, parameters,
owner=None, object_name=None, extra=None):
return new(context, type_name, owner, object_name, extra,
**yaql_integration.filter_parameters_dict(parameters))
**helpers.filter_parameters_dict(parameters))
@specs.parameter('sender', dsl_types.MuranoObject)
@specs.parameter('func', yaqltypes.Lambda())
@specs.extension_method
def super_(context, sender, func=None):
cast_type = helpers.get_type(context)
if func is None:
@ -81,7 +79,6 @@ def super_(context, sender, func=None):
@specs.parameter('value', dsl_types.MuranoObject)
@specs.parameter('func', yaqltypes.Lambda())
@specs.extension_method
def psuper(context, value, func=None):
if func is None:
return super_(context, value)
@ -113,7 +110,6 @@ def sleep_(seconds):
@specs.parameter('object_', dsl_types.MuranoObject)
@specs.extension_method
def type_(object_):
return object_.type.name
@ -135,8 +131,12 @@ def obj_attribution(context, obj, property_name):
@specs.inject('operator', yaqltypes.Super(with_context=True))
@specs.name('#operator_.')
def op_dot(context, sender, expr, operator):
ctx2 = context.create_child_context()
sender.type.register_methods(ctx2)
executor = helpers.get_executor(context)
type_context = executor.context_manager.create_class_context(sender.type)
obj_context = executor.context_manager.create_object_context(sender)
ctx2 = linked_context.link(
linked_context.link(context, type_context),
obj_context)
return operator(ctx2, sender, expr)
@ -165,16 +165,7 @@ def not_equal(obj1, obj2):
return obj1 is not obj2
@specs.parameter('logger_name', yaqltypes.String(True))
def logger(context, logger_name):
"""Instantiate Logger"""
log = yaql_integration.call_func(
context, 'new', 'io.murano.system.Logger',
logger_name=logger_name)
return log
def register(context):
def register(context, runtime_version):
context.register_function(cast)
context.register_function(new)
context.register_function(new_from_dict)
@ -191,4 +182,8 @@ def register(context):
context.register_function(ns_resolve)
context.register_function(equal)
context.register_function(not_equal)
context.register_function(logger)
if runtime_version < constants.RUNTIME_VERSION_2_0:
for t in ('id', 'cast', 'super', 'psuper', 'type'):
for spec in utils.to_extension_method(t, context):
context.register_function(spec)

View File

@ -14,6 +14,7 @@
import inspect
import yaql
from yaql.language import contexts
from yaql.language import conventions
from yaql.language import factory
@ -25,30 +26,45 @@ from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import dsl_types
from murano.dsl import helpers
from murano.dsl import yaql_functions
LEGACY_ENGINE_OPTIONS = {
ENGINE_10_OPTIONS = {
'yaql.limitIterators': constants.ITERATORS_LIMIT,
'yaql.memoryQuota': constants.EXPRESSION_MEMORY_QUOTA,
'yaql.convertSetsToLists': True,
'yaql.convertTuplesToLists': True,
'yaql.iterableDicts': True
}
ENGINE_20_OPTIONS = {
'yaql.limitIterators': constants.ITERATORS_LIMIT,
'yaql.memoryQuota': constants.EXPRESSION_MEMORY_QUOTA,
'yaql.convertSetsToLists': True,
'yaql.convertTuplesToLists': True
}
def _create_engine():
def _create_engine(runtime_version):
engine_factory = factory.YaqlFactory()
engine_factory.insert_operator(
'.', True, ':', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, True)
return engine_factory.create(options=LEGACY_ENGINE_OPTIONS)
options = (ENGINE_10_OPTIONS
if runtime_version < constants.RUNTIME_VERSION_2_0
else ENGINE_20_OPTIONS)
return engine_factory.create(options=options)
@specs.name('#finalize')
def _finalize(obj, context):
return helpers.evaluate(obj, context)
ENGINE = _create_engine()
CONVENTION = conventions.CamelCaseConvention()
ROOT_CONTEXT = legacy.create_context(
ENGINE_10 = _create_engine(constants.RUNTIME_VERSION_1_0)
ENGINE_20 = _create_engine(constants.RUNTIME_VERSION_2_0)
ROOT_CONTEXT_10 = legacy.create_context(
convention=CONVENTION, finalizer=_finalize)
ROOT_CONTEXT_20 = yaql.create_context(
convention=CONVENTION, finalizer=_finalize)
@ -71,25 +87,34 @@ class ContractedValue(yaqltypes.GenericType):
def create_empty_context():
context = contexts.Context()
context = contexts.Context(convention=CONVENTION)
context.register_function(_finalize)
return context
def create_context():
return ROOT_CONTEXT.create_child_context()
@helpers.memoize
def create_context(runtime_version):
if runtime_version < constants.RUNTIME_VERSION_2_0:
context = ROOT_CONTEXT_10.create_child_context()
else:
context = ROOT_CONTEXT_20.create_child_context()
context[constants.CTX_YAQL_ENGINE] = choose_yaql_engine(runtime_version)
yaql_functions.register(context, runtime_version)
return context
def choose_yaql_engine(version):
return ENGINE
def choose_yaql_engine(runtime_version):
return (ENGINE_10 if runtime_version < constants.RUNTIME_VERSION_1_0
else ENGINE_20)
def parse(expression, version):
return choose_yaql_engine(version)(expression)
def parse(expression, runtime_version):
return choose_yaql_engine(runtime_version)(expression)
def call_func(__context, __name, *args, **kwargs):
return __context(__name, ENGINE)(*args, **kwargs)
engine = __context[constants.CTX_YAQL_ENGINE]
return __context(__name, engine)(*args, **kwargs)
def _infer_parameter_type(name, class_name):
@ -149,12 +174,15 @@ def build_wrapper_function_definition(murano_method):
def _build_native_wrapper_function_definition(murano_method):
runtime_version = murano_method.murano_class.package.runtime_version
engine = choose_yaql_engine(runtime_version)
@specs.method
@specs.name(murano_method.name)
def payload(__context, __sender, *args, **kwargs):
executor = helpers.get_executor(__context)
args = tuple(to_mutable(arg) for arg in args)
kwargs = to_mutable(kwargs)
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
kwargs = dsl.to_mutable(kwargs, engine)
return murano_method.invoke(
executor, __sender, args, kwargs, __context, True)
@ -186,11 +214,14 @@ def _build_mpl_wrapper_function_definition(murano_method):
return fd
def get_class_factory_definition(cls):
def get_class_factory_definition(cls, murano_class):
runtime_version = murano_class.package.runtime_version
engine = choose_yaql_engine(runtime_version)
def payload(__context, __sender, *args, **kwargs):
assert __sender is None
args = tuple(to_mutable(arg) for arg in args)
kwargs = to_mutable(kwargs)
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
kwargs = dsl.to_mutable(kwargs, engine)
with helpers.contextual(__context):
return cls(*args, **kwargs)
@ -227,15 +258,3 @@ def filter_parameters(__fd, *args, **kwargs):
if name not in __fd.parameters:
del kwargs[name]
return args, kwargs
def filter_parameters_dict(parameters):
parameters = parameters.copy()
for name in parameters.keys():
if not helpers.is_keyword(name):
del parameters[name]
return parameters
def to_mutable(obj):
return dsl.to_mutable(obj, ENGINE)

View File

@ -1,27 +0,0 @@
# Copyright (c) 2015 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.
from murano.dsl import executor
from murano.engine.system import yaql_functions
class Executor(executor.MuranoDslExecutor):
def __init__(self, package_loader, env):
super(Executor, self).__init__(package_loader, env)
def create_root_context(self):
context = super(Executor, self).create_root_context()
yaql_functions.register(context)
return context

View File

@ -28,6 +28,8 @@ from yaql.language import utils
from yaql.language import yaqltypes
from murano.common import config as cfg
from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import helpers
from murano.dsl import yaql_integration
@ -111,13 +113,13 @@ def substr(delegate, string, start, length=-1):
@specs.extension_method
def patch_(obj, patch):
def patch_(engine, obj, patch):
if not isinstance(patch, tuple):
patch = (patch,)
patch = yaql_integration.to_mutable(patch)
patch = dsl.to_mutable(patch, engine)
patch = jsonpatch.JsonPatch(patch)
try:
obj = yaql_integration.to_mutable(obj)
obj = dsl.to_mutable(obj, engine)
return patch.apply(obj, in_place=True)
except jsonpointer.JsonPointerException:
return obj
@ -182,7 +184,18 @@ def first_or_default(collection, default=None):
return default
def register(context):
@specs.parameter('logger_name', yaqltypes.String(True))
def logger(context, logger_name):
"""Instantiate Logger"""
log = yaql_integration.call_func(
context, 'new', 'io.murano.system.Logger',
logger_name=logger_name)
return log
@helpers.memoize
def get_context(runtime_version):
context = yaql_integration.create_empty_context()
context.register_function(base64decode)
context.register_function(base64encode)
context.register_function(pselect)
@ -191,11 +204,16 @@ def register(context):
context.register_function(patch_)
context.register_function(config)
context.register_function(config_default)
context.register_function(substr)
context.register_function(first_or_default)
context.register_function(logger)
for t in ('to_lower', 'to_upper', 'trim', 'join', 'split',
'starts_with', 'ends_with', 'matches', 'replace',
'flatten'):
for spec in utils.to_extension_method(t, context):
context.register_function(spec)
if runtime_version < constants.RUNTIME_VERSION_2_0:
context.register_function(substr)
context.register_function(first_or_default)
root_context = yaql_integration.create_context(runtime_version)
for t in ('to_lower', 'to_upper', 'trim', 'join', 'split',
'starts_with', 'ends_with', 'matches', 'replace',
'flatten'):
for spec in utils.to_extension_method(t, root_context):
context.register_function(spec)
return context

View File

@ -22,6 +22,7 @@ from murano.dsl import helpers
from murano.dsl import yaql_expression
@helpers.memoize
def get_loader(version):
version = helpers.parse_version(version)

View File

@ -16,8 +16,11 @@
import sys
import types
from murano.dsl import context_manager
from murano.dsl import dsl
from murano.dsl import dsl_exception
from murano.dsl import executor
from murano.dsl import linked_context
from murano.dsl import murano_object
from murano.dsl import serializer
from murano.dsl import yaql_integration
@ -26,14 +29,16 @@ from murano.engine.system import yaql_functions
from murano.tests.unit.dsl.foundation import object_model
class TestExecutor(executor.MuranoDslExecutor):
def __init__(self, package_loader, env, functions):
class TestContextManager(context_manager.ContextManager):
def __init__(self, functions):
self.__functions = functions
super(TestExecutor, self).__init__(package_loader, env)
def create_root_context(self):
context = super(TestExecutor, self).create_root_context()
yaql_functions.register(context)
def create_root_context(self, runtime_version):
root_context = super(TestContextManager, self).create_root_context(
runtime_version)
context = linked_context.link(
root_context, yaql_functions.get_context(runtime_version))
context = context.create_child_context()
for name, func in self.__functions.iteritems():
context.register_function(func, name)
return context
@ -69,8 +74,9 @@ class Runner(object):
if 'Objects' not in model:
model = {'Objects': model}
self.executor = TestExecutor(
package_loader, environment.Environment(), functions)
self.executor = executor.MuranoDslExecutor(
package_loader, TestContextManager(functions),
environment.Environment())
self._root = self.executor.load(model).object
def _execute(self, name, object_id, *args, **kwargs):
@ -86,8 +92,11 @@ class Runner(object):
if isinstance(arg, object_model.Object):
arg = object_model.build_model(arg)
final_kwargs[name] = arg
return yaql_integration.to_mutable(obj.type.invoke(
name, self.executor, obj, tuple(final_args), final_kwargs))
runtime_version = obj.type.package.runtime_version
yaql_engine = yaql_integration.choose_yaql_engine(runtime_version)
return dsl.to_mutable(obj.type.invoke(
name, self.executor, obj, tuple(final_args), final_kwargs),
yaql_engine)
except dsl_exception.MuranoPlException as e:
if not self.preserve_exception:
original_exception = getattr(e, 'original_exception', None)

View File

@ -52,7 +52,7 @@ class TestPackageLoader(package_loader.MuranoPackageLoader):
self._parent = parent_loader
self._configs = {}
self._package = TestPackage(
self, package_name, None, None, None, self._configs)
self, package_name, None, '1.0', None, self._configs)
for name, payload in self._classes.iteritems():
self._package.register_class(payload, name)
super(TestPackageLoader, self).__init__()