def test_nullable_collections(self): @specs.parameter('arg', yaqltypes.Sequence()) def foo1(arg): return arg is None @specs.parameter('arg', yaqltypes.Sequence(nullable=True)) def foo2(arg): return arg is None @specs.parameter('arg', yaqltypes.Iterable()) def bar1(arg): return arg is None @specs.parameter('arg', yaqltypes.Iterable(nullable=True)) def bar2(arg): return arg is None @specs.parameter('arg', yaqltypes.Iterator()) def baz1(arg): return arg is None @specs.parameter('arg', yaqltypes.Iterator(nullable=True)) def baz2(arg): return arg is None for func in (foo1, foo2, bar1, bar2, baz1, baz2): self.context.register_function(func) self.assertFalse(self.eval('foo1([1, 2])')) self.assertRaises(exceptions.NoMatchingFunctionException, self.eval, 'foo1(null)') self.assertFalse(self.eval('foo2([1, 2])')) self.assertTrue(self.eval('foo2(null)')) self.assertFalse(self.eval('bar1([1, 2])')) self.assertRaises(exceptions.NoMatchingFunctionException, self.eval, 'bar1(null)') self.assertFalse(self.eval('bar2([1, 2])')) self.assertTrue(self.eval('bar2(null)')) self.assertFalse(self.eval('baz1($)', data=iter([1, 2]))) self.assertRaises(exceptions.NoMatchingFunctionException, self.eval, 'baz1(null)') self.assertFalse(self.eval('baz2($)', data=iter([1, 2]))) self.assertTrue(self.eval('baz2(null)'))
def class_factory(context): """Factory for class() contract function that generates schema instead""" @specs.parameter('schema', Schema) @specs.parameter('name', dsl.MuranoTypeParameter(nullable=False, context=context)) @specs.parameter('default_name', dsl.MuranoTypeParameter(nullable=True, context=context)) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.method def class_(schema, name, default_name=None, version_spec=None): types = 'muranoObject' if '_notNull' not in schema.data: types = [types] + ['null'] return Schema({'type': types, 'muranoType': name.type.name}) @specs.parameter('schema', Schema) @specs.parameter('type_', dsl.MuranoTypeParameter(nullable=False, context=context)) @specs.parameter('default_type', dsl.MuranoTypeParameter(nullable=True, context=context)) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.parameter('exclude_properties', yaqltypes.Sequence(nullable=True)) @specs.method def template(schema, type_, exclude_properties=None, default_type=None, version_spec=None): result = class_(schema, type_, default_type, version_spec) result.data['owned'] = True if exclude_properties: result.data['excludedProperties'] = exclude_properties return result return class_, template
@specs.parameter('d', utils.MappingType, alias='dict') @specs.name('values') @specs.method def dict_values(d): return six.itervalues(d) @specs.parameter('d', utils.MappingType, alias='dict') @specs.name('items') @specs.method def dict_items(d): return six.iteritems(d) @specs.parameter('lst', yaqltypes.Sequence(), alias='list') @specs.parameter('index', int, nullable=False) @specs.name('#indexer') def list_indexer(lst, index): return lst[index] @specs.parameter('value', nullable=True) @specs.parameter('collection', yaqltypes.Iterable()) @specs.name('#operator_in') def in_(value, collection): return value in collection @specs.parameter('value', nullable=True) @specs.parameter('collection', yaqltypes.Iterable())
:arg right: object property name :argType right: keyword :returnType: any .. code:: yaql> now().year 2016 """ func_name = '#property#{0}'.format(name) return func(func_name, obj) @specs.name('call') @specs.parameter('name', yaqltypes.String()) @specs.parameter('args', yaqltypes.Sequence()) @specs.parameter('kwargs', utils.MappingType) def call_func(context, engine, name, args, kwargs, receiver=utils.NO_VALUE): """:yaql:call Evaluates function name with specified args and kwargs and returns the result. :signature: call(name, args, kwargs) :arg name: name of callable :argType name: string :arg args: sequence of items to be used for calling :argType args: sequence :arg kwargs: dictionary with kwargs to be used for calling :argType kwargs: mapping :returnType: any (callable return type)
class Template(contracts.ContractMethod): name = 'template' @specs.parameter('type_', dsl.MuranoTypeParameter(nullable=False, lazy=True)) @specs.parameter('default_type', dsl.MuranoTypeParameter(nullable=True, lazy=True)) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.parameter('exclude_properties', yaqltypes.Sequence(nullable=True)) def __init__(self, engine, type_, default_type=None, version_spec=None, exclude_properties=None): self.type = type_(self.context).type self.default_type = default_type(self.context) or self.type self.version_spec = version_spec self.exclude_properties = exclude_properties self.engine = engine def validate(self): if self.value is None or helpers.is_instance_of( self.value, self.type.name, self.version_spec or helpers.get_names_scope(self.root_context)): return self.value if not isinstance( self.value, (dsl_types.MuranoObject, dsl_types.MuranoObjectInterface)): raise exceptions.ContractViolationException( 'Value is not an object') raise exceptions.ContractViolationException( 'Object of type {0} is not compatible with ' 'requested type {1}'.format(self.value.type, self.type)) def check_type(self): if isinstance(self.value, utils.MappingType): return self.value return self.validate() def transform(self): object_store = helpers.get_object_store() if self.value is None: return None if isinstance(self.value, dsl_types.MuranoObject): obj = self.value elif isinstance(self.value, dsl_types.MuranoObjectInterface): obj = self.value.object elif isinstance(self.value, utils.MappingType): passkey = utils.create_marker('<Contract Passkey>') if self.exclude_properties: parsed = helpers.parse_object_definition( self.value, self.calling_type, self.context) props = dsl.to_mutable(parsed['properties'], self.engine) for p in self.exclude_properties: helpers.patch_dict(props, p, passkey) parsed['properties'] = props value = helpers.assemble_object_definition(parsed) else: value = self.value with helpers.thread_local_attribute(constants.TL_CONTRACT_PASSKEY, passkey): with helpers.thread_local_attribute( constants.TL_OBJECTS_DRY_RUN, True): obj = object_store.load(value, self.owner, context=self.context, default_type=self.default_type, scope_type=self.calling_type) obj.__passkey__ = passkey else: raise exceptions.ContractViolationException( 'Value {0} cannot be represented as class {1}'.format( helpers.format_scalar(self.value), self.type)) self.value = obj return self.validate() def finalize(self): if self.value is None: return None object_store = helpers.get_object_store() if object_store.initializing: return {} passkey = getattr(self.value, '__passkey__', None) with helpers.thread_local_attribute(constants.TL_CONTRACT_PASSKEY, passkey): result = serializer.serialize(self.value.real_this, object_store.executor, dsl_types.DumpTypes.Mixed) if self.exclude_properties: for p in self.exclude_properties: helpers.patch_dict(result, p, utils.NO_VALUE) return result def generate_schema(self): result = Class.generate_class_schema(self.value, self.type) result['owned'] = True if self.exclude_properties: result['excludedProperties'] = self.exclude_properties return result
def prepare_transform_context(root_context, this, owner, default, calling_type): @specs.parameter('value', nullable=True) @specs.method def int_(value): if value is dsl.NO_VALUE: value = default if value is None: return None try: return int(value) except Exception: raise exceptions.ContractViolationException( 'Value {0} violates int() contract'.format( format_scalar(value))) @specs.parameter('value', nullable=True) @specs.method def string(value): if value is dsl.NO_VALUE: value = default if value is None: return None try: return six.text_type(value) except Exception: raise exceptions.ContractViolationException( 'Value {0} violates string() contract'.format( format_scalar(value))) @specs.parameter('value', nullable=True) @specs.method def bool_(value): if value is dsl.NO_VALUE: value = default if value is None: return None return True if value else False @specs.parameter('value', nullable=True) @specs.method def not_null(value): if isinstance(value, TypeScheme.ObjRef): return value if value is None: raise exceptions.ContractViolationException( 'null value violates notNull() contract') return value @specs.parameter('value', nullable=True) @specs.method def error(value): raise exceptions.ContractViolationException('error() contract') @specs.parameter('value', nullable=True) @specs.parameter('predicate', yaqltypes.Lambda(with_context=True)) @specs.parameter('msg', yaqltypes.String(nullable=True)) @specs.method def check(value, predicate, msg=None): if isinstance(value, TypeScheme.ObjRef) or predicate( root_context.create_child_context(), value): return value else: if not msg: msg = "Value {0} doesn't match predicate".format( format_scalar(value)) raise exceptions.ContractViolationException(msg) @specs.parameter('obj', TypeScheme.ObjRef, nullable=True) @specs.name('owned') @specs.method def owned_ref(obj): if obj is None: return None if isinstance(obj, TypeScheme.ObjRef): return obj @specs.parameter('obj', dsl_types.MuranoObject) @specs.method def owned(obj): p = obj.owner while p is not None: if p is this: return obj p = p.owner raise exceptions.ContractViolationException( 'Object {0} violates owned() contract'.format(obj)) @specs.parameter('obj', TypeScheme.ObjRef, nullable=True) @specs.name('not_owned') @specs.method def not_owned_ref(obj): if isinstance(obj, TypeScheme.ObjRef): return obj if obj is None: return None @specs.parameter('obj', dsl_types.MuranoObject) @specs.method def not_owned(obj): try: owned(obj) except exceptions.ContractViolationException: return obj else: raise exceptions.ContractViolationException( 'Object {0} violates notOwned() contract'.format(obj)) @specs.parameter('name', dsl.MuranoTypeParameter(nullable=False, context=root_context)) @specs.parameter('default_name', dsl.MuranoTypeParameter(nullable=True, context=root_context)) @specs.parameter('value', nullable=True) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.method def class_(value, name, default_name=None, version_spec=None): object_store = helpers.get_object_store() if not default_name: default_name = name murano_class = name.type if isinstance(value, TypeScheme.ObjRef): value = value.object_id if value is None: return None if isinstance(value, dsl_types.MuranoObject): obj = value elif isinstance(value, dsl_types.MuranoObjectInterface): obj = value.object elif isinstance(value, utils.MappingType): obj = object_store.load(value, owner, context=root_context, default_type=default_name, scope_type=calling_type) elif isinstance(value, six.string_types): obj = object_store.get(value) if obj is None: if not object_store.initializing: raise exceptions.NoObjectFoundError(value) else: return TypeScheme.ObjRef(value) else: raise exceptions.ContractViolationException( 'Value {0} cannot be represented as class {1}'.format( format_scalar(value), name)) if not helpers.is_instance_of( obj, murano_class.name, version_spec or helpers.get_type(root_context)): raise exceptions.ContractViolationException( 'Object of type {0} is not compatible with ' 'requested type {1}'.format(obj.type.name, murano_class)) return obj @specs.parameter('type_', dsl.MuranoTypeParameter(nullable=False, context=root_context)) @specs.parameter('default_type', dsl.MuranoTypeParameter(nullable=True, context=root_context)) @specs.parameter('value', nullable=True) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.parameter('exclude_properties', yaqltypes.Sequence(nullable=True)) @specs.method def template(engine, value, type_, exclude_properties=None, default_type=None, version_spec=None): object_store = helpers.get_object_store() passkey = None if not default_type: default_type = type_ murano_class = type_.type if value is None: return None if isinstance(value, dsl_types.MuranoObject): obj = value elif isinstance(value, dsl_types.MuranoObjectInterface): obj = value.object elif isinstance(value, utils.MappingType): passkey = utils.create_marker('<Contract Passkey>') if exclude_properties: parsed = helpers.parse_object_definition( value, calling_type, context) props = dsl.to_mutable(parsed['properties'], engine) for p in exclude_properties: helpers.patch_dict(props, p, passkey) parsed['properties'] = props value = helpers.assemble_object_definition(parsed) with helpers.thread_local_attribute( constants.TL_CONTRACT_PASSKEY, passkey): with helpers.thread_local_attribute( constants.TL_OBJECTS_DRY_RUN, True): obj = object_store.load(value, owner, context=context, default_type=default_type, scope_type=calling_type) else: raise exceptions.ContractViolationException( 'Value {0} cannot be represented as class {1}'.format( format_scalar(value), type_)) if not helpers.is_instance_of( obj, murano_class.name, version_spec or helpers.get_type(root_context)): raise exceptions.ContractViolationException( 'Object of type {0} is not compatible with ' 'requested type {1}'.format(obj.type.name, type_)) with helpers.thread_local_attribute(constants.TL_CONTRACT_PASSKEY, passkey): result = serializer.serialize(obj.real_this, object_store.executor, dsl_types.DumpTypes.Mixed) if exclude_properties: for p in exclude_properties: helpers.patch_dict(result, p, utils.NO_VALUE) return result context = root_context.create_child_context() context.register_function(int_) context.register_function(string) context.register_function(bool_) context.register_function(check) context.register_function(not_null) context.register_function(error) context.register_function(class_) context.register_function(template) context.register_function(owned_ref) context.register_function(owned) context.register_function(not_owned_ref) context.register_function(not_owned) return context
def prepare_validate_context(root_context): @specs.parameter('value', nullable=True) @specs.method def int_(value): if value is None or isinstance( value, int) and not isinstance(value, bool): return value raise exceptions.ContractViolationException() @specs.parameter('value', nullable=True) @specs.method def string(value): if value is None or isinstance(value, six.string_types): return value raise exceptions.ContractViolationException() @specs.parameter('value', nullable=True) @specs.method def bool_(value): if value is None or isinstance(value, bool): return value raise exceptions.ContractViolationException() @specs.parameter('value', nullable=True) @specs.method def not_null(value): if value is None: raise exceptions.ContractViolationException() return value @specs.parameter('value', nullable=True) @specs.parameter('predicate', yaqltypes.Lambda(with_context=True)) @specs.method def check(value, predicate): if predicate(root_context.create_child_context(), value): return value raise exceptions.ContractViolationException() @specs.parameter('type', dsl.MuranoTypeParameter(nullable=False, context=root_context)) @specs.parameter('value', nullable=True) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.method def class_(value, type, version_spec=None): if value is None or helpers.is_instance_of( value, type.type.name, version_spec or helpers.get_names_scope(root_context)): return value raise exceptions.ContractViolationException() @specs.parameter('type_', dsl.MuranoTypeParameter(nullable=False, context=root_context)) @specs.parameter('default_type', dsl.MuranoTypeParameter(nullable=True, context=root_context)) @specs.parameter('value', nullable=True) @specs.parameter('version_spec', yaqltypes.String(True)) @specs.parameter('exclude_properties', yaqltypes.Sequence(nullable=True)) @specs.method def template(value, type_, exclude_properties=None, default_type=None, version_spec=None): if value is None or isinstance(value, utils.MappingType): return value if helpers.is_instance_of( value, type_.type.name, version_spec or helpers.get_names_scope(root_context)): return value raise exceptions.ContractViolationException() context = root_context.create_child_context() context.register_function(int_) context.register_function(string) context.register_function(bool_) context.register_function(check) context.register_function(not_null) context.register_function(class_) context.register_function(template) return context