Allow static methods to detect calls on object
Static methods can be called both on on class instance and on the type object. With this refactoring it is now possible in Python static/class methods to distinguish which way it was called and in case of instance call get the instance. This commit also reworks ResourceManager to use new functionality. Now all ResourceManager methods are static so no class instance is necessary. If resources belonging to some other type are required it is possible to provide the type object explicitly to each method. However it is still possible to create ResourceManager instance and call statics as a normal methods. In this case they will recognize it and will operate that were captured at class construction. Thus it is still possible to create ResourceManager at one place and pass it to another class in another package so that it will access resources of the package where the instance was created rather than that where it used. Change-Id: Ib47be86a99eb7903f7d3f7e1c5f2570df819c2d8
This commit is contained in:
parent
c8bd742478
commit
8fb4eb7ac2
|
@ -76,8 +76,10 @@ class ThisParameterType(yaqltypes.HiddenParameterType, yaqltypes.SmartType):
|
|||
def convert(self, value, sender, context, function_spec, engine,
|
||||
*args, **kwargs):
|
||||
this = helpers.get_this(context)
|
||||
executor = helpers.get_executor(context)
|
||||
return MuranoObjectInterface(this, executor)
|
||||
if isinstance(this, dsl_types.MuranoObject):
|
||||
executor = helpers.get_executor(context)
|
||||
return MuranoObjectInterface(this, executor)
|
||||
return this
|
||||
|
||||
|
||||
class InterfacesParameterType(yaqltypes.HiddenParameterType,
|
||||
|
|
|
@ -90,8 +90,12 @@ class MuranoDslExecutor(object):
|
|||
murano_method.MethodUsages.Action):
|
||||
raise Exception('{0} is not an action'.format(method.name))
|
||||
|
||||
context = self.create_method_context(
|
||||
self.create_object_context(this, context), method)
|
||||
if method.is_static:
|
||||
obj_context = self.create_object_context(
|
||||
method.murano_class, context)
|
||||
else:
|
||||
obj_context = self.create_object_context(this, context)
|
||||
context = self.create_method_context(obj_context, method)
|
||||
|
||||
if isinstance(this, dsl_types.MuranoObject):
|
||||
this = this.real_this
|
||||
|
@ -109,10 +113,10 @@ class MuranoDslExecutor(object):
|
|||
def call():
|
||||
if isinstance(method.body, specs.FunctionDefinition):
|
||||
if isinstance(this, dsl_types.MuranoClass):
|
||||
native_this = utils.NO_VALUE
|
||||
native_this = this.get_reference()
|
||||
else:
|
||||
native_this = this.cast(
|
||||
method.murano_class).extension
|
||||
native_this = dsl.MuranoObjectInterface(this.cast(
|
||||
method.murano_class), self)
|
||||
return method.body(
|
||||
yaql_engine, context, native_this)(*args, **kwargs)
|
||||
else:
|
||||
|
@ -301,6 +305,7 @@ class MuranoDslExecutor(object):
|
|||
else:
|
||||
context = class_context.create_child_context()
|
||||
type_ref = obj_type.get_reference()
|
||||
context[constants.CTX_THIS] = type_ref
|
||||
context['this'] = type_ref
|
||||
context[''] = type_ref
|
||||
|
||||
|
|
|
@ -125,12 +125,13 @@ class MuranoMethod(dsl_types.MuranoMethod):
|
|||
|
||||
def invoke(self, executor, this, args, kwargs, context=None,
|
||||
skip_stub=False):
|
||||
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 and not self.murano_class.is_compatible(this):
|
||||
raise Exception("'this' must be of compatible type")
|
||||
if not this and not self.is_static:
|
||||
raise Exception("A class instance is required")
|
||||
|
||||
if this is not None:
|
||||
this = this.cast(self.murano_class)
|
||||
else:
|
||||
|
|
|
@ -159,7 +159,8 @@ def get_function_definition(func, murano_method, original_name):
|
|||
fd.is_method = True
|
||||
fd.is_function = False
|
||||
if helpers.inspect_is_method(cls, original_name):
|
||||
fd.set_parameter(0, yaqltypes.PythonType(cls), overwrite=True)
|
||||
fd.set_parameter(
|
||||
0, dsl.MuranoType(murano_method.murano_class), overwrite=True)
|
||||
if helpers.inspect_is_classmethod(cls, original_name):
|
||||
_remove_first_parameter(fd)
|
||||
body = func
|
||||
|
@ -168,12 +169,24 @@ def get_function_definition(func, murano_method, original_name):
|
|||
fd.name = name
|
||||
fd.insert_parameter(specs.ParameterDefinition(
|
||||
'?1', yaqltypes.Context(), 0))
|
||||
is_static = (helpers.inspect_is_static(cls, original_name) or
|
||||
helpers.inspect_is_classmethod(cls, original_name))
|
||||
if is_static:
|
||||
fd.insert_parameter(specs.ParameterDefinition(
|
||||
'?2', yaqltypes.PythonType(object), 1))
|
||||
|
||||
def payload(__context, *args, **kwargs):
|
||||
def payload(__context, __self, *args, **kwargs):
|
||||
with helpers.contextual(__context):
|
||||
return body(__self.extension, *args, **kwargs)
|
||||
|
||||
def static_payload(__context, __receiver, *args, **kwargs):
|
||||
with helpers.contextual(__context):
|
||||
return body(*args, **kwargs)
|
||||
|
||||
fd.payload = payload
|
||||
if is_static:
|
||||
fd.payload = static_payload
|
||||
else:
|
||||
fd.payload = payload
|
||||
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
||||
return fd
|
||||
|
||||
|
@ -252,7 +265,7 @@ def get_class_factory_definition(cls, murano_class):
|
|||
engine = choose_yaql_engine(runtime_version)
|
||||
|
||||
def payload(__context, __receiver, *args, **kwargs):
|
||||
assert __receiver is None
|
||||
# assert __receiver is None
|
||||
args = tuple(dsl.to_mutable(arg, engine) for arg in args)
|
||||
kwargs = dsl.to_mutable(kwargs, engine)
|
||||
with helpers.contextual(__context):
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
import json as jsonlib
|
||||
|
||||
import yaml as yamllib
|
||||
from yaql.language import specs
|
||||
from yaql.language import yaqltypes
|
||||
|
||||
from murano.dsl import dsl
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import helpers
|
||||
|
||||
if hasattr(yamllib, 'CSafeLoader'):
|
||||
|
@ -46,13 +49,33 @@ class ResourceManager(object):
|
|||
murano_class = helpers.get_type(helpers.get_caller_context(context))
|
||||
self._package = murano_class.package
|
||||
|
||||
def string(self, name):
|
||||
path = self._package.get_resource(name)
|
||||
@staticmethod
|
||||
@specs.parameter('owner', dsl.MuranoTypeName(nullable=True))
|
||||
@specs.inject('receiver', yaqltypes.Receiver())
|
||||
def string(receiver, name, owner=None):
|
||||
path = ResourceManager._get_package(owner, receiver).get_resource(name)
|
||||
with open(path) as file:
|
||||
return file.read()
|
||||
|
||||
def json(self, name):
|
||||
return jsonlib.loads(self.string(name))
|
||||
@classmethod
|
||||
@specs.parameter('owner', dsl.MuranoTypeName(nullable=True))
|
||||
@specs.inject('receiver', yaqltypes.Receiver())
|
||||
def json(cls, receiver, name, owner=None):
|
||||
return jsonlib.loads(cls.string(receiver, name, owner))
|
||||
|
||||
def yaml(self, name):
|
||||
return yamllib.load(self.string(name), Loader=yaml_loader)
|
||||
@classmethod
|
||||
@specs.parameter('owner', dsl.MuranoTypeName(nullable=True))
|
||||
@specs.inject('receiver', yaqltypes.Receiver())
|
||||
def yaml(cls, receiver, name, owner=None):
|
||||
return yamllib.load(
|
||||
cls.string(receiver, name, owner), Loader=yaml_loader)
|
||||
|
||||
@staticmethod
|
||||
def _get_package(owner, receiver):
|
||||
if owner is None:
|
||||
if isinstance(receiver, dsl_types.MuranoObjectInterface):
|
||||
return receiver.extension._package
|
||||
murano_class = helpers.get_type(helpers.get_caller_context())
|
||||
else:
|
||||
murano_class = owner.murano_class
|
||||
return murano_class.package
|
||||
|
|
|
@ -29,17 +29,24 @@ class TestStatics(test_case.DslTestCase):
|
|||
class PythonClass(object):
|
||||
@staticmethod
|
||||
@specs.parameter('arg', yaqltypes.Integer())
|
||||
def static_python_method(arg):
|
||||
@specs.inject('receiver', yaqltypes.Receiver())
|
||||
def static_python_method(arg, receiver):
|
||||
if isinstance(receiver, dsl_types.MuranoObjectInterface):
|
||||
return 3 * arg
|
||||
return 7 * arg
|
||||
|
||||
@classmethod
|
||||
def classmethod_python_method(cls, arg):
|
||||
@specs.inject('receiver', yaqltypes.Receiver())
|
||||
def classmethod_python_method(cls, arg, receiver):
|
||||
if isinstance(receiver, dsl_types.MuranoObjectInterface):
|
||||
return cls.__name__.upper() + str(arg)
|
||||
return cls.__name__ + str(arg)
|
||||
|
||||
super(TestStatics, self).setUp()
|
||||
self.package_loader.load_class_package(
|
||||
'test.TestStatics', None).register_class(PythonClass)
|
||||
self._runner = self.new_runner(
|
||||
om.Object('test.TestStatics', staticProperty2='INVALID'))
|
||||
self._runner.root.type.package.register_class(PythonClass)
|
||||
|
||||
def test_call_static_method_on_object(self):
|
||||
self.assertEqual(123, self._runner.testCallStaticMethodOnObject())
|
||||
|
@ -122,9 +129,11 @@ class TestStatics(test_case.DslTestCase):
|
|||
self.assertTrue(self._runner.testTypeinfoOfType())
|
||||
|
||||
def test_call_python_static_method(self):
|
||||
self.assertEqual([777] * 4, self._runner.testCallPythonStaticMethod())
|
||||
self.assertEqual(
|
||||
[333] + [777] * 3,
|
||||
self._runner.testCallPythonStaticMethod())
|
||||
|
||||
def test_call_python_classmethod(self):
|
||||
self.assertEqual(
|
||||
['PythonClass!'] * 4,
|
||||
['PYTHONCLASS!'] + ['PythonClass!'] * 3,
|
||||
self._runner.testCallPythonClassMethod())
|
||||
|
|
Loading…
Reference in New Issue