Support for static methods/properties
Both properties and methods can be marked as Usage: Static Statics can be accessed using ns:Class.property / ns:Class.method(), :Class.property / :Class.method() to access class from current namespace or type('full.name').property / type('full.name').method() to use full type name. In static method $ / $this are referencing current class rather than object. Static properties are not loaded from object model. Also methods of io.murano.configuration.Linux class are now static. Since static methods can be called on the instance it doesn't break backward compatibility. Implements blueprint: muranopl-statics Change-Id: Ic7c6beed9222f4bca118877a60fdabfdd9d65e5a
This commit is contained in:
parent
f4ff2fb482
commit
94c904e1cb
@ -19,6 +19,7 @@ Name: Linux
|
|||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
runCommand:
|
runCommand:
|
||||||
|
Usage: Static
|
||||||
Arguments:
|
Arguments:
|
||||||
- agent:
|
- agent:
|
||||||
Contract: $.class(sys:Agent)
|
Contract: $.class(sys:Agent)
|
||||||
@ -54,6 +55,7 @@ Methods:
|
|||||||
- Return: $agent.call($template, $resources)
|
- Return: $agent.call($template, $resources)
|
||||||
|
|
||||||
putFile:
|
putFile:
|
||||||
|
Usage: Static
|
||||||
Arguments:
|
Arguments:
|
||||||
- agent:
|
- agent:
|
||||||
Contract: $.class(sys:Agent)
|
Contract: $.class(sys:Agent)
|
||||||
|
@ -233,21 +233,22 @@ class MuranoTestRunner(object):
|
|||||||
for m in test_cases:
|
for m in test_cases:
|
||||||
# Create new executor for each test case to provide
|
# Create new executor for each test case to provide
|
||||||
# pure test environment
|
# pure test environment
|
||||||
executer = executor.MuranoDslExecutor(
|
dsl_executor = executor.MuranoDslExecutor(
|
||||||
pkg_loader,
|
pkg_loader,
|
||||||
mock_context_manager.MockContextManager(),
|
mock_context_manager.MockContextManager(),
|
||||||
test_env)
|
test_env)
|
||||||
obj = package.find_class(pkg_class, False).new(
|
obj = package.find_class(pkg_class, False).new(
|
||||||
None, executer.object_store)(None)
|
None, dsl_executor.object_store, dsl_executor)(None)
|
||||||
self._call_service_method('setUp', executer, obj)
|
self._call_service_method('setUp', dsl_executor, obj)
|
||||||
obj.type.methods[m].usage = 'Action'
|
obj.type.methods[m].usage = 'Action'
|
||||||
|
|
||||||
test_env.start()
|
test_env.start()
|
||||||
try:
|
try:
|
||||||
obj.type.invoke(m, executer, obj, (), {})
|
obj.type.invoke(m, dsl_executor, obj, (), {})
|
||||||
LOG.debug('\n.....{0}.{1}.....OK'.format(obj.type.name,
|
LOG.debug('\n.....{0}.{1}.....OK'.format(obj.type.name,
|
||||||
m))
|
m))
|
||||||
self._call_service_method('tearDown', executer, obj)
|
self._call_service_method(
|
||||||
|
'tearDown', dsl_executor, obj)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception('\n.....{0}.{1}.....FAILURE\n'
|
LOG.exception('\n.....{0}.{1}.....FAILURE\n'
|
||||||
''.format(obj.type.name, m))
|
''.format(obj.type.name, m))
|
||||||
|
@ -109,9 +109,9 @@ class MuranoTypeName(yaqltypes.PythonType):
|
|||||||
if function_spec.meta.get(constants.META_MURANO_METHOD):
|
if function_spec.meta.get(constants.META_MURANO_METHOD):
|
||||||
context = helpers.get_caller_context(context)
|
context = helpers.get_caller_context(context)
|
||||||
murano_type = helpers.get_type(context)
|
murano_type = helpers.get_type(context)
|
||||||
value = dsl_types.MuranoTypeReference(helpers.get_class(
|
value = helpers.get_class(
|
||||||
murano_type.namespace_resolver.resolve_name(value),
|
murano_type.namespace_resolver.resolve_name(value),
|
||||||
context))
|
context).get_reference()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,8 +45,16 @@ class MuranoTypeReference(object):
|
|||||||
def murano_class(self):
|
def murano_class(self):
|
||||||
return self.__murano_class
|
return self.__murano_class
|
||||||
|
|
||||||
def __str__(self):
|
def __repr__(self):
|
||||||
return self.__murano_class.name
|
return '*' + repr(self.murano_class)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, MuranoTypeReference):
|
||||||
|
return False
|
||||||
|
return self.murano_class == other.murano_class
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.murano_class)
|
||||||
|
|
||||||
|
|
||||||
class YaqlExpression(object):
|
class YaqlExpression(object):
|
||||||
|
@ -160,3 +160,9 @@ class UninitializedPropertyAccessError(PropertyAccessError):
|
|||||||
|
|
||||||
class CircularExpressionDependenciesError(Exception):
|
class CircularExpressionDependenciesError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidLhsTargetError(Exception):
|
||||||
|
def __init__(self, target):
|
||||||
|
super(InvalidLhsTargetError, self).__init__(
|
||||||
|
'Invalid assignment target "%s"' % target)
|
||||||
|
@ -28,6 +28,7 @@ from murano.common.i18n import _LW
|
|||||||
from murano.dsl import attribute_store
|
from murano.dsl import attribute_store
|
||||||
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 murano_method
|
from murano.dsl import murano_method
|
||||||
from murano.dsl import object_store
|
from murano.dsl import object_store
|
||||||
@ -85,7 +86,9 @@ class MuranoDslExecutor(object):
|
|||||||
|
|
||||||
context = self.create_method_context(
|
context = self.create_method_context(
|
||||||
self.create_object_context(this, context), method)
|
self.create_object_context(this, context), method)
|
||||||
this = this.real_this
|
|
||||||
|
if isinstance(this, dsl_types.MuranoObject):
|
||||||
|
this = this.real_this
|
||||||
|
|
||||||
if method.arguments_scheme is not None:
|
if method.arguments_scheme is not None:
|
||||||
args, kwargs = self._canonize_parameters(
|
args, kwargs = self._canonize_parameters(
|
||||||
@ -119,7 +122,10 @@ class MuranoDslExecutor(object):
|
|||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _acquire_method_lock(self, func, this):
|
def _acquire_method_lock(self, func, this):
|
||||||
method_id = id(func)
|
method_id = id(func)
|
||||||
this_id = this.object_id
|
if isinstance(this, dsl_types.MuranoClass):
|
||||||
|
this_id = id(this)
|
||||||
|
else:
|
||||||
|
this_id = this.object_id
|
||||||
thread_id = helpers.get_current_thread_id()
|
thread_id = helpers.get_current_thread_id()
|
||||||
while True:
|
while True:
|
||||||
event, event_owner = self._locks.get(
|
event, event_owner = self._locks.get(
|
||||||
@ -262,13 +268,24 @@ class MuranoDslExecutor(object):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def create_object_context(self, obj, caller_context=None):
|
def create_object_context(self, obj, caller_context=None):
|
||||||
class_context = self.create_class_context(obj.type)
|
if isinstance(obj, dsl_types.MuranoClass):
|
||||||
context = helpers.link_contexts(
|
obj_type = obj
|
||||||
class_context, self.context_manager.create_object_context(
|
obj = None
|
||||||
obj)).create_child_context()
|
else:
|
||||||
context[constants.CTX_THIS] = obj.real_this
|
obj_type = obj.type
|
||||||
context['this'] = obj.real_this
|
class_context = self.create_class_context(obj_type)
|
||||||
context[''] = obj.real_this
|
if obj is not None:
|
||||||
|
context = helpers.link_contexts(
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
context = class_context.create_child_context()
|
||||||
|
type_ref = obj_type.get_reference()
|
||||||
|
context['this'] = type_ref
|
||||||
|
context[''] = type_ref
|
||||||
|
|
||||||
if caller_context is not None:
|
if caller_context is not None:
|
||||||
caller = caller_context
|
caller = caller_context
|
||||||
|
@ -153,7 +153,9 @@ def get_environment(context=None):
|
|||||||
|
|
||||||
def get_object_store(context=None):
|
def get_object_store(context=None):
|
||||||
context = context or get_context()
|
context = context or get_context()
|
||||||
return context[constants.CTX_THIS].object_store
|
this = context[constants.CTX_THIS]
|
||||||
|
return this.object_store if isinstance(
|
||||||
|
this, dsl_types.MuranoObject) else None
|
||||||
|
|
||||||
|
|
||||||
def get_package_loader(context=None):
|
def get_package_loader(context=None):
|
||||||
|
@ -20,8 +20,10 @@ from yaql.language import utils
|
|||||||
from yaql.language import yaqltypes
|
from yaql.language import yaqltypes
|
||||||
|
|
||||||
from murano.dsl import constants
|
from murano.dsl import constants
|
||||||
|
from murano.dsl import dsl
|
||||||
from murano.dsl import dsl_types
|
from murano.dsl import dsl_types
|
||||||
from murano.dsl import exceptions
|
from murano.dsl import exceptions
|
||||||
|
from murano.dsl import yaql_functions
|
||||||
from murano.dsl import yaql_integration
|
from murano.dsl import yaql_integration
|
||||||
|
|
||||||
|
|
||||||
@ -68,6 +70,14 @@ class LhsExpression(object):
|
|||||||
((key, value),))))
|
((key, value),))))
|
||||||
elif isinstance(src, dsl_types.MuranoObject):
|
elif isinstance(src, dsl_types.MuranoObject):
|
||||||
src.set_property(key, value, root_context)
|
src.set_property(key, value, root_context)
|
||||||
|
elif isinstance(src, (
|
||||||
|
dsl_types.MuranoTypeReference,
|
||||||
|
dsl_types.MuranoClass)):
|
||||||
|
if not isinstance(src, dsl_types.MuranoClass):
|
||||||
|
mc = src.murano_class
|
||||||
|
else:
|
||||||
|
mc = src
|
||||||
|
mc.set_property(key, value, root_context)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'attribution may only be applied to '
|
'attribution may only be applied to '
|
||||||
@ -118,16 +128,51 @@ class LhsExpression(object):
|
|||||||
else:
|
else:
|
||||||
return attribution(this, index)
|
return attribution(this, index)
|
||||||
|
|
||||||
|
def _wrap_type_reference(tr):
|
||||||
|
return LhsExpression.Property(lambda: tr, self._invalid_target)
|
||||||
|
|
||||||
|
@specs.parameter('prefix', yaqltypes.Keyword())
|
||||||
|
@specs.parameter('name', yaqltypes.Keyword())
|
||||||
|
@specs.name('#operator_:')
|
||||||
|
def ns_resolve(prefix, name):
|
||||||
|
return _wrap_type_reference(
|
||||||
|
yaql_functions.ns_resolve(context, prefix, name))
|
||||||
|
|
||||||
|
@specs.parameter('name', yaqltypes.Keyword())
|
||||||
|
@specs.name('#unary_operator_:')
|
||||||
|
def ns_resolve_unary(context, name):
|
||||||
|
return _wrap_type_reference(
|
||||||
|
yaql_functions.ns_resolve_unary(context, name))
|
||||||
|
|
||||||
|
@specs.parameter('object_', dsl_types.MuranoObject)
|
||||||
|
def type_(object_):
|
||||||
|
return _wrap_type_reference(yaql_functions.type_(object_))
|
||||||
|
|
||||||
|
@specs.name('type')
|
||||||
|
@specs.parameter('cls', dsl.MuranoTypeName())
|
||||||
|
def type_from_name(cls):
|
||||||
|
return _wrap_type_reference(cls)
|
||||||
|
|
||||||
context = yaql_integration.create_empty_context()
|
context = yaql_integration.create_empty_context()
|
||||||
context.register_function(get_context_data, '#get_context_data')
|
context.register_function(get_context_data, '#get_context_data')
|
||||||
context.register_function(attribution, '#operator_.')
|
context.register_function(attribution, '#operator_.')
|
||||||
context.register_function(indexation, '#indexer')
|
context.register_function(indexation, '#indexer')
|
||||||
|
context.register_function(ns_resolve)
|
||||||
|
context.register_function(ns_resolve_unary)
|
||||||
|
context.register_function(type_)
|
||||||
|
context.register_function(type_from_name)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def _invalid_target(self, *args, **kwargs):
|
||||||
|
raise exceptions.InvalidLhsTargetError(self._expression)
|
||||||
|
|
||||||
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]
|
||||||
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)
|
||||||
|
if not isinstance(property, LhsExpression.Property):
|
||||||
|
self._invalid_target()
|
||||||
property.set(value)
|
property.set(value)
|
||||||
|
@ -46,6 +46,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
package.find_class(constants.CORE_LIBRARY_OBJECT)]
|
package.find_class(constants.CORE_LIBRARY_OBJECT)]
|
||||||
self._context = None
|
self._context = None
|
||||||
self._parent_mappings = self._build_parent_remappings()
|
self._parent_mappings = self._build_parent_remappings()
|
||||||
|
self._property_values = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, data, package, name=None):
|
def create(cls, data, package, name=None):
|
||||||
@ -53,7 +54,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
|
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
name = ns_resolver.resolve_name(data['Name'])
|
name = ns_resolver.resolve_name(str(data['Name']))
|
||||||
|
|
||||||
parent_class_names = data.get('Extends')
|
parent_class_names = data.get('Extends')
|
||||||
parent_classes = []
|
parent_classes = []
|
||||||
@ -61,7 +62,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
if not utils.is_sequence(parent_class_names):
|
if not utils.is_sequence(parent_class_names):
|
||||||
parent_class_names = [parent_class_names]
|
parent_class_names = [parent_class_names]
|
||||||
for parent_name in parent_class_names:
|
for parent_name in parent_class_names:
|
||||||
full_name = ns_resolver.resolve_name(parent_name)
|
full_name = ns_resolver.resolve_name(str(parent_name))
|
||||||
parent_classes.append(package.find_class(full_name))
|
parent_classes.append(package.find_class(full_name))
|
||||||
|
|
||||||
type_obj = cls(ns_resolver, name, package, parent_classes)
|
type_obj = cls(ns_resolver, name, package, parent_classes)
|
||||||
@ -189,6 +190,19 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
return self._choose_symbol(
|
return self._choose_symbol(
|
||||||
lambda cls: cls.properties.get(name))
|
lambda cls: cls.properties.get(name))
|
||||||
|
|
||||||
|
def find_static_property(self, name):
|
||||||
|
def prop_func(cls):
|
||||||
|
prop = cls.properties.get(name)
|
||||||
|
if prop is not None and prop.usage == 'Static':
|
||||||
|
return prop
|
||||||
|
|
||||||
|
result = self._choose_symbol(prop_func)
|
||||||
|
if len(result) < 1:
|
||||||
|
raise exceptions.NoPropertyFound(name)
|
||||||
|
elif len(result) > 1:
|
||||||
|
raise exceptions.AmbiguousPropertyNameError(name)
|
||||||
|
return result[0]
|
||||||
|
|
||||||
def find_single_method(self, name):
|
def find_single_method(self, name):
|
||||||
result = self.find_method(name)
|
result = self.find_method(name)
|
||||||
if len(result) < 1:
|
if len(result) < 1:
|
||||||
@ -242,12 +256,13 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
return True
|
return True
|
||||||
return any(cls is self for cls in obj.ancestors())
|
return any(cls is self for cls in obj.ancestors())
|
||||||
|
|
||||||
def new(self, owner, object_store, **kwargs):
|
def new(self, owner, object_store, executor, **kwargs):
|
||||||
obj = murano_object.MuranoObject(self, owner, object_store, **kwargs)
|
obj = murano_object.MuranoObject(
|
||||||
|
self, owner, object_store, executor, **kwargs)
|
||||||
|
|
||||||
def initializer(__context, **params):
|
def initializer(__context, **params):
|
||||||
if __context is None:
|
if __context is None:
|
||||||
__context = object_store.executor.create_object_context(obj)
|
__context = executor.create_object_context(obj)
|
||||||
init_context = __context.create_child_context()
|
init_context = __context.create_child_context()
|
||||||
init_context[constants.CTX_ALLOW_PROPERTY_WRITES] = True
|
init_context[constants.CTX_ALLOW_PROPERTY_WRITES] = True
|
||||||
obj.initialize(init_context, object_store, params)
|
obj.initialize(init_context, object_store, params)
|
||||||
@ -359,3 +374,17 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||||||
m.yaql_function_definition,
|
m.yaql_function_definition,
|
||||||
name=m.yaql_function_definition.name)
|
name=m.yaql_function_definition.name)
|
||||||
return self._context
|
return self._context
|
||||||
|
|
||||||
|
def get_property(self, name, context):
|
||||||
|
prop = self.find_static_property(name)
|
||||||
|
cls = prop.murano_class
|
||||||
|
value = cls._property_values.get(name, prop.default)
|
||||||
|
return prop.validate(value, cls, None, context)
|
||||||
|
|
||||||
|
def set_property(self, name, value, context):
|
||||||
|
prop = self.find_static_property(name)
|
||||||
|
cls = prop.murano_class
|
||||||
|
cls._property_values[name] = prop.validate(value, cls, None, context)
|
||||||
|
|
||||||
|
def get_reference(self):
|
||||||
|
return dsl_types.MuranoTypeReference(self)
|
||||||
|
@ -35,7 +35,8 @@ virtual_exceptions.register()
|
|||||||
class MethodUsages(object):
|
class MethodUsages(object):
|
||||||
Action = 'Action'
|
Action = 'Action'
|
||||||
Runtime = 'Runtime'
|
Runtime = 'Runtime'
|
||||||
All = set([Action, Runtime])
|
Static = 'Static'
|
||||||
|
All = set([Action, Runtime, Static])
|
||||||
|
|
||||||
|
|
||||||
class MuranoMethod(dsl_types.MuranoMethod):
|
class MuranoMethod(dsl_types.MuranoMethod):
|
||||||
@ -111,13 +112,18 @@ class MuranoMethod(dsl_types.MuranoMethod):
|
|||||||
|
|
||||||
def invoke(self, executor, this, args, kwargs, context=None,
|
def invoke(self, executor, this, args, kwargs, context=None,
|
||||||
skip_stub=False):
|
skip_stub=False):
|
||||||
if not self.murano_class.is_compatible(this):
|
if self.usage == 'Static':
|
||||||
|
this = None
|
||||||
|
elif not self.murano_class.is_compatible(this):
|
||||||
raise Exception("'this' must be of compatible type")
|
raise Exception("'this' must be of compatible type")
|
||||||
if isinstance(this, dsl.MuranoObjectInterface):
|
if isinstance(this, dsl.MuranoObjectInterface):
|
||||||
this = this.object
|
this = this.object
|
||||||
|
if this is not None:
|
||||||
|
this = this.cast(self.murano_class)
|
||||||
|
else:
|
||||||
|
this = self.murano_class
|
||||||
return executor.invoke_method(
|
return executor.invoke_method(
|
||||||
self, this.cast(self.murano_class),
|
self, this, context, args, kwargs, skip_stub)
|
||||||
context, args, kwargs, skip_stub)
|
|
||||||
|
|
||||||
|
|
||||||
class MuranoMethodArgument(dsl_types.MuranoMethodArgument, typespec.Spec):
|
class MuranoMethodArgument(dsl_types.MuranoMethodArgument, typespec.Spec):
|
||||||
|
@ -26,8 +26,9 @@ from murano.dsl import yaql_integration
|
|||||||
|
|
||||||
|
|
||||||
class MuranoObject(dsl_types.MuranoObject):
|
class MuranoObject(dsl_types.MuranoObject):
|
||||||
def __init__(self, murano_class, owner, object_store, object_id=None,
|
def __init__(self, murano_class, owner, object_store, executor,
|
||||||
name=None, known_classes=None, defaults=None, this=None):
|
object_id=None, name=None, known_classes=None,
|
||||||
|
defaults=None, this=None):
|
||||||
if known_classes is None:
|
if known_classes is None:
|
||||||
known_classes = {}
|
known_classes = {}
|
||||||
self.__owner = owner.real_this if owner else None
|
self.__owner = owner.real_this if owner else None
|
||||||
@ -39,7 +40,9 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
self.__this = this
|
self.__this = this
|
||||||
self.__name = name
|
self.__name = name
|
||||||
self.__extension = None
|
self.__extension = None
|
||||||
self.__object_store = weakref.ref(object_store)
|
self.__object_store = \
|
||||||
|
None if object_store is None else weakref.ref(object_store)
|
||||||
|
self.__executor = weakref.ref(executor)
|
||||||
self.__config = murano_class.package.get_class_config(
|
self.__config = murano_class.package.get_class_config(
|
||||||
murano_class.name)
|
murano_class.name)
|
||||||
if not isinstance(self.__config, dict):
|
if not isinstance(self.__config, dict):
|
||||||
@ -49,7 +52,7 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
name = parent_class.name
|
name = parent_class.name
|
||||||
if name not in known_classes:
|
if name not in known_classes:
|
||||||
obj = parent_class.new(
|
obj = parent_class.new(
|
||||||
owner, object_store, object_id=self.__object_id,
|
owner, object_store, executor, object_id=self.__object_id,
|
||||||
known_classes=known_classes, defaults=defaults,
|
known_classes=known_classes, defaults=defaults,
|
||||||
this=self.real_this).object
|
this=self.real_this).object
|
||||||
|
|
||||||
@ -72,7 +75,11 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def object_store(self):
|
def object_store(self):
|
||||||
return self.__object_store()
|
return None if self.__object_store is None else self.__object_store()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def executor(self):
|
||||||
|
return self.__executor()
|
||||||
|
|
||||||
def initialize(self, context, object_store, params):
|
def initialize(self, context, object_store, params):
|
||||||
if self.__initialized:
|
if self.__initialized:
|
||||||
@ -105,7 +112,8 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
|
|
||||||
if property_name in used_names:
|
if property_name in used_names:
|
||||||
continue
|
continue
|
||||||
if spec.usage == typespec.PropertyUsages.Config:
|
if spec.usage in (typespec.PropertyUsages.Config,
|
||||||
|
typespec.PropertyUsages.Static):
|
||||||
used_names.add(property_name)
|
used_names.add(property_name)
|
||||||
continue
|
continue
|
||||||
if spec.usage == typespec.PropertyUsages.Runtime:
|
if spec.usage == typespec.PropertyUsages.Runtime:
|
||||||
@ -133,7 +141,8 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
last_errors = errors
|
last_errors = errors
|
||||||
|
|
||||||
executor = helpers.get_executor(context)
|
executor = helpers.get_executor(context)
|
||||||
if not object_store.initializing and self.__extension is None:
|
if ((object_store is None or not object_store.initializing) and
|
||||||
|
self.__extension is None):
|
||||||
method = self.type.methods.get('__init__')
|
method = self.type.methods.get('__init__')
|
||||||
if method:
|
if method:
|
||||||
filtered_params = yaql_integration.filter_parameters(
|
filtered_params = yaql_integration.filter_parameters(
|
||||||
@ -146,7 +155,7 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
for parent in self.__parents.values():
|
for parent in self.__parents.values():
|
||||||
parent.initialize(context, object_store, params)
|
parent.initialize(context, object_store, params)
|
||||||
|
|
||||||
if not object_store.initializing and init:
|
if (object_store is None or not object_store.initializing) and init:
|
||||||
context[constants.CTX_ARGUMENT_OWNER] = self.real_this
|
context[constants.CTX_ARGUMENT_OWNER] = self.real_this
|
||||||
init.invoke(executor, self.real_this, (), init_args, context)
|
init.invoke(executor, self.real_this, (), init_args, context)
|
||||||
self.__initialized = True
|
self.__initialized = True
|
||||||
@ -173,11 +182,18 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
if caller_class is not None and caller_class.is_compatible(self):
|
if caller_class is not None and caller_class.is_compatible(self):
|
||||||
start_type, derived = caller_class, True
|
start_type, derived = caller_class, True
|
||||||
if name in start_type.properties:
|
if name in start_type.properties:
|
||||||
return self.cast(start_type)._get_property_value(name)
|
spec = start_type.properties[name]
|
||||||
|
if spec.usage == typespec.PropertyUsages.Static:
|
||||||
|
return spec.murano_class.get_property(name, context)
|
||||||
|
else:
|
||||||
|
return self.cast(start_type)._get_property_value(name)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
spec = start_type.find_single_property(name)
|
spec = start_type.find_single_property(name)
|
||||||
return self.cast(spec.murano_class).__properties[name]
|
if spec.usage == typespec.PropertyUsages.Static:
|
||||||
|
return spec.murano_class.get_property(name, context)
|
||||||
|
else:
|
||||||
|
return self.cast(spec.murano_class).__properties[name]
|
||||||
except exceptions.NoPropertyFound:
|
except exceptions.NoPropertyFound:
|
||||||
if derived:
|
if derived:
|
||||||
return self.cast(caller_class)._get_property_value(name)
|
return self.cast(caller_class)._get_property_value(name)
|
||||||
@ -199,11 +215,12 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
declared_properties = start_type.find_properties(
|
declared_properties = start_type.find_properties(
|
||||||
lambda p: p.name == name)
|
lambda p: p.name == name)
|
||||||
if context is None:
|
if context is None:
|
||||||
context = self.object_store.executor.create_object_context(self)
|
context = self.executor.create_object_context(self)
|
||||||
if len(declared_properties) > 0:
|
if len(declared_properties) > 0:
|
||||||
declared_properties = self.type.find_properties(
|
declared_properties = self.type.find_properties(
|
||||||
lambda p: p.name == name)
|
lambda p: p.name == name)
|
||||||
values_to_assign = []
|
values_to_assign = []
|
||||||
|
classes_for_static_properties = []
|
||||||
for spec in declared_properties:
|
for spec in declared_properties:
|
||||||
if (caller_class is not None and not
|
if (caller_class is not None and not
|
||||||
helpers.are_property_modifications_allowed(context) and
|
helpers.are_property_modifications_allowed(context) and
|
||||||
@ -211,16 +228,21 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||||||
not derived)):
|
not derived)):
|
||||||
raise exceptions.NoWriteAccessError(name)
|
raise exceptions.NoWriteAccessError(name)
|
||||||
|
|
||||||
default = self.__config.get(name, spec.default)
|
if spec.usage == typespec.PropertyUsages.Static:
|
||||||
default = self.__defaults.get(name, default)
|
classes_for_static_properties.append(spec.murano_class)
|
||||||
default = helpers.evaluate(default, context)
|
else:
|
||||||
|
default = self.__config.get(name, spec.default)
|
||||||
|
default = self.__defaults.get(name, default)
|
||||||
|
default = helpers.evaluate(default, context)
|
||||||
|
|
||||||
obj = self.cast(spec.murano_class)
|
obj = self.cast(spec.murano_class)
|
||||||
values_to_assign.append((obj, spec.validate(
|
values_to_assign.append((obj, spec.validate(
|
||||||
value, self.real_this,
|
value, self.real_this,
|
||||||
self.real_this, default=default)))
|
self.real_this, context, default=default)))
|
||||||
for obj, value in values_to_assign:
|
for obj, value in values_to_assign:
|
||||||
obj.__properties[name] = value
|
obj.__properties[name] = value
|
||||||
|
for cls in classes_for_static_properties:
|
||||||
|
cls.set_property(name, value, context)
|
||||||
elif derived:
|
elif derived:
|
||||||
obj = self.cast(caller_class)
|
obj = self.cast(caller_class)
|
||||||
obj.__properties[name] = value
|
obj.__properties[name] = value
|
||||||
|
@ -12,26 +12,42 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
TYPE_NAME_RE = re.compile(r'^([a-zA-Z_]\w*:|:)?[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*$')
|
||||||
|
NS_RE = re.compile(r'^([a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*)?$')
|
||||||
|
PREFIX_RE = re.compile(r'^([a-zA-Z_]\w*|=)$')
|
||||||
|
|
||||||
|
|
||||||
class NamespaceResolver(object):
|
class NamespaceResolver(object):
|
||||||
def __init__(self, namespaces):
|
def __init__(self, namespaces):
|
||||||
self._namespaces = namespaces
|
for prefix, ns in namespaces.items():
|
||||||
|
if PREFIX_RE.match(prefix) is None:
|
||||||
|
raise ValueError(
|
||||||
|
'Invalid namespace prefix "{0}"'.format(prefix))
|
||||||
|
if NS_RE.match(ns) is None:
|
||||||
|
raise ValueError('Invalid namespace "{0}"'.format(ns))
|
||||||
|
self._namespaces = namespaces.copy()
|
||||||
|
self._namespaces.setdefault('=', '')
|
||||||
self._namespaces[''] = ''
|
self._namespaces[''] = ''
|
||||||
|
|
||||||
def resolve_name(self, name, relative=None):
|
def resolve_name(self, name):
|
||||||
if name is None:
|
if name is None or TYPE_NAME_RE.match(name) is None:
|
||||||
raise ValueError()
|
raise ValueError('Invalid type name "{0}"'.format(name))
|
||||||
if name and name.startswith(':'):
|
if ':' not in name:
|
||||||
return name[1:]
|
if '.' in name:
|
||||||
if ':' in name:
|
parts = ['', name]
|
||||||
|
else:
|
||||||
|
parts = ['=', name]
|
||||||
|
else:
|
||||||
parts = name.split(':')
|
parts = name.split(':')
|
||||||
if len(parts) != 2 or not parts[1]:
|
if not parts[0]:
|
||||||
raise NameError('Incorrectly formatted name ' + name)
|
parts[0] = '='
|
||||||
if parts[0] not in self._namespaces:
|
|
||||||
raise KeyError('Unknown namespace prefix ' + parts[0])
|
if parts[0] not in self._namespaces:
|
||||||
return '.'.join((self._namespaces[parts[0]], parts[1]))
|
raise KeyError('Unknown namespace prefix ' + parts[0])
|
||||||
if not relative and '=' in self._namespaces and '.' not in name:
|
|
||||||
return '.'.join((self._namespaces['='], name))
|
ns = self._namespaces[parts[0]]
|
||||||
if relative and '.' not in name:
|
if not ns:
|
||||||
return '.'.join((relative, name))
|
return name
|
||||||
return name
|
return '.'.join((ns, parts[1]))
|
||||||
|
@ -81,7 +81,7 @@ class ObjectStore(object):
|
|||||||
return factory
|
return factory
|
||||||
else:
|
else:
|
||||||
factory = class_obj.new(
|
factory = class_obj.new(
|
||||||
owner, self,
|
owner, self, self.executor,
|
||||||
name=system_key.get('name'),
|
name=system_key.get('name'),
|
||||||
object_id=object_id, defaults=defaults)
|
object_id=object_id, defaults=defaults)
|
||||||
self._store[object_id] = factory
|
self._store[object_id] = factory
|
||||||
|
@ -157,6 +157,12 @@ def argument_owner(method_argument):
|
|||||||
return method_argument.murano_method
|
return method_argument.murano_method
|
||||||
|
|
||||||
|
|
||||||
|
@specs.yaql_property(dsl_types.MuranoClass)
|
||||||
|
@specs.name('type')
|
||||||
|
def type_to_type_ref(murano_class):
|
||||||
|
return murano_class.get_reference()
|
||||||
|
|
||||||
|
|
||||||
def register(context):
|
def register(context):
|
||||||
funcs = (
|
funcs = (
|
||||||
class_name, methods, properties, ancestors, package, class_version,
|
class_name, methods, properties, ancestors, package, class_version,
|
||||||
@ -164,7 +170,8 @@ def register(context):
|
|||||||
property_usage,
|
property_usage,
|
||||||
method_name, arguments, method_owner,
|
method_name, arguments, method_owner,
|
||||||
types, package_name, package_version,
|
types, package_name, package_version,
|
||||||
argument_name, argument_has_default, argument_owner
|
argument_name, argument_has_default, argument_owner,
|
||||||
|
type_to_type_ref
|
||||||
)
|
)
|
||||||
for f in funcs:
|
for f in funcs:
|
||||||
context.register_function(f)
|
context.register_function(f)
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
|
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
from murano.dsl import dsl_types
|
||||||
from murano.dsl import exceptions
|
from murano.dsl import exceptions
|
||||||
|
from murano.dsl import helpers
|
||||||
from murano.dsl import type_scheme
|
from murano.dsl import type_scheme
|
||||||
|
|
||||||
|
|
||||||
@ -25,8 +27,9 @@ class PropertyUsages(object):
|
|||||||
Runtime = 'Runtime'
|
Runtime = 'Runtime'
|
||||||
Const = 'Const'
|
Const = 'Const'
|
||||||
Config = 'Config'
|
Config = 'Config'
|
||||||
All = set([In, Out, InOut, Runtime, Const, Config])
|
Static = 'Static'
|
||||||
Writable = set([Out, InOut, Runtime])
|
All = set([In, Out, InOut, Runtime, Const, Config, Static])
|
||||||
|
Writable = set([Out, InOut, Runtime, Static])
|
||||||
|
|
||||||
|
|
||||||
class Spec(object):
|
class Spec(object):
|
||||||
@ -41,13 +44,19 @@ class Spec(object):
|
|||||||
'Unknown type {0}. Must be one of ({1})'.format(
|
'Unknown type {0}. Must be one of ({1})'.format(
|
||||||
self._usage, ', '.join(PropertyUsages.All)))
|
self._usage, ', '.join(PropertyUsages.All)))
|
||||||
|
|
||||||
def validate(self, value, this, owner, default=None):
|
def validate(self, value, this, owner, context, default=None):
|
||||||
if default is None:
|
if default is None:
|
||||||
default = self.default
|
default = self.default
|
||||||
return self._contract(
|
executor = helpers.get_executor(context)
|
||||||
value, this.object_store.executor.create_object_context(
|
if isinstance(this, dsl_types.MuranoClass):
|
||||||
this.cast(self._container_class())),
|
return self._contract(
|
||||||
this, owner, default)
|
value, executor.create_object_context(this),
|
||||||
|
None, None, default)
|
||||||
|
else:
|
||||||
|
return self._contract(
|
||||||
|
value, executor.create_object_context(
|
||||||
|
this.cast(self._container_class())),
|
||||||
|
this, owner, default)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default(self):
|
def default(self):
|
||||||
|
@ -68,7 +68,7 @@ class YaqlExpression(dsl_types.YaqlExpression):
|
|||||||
def is_expression(expression, version):
|
def is_expression(expression, version):
|
||||||
if not isinstance(expression, six.string_types):
|
if not isinstance(expression, six.string_types):
|
||||||
return False
|
return False
|
||||||
if re.match('^[\s\w\d.:]*$', expression):
|
if re.match('^[\s\w\d.]*$', expression):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
yaql_integration.parse(expression, version)
|
yaql_integration.parse(expression, version)
|
||||||
|
@ -46,12 +46,14 @@ def cast(context, object_, type__, version_spec=None):
|
|||||||
def new(__context, __type_name, __owner=None, __object_name=None, __extra=None,
|
def new(__context, __type_name, __owner=None, __object_name=None, __extra=None,
|
||||||
**parameters):
|
**parameters):
|
||||||
object_store = helpers.get_object_store(__context)
|
object_store = helpers.get_object_store(__context)
|
||||||
|
executor = helpers.get_executor(__context)
|
||||||
new_context = __context.create_child_context()
|
new_context = __context.create_child_context()
|
||||||
for key, value in six.iteritems(parameters):
|
for key, value in six.iteritems(parameters):
|
||||||
if utils.is_keyword(key):
|
if utils.is_keyword(key):
|
||||||
new_context[key] = value
|
new_context[key] = value
|
||||||
return __type_name.murano_class.new(
|
return __type_name.murano_class.new(
|
||||||
__owner, object_store, name=__object_name)(new_context, **parameters)
|
__owner, object_store, executor, name=__object_name)(
|
||||||
|
new_context, **parameters)
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('type_name', dsl.MuranoTypeName())
|
@specs.parameter('type_name', dsl.MuranoTypeName())
|
||||||
@ -110,14 +112,32 @@ def sleep_(seconds):
|
|||||||
|
|
||||||
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||||
def type_(object_):
|
def type_(object_):
|
||||||
|
return None if object_ is None else object_.type.get_reference()
|
||||||
|
|
||||||
|
|
||||||
|
@specs.name('type')
|
||||||
|
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||||
|
def type_legacy(object_):
|
||||||
return None if object_ is None else object_.type.name
|
return None if object_ is None else object_.type.name
|
||||||
|
|
||||||
|
|
||||||
|
@specs.name('type')
|
||||||
|
@specs.parameter('cls', dsl.MuranoTypeName())
|
||||||
|
def type_from_name(cls):
|
||||||
|
return cls
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||||
def typeinfo(object_):
|
def typeinfo(object_):
|
||||||
return None if object_ is None else object_.type
|
return None if object_ is None else object_.type
|
||||||
|
|
||||||
|
|
||||||
|
@specs.parameter('cls', dsl.MuranoTypeName())
|
||||||
|
@specs.name('typeinfo')
|
||||||
|
def typeinfo_for_class(cls):
|
||||||
|
return cls.murano_class
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||||
def name(object_):
|
def name(object_):
|
||||||
return None if object_ is None else object_.name
|
return None if object_ is None else object_.name
|
||||||
@ -130,6 +150,13 @@ def obj_attribution(context, obj, property_name):
|
|||||||
return obj.get_property(property_name, context)
|
return obj.get_property(property_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
@specs.parameter('cls', dsl_types.MuranoTypeReference)
|
||||||
|
@specs.parameter('property_name', yaqltypes.Keyword())
|
||||||
|
@specs.name('#operator_.')
|
||||||
|
def obj_attribution_static(context, cls, property_name):
|
||||||
|
return cls.murano_class.get_property(property_name, context)
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('receiver', dsl.MuranoObjectParameterType())
|
@specs.parameter('receiver', dsl.MuranoObjectParameterType())
|
||||||
@specs.parameter('expr', yaqltypes.Lambda(method=True))
|
@specs.parameter('expr', yaqltypes.Lambda(method=True))
|
||||||
@specs.inject('operator', yaqltypes.Super(with_context=True))
|
@specs.inject('operator', yaqltypes.Super(with_context=True))
|
||||||
@ -144,14 +171,32 @@ def op_dot(context, receiver, expr, operator):
|
|||||||
return operator(ctx2, receiver, expr)
|
return operator(ctx2, receiver, expr)
|
||||||
|
|
||||||
|
|
||||||
|
@specs.parameter('sender', dsl_types.MuranoTypeReference)
|
||||||
|
@specs.parameter('expr', yaqltypes.Lambda(method=True))
|
||||||
|
@specs.inject('operator', yaqltypes.Super(with_context=True))
|
||||||
|
@specs.name('#operator_.')
|
||||||
|
def op_dot_static(context, sender, expr, operator):
|
||||||
|
executor = helpers.get_executor(context)
|
||||||
|
type_context = executor.context_manager.create_class_context(
|
||||||
|
sender.murano_class)
|
||||||
|
ctx2 = helpers.link_contexts(context, type_context)
|
||||||
|
return operator(ctx2, None, expr)
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('prefix', yaqltypes.Keyword())
|
@specs.parameter('prefix', yaqltypes.Keyword())
|
||||||
@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)
|
murano_type = helpers.get_type(context)
|
||||||
return dsl_types.MuranoTypeReference(helpers.get_class(
|
return helpers.get_class(
|
||||||
murano_type.namespace_resolver.resolve_name(
|
murano_type.namespace_resolver.resolve_name(
|
||||||
prefix + ':' + name), context))
|
prefix + ':' + name), context).get_reference()
|
||||||
|
|
||||||
|
|
||||||
|
@specs.parameter('name', yaqltypes.Keyword())
|
||||||
|
@specs.name('#unary_operator_:')
|
||||||
|
def ns_resolve_unary(context, name):
|
||||||
|
return ns_resolve(context, '', name)
|
||||||
|
|
||||||
|
|
||||||
@specs.parameter('obj', dsl.MuranoObjectParameterType(nullable=True))
|
@specs.parameter('obj', dsl.MuranoObjectParameterType(nullable=True))
|
||||||
@ -173,20 +218,28 @@ def register(context, runtime_version):
|
|||||||
context.register_function(require)
|
context.register_function(require)
|
||||||
context.register_function(find)
|
context.register_function(find)
|
||||||
context.register_function(sleep_)
|
context.register_function(sleep_)
|
||||||
context.register_function(type_)
|
|
||||||
context.register_function(typeinfo)
|
context.register_function(typeinfo)
|
||||||
|
context.register_function(typeinfo_for_class)
|
||||||
context.register_function(name)
|
context.register_function(name)
|
||||||
context.register_function(obj_attribution)
|
context.register_function(obj_attribution)
|
||||||
|
context.register_function(obj_attribution_static)
|
||||||
context.register_function(op_dot)
|
context.register_function(op_dot)
|
||||||
|
context.register_function(op_dot_static)
|
||||||
context.register_function(ns_resolve)
|
context.register_function(ns_resolve)
|
||||||
|
context.register_function(ns_resolve_unary)
|
||||||
reflection.register(context)
|
reflection.register(context)
|
||||||
context.register_function(is_instance_of)
|
context.register_function(is_instance_of)
|
||||||
|
if runtime_version <= constants.RUNTIME_VERSION_1_3:
|
||||||
|
context.register_function(type_legacy)
|
||||||
|
else:
|
||||||
|
context.register_function(type_)
|
||||||
|
|
||||||
if runtime_version <= constants.RUNTIME_VERSION_1_1:
|
if runtime_version <= constants.RUNTIME_VERSION_1_1:
|
||||||
context2 = context.create_child_context()
|
context = context.create_child_context()
|
||||||
for t in ('id', 'cast', 'super', 'psuper', 'type'):
|
for t in ('id', 'cast', 'super', 'psuper', 'type'):
|
||||||
for spec in utils.to_extension_method(t, context):
|
for spec in utils.to_extension_method(t, context):
|
||||||
context2.register_function(spec)
|
context.register_function(spec)
|
||||||
return context2
|
|
||||||
|
context.register_function(type_from_name)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@ -51,7 +51,10 @@ def _add_operators(engine_factory):
|
|||||||
engine_factory.insert_operator(
|
engine_factory.insert_operator(
|
||||||
'>', True, 'is', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, False)
|
'>', True, 'is', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, False)
|
||||||
engine_factory.insert_operator(
|
engine_factory.insert_operator(
|
||||||
'.', True, ':', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, True)
|
None, True, ':', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, True)
|
||||||
|
engine_factory.insert_operator(
|
||||||
|
':', True, ':', factory.OperatorType.PREFIX_UNARY, False)
|
||||||
|
engine_factory.operators.insert(0, ())
|
||||||
|
|
||||||
|
|
||||||
def _create_engine(runtime_version):
|
def _create_engine(runtime_version):
|
||||||
@ -86,7 +89,7 @@ class ContractedValue(yaqltypes.GenericType):
|
|||||||
lambda value, sender, context, *args, **kwargs:
|
lambda value, sender, context, *args, **kwargs:
|
||||||
self._value_spec.validate(
|
self._value_spec.validate(
|
||||||
value, sender.real_this,
|
value, sender.real_this,
|
||||||
context[constants.CTX_ARGUMENT_OWNER]))
|
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:
|
||||||
@ -220,8 +223,9 @@ def _build_mpl_wrapper_function_definition(murano_method):
|
|||||||
fd.set_parameter(specs.ParameterDefinition(
|
fd.set_parameter(specs.ParameterDefinition(
|
||||||
'__context', yaqltypes.Context(), 0))
|
'__context', yaqltypes.Context(), 0))
|
||||||
|
|
||||||
fd.set_parameter(specs.ParameterDefinition(
|
nullable = murano_method.usage == 'Static'
|
||||||
'__sender', yaqltypes.PythonType(dsl_types.MuranoObject, False), 1))
|
sender_type = yaqltypes.PythonType(dsl_types.MuranoObject, nullable)
|
||||||
|
fd.set_parameter(specs.ParameterDefinition('__sender', sender_type, 1))
|
||||||
|
|
||||||
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
||||||
return fd
|
return fd
|
||||||
|
@ -80,7 +80,9 @@ class TestPackageLoader(package_loader.MuranoPackageLoader):
|
|||||||
def _build_index(self, directory):
|
def _build_index(self, directory):
|
||||||
yamls = [os.path.join(dirpath, f)
|
yamls = [os.path.join(dirpath, f)
|
||||||
for dirpath, _, files in os.walk(directory)
|
for dirpath, _, files in os.walk(directory)
|
||||||
for f in fnmatch.filter(files, '*.yaml')]
|
for f in fnmatch.filter(files, '*.yaml')
|
||||||
|
if f != 'manifest.yaml'
|
||||||
|
]
|
||||||
for class_def_file in yamls:
|
for class_def_file in yamls:
|
||||||
self._load_class(class_def_file)
|
self._load_class(class_def_file)
|
||||||
|
|
||||||
|
192
murano/tests/unit/dsl/meta/TestStatics.yaml
Normal file
192
murano/tests/unit/dsl/meta/TestStatics.yaml
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
Namespaces:
|
||||||
|
ns: test
|
||||||
|
=: test
|
||||||
|
|
||||||
|
Name: TestStatics
|
||||||
|
|
||||||
|
Extends: TestStaticsBase
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
staticProperty:
|
||||||
|
Contract: $.string()
|
||||||
|
Usage: Static
|
||||||
|
Default: xxx
|
||||||
|
|
||||||
|
conflictingStaticProperty:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: 'conflictingStaticProperty-child'
|
||||||
|
Usage: Static
|
||||||
|
|
||||||
|
instanceProperty:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: instanceProperty
|
||||||
|
|
||||||
|
staticProperty2:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: staticProperty
|
||||||
|
Usage: Static
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
testStaticTest:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: $
|
||||||
|
|
||||||
|
testCallStaticMethodOnObject:
|
||||||
|
Body:
|
||||||
|
Return: $.simpleStaticMethod()
|
||||||
|
|
||||||
|
testCallStaticMethodOnClassName:
|
||||||
|
Body:
|
||||||
|
Return: :TestStatics.simpleStaticMethod()
|
||||||
|
|
||||||
|
testCallStaticMethodOnClassNameWithNs:
|
||||||
|
Body:
|
||||||
|
Return: ns:TestStatics.simpleStaticMethod()
|
||||||
|
|
||||||
|
testCallStaticMethodFromAnotherMethod:
|
||||||
|
Body:
|
||||||
|
Return: ns:TestStatics.simpleStaticMethod2()
|
||||||
|
|
||||||
|
testStaticThis:
|
||||||
|
Body:
|
||||||
|
Return: $.returnStaticThis()
|
||||||
|
|
||||||
|
testNoAccessToInstanceProperties:
|
||||||
|
Body:
|
||||||
|
Return: $.accessInstanceProperty()
|
||||||
|
|
||||||
|
testAccessStaticPropertyFromInstanceMethod:
|
||||||
|
Body:
|
||||||
|
Return: $.staticProperty
|
||||||
|
|
||||||
|
testAccessStaticPropertyFromStaticMethod:
|
||||||
|
Body:
|
||||||
|
Return: $.accessStaticProperty()
|
||||||
|
|
||||||
|
simpleStaticMethod:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: 123
|
||||||
|
|
||||||
|
simpleStaticMethod2:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: $.simpleStaticMethod() +
|
||||||
|
$this.simpleStaticMethod() +
|
||||||
|
ns:TestStatics.simpleStaticMethod() +
|
||||||
|
:TestStatics.simpleStaticMethod() +
|
||||||
|
type('test.TestStatics').simpleStaticMethod()
|
||||||
|
|
||||||
|
returnStaticThis:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: $
|
||||||
|
|
||||||
|
accessInstanceProperty:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: $.instanceProperty
|
||||||
|
|
||||||
|
accessStaticProperty:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
Return: $.staticProperty
|
||||||
|
|
||||||
|
testModifyStaticPropertyUsingDollar:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyUsingDollar()
|
||||||
|
|
||||||
|
modifyStaticPropertyUsingDollar:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- $.staticProperty: qq
|
||||||
|
- Return: $.staticProperty
|
||||||
|
|
||||||
|
testModifyStaticPropertyUsingThis:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyUsingThis()
|
||||||
|
|
||||||
|
modifyStaticPropertyUsingThis:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- $this.staticProperty: qq
|
||||||
|
- Return: $this.staticProperty
|
||||||
|
|
||||||
|
testModifyStaticPropertyUsingClassName:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyUsingClassName()
|
||||||
|
|
||||||
|
modifyStaticPropertyUsingClassName:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- :TestStatics.staticProperty: qq
|
||||||
|
- Return: :TestStatics.staticProperty
|
||||||
|
|
||||||
|
testModifyStaticPropertyUsingNsClassName:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyUsingNsClassName()
|
||||||
|
|
||||||
|
modifyStaticPropertyUsingNsClassName:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- ns:TestStatics.staticProperty: qq
|
||||||
|
- Return: ns:TestStatics.staticProperty
|
||||||
|
|
||||||
|
testModifyStaticPropertyUsingTypeFunc:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyUsingTypeFunc()
|
||||||
|
|
||||||
|
modifyStaticPropertyUsingTypeFunc:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- type('test.TestStatics').staticProperty: qq
|
||||||
|
- Return: type('test.TestStatics').staticProperty
|
||||||
|
|
||||||
|
testPropertyIsStatic:
|
||||||
|
Body:
|
||||||
|
Return: $.modifyStaticPropertyOnInstance()
|
||||||
|
|
||||||
|
modifyStaticPropertyOnInstance:
|
||||||
|
Usage: Static
|
||||||
|
Body:
|
||||||
|
- $obj1: new(TestStatics)
|
||||||
|
- $obj2: new(TestStatics)
|
||||||
|
- $obj1.modifyStaticPropertyUsingClassName()
|
||||||
|
- Return: $obj2.staticProperty
|
||||||
|
|
||||||
|
testStaticPropertisNotLoaded:
|
||||||
|
Body:
|
||||||
|
Return: $.staticProperty2
|
||||||
|
|
||||||
|
testTypeIsSingleton:
|
||||||
|
Body:
|
||||||
|
- $t11: :TestStatics
|
||||||
|
- $t12: :TestStatics
|
||||||
|
- $t21: ns:TestStatics
|
||||||
|
- $t22: ns:TestStatics
|
||||||
|
- $t31: type('test.TestStatics')
|
||||||
|
- $t32: type('test.TestStatics')
|
||||||
|
- Return: $t11 = $t12 and $t21 = $t22 and $t31 = $t32
|
||||||
|
|
||||||
|
testStaticPropertyInheritance:
|
||||||
|
Body:
|
||||||
|
Return: $.baseStaticProperty +
|
||||||
|
:TestStaticsBase.baseStaticProperty +
|
||||||
|
:TestStatics.baseStaticProperty
|
||||||
|
|
||||||
|
testStaticPropertyOverride:
|
||||||
|
Body:
|
||||||
|
Return:
|
||||||
|
- $.conflictingStaticProperty
|
||||||
|
- :TestStatics.conflictingStaticProperty
|
||||||
|
- :TestStaticsBase.conflictingStaticProperty
|
||||||
|
- type('test.TestStatics').conflictingStaticProperty
|
||||||
|
- type('test.TestStaticsBase').conflictingStaticProperty
|
||||||
|
|
||||||
|
testTypeinfoOfType:
|
||||||
|
Body:
|
||||||
|
- $typeObj: type('test.TestStatics')
|
||||||
|
- $typeInfoOfType: typeinfo($typeObj)
|
||||||
|
- $obj: new('TestStatics')
|
||||||
|
- Return: typeinfo($obj) = $typeInfoOfType
|
15
murano/tests/unit/dsl/meta/TestStaticsBase.yaml
Normal file
15
murano/tests/unit/dsl/meta/TestStaticsBase.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Namespaces:
|
||||||
|
=: test
|
||||||
|
|
||||||
|
Name: TestStaticsBase
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
baseStaticProperty:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: baseStaticProperty
|
||||||
|
Usage: Static
|
||||||
|
|
||||||
|
conflictingStaticProperty:
|
||||||
|
Contract: $.string()
|
||||||
|
Default: 'conflictingStaticProperty-base'
|
||||||
|
Usage: Static
|
106
murano/tests/unit/dsl/test_statics.py
Normal file
106
murano/tests/unit/dsl/test_statics.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# 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 murano.dsl import dsl_types
|
||||||
|
from murano.dsl import exceptions
|
||||||
|
from murano.tests.unit.dsl.foundation import object_model as om
|
||||||
|
from murano.tests.unit.dsl.foundation import test_case
|
||||||
|
|
||||||
|
|
||||||
|
class TestStatics(test_case.DslTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestStatics, self).setUp()
|
||||||
|
self._runner = self.new_runner(
|
||||||
|
om.Object('test.TestStatics', staticProperty2='INVALID'))
|
||||||
|
|
||||||
|
def test_call_static_method_on_object(self):
|
||||||
|
self.assertEqual(123, self._runner.testCallStaticMethodOnObject())
|
||||||
|
|
||||||
|
def test_call_static_method_on_class_name(self):
|
||||||
|
self.assertEqual(123, self._runner.testCallStaticMethodOnClassName())
|
||||||
|
|
||||||
|
def test_call_static_method_on_class_name_with_ns(self):
|
||||||
|
self.assertEqual(
|
||||||
|
123, self._runner.testCallStaticMethodOnClassNameWithNs())
|
||||||
|
|
||||||
|
def test_call_static_method_from_another_method(self):
|
||||||
|
self.assertEqual(
|
||||||
|
123 * 5, self._runner.testCallStaticMethodFromAnotherMethod())
|
||||||
|
|
||||||
|
def test_static_this(self):
|
||||||
|
self.assertIsInstance(
|
||||||
|
self._runner.testStaticThis(), dsl_types.MuranoTypeReference)
|
||||||
|
|
||||||
|
def test_no_access_to_instance_properties(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.NoPropertyFound,
|
||||||
|
self._runner.testNoAccessToInstanceProperties)
|
||||||
|
|
||||||
|
def test_access_static_property_from_instance_method(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'xxx', self._runner.testAccessStaticPropertyFromInstanceMethod())
|
||||||
|
|
||||||
|
def test_access_static_property_from_static_method(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'xxx', self._runner.testAccessStaticPropertyFromStaticMethod())
|
||||||
|
|
||||||
|
def test_modify_static_property_using_dollar(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'qq', self._runner.testModifyStaticPropertyUsingDollar())
|
||||||
|
|
||||||
|
def test_modify_static_property_using_this(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'qq', self._runner.testModifyStaticPropertyUsingThis())
|
||||||
|
|
||||||
|
def test_modify_static_property_using_class_name(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'qq', self._runner.testModifyStaticPropertyUsingClassName())
|
||||||
|
|
||||||
|
def test_modify_static_property_using_ns_class_name(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'qq', self._runner.testModifyStaticPropertyUsingNsClassName())
|
||||||
|
|
||||||
|
def test_modify_static_property_using_type_func(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'qq', self._runner.testModifyStaticPropertyUsingTypeFunc())
|
||||||
|
|
||||||
|
def test_property_is_static(self):
|
||||||
|
self.assertEqual('qq', self._runner.testPropertyIsStatic())
|
||||||
|
|
||||||
|
def test_static_properties_excluded_from_object_model(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'staticProperty',
|
||||||
|
self._runner.testStaticPropertisNotLoaded())
|
||||||
|
|
||||||
|
def test_type_is_singleton(self):
|
||||||
|
self.assertTrue(self._runner.testTypeIsSingleton())
|
||||||
|
|
||||||
|
def test_static_property_inheritance(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'baseStaticProperty' * 3,
|
||||||
|
self._runner.testStaticPropertyInheritance())
|
||||||
|
|
||||||
|
def test_static_property_override(self):
|
||||||
|
self.assertEqual(
|
||||||
|
[
|
||||||
|
'conflictingStaticProperty-child',
|
||||||
|
'conflictingStaticProperty-child',
|
||||||
|
'conflictingStaticProperty-base',
|
||||||
|
'conflictingStaticProperty-child',
|
||||||
|
'conflictingStaticProperty-base'
|
||||||
|
], self._runner.testStaticPropertyOverride())
|
||||||
|
|
||||||
|
def test_type_info_of_type(self):
|
||||||
|
self.assertTrue(self._runner.testTypeinfoOfType())
|
@ -50,23 +50,24 @@ class TestNamespaceResolving(base.MuranoTestCase):
|
|||||||
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
|
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
|
||||||
name = 'sys:'
|
name = 'sys:'
|
||||||
|
|
||||||
self.assertRaises(NameError, resolver.resolve_name, name)
|
self.assertRaises(ValueError, resolver.resolve_name, name)
|
||||||
|
|
||||||
def test_fails_w_excessive_prefix(self):
|
def test_fails_w_excessive_prefix(self):
|
||||||
ns = {'sys': 'com.example.murano.system'}
|
ns = {'sys': 'com.example.murano.system'}
|
||||||
resolver = ns_resolver.NamespaceResolver(ns)
|
resolver = ns_resolver.NamespaceResolver(ns)
|
||||||
invalid_name = 'sys:excessive_ns:muranoResource'
|
invalid_name = 'sys:excessive_ns:muranoResource'
|
||||||
|
|
||||||
self.assertRaises(NameError, resolver.resolve_name, invalid_name)
|
self.assertRaises(ValueError, resolver.resolve_name, invalid_name)
|
||||||
|
|
||||||
def test_cuts_empty_prefix(self):
|
def test_empty_prefix_is_default(self):
|
||||||
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
|
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
|
||||||
# name without prefix delimiter
|
# name without prefix delimiter
|
||||||
name = 'some.arbitrary.name'
|
name = 'some.arbitrary.name'
|
||||||
|
|
||||||
resolved_name = resolver.resolve_name(':' + name)
|
resolved_name = resolver.resolve_name(':' + name)
|
||||||
|
|
||||||
self.assertEqual(name, resolved_name)
|
self.assertEqual(
|
||||||
|
'com.example.murano.some.arbitrary.name', resolved_name)
|
||||||
|
|
||||||
def test_resolves_specified_ns_prefix(self):
|
def test_resolves_specified_ns_prefix(self):
|
||||||
ns = {'sys': 'com.example.murano.system'}
|
ns = {'sys': 'com.example.murano.system'}
|
||||||
@ -85,20 +86,6 @@ class TestNamespaceResolving(base.MuranoTestCase):
|
|||||||
|
|
||||||
self.assertEqual(full_name, resolved_name)
|
self.assertEqual(full_name, resolved_name)
|
||||||
|
|
||||||
def test_resolves_explicit_base(self):
|
|
||||||
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
|
|
||||||
|
|
||||||
resolved_name = resolver.resolve_name('Resource', relative='com.base')
|
|
||||||
|
|
||||||
self.assertEqual('com.base.Resource', resolved_name)
|
|
||||||
|
|
||||||
def test_resolves_explicit_base_w_empty_namespaces(self):
|
|
||||||
resolver = ns_resolver.NamespaceResolver({})
|
|
||||||
|
|
||||||
resolved_name = resolver.resolve_name('File', 'com.base')
|
|
||||||
|
|
||||||
self.assertEqual('com.base.File', resolved_name)
|
|
||||||
|
|
||||||
def test_resolves_w_empty_namespaces(self):
|
def test_resolves_w_empty_namespaces(self):
|
||||||
resolver = ns_resolver.NamespaceResolver({})
|
resolver = ns_resolver.NamespaceResolver({})
|
||||||
|
|
||||||
|
9
releasenotes/notes/statics-9943fe9873138dac.yaml
Normal file
9
releasenotes/notes/statics-9943fe9873138dac.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- "Static methods and properties were introduced.
|
||||||
|
Both properties and methods can be marked as Usage: Static
|
||||||
|
Statics can be accessed using ns:Class.property / ns:Class.method(),
|
||||||
|
:Class.property / :Class.method() to access class from current namespace
|
||||||
|
or type('full.name').property / type('full.name').method() to use full
|
||||||
|
type name."
|
||||||
|
- io.murano.configuration.Linux methods are now static
|
Loading…
Reference in New Issue
Block a user