Adds engine option to make dicts iterable
By default yaql 1.0 will not assume dicts to be iterable. However because of yaql 0.2 had such behavior and some users may still want to have it (for example because Python has it) now in can be turned on. This is done by default for legacy engine but not for modern one. Also because SmartType's check method had no access to engine options additional parameter (engine) was added. Because previously signature was changed to have *args/**kwargs backward compatibility retained Change-Id: Ic3d65d8cb5caff43dee976dd9ba63f4caecf7dff
This commit is contained in:
parent
df4f77df33
commit
8b9f154676
@ -85,7 +85,7 @@ def choose_overload(name, candidates, engine, sender, context, args, kwargs):
|
||||
elif no_kwargs != c.no_kwargs:
|
||||
raise_ambiguous()
|
||||
|
||||
mapping = c.map_args(args, kwargs, context)
|
||||
mapping = c.map_args(args, kwargs, context, engine)
|
||||
if mapping is None:
|
||||
continue
|
||||
pos, kwd = mapping
|
||||
|
@ -192,7 +192,7 @@ class FunctionDefinition(object):
|
||||
if p.position is not None and p.position >= pd.position:
|
||||
p.position += 1
|
||||
|
||||
def map_args(self, args, kwargs, context):
|
||||
def map_args(self, args, kwargs, context, engine):
|
||||
kwargs = dict(kwargs)
|
||||
positional_args = len(args) * [
|
||||
self.parameters.get('*', utils.NO_VALUE)]
|
||||
@ -248,17 +248,18 @@ class FunctionDefinition(object):
|
||||
value = args[i]
|
||||
if value is utils.NO_VALUE:
|
||||
value = positional_args[i].default
|
||||
if not positional_args[i].value_type.check(value, context):
|
||||
if not positional_args[i].value_type.check(value, context, engine):
|
||||
return None
|
||||
for kwd in six.iterkeys(kwargs):
|
||||
if not keyword_args[kwd].value_type.check(kwargs[kwd], context):
|
||||
if not keyword_args[kwd].value_type.check(
|
||||
kwargs[kwd], context, engine):
|
||||
return None
|
||||
|
||||
return tuple(positional_args), keyword_args
|
||||
|
||||
def get_delegate(self, sender, engine, context, args, kwargs):
|
||||
def checked(val, param):
|
||||
if not param.value_type.check(val, context):
|
||||
if not param.value_type.check(val, context, engine):
|
||||
raise exceptions.ArgumentException(param.name)
|
||||
|
||||
def convert_arg_func(context2):
|
||||
|
@ -23,7 +23,7 @@ from yaql.language import utils
|
||||
|
||||
class HiddenParameterType(object):
|
||||
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
||||
def check(self, value, context, *args, **kwargs):
|
||||
def check(self, value, context, engine, *args, **kwargs):
|
||||
return True
|
||||
|
||||
|
||||
@ -35,14 +35,14 @@ class SmartType(object):
|
||||
def __init__(self, nullable):
|
||||
self.nullable = nullable
|
||||
|
||||
def check(self, value, context, *args, **kwargs):
|
||||
def check(self, value, context, engine, *args, **kwargs):
|
||||
if value is None and not self.nullable:
|
||||
return False
|
||||
return True
|
||||
|
||||
def convert(self, value, sender, context, function_spec, engine,
|
||||
*args, **kwargs):
|
||||
if not self.check(value, context, *args, **kwargs):
|
||||
if not self.check(value, context, engine, *args, **kwargs):
|
||||
raise exceptions.ArgumentValueException()
|
||||
utils.limit_memory_usage(engine, (1, value))
|
||||
|
||||
@ -56,11 +56,12 @@ class GenericType(SmartType):
|
||||
self.checker = checker
|
||||
self.converter = converter
|
||||
|
||||
def check(self, value, context, *args, **kwargs):
|
||||
def check(self, value, context, engine, *args, **kwargs):
|
||||
if isinstance(value, expressions.Constant):
|
||||
value = value.value
|
||||
|
||||
if not super(GenericType, self).check(value, context, *args, **kwargs):
|
||||
if not super(GenericType, self).check(
|
||||
value, context, engine, *args, **kwargs):
|
||||
return False
|
||||
if value is None or isinstance(value, expressions.Expression):
|
||||
return True
|
||||
@ -144,6 +145,13 @@ class Iterable(PythonType):
|
||||
lambda t: not isinstance(t, six.string_types + (
|
||||
utils.MappingType,))] + (validators or []))
|
||||
|
||||
def check(self, value, context, engine, *args, **kwargs):
|
||||
if isinstance(value, utils.MappingType) and engine.options.get(
|
||||
'yaql.iterableDicts', False):
|
||||
return True
|
||||
return super(Iterable, self).check(
|
||||
value, context, engine, *args, **kwargs)
|
||||
|
||||
def convert(self, value, sender, context, function_spec, engine,
|
||||
*args, **kwargs):
|
||||
res = super(Iterable, self).convert(
|
||||
|
@ -29,6 +29,7 @@ class YaqlFactory(factory.YaqlFactory):
|
||||
def create(self, options=None):
|
||||
options = dict(options or {})
|
||||
options['yaql.convertTuplesToLists'] = False
|
||||
options['yaql.iterableDicts'] = True
|
||||
return super(YaqlFactory, self).create(options)
|
||||
|
||||
|
||||
|
@ -133,3 +133,8 @@ class TestLegacy(TestLegacyNewEngine):
|
||||
self.assertEqual((1, 2, 3), self.eval('1 => 2 => 3'))
|
||||
self.assertEqual(((1, 2), 3), self.eval('(1 => 2) => 3'))
|
||||
self.assertEqual((1, (2, 3)), self.eval('1 => (2 => 3)'))
|
||||
|
||||
def test_dicts_are_iterable(self):
|
||||
data = {'a': 1, 'b': 2}
|
||||
self.assertTrue(self.eval('a in $', data))
|
||||
self.assertItemsEqual('ab', self.eval('$.sum()', data))
|
||||
|
Loading…
Reference in New Issue
Block a user