Merge "Extension methods were introduced to MuranoPL"
This commit is contained in:
commit
e5e58b2077
|
@ -27,6 +27,7 @@ CTX_CURRENT_EXCEPTION = '$?currentException'
|
||||||
CTX_CURRENT_METHOD = '$?currentMethod'
|
CTX_CURRENT_METHOD = '$?currentMethod'
|
||||||
CTX_EXECUTOR = '$?executor'
|
CTX_EXECUTOR = '$?executor'
|
||||||
CTX_EXECUTION_SESSION = '$?executionSession'
|
CTX_EXECUTION_SESSION = '$?executionSession'
|
||||||
|
CTX_NAMES_SCOPE = '$?namesScope'
|
||||||
CTX_ORIGINAL_CONTEXT = '$?originalContext'
|
CTX_ORIGINAL_CONTEXT = '$?originalContext'
|
||||||
CTX_PACKAGE_LOADER = '$?packageLoader'
|
CTX_PACKAGE_LOADER = '$?packageLoader'
|
||||||
CTX_SKIP_FRAME = '$?skipFrame'
|
CTX_SKIP_FRAME = '$?skipFrame'
|
||||||
|
|
|
@ -108,9 +108,11 @@ class InterfacesParameter(yaqltypes.HiddenParameterType,
|
||||||
|
|
||||||
|
|
||||||
class MuranoTypeParameter(yaqltypes.PythonType):
|
class MuranoTypeParameter(yaqltypes.PythonType):
|
||||||
def __init__(self, base_type=None, nullable=False, context=None):
|
def __init__(self, base_type=None, nullable=False, context=None,
|
||||||
|
resolve_strings=True):
|
||||||
self._context = context
|
self._context = context
|
||||||
self._base_type = base_type
|
self._base_type = base_type
|
||||||
|
self._resolve_strings = resolve_strings
|
||||||
super(MuranoTypeParameter, self).__init__(
|
super(MuranoTypeParameter, self).__init__(
|
||||||
(dsl_types.MuranoTypeReference,
|
(dsl_types.MuranoTypeReference,
|
||||||
six.string_types), nullable)
|
six.string_types), nullable)
|
||||||
|
@ -119,6 +121,10 @@ class MuranoTypeParameter(yaqltypes.PythonType):
|
||||||
if not super(MuranoTypeParameter, self).check(
|
if not super(MuranoTypeParameter, self).check(
|
||||||
value, context, *args, **kwargs):
|
value, context, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
if isinstance(value, six.string_types):
|
||||||
|
if not self._resolve_strings:
|
||||||
|
return False
|
||||||
|
value = helpers.get_class(value, context).get_reference()
|
||||||
if isinstance(value, dsl_types.MuranoTypeReference):
|
if isinstance(value, dsl_types.MuranoTypeReference):
|
||||||
if not self._base_type:
|
if not self._base_type:
|
||||||
return True
|
return True
|
||||||
|
@ -133,12 +139,7 @@ class MuranoTypeParameter(yaqltypes.PythonType):
|
||||||
value = super(MuranoTypeParameter, self).convert(
|
value = super(MuranoTypeParameter, self).convert(
|
||||||
value, sender, context, function_spec, engine)
|
value, sender, context, function_spec, engine)
|
||||||
if isinstance(value, six.string_types):
|
if isinstance(value, six.string_types):
|
||||||
if function_spec.meta.get(constants.META_MURANO_METHOD):
|
value = helpers.get_class(value, context).get_reference()
|
||||||
context = helpers.get_caller_context(context)
|
|
||||||
murano_type = helpers.get_type(context)
|
|
||||||
value = helpers.get_class(
|
|
||||||
murano_type.namespace_resolver.resolve_name(value),
|
|
||||||
context).get_reference()
|
|
||||||
if self._base_type and not self._base_type.is_compatible(value):
|
if self._base_type and not self._base_type.is_compatible(value):
|
||||||
raise ValueError('Value must be subtype of {0}'.format(
|
raise ValueError('Value must be subtype of {0}'.format(
|
||||||
self._base_type.name
|
self._base_type.name
|
||||||
|
|
|
@ -50,7 +50,11 @@ class MethodUsages(object):
|
||||||
Action = 'Action'
|
Action = 'Action'
|
||||||
Runtime = 'Runtime'
|
Runtime = 'Runtime'
|
||||||
Static = 'Static'
|
Static = 'Static'
|
||||||
All = {Action, Runtime, Static}
|
Extension = 'Extension'
|
||||||
|
|
||||||
|
All = {Action, Runtime, Static, Extension}
|
||||||
|
InstanceMethods = {Runtime, Action}
|
||||||
|
StaticMethods = {Static, Extension}
|
||||||
|
|
||||||
|
|
||||||
class MuranoType(object):
|
class MuranoType(object):
|
||||||
|
|
|
@ -82,8 +82,16 @@ class MuranoDslExecutor(object):
|
||||||
self.create_object_context(this, context), method)
|
self.create_object_context(this, context), method)
|
||||||
method_context[constants.CTX_SKIP_FRAME] = True
|
method_context[constants.CTX_SKIP_FRAME] = True
|
||||||
method_context[constants.CTX_ACTIONS_ONLY] = actions_only
|
method_context[constants.CTX_ACTIONS_ONLY] = actions_only
|
||||||
return method.yaql_function_definition(
|
|
||||||
yaql_engine, method_context, this.real_this)(*args, **kwargs)
|
stub = method.static_stub if isinstance(
|
||||||
|
this, dsl_types.MuranoType) else method.instance_stub
|
||||||
|
if stub is None:
|
||||||
|
raise ValueError(
|
||||||
|
'Method {0} cannot be called on receiver {1}'.format(
|
||||||
|
method, this))
|
||||||
|
|
||||||
|
return stub(yaql_engine, method_context, this.real_this)(
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
if (context[constants.CTX_ACTIONS_ONLY] and method.usage !=
|
if (context[constants.CTX_ACTIONS_ONLY] and method.usage !=
|
||||||
dsl_types.MethodUsages.Action):
|
dsl_types.MethodUsages.Action):
|
||||||
|
@ -119,6 +127,8 @@ class MuranoDslExecutor(object):
|
||||||
return method.body(
|
return method.body(
|
||||||
yaql_engine, context, native_this)(*args, **kwargs)
|
yaql_engine, context, native_this)(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
|
context[constants.CTX_NAMES_SCOPE] = \
|
||||||
|
method.declaring_type
|
||||||
return (None if method.body is None
|
return (None if method.body is None
|
||||||
else method.body.execute(context))
|
else method.body.execute(context))
|
||||||
|
|
||||||
|
@ -312,9 +322,13 @@ class MuranoDslExecutor(object):
|
||||||
caller = caller_context
|
caller = caller_context
|
||||||
while caller is not None and caller[constants.CTX_SKIP_FRAME]:
|
while caller is not None and caller[constants.CTX_SKIP_FRAME]:
|
||||||
caller = caller[constants.CTX_CALLER_CONTEXT]
|
caller = caller[constants.CTX_CALLER_CONTEXT]
|
||||||
|
context[constants.CTX_NAMES_SCOPE] = caller_context[
|
||||||
|
constants.CTX_NAMES_SCOPE]
|
||||||
context[constants.CTX_CALLER_CONTEXT] = caller
|
context[constants.CTX_CALLER_CONTEXT] = caller
|
||||||
context[constants.CTX_ALLOW_PROPERTY_WRITES] = caller_context[
|
context[constants.CTX_ALLOW_PROPERTY_WRITES] = caller_context[
|
||||||
constants.CTX_ALLOW_PROPERTY_WRITES]
|
constants.CTX_ALLOW_PROPERTY_WRITES]
|
||||||
|
else:
|
||||||
|
context[constants.CTX_NAMES_SCOPE] = obj_type
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -216,10 +216,16 @@ def are_property_modifications_allowed(context=None):
|
||||||
return context[constants.CTX_ALLOW_PROPERTY_WRITES] or False
|
return context[constants.CTX_ALLOW_PROPERTY_WRITES] or False
|
||||||
|
|
||||||
|
|
||||||
|
def get_names_scope(context=None):
|
||||||
|
context = context or get_context()
|
||||||
|
return context[constants.CTX_NAMES_SCOPE]
|
||||||
|
|
||||||
|
|
||||||
def get_class(name, context=None):
|
def get_class(name, context=None):
|
||||||
context = context or get_context()
|
context = context or get_context()
|
||||||
murano_class = get_type(context)
|
murano_type = get_names_scope(context)
|
||||||
return murano_class.package.find_class(name)
|
name = murano_type.namespace_resolver.resolve_name(name)
|
||||||
|
return murano_type.package.find_class(name)
|
||||||
|
|
||||||
|
|
||||||
def get_current_thread_id():
|
def get_current_thread_id():
|
||||||
|
@ -538,3 +544,11 @@ def function(c):
|
||||||
if hasattr(c, 'im_func'):
|
if hasattr(c, 'im_func'):
|
||||||
return c.im_func
|
return c.im_func
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def list_value(v):
|
||||||
|
if v is None:
|
||||||
|
return []
|
||||||
|
if not yaqlutils.is_sequence(v):
|
||||||
|
v = [v]
|
||||||
|
return v
|
||||||
|
|
|
@ -169,7 +169,8 @@ class LhsExpression(object):
|
||||||
def __call__(self, value, context):
|
def __call__(self, value, context):
|
||||||
new_context = self._create_context(context)
|
new_context = self._create_context(context)
|
||||||
new_context[''] = context['$']
|
new_context[''] = context['$']
|
||||||
new_context[constants.CTX_TYPE] = context[constants.CTX_TYPE]
|
for name in (constants.CTX_NAMES_SCOPE,):
|
||||||
|
new_context[name] = context[name]
|
||||||
self._current_obj = None
|
self._current_obj = None
|
||||||
self._current_obj_name = None
|
self._current_obj_name = None
|
||||||
property = self._expression(context=new_context)
|
property = self._expression(context=new_context)
|
||||||
|
|
|
@ -25,8 +25,7 @@ from murano.dsl import yaql_expression
|
||||||
|
|
||||||
class CodeBlock(expressions.DslExpression):
|
class CodeBlock(expressions.DslExpression):
|
||||||
def __init__(self, body):
|
def __init__(self, body):
|
||||||
if not isinstance(body, list):
|
body = helpers.list_value(body)
|
||||||
body = [body]
|
|
||||||
self.code_block = list(map(expressions.parse_expression, body))
|
self.code_block = list(map(expressions.parse_expression, body))
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
|
|
@ -32,10 +32,7 @@ class MetaProvider(object):
|
||||||
class MetaData(MetaProvider):
|
class MetaData(MetaProvider):
|
||||||
def __init__(self, definition, target, scope_type):
|
def __init__(self, definition, target, scope_type):
|
||||||
scope_type = weakref.ref(scope_type)
|
scope_type = weakref.ref(scope_type)
|
||||||
if not definition:
|
definition = helpers.list_value(definition)
|
||||||
definition = []
|
|
||||||
elif not isinstance(definition, list):
|
|
||||||
definition = [definition]
|
|
||||||
factories = []
|
factories = []
|
||||||
used_types = set()
|
used_types = set()
|
||||||
for d in definition:
|
for d in definition:
|
||||||
|
|
|
@ -50,14 +50,21 @@ class MuranoMethod(dsl_types.MuranoMethod, meta.MetaProvider):
|
||||||
payload, weakref.proxy(self), original_name)
|
payload, weakref.proxy(self), original_name)
|
||||||
self._arguments_scheme = None
|
self._arguments_scheme = None
|
||||||
if any((
|
if any((
|
||||||
helpers.inspect_is_static(
|
helpers.inspect_is_static(
|
||||||
declaring_type.extension_class, original_name),
|
declaring_type.extension_class, original_name),
|
||||||
helpers.inspect_is_classmethod(
|
helpers.inspect_is_classmethod(
|
||||||
declaring_type.extension_class, original_name))):
|
declaring_type.extension_class, original_name))):
|
||||||
self._usage = dsl_types.MethodUsages.Static
|
self._usage = self._body.meta.get(
|
||||||
|
constants.META_USAGE, dsl_types.MethodUsages.Static)
|
||||||
|
if self._usage not in dsl_types.MethodUsages.StaticMethods:
|
||||||
|
raise ValueError(
|
||||||
|
'Invalid Usage for static method ' + self.name)
|
||||||
else:
|
else:
|
||||||
self._usage = (self._body.meta.get(constants.META_USAGE) or
|
self._usage = (self._body.meta.get(constants.META_USAGE) or
|
||||||
dsl_types.MethodUsages.Runtime)
|
dsl_types.MethodUsages.Runtime)
|
||||||
|
if self._usage not in dsl_types.MethodUsages.InstanceMethods:
|
||||||
|
raise ValueError(
|
||||||
|
'Invalid Usage for instance method ' + self.name)
|
||||||
if (self._body.name.startswith('#') or
|
if (self._body.name.startswith('#') or
|
||||||
self._body.name.startswith('*')):
|
self._body.name.startswith('*')):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -68,10 +75,10 @@ class MuranoMethod(dsl_types.MuranoMethod, meta.MetaProvider):
|
||||||
declaring_type)
|
declaring_type)
|
||||||
else:
|
else:
|
||||||
payload = payload or {}
|
payload = payload or {}
|
||||||
self._body = macros.MethodBlock(payload.get('Body') or [], name)
|
self._body = macros.MethodBlock(payload.get('Body'), name)
|
||||||
self._usage = payload.get(
|
self._usage = payload.get(
|
||||||
'Usage') or dsl_types.MethodUsages.Runtime
|
'Usage') or dsl_types.MethodUsages.Runtime
|
||||||
arguments_scheme = payload.get('Arguments') or []
|
arguments_scheme = helpers.list_value(payload.get('Arguments'))
|
||||||
if isinstance(arguments_scheme, dict):
|
if isinstance(arguments_scheme, dict):
|
||||||
arguments_scheme = [{key: value} for key, value in
|
arguments_scheme = [{key: value} for key, value in
|
||||||
six.iteritems(arguments_scheme)]
|
six.iteritems(arguments_scheme)]
|
||||||
|
@ -87,8 +94,9 @@ class MuranoMethod(dsl_types.MuranoMethod, meta.MetaProvider):
|
||||||
payload.get('Meta'),
|
payload.get('Meta'),
|
||||||
dsl_types.MetaTargets.Method,
|
dsl_types.MetaTargets.Method,
|
||||||
declaring_type)
|
declaring_type)
|
||||||
self._yaql_function_definition = \
|
|
||||||
yaql_integration.build_wrapper_function_definition(
|
self._instance_stub, self._static_stub = \
|
||||||
|
yaql_integration.build_stub_function_definitions(
|
||||||
weakref.proxy(self))
|
weakref.proxy(self))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -104,8 +112,12 @@ class MuranoMethod(dsl_types.MuranoMethod, meta.MetaProvider):
|
||||||
return self._arguments_scheme
|
return self._arguments_scheme
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def yaql_function_definition(self):
|
def instance_stub(self):
|
||||||
return self._yaql_function_definition
|
return self._instance_stub
|
||||||
|
|
||||||
|
@property
|
||||||
|
def static_stub(self):
|
||||||
|
return self._static_stub
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self):
|
def usage(self):
|
||||||
|
@ -121,7 +133,7 @@ class MuranoMethod(dsl_types.MuranoMethod, meta.MetaProvider):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_static(self):
|
def is_static(self):
|
||||||
return self.usage == dsl_types.MethodUsages.Static
|
return self.usage in dsl_types.MethodUsages.StaticMethods
|
||||||
|
|
||||||
def get_meta(self, context):
|
def get_meta(self, context):
|
||||||
def meta_producer(cls):
|
def meta_producer(cls):
|
||||||
|
@ -168,9 +180,12 @@ class MuranoMethodArgument(dsl_types.MuranoMethodArgument, typespec.Spec,
|
||||||
declaration.get('Meta'),
|
declaration.get('Meta'),
|
||||||
dsl_types.MetaTargets.Argument, self.murano_method.declaring_type)
|
dsl_types.MetaTargets.Argument, self.murano_method.declaring_type)
|
||||||
|
|
||||||
def validate(self, *args, **kwargs):
|
def transform(self, value, this, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return super(MuranoMethodArgument, self).validate(*args, **kwargs)
|
if self.murano_method.usage == dsl_types.MethodUsages.Extension:
|
||||||
|
this = self.murano_method.declaring_type
|
||||||
|
return super(MuranoMethodArgument, self).transform(
|
||||||
|
value, this, *args, **kwargs)
|
||||||
except exceptions.ContractViolationException as e:
|
except exceptions.ContractViolationException as e:
|
||||||
msg = u'[{0}::{1}({2}{3})] {4}'.format(
|
msg = u'[{0}::{1}({2}{3})] {4}'.format(
|
||||||
self.murano_method.declaring_type.name,
|
self.murano_method.declaring_type.name,
|
||||||
|
|
|
@ -232,7 +232,7 @@ class MuranoObject(dsl_types.MuranoObject):
|
||||||
# default = helpers.evaluate(default, context)
|
# default = helpers.evaluate(default, context)
|
||||||
|
|
||||||
obj = self.cast(spec.declaring_type)
|
obj = self.cast(spec.declaring_type)
|
||||||
values_to_assign.append((obj, spec.validate(
|
values_to_assign.append((obj, spec.transform(
|
||||||
value, self.real_this,
|
value, self.real_this,
|
||||||
self.real_this, context, default=default)))
|
self.real_this, context, default=default)))
|
||||||
for obj, value in values_to_assign:
|
for obj, value in values_to_assign:
|
||||||
|
|
|
@ -98,12 +98,11 @@ class MuranoPackage(dsl_types.MuranoPackage, dslmeta.MetaProvider):
|
||||||
return type_obj
|
return type_obj
|
||||||
if callable(data):
|
if callable(data):
|
||||||
data = data()
|
data = data()
|
||||||
if not utils.is_sequence(data):
|
data = helpers.list_value(data)
|
||||||
data = [data]
|
|
||||||
unnamed_class = None
|
unnamed_class = None
|
||||||
last_ns = {}
|
last_ns = {}
|
||||||
for cls_data in data:
|
for cls_data in data:
|
||||||
last_ns = cls_data.setdefault('Namespaces', last_ns)
|
last_ns = cls_data.setdefault('Namespaces', last_ns.copy())
|
||||||
if len(cls_data) == 1:
|
if len(cls_data) == 1:
|
||||||
continue
|
continue
|
||||||
cls_name = cls_data.get('Name')
|
cls_name = cls_data.get('Name')
|
||||||
|
|
|
@ -34,9 +34,9 @@ class MuranoProperty(dsl_types.MuranoProperty, typespec.Spec,
|
||||||
dsl_types.MetaTargets.Property, declaring_type)
|
dsl_types.MetaTargets.Property, declaring_type)
|
||||||
self._meta_values = None
|
self._meta_values = None
|
||||||
|
|
||||||
def validate(self, *args, **kwargs):
|
def transform(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return super(MuranoProperty, self).validate(*args, **kwargs)
|
return super(MuranoProperty, self).transform(*args, **kwargs)
|
||||||
except exceptions.ContractViolationException as e:
|
except exceptions.ContractViolationException as e:
|
||||||
msg = u'[{0}.{1}{2}] {3}'.format(
|
msg = u'[{0}.{1}{2}] {3}'.format(
|
||||||
self.declaring_type.name, self.name, e.path, six.text_type(e))
|
self.declaring_type.name, self.name, e.path, six.text_type(e))
|
||||||
|
|
|
@ -51,7 +51,6 @@ class MuranoType(dsl_types.MuranoType):
|
||||||
return self._namespace_resolver
|
return self._namespace_resolver
|
||||||
|
|
||||||
@abc.abstractproperty
|
@abc.abstractproperty
|
||||||
@property
|
|
||||||
def usage(self):
|
def usage(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -66,7 +65,8 @@ class MuranoType(dsl_types.MuranoType):
|
||||||
class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
_allowed_usages = {dsl_types.ClassUsages.Class}
|
_allowed_usages = {dsl_types.ClassUsages.Class}
|
||||||
|
|
||||||
def __init__(self, ns_resolver, name, package, parents, meta=None):
|
def __init__(self, ns_resolver, name, package, parents, meta=None,
|
||||||
|
imports=None):
|
||||||
super(MuranoClass, self).__init__(ns_resolver, name, package)
|
super(MuranoClass, self).__init__(ns_resolver, name, package)
|
||||||
self._methods = {}
|
self._methods = {}
|
||||||
self._properties = {}
|
self._properties = {}
|
||||||
|
@ -84,10 +84,12 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
u'Type {0} cannot have parent with Usage {1}'.format(
|
u'Type {0} cannot have parent with Usage {1}'.format(
|
||||||
self.name, p.usage))
|
self.name, p.usage))
|
||||||
self._context = None
|
self._context = None
|
||||||
|
self._exported_context = None
|
||||||
self._parent_mappings = self._build_parent_remappings()
|
self._parent_mappings = self._build_parent_remappings()
|
||||||
self._property_values = {}
|
self._property_values = {}
|
||||||
self._meta = dslmeta.MetaData(meta, dsl_types.MetaTargets.Type, self)
|
self._meta = dslmeta.MetaData(meta, dsl_types.MetaTargets.Type, self)
|
||||||
self._meta_values = None
|
self._meta_values = None
|
||||||
|
self._imports = list(self._resolve_imports(imports))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self):
|
def usage(self):
|
||||||
|
@ -126,6 +128,7 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
method = murano_method.MuranoMethod(self, name, payload, original_name)
|
method = murano_method.MuranoMethod(self, name, payload, original_name)
|
||||||
self._methods[name] = method
|
self._methods[name] = method
|
||||||
self._context = None
|
self._context = None
|
||||||
|
self._exported_context = None
|
||||||
return method
|
return method
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -155,10 +158,22 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
leaf = False
|
leaf = False
|
||||||
queue.append((p, path + segment))
|
queue.append((p, path + segment))
|
||||||
if leaf:
|
if leaf:
|
||||||
path = path + segment
|
path += segment
|
||||||
if path:
|
if path:
|
||||||
yield path
|
yield path
|
||||||
|
|
||||||
|
def _resolve_imports(self, imports):
|
||||||
|
seen = {self.name}
|
||||||
|
for imp in helpers.list_value(imports):
|
||||||
|
if imp in seen:
|
||||||
|
continue
|
||||||
|
type = helpers.resolve_type(imp, self)
|
||||||
|
if type in seen:
|
||||||
|
continue
|
||||||
|
seen.add(imp)
|
||||||
|
seen.add(type)
|
||||||
|
yield type
|
||||||
|
|
||||||
def _choose_symbol(self, func):
|
def _choose_symbol(self, func):
|
||||||
chains = sorted(
|
chains = sorted(
|
||||||
self._find_symbol_chains(func, self),
|
self._find_symbol_chains(func, self),
|
||||||
|
@ -366,23 +381,51 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
@property
|
@property
|
||||||
def context(self):
|
def context(self):
|
||||||
if not self._context:
|
if not self._context:
|
||||||
self._context = yaql_integration.create_empty_context()
|
ctx = None
|
||||||
|
for imp in reversed(self._imports):
|
||||||
|
if ctx is None:
|
||||||
|
ctx = imp.exported_context
|
||||||
|
else:
|
||||||
|
ctx = helpers.link_contexts(ctx, imp.exported_context)
|
||||||
|
|
||||||
|
if ctx is None:
|
||||||
|
self._context = yaql_integration.create_empty_context()
|
||||||
|
else:
|
||||||
|
self._context = ctx.create_child_context()
|
||||||
|
|
||||||
for m in self._iterate_unique_methods():
|
for m in self._iterate_unique_methods():
|
||||||
self._context.register_function(
|
if m.instance_stub:
|
||||||
m.yaql_function_definition,
|
self._context.register_function(
|
||||||
name=m.yaql_function_definition.name)
|
m.instance_stub, name=m.instance_stub.name)
|
||||||
|
if m.static_stub:
|
||||||
|
self._context.register_function(
|
||||||
|
m.static_stub, name=m.static_stub.name)
|
||||||
return self._context
|
return self._context
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exported_context(self):
|
||||||
|
if not self._exported_context:
|
||||||
|
self._exported_context = yaql_integration.create_empty_context()
|
||||||
|
for m in self._iterate_unique_methods():
|
||||||
|
if m.usage == dsl_types.MethodUsages.Extension:
|
||||||
|
if m.instance_stub:
|
||||||
|
self._exported_context.register_function(
|
||||||
|
m.instance_stub, name=m.instance_stub.name)
|
||||||
|
if m.static_stub:
|
||||||
|
self._exported_context.register_function(
|
||||||
|
m.static_stub, name=m.static_stub.name)
|
||||||
|
return self._exported_context
|
||||||
|
|
||||||
def get_property(self, name, context):
|
def get_property(self, name, context):
|
||||||
prop = self.find_static_property(name)
|
prop = self.find_static_property(name)
|
||||||
cls = prop.declaring_type
|
cls = prop.declaring_type
|
||||||
value = cls._property_values.get(name, prop.default)
|
value = cls._property_values.get(name, prop.default)
|
||||||
return prop.validate(value, cls, None, context)
|
return prop.transform(value, cls, None, context)
|
||||||
|
|
||||||
def set_property(self, name, value, context):
|
def set_property(self, name, value, context):
|
||||||
prop = self.find_static_property(name)
|
prop = self.find_static_property(name)
|
||||||
cls = prop.declaring_type
|
cls = prop.declaring_type
|
||||||
cls._property_values[name] = prop.validate(value, cls, None, context)
|
cls._property_values[name] = prop.transform(value, cls, None, context)
|
||||||
|
|
||||||
def get_meta(self, context):
|
def get_meta(self, context):
|
||||||
if self._meta_values is None:
|
if self._meta_values is None:
|
||||||
|
@ -394,9 +437,10 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
|
||||||
class MuranoMetaClass(dsl_types.MuranoMetaClass, MuranoClass):
|
class MuranoMetaClass(dsl_types.MuranoMetaClass, MuranoClass):
|
||||||
_allowed_usages = {dsl_types.ClassUsages.Meta, dsl_types.ClassUsages.Class}
|
_allowed_usages = {dsl_types.ClassUsages.Meta, dsl_types.ClassUsages.Class}
|
||||||
|
|
||||||
def __init__(self, ns_resolver, name, package, parents, meta=None):
|
def __init__(self, ns_resolver, name, package, parents, meta=None,
|
||||||
|
imports=None):
|
||||||
super(MuranoMetaClass, self).__init__(
|
super(MuranoMetaClass, self).__init__(
|
||||||
ns_resolver, name, package, parents, meta)
|
ns_resolver, name, package, parents, meta, imports)
|
||||||
self._cardinality = dsl_types.MetaCardinality.One
|
self._cardinality = dsl_types.MetaCardinality.One
|
||||||
self._targets = list(dsl_types.MetaCardinality.All)
|
self._targets = list(dsl_types.MetaCardinality.All)
|
||||||
self._inherited = False
|
self._inherited = False
|
||||||
|
@ -456,7 +500,7 @@ def _create_class(cls, name, ns_resolver, data, package, *args, **kwargs):
|
||||||
|
|
||||||
type_obj = cls(
|
type_obj = cls(
|
||||||
ns_resolver, name, package, parent_classes, data.get('Meta'),
|
ns_resolver, name, package, parent_classes, data.get('Meta'),
|
||||||
*args, **kwargs)
|
data.get('Import'), *args, **kwargs)
|
||||||
|
|
||||||
properties = data.get('Properties') or {}
|
properties = data.get('Properties') or {}
|
||||||
for property_name, property_spec in six.iteritems(properties):
|
for property_name, property_spec in six.iteritems(properties):
|
||||||
|
|
|
@ -32,7 +32,8 @@ class TypeScheme(object):
|
||||||
self._spec = spec
|
self._spec = spec
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def prepare_context(root_context, this, owner, default, calling_type):
|
def prepare_transform_context(root_context, this, owner, default,
|
||||||
|
calling_type):
|
||||||
@specs.parameter('value', nullable=True)
|
@specs.parameter('value', nullable=True)
|
||||||
@specs.method
|
@specs.method
|
||||||
def int_(value):
|
def int_(value):
|
||||||
|
@ -150,7 +151,7 @@ class TypeScheme(object):
|
||||||
@specs.parameter('version_spec', yaqltypes.String(True))
|
@specs.parameter('version_spec', yaqltypes.String(True))
|
||||||
@specs.method
|
@specs.method
|
||||||
def class_(value, name, default_name=None, version_spec=None):
|
def class_(value, name, default_name=None, version_spec=None):
|
||||||
object_store = this.object_store
|
object_store = None if this is None else this.object_store
|
||||||
if not default_name:
|
if not default_name:
|
||||||
default_name = name
|
default_name = name
|
||||||
murano_class = name.type
|
murano_class = name.type
|
||||||
|
@ -164,7 +165,7 @@ class TypeScheme(object):
|
||||||
obj = helpers.instantiate(
|
obj = helpers.instantiate(
|
||||||
value, owner, object_store, root_context,
|
value, owner, object_store, root_context,
|
||||||
calling_type, default_name, default)
|
calling_type, default_name, default)
|
||||||
elif isinstance(value, six.string_types):
|
elif isinstance(value, six.string_types) and object_store:
|
||||||
obj = object_store.get(value)
|
obj = object_store.get(value)
|
||||||
if obj is None:
|
if obj is None:
|
||||||
if not object_store.initializing:
|
if not object_store.initializing:
|
||||||
|
@ -197,6 +198,66 @@ class TypeScheme(object):
|
||||||
context.register_function(not_owned)
|
context.register_function(not_owned)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def prepare_validate_context(root_context):
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.method
|
||||||
|
def int_(value):
|
||||||
|
if value is None or isinstance(
|
||||||
|
value, int) and not isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.method
|
||||||
|
def string(value):
|
||||||
|
if value is None or isinstance(value, six.string_types):
|
||||||
|
return value
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.method
|
||||||
|
def bool_(value):
|
||||||
|
if value is None or isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.method
|
||||||
|
def not_null(value):
|
||||||
|
if value is None:
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
return value
|
||||||
|
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.parameter('predicate', yaqltypes.Lambda(with_context=True))
|
||||||
|
@specs.method
|
||||||
|
def check(value, predicate):
|
||||||
|
if predicate(root_context.create_child_context(), value):
|
||||||
|
return value
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
|
||||||
|
@specs.parameter('type', dsl.MuranoTypeParameter(
|
||||||
|
nullable=False, context=root_context))
|
||||||
|
@specs.parameter('value', nullable=True)
|
||||||
|
@specs.parameter('version_spec', yaqltypes.String(True))
|
||||||
|
@specs.method
|
||||||
|
def class_(value, type, version_spec=None):
|
||||||
|
if helpers.is_instance_of(
|
||||||
|
value, type.type.name,
|
||||||
|
version_spec or helpers.get_names_scope(root_context)):
|
||||||
|
return value
|
||||||
|
raise exceptions.ContractViolationException()
|
||||||
|
|
||||||
|
context = root_context.create_child_context()
|
||||||
|
context.register_function(int_)
|
||||||
|
context.register_function(string)
|
||||||
|
context.register_function(bool_)
|
||||||
|
context.register_function(check)
|
||||||
|
context.register_function(not_null)
|
||||||
|
context.register_function(class_)
|
||||||
|
return context
|
||||||
|
|
||||||
def _map_dict(self, data, spec, context, path):
|
def _map_dict(self, data, spec, context, path):
|
||||||
if data is None or data is dsl.NO_VALUE:
|
if data is None or data is dsl.NO_VALUE:
|
||||||
data = {}
|
data = {}
|
||||||
|
@ -298,7 +359,7 @@ class TypeScheme(object):
|
||||||
else:
|
else:
|
||||||
return self._map_scalar(data, spec)
|
return self._map_scalar(data, spec)
|
||||||
|
|
||||||
def __call__(self, data, context, this, owner, default, calling_type):
|
def transform(self, data, context, this, owner, default, calling_type):
|
||||||
# TODO(ativelkov, slagun): temporary fix, need a better way of handling
|
# TODO(ativelkov, slagun): temporary fix, need a better way of handling
|
||||||
# composite defaults
|
# composite defaults
|
||||||
# A bug (#1313694) has been filed
|
# A bug (#1313694) has been filed
|
||||||
|
@ -306,10 +367,21 @@ class TypeScheme(object):
|
||||||
if data is dsl.NO_VALUE:
|
if data is dsl.NO_VALUE:
|
||||||
data = helpers.evaluate(default, context)
|
data = helpers.evaluate(default, context)
|
||||||
|
|
||||||
context = self.prepare_context(
|
context = self.prepare_transform_context(
|
||||||
context, this, owner, default, calling_type)
|
context, this, owner, default, calling_type)
|
||||||
return self._map(data, self._spec, context, '')
|
return self._map(data, self._spec, context, '')
|
||||||
|
|
||||||
|
def validate(self, data, context, default):
|
||||||
|
if data is dsl.NO_VALUE:
|
||||||
|
data = helpers.evaluate(default, context)
|
||||||
|
|
||||||
|
context = self.prepare_validate_context(context)
|
||||||
|
try:
|
||||||
|
self._map(data, self._spec, context, '')
|
||||||
|
return True
|
||||||
|
except exceptions.ContractViolationException:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def format_scalar(value):
|
def format_scalar(value):
|
||||||
if isinstance(value, six.string_types):
|
if isinstance(value, six.string_types):
|
||||||
|
|
|
@ -32,20 +32,25 @@ class Spec(object):
|
||||||
'Unknown type {0}. Must be one of ({1})'.format(
|
'Unknown type {0}. Must be one of ({1})'.format(
|
||||||
self._usage, ', '.join(dsl_types.PropertyUsages.All)))
|
self._usage, ', '.join(dsl_types.PropertyUsages.All)))
|
||||||
|
|
||||||
def validate(self, value, this, owner, context, default=None):
|
def transform(self, value, this, owner, context, default=None):
|
||||||
if default is None:
|
if default is None:
|
||||||
default = self.default
|
default = self.default
|
||||||
executor = helpers.get_executor(context)
|
executor = helpers.get_executor(context)
|
||||||
if isinstance(this, dsl_types.MuranoType):
|
if isinstance(this, dsl_types.MuranoType):
|
||||||
return self._contract(
|
return self._contract.transform(
|
||||||
value, executor.create_object_context(this),
|
value, executor.create_object_context(this),
|
||||||
None, None, default, helpers.get_type(context))
|
None, None, default, helpers.get_type(context))
|
||||||
else:
|
else:
|
||||||
return self._contract(
|
return self._contract.transform(
|
||||||
value, executor.create_object_context(
|
value, executor.create_object_context(
|
||||||
this.cast(self._container_type())),
|
this.cast(self._container_type())),
|
||||||
this, owner, default, helpers.get_type(context))
|
this, owner, default, helpers.get_type(context))
|
||||||
|
|
||||||
|
def validate(self, value, context, default=None):
|
||||||
|
if default is None:
|
||||||
|
default = self.default
|
||||||
|
return self._contract.validate(value, context, default)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default(self):
|
def default(self):
|
||||||
return self._default
|
return self._default
|
||||||
|
|
|
@ -183,10 +183,7 @@ def op_dot_static(context, receiver, expr, operator):
|
||||||
@specs.parameter('name', yaqltypes.Keyword())
|
@specs.parameter('name', yaqltypes.Keyword())
|
||||||
@specs.name('#operator_:')
|
@specs.name('#operator_:')
|
||||||
def ns_resolve(context, prefix, name):
|
def ns_resolve(context, prefix, name):
|
||||||
murano_type = helpers.get_type(context)
|
return helpers.get_class(prefix + ':' + name, context).get_reference()
|
||||||
return helpers.get_class(
|
|
||||||
murano_type.namespace_resolver.resolve_name(
|
|
||||||
prefix + ':' + name), context).get_reference()
|
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('name', yaqltypes.Keyword())
|
@specs.parameter('name', yaqltypes.Keyword())
|
||||||
|
|
|
@ -26,6 +26,7 @@ from yaql import legacy
|
||||||
|
|
||||||
from murano.dsl import constants
|
from murano.dsl import constants
|
||||||
from murano.dsl import dsl
|
from murano.dsl import dsl
|
||||||
|
from murano.dsl import dsl_types
|
||||||
from murano.dsl import helpers
|
from murano.dsl import helpers
|
||||||
from murano.dsl import yaql_functions
|
from murano.dsl import yaql_functions
|
||||||
|
|
||||||
|
@ -79,16 +80,21 @@ ROOT_CONTEXT_12 = yaql.create_context(
|
||||||
|
|
||||||
|
|
||||||
class ContractedValue(yaqltypes.GenericType):
|
class ContractedValue(yaqltypes.GenericType):
|
||||||
def __init__(self, value_spec):
|
def __init__(self, value_spec, with_check=False):
|
||||||
self._value_spec = value_spec
|
def converter(value, receiver, context, *args, **kwargs):
|
||||||
self._last_result = False
|
if isinstance(receiver, dsl_types.MuranoObject):
|
||||||
|
this = receiver.real_this
|
||||||
|
else:
|
||||||
|
this = receiver
|
||||||
|
return value_spec.transform(
|
||||||
|
value, this, context[constants.CTX_ARGUMENT_OWNER],
|
||||||
|
context)
|
||||||
|
|
||||||
|
def checker(value, context, *args, **kwargs):
|
||||||
|
return value_spec.validate(value, context)
|
||||||
|
|
||||||
super(ContractedValue, self).__init__(
|
super(ContractedValue, self).__init__(
|
||||||
True, None,
|
True, checker if with_check else None, converter)
|
||||||
lambda value, receiver, context, *args, **kwargs:
|
|
||||||
self._value_spec.validate(
|
|
||||||
value, receiver.real_this,
|
|
||||||
context[constants.CTX_ARGUMENT_OWNER], context))
|
|
||||||
|
|
||||||
def convert(self, value, *args, **kwargs):
|
def convert(self, value, *args, **kwargs):
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -179,10 +185,14 @@ def get_function_definition(func, murano_method, original_name):
|
||||||
|
|
||||||
def payload(__context, __self, *args, **kwargs):
|
def payload(__context, __self, *args, **kwargs):
|
||||||
with helpers.contextual(__context):
|
with helpers.contextual(__context):
|
||||||
|
__context[constants.CTX_NAMES_SCOPE] = \
|
||||||
|
murano_method.declaring_type
|
||||||
return body(__self.extension, *args, **kwargs)
|
return body(__self.extension, *args, **kwargs)
|
||||||
|
|
||||||
def static_payload(__context, __receiver, *args, **kwargs):
|
def static_payload(__context, __receiver, *args, **kwargs):
|
||||||
with helpers.contextual(__context):
|
with helpers.contextual(__context):
|
||||||
|
__context[constants.CTX_NAMES_SCOPE] = \
|
||||||
|
murano_method.declaring_type
|
||||||
return body(*args, **kwargs)
|
return body(*args, **kwargs)
|
||||||
|
|
||||||
if is_static:
|
if is_static:
|
||||||
|
@ -211,20 +221,22 @@ def _remove_first_parameter(fd):
|
||||||
p.position -= 1
|
p.position -= 1
|
||||||
|
|
||||||
|
|
||||||
def build_wrapper_function_definition(murano_method):
|
def build_stub_function_definitions(murano_method):
|
||||||
if isinstance(murano_method.body, specs.FunctionDefinition):
|
if isinstance(murano_method.body, specs.FunctionDefinition):
|
||||||
return _build_native_wrapper_function_definition(murano_method)
|
return _build_native_stub_function_definitions(murano_method)
|
||||||
else:
|
else:
|
||||||
return _build_mpl_wrapper_function_definition(murano_method)
|
return _build_mpl_stub_function_definitions(murano_method)
|
||||||
|
|
||||||
|
|
||||||
def _build_native_wrapper_function_definition(murano_method):
|
def _build_native_stub_function_definitions(murano_method):
|
||||||
runtime_version = murano_method.declaring_type.package.runtime_version
|
runtime_version = murano_method.declaring_type.package.runtime_version
|
||||||
engine = choose_yaql_engine(runtime_version)
|
engine = choose_yaql_engine(runtime_version)
|
||||||
|
|
||||||
@specs.method
|
@specs.method
|
||||||
@specs.name(murano_method.name)
|
@specs.name(murano_method.name)
|
||||||
@specs.meta(constants.META_MURANO_METHOD, murano_method)
|
@specs.meta(constants.META_MURANO_METHOD, murano_method)
|
||||||
|
@specs.parameter('__receiver', yaqltypes.NotOfType(
|
||||||
|
dsl_types.MuranoTypeReference))
|
||||||
def payload(__context, __receiver, *args, **kwargs):
|
def payload(__context, __receiver, *args, **kwargs):
|
||||||
executor = helpers.get_executor(__context)
|
executor = helpers.get_executor(__context)
|
||||||
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
||||||
|
@ -232,35 +244,106 @@ def _build_native_wrapper_function_definition(murano_method):
|
||||||
return helpers.evaluate(murano_method.invoke(
|
return helpers.evaluate(murano_method.invoke(
|
||||||
executor, __receiver, args, kwargs, __context, True), __context)
|
executor, __receiver, args, kwargs, __context, True), __context)
|
||||||
|
|
||||||
return specs.get_function_definition(payload)
|
@specs.method
|
||||||
|
@specs.name(murano_method.name)
|
||||||
|
@specs.meta(constants.META_MURANO_METHOD, murano_method)
|
||||||
|
@specs.parameter('__receiver', yaqltypes.NotOfType(
|
||||||
|
dsl_types.MuranoTypeReference))
|
||||||
|
def extension_payload(__context, __receiver, *args, **kwargs):
|
||||||
|
executor = helpers.get_executor(__context)
|
||||||
|
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
||||||
|
kwargs = dsl.to_mutable(kwargs, engine)
|
||||||
|
return helpers.evaluate(murano_method.invoke(
|
||||||
|
executor, murano_method.declaring_type,
|
||||||
|
(__receiver,) + args, kwargs, __context, True), __context)
|
||||||
|
|
||||||
|
@specs.method
|
||||||
|
@specs.name(murano_method.name)
|
||||||
|
@specs.meta(constants.META_MURANO_METHOD, murano_method)
|
||||||
|
@specs.parameter('__receiver', dsl_types.MuranoTypeReference)
|
||||||
|
def static_payload(__context, __receiver, *args, **kwargs):
|
||||||
|
executor = helpers.get_executor(__context)
|
||||||
|
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
||||||
|
kwargs = dsl.to_mutable(kwargs, engine)
|
||||||
|
return helpers.evaluate(murano_method.invoke(
|
||||||
|
executor, __receiver, args, kwargs, __context, True), __context)
|
||||||
|
|
||||||
|
if murano_method.usage in dsl_types.MethodUsages.InstanceMethods:
|
||||||
|
return specs.get_function_definition(payload), None
|
||||||
|
elif murano_method.usage == dsl_types.MethodUsages.Static:
|
||||||
|
return (specs.get_function_definition(payload),
|
||||||
|
specs.get_function_definition(static_payload))
|
||||||
|
elif murano_method.usage == dsl_types.MethodUsages.Extension:
|
||||||
|
return (specs.get_function_definition(extension_payload),
|
||||||
|
specs.get_function_definition(static_payload))
|
||||||
|
else:
|
||||||
|
raise ValueError('Unknown method usage ' + murano_method.usage)
|
||||||
|
|
||||||
|
|
||||||
def _build_mpl_wrapper_function_definition(murano_method):
|
def _build_mpl_stub_function_definitions(murano_method):
|
||||||
|
if murano_method.usage in dsl_types.MethodUsages.InstanceMethods:
|
||||||
|
return _create_instance_mpl_stub(murano_method), None
|
||||||
|
elif murano_method.usage == dsl_types.MethodUsages.Static:
|
||||||
|
return (_create_instance_mpl_stub(murano_method),
|
||||||
|
_create_static_mpl_stub(murano_method))
|
||||||
|
elif murano_method.usage == dsl_types.MethodUsages.Extension:
|
||||||
|
return (_create_extension_mpl_stub(murano_method),
|
||||||
|
_create_static_mpl_stub(murano_method))
|
||||||
|
else:
|
||||||
|
raise ValueError('Unknown method usage ' + murano_method.usage)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_instance_mpl_stub(murano_method):
|
||||||
def payload(__context, __receiver, *args, **kwargs):
|
def payload(__context, __receiver, *args, **kwargs):
|
||||||
executor = helpers.get_executor(__context)
|
executor = helpers.get_executor(__context)
|
||||||
return murano_method.invoke(
|
return murano_method.invoke(
|
||||||
executor, __receiver, args, kwargs, __context, True)
|
executor, __receiver, args, kwargs, __context, True)
|
||||||
|
fd = _create_basic_mpl_stub(murano_method, 1, payload, False)
|
||||||
|
|
||||||
|
receiver_type = dsl.MuranoObjectParameter(
|
||||||
|
weakref.proxy(murano_method.declaring_type), decorate=False)
|
||||||
|
fd.set_parameter(specs.ParameterDefinition('__receiver', receiver_type, 1))
|
||||||
|
return fd
|
||||||
|
|
||||||
|
|
||||||
|
def _create_static_mpl_stub(murano_method):
|
||||||
|
def payload(__context, __receiver, *args, **kwargs):
|
||||||
|
executor = helpers.get_executor(__context)
|
||||||
|
return murano_method.invoke(
|
||||||
|
executor, __receiver, args, kwargs, __context, True)
|
||||||
|
fd = _create_basic_mpl_stub(murano_method, 1, payload, False)
|
||||||
|
|
||||||
|
receiver_type = dsl.MuranoTypeParameter(
|
||||||
|
weakref.proxy(murano_method.declaring_type), resolve_strings=False)
|
||||||
|
fd.set_parameter(specs.ParameterDefinition('__receiver', receiver_type, 1))
|
||||||
|
return fd
|
||||||
|
|
||||||
|
|
||||||
|
def _create_extension_mpl_stub(murano_method):
|
||||||
|
def payload(__context, __receiver, *args, **kwargs):
|
||||||
|
executor = helpers.get_executor(__context)
|
||||||
|
return murano_method.invoke(
|
||||||
|
executor, murano_method.declaring_type,
|
||||||
|
(__receiver,) + args, kwargs, __context, True)
|
||||||
|
return _create_basic_mpl_stub(murano_method, 0, payload, True)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_basic_mpl_stub(murano_method, reserve_params, payload,
|
||||||
|
check_first_arg):
|
||||||
fd = specs.FunctionDefinition(
|
fd = specs.FunctionDefinition(
|
||||||
murano_method.name, payload, is_function=False, is_method=True)
|
murano_method.name, payload, is_function=False, is_method=True)
|
||||||
|
|
||||||
for i, (name, arg_spec) in enumerate(
|
for i, (name, arg_spec) in enumerate(
|
||||||
six.iteritems(murano_method.arguments_scheme), 2):
|
six.iteritems(murano_method.arguments_scheme), reserve_params + 1):
|
||||||
p = specs.ParameterDefinition(
|
p = specs.ParameterDefinition(
|
||||||
name, ContractedValue(arg_spec),
|
name, ContractedValue(arg_spec, with_check=check_first_arg),
|
||||||
position=i, default=dsl.NO_VALUE)
|
position=i, default=dsl.NO_VALUE)
|
||||||
|
check_first_arg = False
|
||||||
fd.parameters[name] = p
|
fd.parameters[name] = p
|
||||||
|
|
||||||
fd.set_parameter(specs.ParameterDefinition(
|
fd.set_parameter(specs.ParameterDefinition(
|
||||||
'__context', yaqltypes.Context(), 0))
|
'__context', yaqltypes.Context(), 0))
|
||||||
|
|
||||||
receiver_type = dsl.MuranoObjectParameter(
|
|
||||||
weakref.proxy(murano_method.declaring_type), decorate=False)
|
|
||||||
if murano_method.is_static:
|
|
||||||
receiver_type = yaqltypes.AnyOf(dsl.MuranoTypeParameter(
|
|
||||||
weakref.proxy(murano_method.declaring_type)), receiver_type)
|
|
||||||
fd.set_parameter(specs.ParameterDefinition('__receiver', receiver_type, 1))
|
|
||||||
|
|
||||||
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
||||||
return fd
|
return fd
|
||||||
|
|
||||||
|
@ -273,6 +356,8 @@ def get_class_factory_definition(cls, murano_class):
|
||||||
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
||||||
kwargs = dsl.to_mutable(kwargs, engine)
|
kwargs = dsl.to_mutable(kwargs, engine)
|
||||||
with helpers.contextual(__context):
|
with helpers.contextual(__context):
|
||||||
|
__context[constants.CTX_NAMES_SCOPE] = \
|
||||||
|
murano_class
|
||||||
return helpers.evaluate(cls(*args, **kwargs), __context)
|
return helpers.evaluate(cls(*args, **kwargs), __context)
|
||||||
|
|
||||||
if '__init__' in cls.__dict__:
|
if '__init__' in cls.__dict__:
|
||||||
|
|
|
@ -111,7 +111,7 @@ def inject_method_with_str(context, target, target_method,
|
||||||
original_class = target.type
|
original_class = target.type
|
||||||
|
|
||||||
original_function = original_class.find_single_method(target_method)
|
original_function = original_class.find_single_method(target_method)
|
||||||
result_fd = original_function.yaql_function_definition.clone()
|
result_fd = original_function.instance_stub.clone()
|
||||||
|
|
||||||
def payload_adapter(__context, __sender, *args, **kwargs):
|
def payload_adapter(__context, __sender, *args, **kwargs):
|
||||||
executor = helpers.get_executor(__context)
|
executor = helpers.get_executor(__context)
|
||||||
|
@ -134,7 +134,7 @@ def inject_method_with_yaql_expr(context, target, target_method, expr):
|
||||||
original_class = target.type
|
original_class = target.type
|
||||||
|
|
||||||
original_function = original_class.find_single_method(target_method)
|
original_function = original_class.find_single_method(target_method)
|
||||||
result_fd = original_function.yaql_function_definition.clone()
|
result_fd = original_function.instance_stub.clone()
|
||||||
|
|
||||||
def payload_adapter(__super, __context, __sender, *args, **kwargs):
|
def payload_adapter(__super, __context, __sender, *args, **kwargs):
|
||||||
new_context = context.create_child_context()
|
new_context = context.create_child_context()
|
||||||
|
|
|
@ -93,7 +93,7 @@ class TestPackageLoader(package_loader.MuranoPackageLoader):
|
||||||
|
|
||||||
last_ns = {}
|
last_ns = {}
|
||||||
for data in data_lst:
|
for data in data_lst:
|
||||||
last_ns = data.get('Namespaces', last_ns)
|
last_ns = data.get('Namespaces', last_ns.copy())
|
||||||
if 'Name' not in data:
|
if 'Name' not in data:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
Namespaces:
|
||||||
|
=: extcls
|
||||||
|
|
||||||
|
--- # ------------------------------------------------------------------ # ---
|
||||||
|
|
||||||
|
Name: Extended
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
prop:
|
||||||
|
Contract: $.int()
|
||||||
|
Default: 123
|
||||||
|
Methods:
|
||||||
|
method:
|
||||||
|
Body:
|
||||||
|
Return: $.prop
|
||||||
|
|
||||||
|
|
||||||
|
--- # ------------------------------------------------------------------ # ---
|
||||||
|
|
||||||
|
Name: Extender
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
importedExtensionMethod:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- obj:
|
||||||
|
Contract: $.class(Extended).notNull()
|
||||||
|
- n:
|
||||||
|
Contract: $.int().notNull()
|
||||||
|
Body:
|
||||||
|
Return: [$obj.prop * $n, $obj.method() * $n]
|
||||||
|
|
||||||
|
nullableExtension:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- obj:
|
||||||
|
Contract: $.class(Extended)
|
||||||
|
Body:
|
||||||
|
Return: $obj?.prop
|
||||||
|
|
||||||
|
extensionMethod:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- obj:
|
||||||
|
Contract: $.class(Extended).notNull()
|
||||||
|
Body:
|
||||||
|
Return: 222
|
||||||
|
|
||||||
|
toTileCase:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- str:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
Body:
|
||||||
|
Return: join($str.toCharArray().select(
|
||||||
|
selectCase($.toLower() = $).switchCase($.toUpper(), $.toLower())), '')
|
||||||
|
|
||||||
|
|
||||||
|
--- # ------------------------------------------------------------------ # ---
|
||||||
|
|
||||||
|
Name: TestClass
|
||||||
|
Import: Extender
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
testSelfExtensionMethod:
|
||||||
|
Body:
|
||||||
|
Return: new(Extended).selfExtensionMethod()
|
||||||
|
|
||||||
|
testImportedExtensionMethod:
|
||||||
|
Body:
|
||||||
|
Return: new(Extended).importedExtensionMethod(2)
|
||||||
|
|
||||||
|
testNullableExtensionMethod:
|
||||||
|
Body:
|
||||||
|
Return:
|
||||||
|
- new(Extended).nullableExtension()
|
||||||
|
- null.nullableExtension()
|
||||||
|
|
||||||
|
testExtensionsPrecedence:
|
||||||
|
Body:
|
||||||
|
Return: new(Extended).extensionMethod()
|
||||||
|
|
||||||
|
testCallOnPrimitiveTypes:
|
||||||
|
Body:
|
||||||
|
Return: QwertY.toTileCase()
|
||||||
|
|
||||||
|
testCallExtensionExplicitly:
|
||||||
|
Body:
|
||||||
|
Return: :Extender.extensionMethod(new(:Extended))
|
||||||
|
|
||||||
|
testExplicitCallDoenstWorkOnInstance:
|
||||||
|
Body:
|
||||||
|
Return: new(Extended).extensionMethod(new(Extended))
|
||||||
|
|
||||||
|
testCallPythonExtension:
|
||||||
|
Body:
|
||||||
|
Return: 4.pythonExtension()
|
||||||
|
|
||||||
|
testCallPythonExtensionExplicitly:
|
||||||
|
Body:
|
||||||
|
Return: :Extender.pythonExtension(5)
|
||||||
|
|
||||||
|
testCallPythonClassmethodExtension:
|
||||||
|
Body:
|
||||||
|
Return: 7.pythonExtension2()
|
||||||
|
|
||||||
|
selfExtensionMethod:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- obj:
|
||||||
|
Contract: $.class(Extended).notNull()
|
||||||
|
Body:
|
||||||
|
Return: [$obj.prop, $obj.method()]
|
||||||
|
|
||||||
|
extensionMethod:
|
||||||
|
Usage: Extension
|
||||||
|
Arguments:
|
||||||
|
- obj:
|
||||||
|
Contract: $.class(Extended).notNull()
|
||||||
|
Body:
|
||||||
|
Return: 111
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Copyright (c) 2016 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 exceptions
|
||||||
|
from yaql.language import specs
|
||||||
|
from yaql.language import yaqltypes
|
||||||
|
|
||||||
|
from murano.dsl import dsl
|
||||||
|
from murano.tests.unit.dsl.foundation import object_model as om
|
||||||
|
from murano.tests.unit.dsl.foundation import test_case
|
||||||
|
|
||||||
|
|
||||||
|
class TestExtensionMethods(test_case.DslTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
@dsl.name('extcls.Extender')
|
||||||
|
class PythonClass(object):
|
||||||
|
def __init__(self, arg):
|
||||||
|
self.value = arg
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@specs.meta('Usage', 'Extension')
|
||||||
|
@specs.parameter('arg', yaqltypes.Integer())
|
||||||
|
def python_extension(arg):
|
||||||
|
return arg * arg
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@specs.meta('Usage', 'Extension')
|
||||||
|
@specs.parameter('arg', yaqltypes.Integer())
|
||||||
|
def python_extension2(cls, arg):
|
||||||
|
return cls(2 * arg).value
|
||||||
|
|
||||||
|
super(TestExtensionMethods, self).setUp()
|
||||||
|
self.package_loader.load_class_package(
|
||||||
|
'extcls.Extender', None).register_class(PythonClass)
|
||||||
|
|
||||||
|
self._runner = self.new_runner(om.Object('extcls.TestClass'))
|
||||||
|
|
||||||
|
def test_call_self_extension_method(self):
|
||||||
|
self.assertEqual([123, 123], self._runner.testSelfExtensionMethod())
|
||||||
|
|
||||||
|
def test_call_imported_extension_method(self):
|
||||||
|
self.assertEqual(
|
||||||
|
[246, 246], self._runner.testImportedExtensionMethod())
|
||||||
|
|
||||||
|
def test_call_nullable_extension_method(self):
|
||||||
|
self.assertEqual(
|
||||||
|
[123, None], self._runner.testNullableExtensionMethod())
|
||||||
|
|
||||||
|
def test_extensions_precedence(self):
|
||||||
|
self.assertEqual(111, self._runner.testExtensionsPrecedence())
|
||||||
|
|
||||||
|
def test_explicit_call(self):
|
||||||
|
self.assertEqual(222, self._runner.testCallExtensionExplicitly())
|
||||||
|
|
||||||
|
def test_explicit_call_on_instance_fails(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.NoMatchingMethodException,
|
||||||
|
self._runner.testExplicitCallDoenstWorkOnInstance)
|
||||||
|
|
||||||
|
def test_call_on_primitive_types(self):
|
||||||
|
self.assertEqual('qWERTy', self._runner.testCallOnPrimitiveTypes())
|
||||||
|
|
||||||
|
def test_call_python_extension(self):
|
||||||
|
self.assertEqual(16, self._runner.testCallPythonExtension())
|
||||||
|
|
||||||
|
def test_call_python_extension_explicitly(self):
|
||||||
|
self.assertEqual(25, self._runner.testCallPythonExtensionExplicitly())
|
||||||
|
|
||||||
|
def test_call_python_classmethod_extension(self):
|
||||||
|
self.assertEqual(14, self._runner.testCallPythonClassmethodExtension())
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- >
|
||||||
|
New method type: extension methods. Extension methods enable you to "add"
|
||||||
|
methods to existing types without modifying the original type.
|
||||||
|
Extension methods are a special kind of static method, but they are called
|
||||||
|
as if they were instance methods on the extended type.
|
||||||
|
Extension methods are identified by "Usage: Extension" and the type
|
||||||
|
they extend is determined by their first argument contract. Thus
|
||||||
|
such methods must have at lease one parameter.
|
||||||
|
- >
|
||||||
|
New type-level keyword "Import" which can be either list or scalar
|
||||||
|
that specifies type names which extensions methods should be imported
|
||||||
|
into class context and thus become available to type members.
|
Loading…
Reference in New Issue