Merge "Support for static methods/properties"
This commit is contained in:
commit
12a8b87302
|
@ -19,6 +19,7 @@ Name: Linux
|
|||
|
||||
Methods:
|
||||
runCommand:
|
||||
Usage: Static
|
||||
Arguments:
|
||||
- agent:
|
||||
Contract: $.class(sys:Agent)
|
||||
|
@ -54,6 +55,7 @@ Methods:
|
|||
- Return: $agent.call($template, $resources)
|
||||
|
||||
putFile:
|
||||
Usage: Static
|
||||
Arguments:
|
||||
- agent:
|
||||
Contract: $.class(sys:Agent)
|
||||
|
|
|
@ -233,21 +233,22 @@ class MuranoTestRunner(object):
|
|||
for m in test_cases:
|
||||
# Create new executor for each test case to provide
|
||||
# pure test environment
|
||||
executer = executor.MuranoDslExecutor(
|
||||
dsl_executor = executor.MuranoDslExecutor(
|
||||
pkg_loader,
|
||||
mock_context_manager.MockContextManager(),
|
||||
test_env)
|
||||
obj = package.find_class(pkg_class, False).new(
|
||||
None, executer.object_store)(None)
|
||||
self._call_service_method('setUp', executer, obj)
|
||||
None, dsl_executor.object_store, dsl_executor)(None)
|
||||
self._call_service_method('setUp', dsl_executor, obj)
|
||||
obj.type.methods[m].usage = 'Action'
|
||||
|
||||
test_env.start()
|
||||
try:
|
||||
obj.type.invoke(m, executer, obj, (), {})
|
||||
obj.type.invoke(m, dsl_executor, obj, (), {})
|
||||
LOG.debug('\n.....{0}.{1}.....OK'.format(obj.type.name,
|
||||
m))
|
||||
self._call_service_method('tearDown', executer, obj)
|
||||
self._call_service_method(
|
||||
'tearDown', dsl_executor, obj)
|
||||
except Exception:
|
||||
LOG.exception('\n.....{0}.{1}.....FAILURE\n'
|
||||
''.format(obj.type.name, m))
|
||||
|
|
|
@ -109,9 +109,9 @@ class MuranoTypeName(yaqltypes.PythonType):
|
|||
if function_spec.meta.get(constants.META_MURANO_METHOD):
|
||||
context = helpers.get_caller_context(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),
|
||||
context))
|
||||
context).get_reference()
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
@ -45,8 +45,16 @@ class MuranoTypeReference(object):
|
|||
def murano_class(self):
|
||||
return self.__murano_class
|
||||
|
||||
def __str__(self):
|
||||
return self.__murano_class.name
|
||||
def __repr__(self):
|
||||
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):
|
||||
|
|
|
@ -160,3 +160,9 @@ class UninitializedPropertyAccessError(PropertyAccessError):
|
|||
|
||||
class CircularExpressionDependenciesError(Exception):
|
||||
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 constants
|
||||
from murano.dsl import dsl
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import helpers
|
||||
from murano.dsl import murano_method
|
||||
from murano.dsl import object_store
|
||||
|
@ -85,7 +86,9 @@ class MuranoDslExecutor(object):
|
|||
|
||||
context = self.create_method_context(
|
||||
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:
|
||||
args, kwargs = self._canonize_parameters(
|
||||
|
@ -119,7 +122,10 @@ class MuranoDslExecutor(object):
|
|||
@contextlib.contextmanager
|
||||
def _acquire_method_lock(self, func, this):
|
||||
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()
|
||||
while True:
|
||||
event, event_owner = self._locks.get(
|
||||
|
@ -262,13 +268,24 @@ class MuranoDslExecutor(object):
|
|||
return context
|
||||
|
||||
def create_object_context(self, obj, caller_context=None):
|
||||
class_context = self.create_class_context(obj.type)
|
||||
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
|
||||
if isinstance(obj, dsl_types.MuranoClass):
|
||||
obj_type = obj
|
||||
obj = None
|
||||
else:
|
||||
obj_type = obj.type
|
||||
class_context = self.create_class_context(obj_type)
|
||||
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:
|
||||
caller = caller_context
|
||||
|
|
|
@ -153,7 +153,9 @@ def get_environment(context=None):
|
|||
|
||||
def get_object_store(context=None):
|
||||
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):
|
||||
|
|
|
@ -20,8 +20,10 @@ from yaql.language import utils
|
|||
from yaql.language import yaqltypes
|
||||
|
||||
from murano.dsl import constants
|
||||
from murano.dsl import dsl
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import exceptions
|
||||
from murano.dsl import yaql_functions
|
||||
from murano.dsl import yaql_integration
|
||||
|
||||
|
||||
|
@ -68,6 +70,14 @@ class LhsExpression(object):
|
|||
((key, value),))))
|
||||
elif isinstance(src, dsl_types.MuranoObject):
|
||||
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:
|
||||
raise ValueError(
|
||||
'attribution may only be applied to '
|
||||
|
@ -118,16 +128,51 @@ class LhsExpression(object):
|
|||
else:
|
||||
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.register_function(get_context_data, '#get_context_data')
|
||||
context.register_function(attribution, '#operator_.')
|
||||
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
|
||||
|
||||
def _invalid_target(self, *args, **kwargs):
|
||||
raise exceptions.InvalidLhsTargetError(self._expression)
|
||||
|
||||
def __call__(self, value, context):
|
||||
new_context = self._create_context(context)
|
||||
new_context[''] = context['$']
|
||||
new_context[constants.CTX_TYPE] = context[constants.CTX_TYPE]
|
||||
self._current_obj = None
|
||||
self._current_obj_name = None
|
||||
property = self._expression(context=new_context)
|
||||
if not isinstance(property, LhsExpression.Property):
|
||||
self._invalid_target()
|
||||
property.set(value)
|
||||
|
|
|
@ -46,6 +46,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
package.find_class(constants.CORE_LIBRARY_OBJECT)]
|
||||
self._context = None
|
||||
self._parent_mappings = self._build_parent_remappings()
|
||||
self._property_values = {}
|
||||
|
||||
@classmethod
|
||||
def create(cls, data, package, name=None):
|
||||
|
@ -53,7 +54,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
|
||||
|
||||
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_classes = []
|
||||
|
@ -61,7 +62,7 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
if not utils.is_sequence(parent_class_names):
|
||||
parent_class_names = [parent_class_names]
|
||||
for parent_name in parent_class_names:
|
||||
full_name = ns_resolver.resolve_name(parent_name)
|
||||
full_name = ns_resolver.resolve_name(str(parent_name))
|
||||
parent_classes.append(package.find_class(full_name))
|
||||
|
||||
type_obj = cls(ns_resolver, name, package, parent_classes)
|
||||
|
@ -189,6 +190,19 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
return self._choose_symbol(
|
||||
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):
|
||||
result = self.find_method(name)
|
||||
if len(result) < 1:
|
||||
|
@ -242,12 +256,13 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
return True
|
||||
return any(cls is self for cls in obj.ancestors())
|
||||
|
||||
def new(self, owner, object_store, **kwargs):
|
||||
obj = murano_object.MuranoObject(self, owner, object_store, **kwargs)
|
||||
def new(self, owner, object_store, executor, **kwargs):
|
||||
obj = murano_object.MuranoObject(
|
||||
self, owner, object_store, executor, **kwargs)
|
||||
|
||||
def initializer(__context, **params):
|
||||
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[constants.CTX_ALLOW_PROPERTY_WRITES] = True
|
||||
obj.initialize(init_context, object_store, params)
|
||||
|
@ -359,3 +374,17 @@ class MuranoClass(dsl_types.MuranoClass):
|
|||
m.yaql_function_definition,
|
||||
name=m.yaql_function_definition.name)
|
||||
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):
|
||||
Action = 'Action'
|
||||
Runtime = 'Runtime'
|
||||
All = set([Action, Runtime])
|
||||
Static = 'Static'
|
||||
All = set([Action, Runtime, Static])
|
||||
|
||||
|
||||
class MuranoMethod(dsl_types.MuranoMethod):
|
||||
|
@ -111,13 +112,18 @@ class MuranoMethod(dsl_types.MuranoMethod):
|
|||
|
||||
def invoke(self, executor, this, args, kwargs, context=None,
|
||||
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")
|
||||
if isinstance(this, dsl.MuranoObjectInterface):
|
||||
this = this.object
|
||||
if this is not None:
|
||||
this = this.cast(self.murano_class)
|
||||
else:
|
||||
this = self.murano_class
|
||||
return executor.invoke_method(
|
||||
self, this.cast(self.murano_class),
|
||||
context, args, kwargs, skip_stub)
|
||||
self, this, context, args, kwargs, skip_stub)
|
||||
|
||||
|
||||
class MuranoMethodArgument(dsl_types.MuranoMethodArgument, typespec.Spec):
|
||||
|
|
|
@ -26,8 +26,9 @@ from murano.dsl import yaql_integration
|
|||
|
||||
|
||||
class MuranoObject(dsl_types.MuranoObject):
|
||||
def __init__(self, murano_class, owner, object_store, object_id=None,
|
||||
name=None, known_classes=None, defaults=None, this=None):
|
||||
def __init__(self, murano_class, owner, object_store, executor,
|
||||
object_id=None, name=None, known_classes=None,
|
||||
defaults=None, this=None):
|
||||
if known_classes is None:
|
||||
known_classes = {}
|
||||
self.__owner = owner.real_this if owner else None
|
||||
|
@ -39,7 +40,9 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
self.__this = this
|
||||
self.__name = name
|
||||
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(
|
||||
murano_class.name)
|
||||
if not isinstance(self.__config, dict):
|
||||
|
@ -49,7 +52,7 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
name = parent_class.name
|
||||
if name not in known_classes:
|
||||
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,
|
||||
this=self.real_this).object
|
||||
|
||||
|
@ -72,7 +75,11 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
|
||||
@property
|
||||
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):
|
||||
if self.__initialized:
|
||||
|
@ -105,7 +112,8 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
|
||||
if property_name in used_names:
|
||||
continue
|
||||
if spec.usage == typespec.PropertyUsages.Config:
|
||||
if spec.usage in (typespec.PropertyUsages.Config,
|
||||
typespec.PropertyUsages.Static):
|
||||
used_names.add(property_name)
|
||||
continue
|
||||
if spec.usage == typespec.PropertyUsages.Runtime:
|
||||
|
@ -133,7 +141,8 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
last_errors = errors
|
||||
|
||||
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__')
|
||||
if method:
|
||||
filtered_params = yaql_integration.filter_parameters(
|
||||
|
@ -146,7 +155,7 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
for parent in self.__parents.values():
|
||||
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
|
||||
init.invoke(executor, self.real_this, (), init_args, context)
|
||||
self.__initialized = True
|
||||
|
@ -173,11 +182,18 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
if caller_class is not None and caller_class.is_compatible(self):
|
||||
start_type, derived = caller_class, True
|
||||
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:
|
||||
try:
|
||||
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:
|
||||
if derived:
|
||||
return self.cast(caller_class)._get_property_value(name)
|
||||
|
@ -199,11 +215,12 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
declared_properties = start_type.find_properties(
|
||||
lambda p: p.name == name)
|
||||
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:
|
||||
declared_properties = self.type.find_properties(
|
||||
lambda p: p.name == name)
|
||||
values_to_assign = []
|
||||
classes_for_static_properties = []
|
||||
for spec in declared_properties:
|
||||
if (caller_class is not None and not
|
||||
helpers.are_property_modifications_allowed(context) and
|
||||
|
@ -211,16 +228,21 @@ class MuranoObject(dsl_types.MuranoObject):
|
|||
not derived)):
|
||||
raise exceptions.NoWriteAccessError(name)
|
||||
|
||||
default = self.__config.get(name, spec.default)
|
||||
default = self.__defaults.get(name, default)
|
||||
default = helpers.evaluate(default, context)
|
||||
if spec.usage == typespec.PropertyUsages.Static:
|
||||
classes_for_static_properties.append(spec.murano_class)
|
||||
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)
|
||||
values_to_assign.append((obj, spec.validate(
|
||||
value, self.real_this,
|
||||
self.real_this, default=default)))
|
||||
obj = self.cast(spec.murano_class)
|
||||
values_to_assign.append((obj, spec.validate(
|
||||
value, self.real_this,
|
||||
self.real_this, context, default=default)))
|
||||
for obj, value in values_to_assign:
|
||||
obj.__properties[name] = value
|
||||
for cls in classes_for_static_properties:
|
||||
cls.set_property(name, value, context)
|
||||
elif derived:
|
||||
obj = self.cast(caller_class)
|
||||
obj.__properties[name] = value
|
||||
|
|
|
@ -12,26 +12,42 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# 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):
|
||||
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[''] = ''
|
||||
|
||||
def resolve_name(self, name, relative=None):
|
||||
if name is None:
|
||||
raise ValueError()
|
||||
if name and name.startswith(':'):
|
||||
return name[1:]
|
||||
if ':' in name:
|
||||
def resolve_name(self, name):
|
||||
if name is None or TYPE_NAME_RE.match(name) is None:
|
||||
raise ValueError('Invalid type name "{0}"'.format(name))
|
||||
if ':' not in name:
|
||||
if '.' in name:
|
||||
parts = ['', name]
|
||||
else:
|
||||
parts = ['=', name]
|
||||
else:
|
||||
parts = name.split(':')
|
||||
if len(parts) != 2 or not parts[1]:
|
||||
raise NameError('Incorrectly formatted name ' + name)
|
||||
if parts[0] not in self._namespaces:
|
||||
raise KeyError('Unknown namespace prefix ' + parts[0])
|
||||
return '.'.join((self._namespaces[parts[0]], parts[1]))
|
||||
if not relative and '=' in self._namespaces and '.' not in name:
|
||||
return '.'.join((self._namespaces['='], name))
|
||||
if relative and '.' not in name:
|
||||
return '.'.join((relative, name))
|
||||
return name
|
||||
if not parts[0]:
|
||||
parts[0] = '='
|
||||
|
||||
if parts[0] not in self._namespaces:
|
||||
raise KeyError('Unknown namespace prefix ' + parts[0])
|
||||
|
||||
ns = self._namespaces[parts[0]]
|
||||
if not ns:
|
||||
return name
|
||||
return '.'.join((ns, parts[1]))
|
||||
|
|
|
@ -81,7 +81,7 @@ class ObjectStore(object):
|
|||
return factory
|
||||
else:
|
||||
factory = class_obj.new(
|
||||
owner, self,
|
||||
owner, self, self.executor,
|
||||
name=system_key.get('name'),
|
||||
object_id=object_id, defaults=defaults)
|
||||
self._store[object_id] = factory
|
||||
|
|
|
@ -157,6 +157,12 @@ def argument_owner(method_argument):
|
|||
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):
|
||||
funcs = (
|
||||
class_name, methods, properties, ancestors, package, class_version,
|
||||
|
@ -164,7 +170,8 @@ def register(context):
|
|||
property_usage,
|
||||
method_name, arguments, method_owner,
|
||||
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:
|
||||
context.register_function(f)
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
import weakref
|
||||
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import exceptions
|
||||
from murano.dsl import helpers
|
||||
from murano.dsl import type_scheme
|
||||
|
||||
|
||||
|
@ -25,8 +27,9 @@ class PropertyUsages(object):
|
|||
Runtime = 'Runtime'
|
||||
Const = 'Const'
|
||||
Config = 'Config'
|
||||
All = set([In, Out, InOut, Runtime, Const, Config])
|
||||
Writable = set([Out, InOut, Runtime])
|
||||
Static = 'Static'
|
||||
All = set([In, Out, InOut, Runtime, Const, Config, Static])
|
||||
Writable = set([Out, InOut, Runtime, Static])
|
||||
|
||||
|
||||
class Spec(object):
|
||||
|
@ -41,13 +44,19 @@ class Spec(object):
|
|||
'Unknown type {0}. Must be one of ({1})'.format(
|
||||
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:
|
||||
default = self.default
|
||||
return self._contract(
|
||||
value, this.object_store.executor.create_object_context(
|
||||
this.cast(self._container_class())),
|
||||
this, owner, default)
|
||||
executor = helpers.get_executor(context)
|
||||
if isinstance(this, dsl_types.MuranoClass):
|
||||
return self._contract(
|
||||
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
|
||||
def default(self):
|
||||
|
|
|
@ -68,7 +68,7 @@ class YaqlExpression(dsl_types.YaqlExpression):
|
|||
def is_expression(expression, version):
|
||||
if not isinstance(expression, six.string_types):
|
||||
return False
|
||||
if re.match('^[\s\w\d.:]*$', expression):
|
||||
if re.match('^[\s\w\d.]*$', expression):
|
||||
return False
|
||||
try:
|
||||
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,
|
||||
**parameters):
|
||||
object_store = helpers.get_object_store(__context)
|
||||
executor = helpers.get_executor(__context)
|
||||
new_context = __context.create_child_context()
|
||||
for key, value in six.iteritems(parameters):
|
||||
if utils.is_keyword(key):
|
||||
new_context[key] = value
|
||||
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())
|
||||
|
@ -110,14 +112,32 @@ def sleep_(seconds):
|
|||
|
||||
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||
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
|
||||
|
||||
|
||||
@specs.name('type')
|
||||
@specs.parameter('cls', dsl.MuranoTypeName())
|
||||
def type_from_name(cls):
|
||||
return cls
|
||||
|
||||
|
||||
@specs.parameter('object_', dsl.MuranoObjectParameterType(nullable=True))
|
||||
def typeinfo(object_):
|
||||
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))
|
||||
def name(object_):
|
||||
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)
|
||||
|
||||
|
||||
@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('expr', yaqltypes.Lambda(method=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)
|
||||
|
||||
|
||||
@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('name', yaqltypes.Keyword())
|
||||
@specs.name('#operator_:')
|
||||
def ns_resolve(context, prefix, name):
|
||||
murano_type = helpers.get_type(context)
|
||||
return dsl_types.MuranoTypeReference(helpers.get_class(
|
||||
return helpers.get_class(
|
||||
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))
|
||||
|
@ -173,20 +218,28 @@ def register(context, runtime_version):
|
|||
context.register_function(require)
|
||||
context.register_function(find)
|
||||
context.register_function(sleep_)
|
||||
context.register_function(type_)
|
||||
context.register_function(typeinfo)
|
||||
context.register_function(typeinfo_for_class)
|
||||
context.register_function(name)
|
||||
context.register_function(obj_attribution)
|
||||
context.register_function(obj_attribution_static)
|
||||
context.register_function(op_dot)
|
||||
context.register_function(op_dot_static)
|
||||
context.register_function(ns_resolve)
|
||||
context.register_function(ns_resolve_unary)
|
||||
reflection.register(context)
|
||||
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:
|
||||
context2 = context.create_child_context()
|
||||
context = context.create_child_context()
|
||||
for t in ('id', 'cast', 'super', 'psuper', 'type'):
|
||||
for spec in utils.to_extension_method(t, context):
|
||||
context2.register_function(spec)
|
||||
return context2
|
||||
context.register_function(spec)
|
||||
|
||||
context.register_function(type_from_name)
|
||||
|
||||
return context
|
||||
|
|
|
@ -51,7 +51,10 @@ def _add_operators(engine_factory):
|
|||
engine_factory.insert_operator(
|
||||
'>', True, 'is', factory.OperatorType.BINARY_LEFT_ASSOCIATIVE, False)
|
||||
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):
|
||||
|
@ -86,7 +89,7 @@ class ContractedValue(yaqltypes.GenericType):
|
|||
lambda value, sender, context, *args, **kwargs:
|
||||
self._value_spec.validate(
|
||||
value, sender.real_this,
|
||||
context[constants.CTX_ARGUMENT_OWNER]))
|
||||
context[constants.CTX_ARGUMENT_OWNER], context))
|
||||
|
||||
def convert(self, value, *args, **kwargs):
|
||||
if value is None:
|
||||
|
@ -220,8 +223,9 @@ def _build_mpl_wrapper_function_definition(murano_method):
|
|||
fd.set_parameter(specs.ParameterDefinition(
|
||||
'__context', yaqltypes.Context(), 0))
|
||||
|
||||
fd.set_parameter(specs.ParameterDefinition(
|
||||
'__sender', yaqltypes.PythonType(dsl_types.MuranoObject, False), 1))
|
||||
nullable = murano_method.usage == 'Static'
|
||||
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
|
||||
return fd
|
||||
|
|
|
@ -80,7 +80,9 @@ class TestPackageLoader(package_loader.MuranoPackageLoader):
|
|||
def _build_index(self, directory):
|
||||
yamls = [os.path.join(dirpath, f)
|
||||
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:
|
||||
self._load_class(class_def_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
|
|
@ -0,0 +1,15 @@
|
|||
Namespaces:
|
||||
=: test
|
||||
|
||||
Name: TestStaticsBase
|
||||
|
||||
Properties:
|
||||
baseStaticProperty:
|
||||
Contract: $.string()
|
||||
Default: baseStaticProperty
|
||||
Usage: Static
|
||||
|
||||
conflictingStaticProperty:
|
||||
Contract: $.string()
|
||||
Default: 'conflictingStaticProperty-base'
|
||||
Usage: Static
|
|
@ -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'})
|
||||
name = 'sys:'
|
||||
|
||||
self.assertRaises(NameError, resolver.resolve_name, name)
|
||||
self.assertRaises(ValueError, resolver.resolve_name, name)
|
||||
|
||||
def test_fails_w_excessive_prefix(self):
|
||||
ns = {'sys': 'com.example.murano.system'}
|
||||
resolver = ns_resolver.NamespaceResolver(ns)
|
||||
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'})
|
||||
# name without prefix delimiter
|
||||
name = 'some.arbitrary.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):
|
||||
ns = {'sys': 'com.example.murano.system'}
|
||||
|
@ -85,20 +86,6 @@ class TestNamespaceResolving(base.MuranoTestCase):
|
|||
|
||||
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):
|
||||
resolver = ns_resolver.NamespaceResolver({})
|
||||
|
||||
|
|
|
@ -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