Merge "Strengthen validation of receiver type for methods"

This commit is contained in:
Jenkins 2016-02-29 17:59:33 +00:00 committed by Gerrit Code Review
commit 4fb6a7d395
9 changed files with 46 additions and 16 deletions

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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())

View File

@ -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):

View File

@ -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()

View File

@ -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)