Merge "Strengthen validation of receiver type for methods"
This commit is contained in:
commit
4fb6a7d395
@ -58,12 +58,11 @@ class MuranoObjectParameter(yaqltypes.PythonType):
|
||||
if self.murano_class:
|
||||
murano_class = self.murano_class
|
||||
if isinstance(murano_class, six.string_types):
|
||||
murano_class_name = murano_class
|
||||
return helpers.is_instance_of(
|
||||
value, murano_class,
|
||||
self.version_spec or helpers.get_type(context))
|
||||
else:
|
||||
murano_class_name = murano_class.name
|
||||
return helpers.is_instance_of(
|
||||
value, murano_class_name,
|
||||
self.version_spec or helpers.get_type(context))
|
||||
return murano_class.is_compatible(value)
|
||||
else:
|
||||
return True
|
||||
|
||||
@ -108,12 +107,23 @@ class InterfacesParameter(yaqltypes.HiddenParameterType,
|
||||
|
||||
|
||||
class MuranoTypeParameter(yaqltypes.PythonType):
|
||||
def __init__(self, nullable=False, context=None):
|
||||
def __init__(self, base_type=None, nullable=False, context=None):
|
||||
self._context = context
|
||||
self._base_type = base_type
|
||||
super(MuranoTypeParameter, self).__init__(
|
||||
(dsl_types.MuranoTypeReference,
|
||||
six.string_types), nullable)
|
||||
|
||||
def check(self, value, context, *args, **kwargs):
|
||||
if not super(MuranoTypeParameter, self).check(
|
||||
value, context, *args, **kwargs):
|
||||
return False
|
||||
if isinstance(value, dsl_types.MuranoTypeReference):
|
||||
if not self._base_type:
|
||||
return True
|
||||
return self._base_type.is_compatible(value)
|
||||
return True
|
||||
|
||||
def convert(self, value, sender, context, function_spec, engine,
|
||||
*args, **kwargs):
|
||||
context = self._context or context
|
||||
@ -128,6 +138,10 @@ class MuranoTypeParameter(yaqltypes.PythonType):
|
||||
value = helpers.get_class(
|
||||
murano_type.namespace_resolver.resolve_name(value),
|
||||
context).get_reference()
|
||||
if self._base_type and not self._base_type.is_compatible(value):
|
||||
raise ValueError('Value must be subtype of {0}'.format(
|
||||
self._base_type.name
|
||||
))
|
||||
return value
|
||||
|
||||
|
||||
|
@ -259,6 +259,8 @@ class MuranoClass(dsl_types.MuranoClass):
|
||||
if isinstance(obj, (murano_object.MuranoObject,
|
||||
dsl.MuranoObjectInterface)):
|
||||
obj = obj.type
|
||||
elif isinstance(obj, dsl_types.MuranoTypeReference):
|
||||
obj = obj.murano_class
|
||||
if obj is self:
|
||||
return True
|
||||
return any(cls is self for cls in obj.ancestors())
|
||||
|
@ -132,7 +132,7 @@ class MuranoMethod(dsl_types.MuranoMethod):
|
||||
if not this and not self.is_static:
|
||||
raise Exception("A class instance is required")
|
||||
|
||||
if this is not None:
|
||||
if isinstance(this, dsl_types.MuranoObject):
|
||||
this = this.cast(self.murano_class)
|
||||
else:
|
||||
this = self.murano_class
|
||||
|
@ -20,7 +20,7 @@ from murano.dsl import helpers
|
||||
|
||||
@dsl.name('io.murano.Object')
|
||||
class SysObject(object):
|
||||
@specs.parameter('owner', dsl.MuranoTypeParameter(True), nullable=False)
|
||||
@specs.parameter('owner', dsl.MuranoTypeParameter(nullable=True))
|
||||
def set_attr(self, this, context, name, value, owner=None):
|
||||
if owner is None:
|
||||
owner = helpers.get_type(helpers.get_caller_context(context))
|
||||
@ -28,7 +28,7 @@ class SysObject(object):
|
||||
attribute_store = helpers.get_attribute_store(context)
|
||||
attribute_store.set(this.object, owner, name, value)
|
||||
|
||||
@specs.parameter('owner', dsl.MuranoTypeParameter(True), nullable=False)
|
||||
@specs.parameter('owner', dsl.MuranoTypeParameter(nullable=True))
|
||||
def get_attr(self, this, context, name, default=None, owner=None):
|
||||
if owner is None:
|
||||
owner = helpers.get_type(helpers.get_caller_context(context))
|
||||
|
@ -146,9 +146,9 @@ class TypeScheme(object):
|
||||
'Object {0} violates notOwned() contract'.format(obj))
|
||||
|
||||
@specs.parameter('name', dsl.MuranoTypeParameter(
|
||||
False, root_context))
|
||||
nullable=False, context=root_context))
|
||||
@specs.parameter('default_name', dsl.MuranoTypeParameter(
|
||||
True, root_context))
|
||||
nullable=True, context=root_context))
|
||||
@specs.parameter('value', nullable=True)
|
||||
@specs.parameter('version_spec', yaqltypes.String(True))
|
||||
@specs.method
|
||||
|
@ -176,7 +176,7 @@ def op_dot_static(context, receiver, expr, operator):
|
||||
type_context = executor.context_manager.create_class_context(
|
||||
receiver.murano_class)
|
||||
ctx2 = helpers.link_contexts(context, type_context)
|
||||
return operator(ctx2, None, expr)
|
||||
return operator(ctx2, receiver, expr)
|
||||
|
||||
|
||||
@specs.parameter('prefix', yaqltypes.Keyword())
|
||||
|
@ -12,6 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import weakref
|
||||
|
||||
import six
|
||||
import yaql
|
||||
from yaql.language import contexts
|
||||
@ -24,7 +26,6 @@ from yaql import legacy
|
||||
|
||||
from murano.dsl import constants
|
||||
from murano.dsl import dsl
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import helpers
|
||||
from murano.dsl import yaql_functions
|
||||
|
||||
@ -254,8 +255,11 @@ def _build_mpl_wrapper_function_definition(murano_method):
|
||||
fd.set_parameter(specs.ParameterDefinition(
|
||||
'__context', yaqltypes.Context(), 0))
|
||||
|
||||
nullable = murano_method.usage == 'Static'
|
||||
receiver_type = yaqltypes.PythonType(dsl_types.MuranoObject, nullable)
|
||||
receiver_type = dsl.MuranoObjectParameter(
|
||||
weakref.proxy(murano_method.murano_class), decorate=False)
|
||||
if murano_method.is_static:
|
||||
receiver_type = yaqltypes.AnyOf(dsl.MuranoTypeParameter(
|
||||
weakref.proxy(murano_method.murano_class)), receiver_type)
|
||||
fd.set_parameter(specs.ParameterDefinition('__receiver', receiver_type, 1))
|
||||
|
||||
fd.meta[constants.META_MURANO_METHOD] = murano_method
|
||||
@ -267,7 +271,6 @@ def get_class_factory_definition(cls, murano_class):
|
||||
engine = choose_yaql_engine(runtime_version)
|
||||
|
||||
def payload(__context, __receiver, *args, **kwargs):
|
||||
# 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):
|
||||
|
@ -1,6 +1,7 @@
|
||||
Namespaces:
|
||||
ns: test
|
||||
=: test
|
||||
e: ''
|
||||
|
||||
Name: TestStatics
|
||||
|
||||
@ -40,6 +41,10 @@ Methods:
|
||||
Body:
|
||||
Return: :TestStatics.simpleStaticMethod()
|
||||
|
||||
testCallStaticMethodOnInvalidClass:
|
||||
Body:
|
||||
Return: e:TestUnicode.simpleStaticMethod()
|
||||
|
||||
testCallStaticMethodOnClassNameWithNs:
|
||||
Body:
|
||||
Return: ns:TestStatics.simpleStaticMethod()
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
from yaql.language import exceptions as yaql_exceptions
|
||||
from yaql.language import specs
|
||||
from yaql.language import yaqltypes
|
||||
|
||||
@ -137,3 +138,8 @@ class TestStatics(test_case.DslTestCase):
|
||||
self.assertEqual(
|
||||
['PYTHONCLASS!'] + ['PythonClass!'] * 3,
|
||||
self._runner.testCallPythonClassMethod())
|
||||
|
||||
def test_call_static_method_on_invalid_class(self):
|
||||
self.assertRaises(
|
||||
yaql_exceptions.NoMatchingMethodException,
|
||||
self._runner.testCallStaticMethodOnInvalidClass)
|
||||
|
Loading…
x
Reference in New Issue
Block a user