diff --git a/CHANGELOG b/CHANGELOG index 5fb54f1170..bd410367ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add Len to PYSON * Use bcrypt to hash password if possible * Use a sequence of ids, values to set fields * Client side actions on button and wizard diff --git a/doc/ref/pyson.rst b/doc/ref/pyson.rst index 5f012b91a7..fd1640be50 100644 --- a/doc/ref/pyson.rst +++ b/doc/ref/pyson.rst @@ -250,6 +250,11 @@ Arguments: ``delta_microseconds`` Contains a PYSON statement of type int or long. +.. class:: Len(value) + +A :class:`Len` object represents the PYSON ``Len()`` statement for length of a +dictionary, list or string. Returns the number of items in ``value``. + .. class:: Id(module, fs_id) An :class:`Id` object represents the PYSON ``Id()`` statement for filesystem id diff --git a/trytond/pyson.py b/trytond/pyson.py index 1fc1e6440d..6771f20ce6 100644 --- a/trytond/pyson.py +++ b/trytond/pyson.py @@ -537,6 +537,32 @@ class DateTime(Date): ) +class Len(PYSON): + + def __init__(self, value): + super(Len, self).__init__() + if isinstance(value, PYSON): + assert value.types().issubset(set([dict, list, str])), \ + 'value must be a dict or a list or a string' + else: + assert type(value) in [dict, list, str], \ + 'value must be a dict or list or a string' + self._value = value + + def pyson(self): + return { + '__class__': 'Len', + 'v': self._value, + } + + def types(self): + return set([int, long]) + + @staticmethod + def eval(dct, context): + return len(dct['v']) + + class Id(PYSON): """The database id for filesystem id""" @@ -567,4 +593,5 @@ CONTEXT = { 'In': In, 'Date': Date, 'DateTime': DateTime, + 'Len': Len, } diff --git a/trytond/tests/test_pyson.py b/trytond/tests/test_pyson.py index d49c7ed6e5..d295b98021 100644 --- a/trytond/tests/test_pyson.py +++ b/trytond/tests/test_pyson.py @@ -496,6 +496,26 @@ class PYSONTestCase(unittest.TestCase): self.assert_(pyson.PYSONDecoder().decode(eval) == datetime.datetime(2010, 2, 22, 10, 30, 20, 200)) + def test0140Len(self): + 'Test pyson.Len' + self.assert_(pyson.Len([1, 2, 3]).pyson() == { + '__class__': 'Len', + 'v': [1, 2, 3], + }) + + self.assertRaises(AssertionError, pyson.Len, object()) + + self.assert_(pyson.Len([1, 2, 3]).types() == set([int, long])) + + eval = pyson.PYSONEncoder().encode(pyson.Len([1, 2, 3])) + self.assertEqual(pyson.PYSONDecoder().decode(eval), 3) + + eval = pyson.PYSONEncoder().encode(pyson.Len({1: 2, 3: 4})) + self.assertEqual(pyson.PYSONDecoder().decode(eval), 2) + + eval = pyson.PYSONEncoder().encode(pyson.Len('foo bar')) + self.assertEqual(pyson.PYSONDecoder().decode(eval), 7) + def test0900Composite(self): 'Test Composite' eval = pyson.PYSONEncoder().encode(['id', pyson.If(pyson.Not(