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:
parent
b1fc727e73
commit
16030aeec8
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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')
|
||||
|
37
murano/dsl/context_manager.py
Normal file
37
murano/dsl/context_manager.py
Normal 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
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
69
murano/dsl/linked_context.py
Normal file
69
murano/dsl/linked_context.py
Normal 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)
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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_)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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__()
|
||||
|
Loading…
Reference in New Issue
Block a user