diff --git a/gluon/storage.py b/gluon/storage.py index 4a1e46a7..1bb507f5 100644 --- a/gluon/storage.py +++ b/gluon/storage.py @@ -271,28 +271,38 @@ class FastStorage(dict): class List(list): """ - Like a regular python list but a[i] if i is out of bounds returns None - instead of `IndexOutOfBounds`. + Like a regular python list but callable. + When a(i) is called if i is out of bounds returns None + instead of `IndexError`. """ def __call__(self, i, default=DEFAULT, cast=None, otherwise=None): - """Allows to use a special syntax for fast-check of `request.args()` - validity - Args: + """Allows to use a special syntax for fast-check of + `request.args()` validity. + :params: i: index default: use this value if arg not found cast: type cast - otherwise: can be: - - None: results in a 404 - - str: redirect to this address - - callable: calls the function (nothing is passed) + otherwise: + will be executed when: + - casts fail + - value not found, dont have default and otherwise is + especified + can be: + - None: results in a 404 + - str: redirect to this address + - callable: calls the function (nothing is passed) Example: You can use:: request.args(0,default=0,cast=int,otherwise='http://error_url') request.args(0,default=0,cast=int,otherwise=lambda:...) """ - value = self[i] - if not value and default is not DEFAULT: + n = len(self) + if 0 <= i < n or -n <= i < 0: + value = self[i] + elif default is DEFAULT: + value = None + else: value, cast, otherwise = default, False, False try: if cast: @@ -311,13 +321,6 @@ class List(list): raise RuntimeError("invalid otherwise") return value - def __getitem__(self, i): - n = len(self) - if 0 <= i < n or -n <= i < 0: - return super(List, self).__getitem__(i) - return None - - if __name__ == '__main__': import doctest doctest.testmod() diff --git a/gluon/tests/test_storage.py b/gluon/tests/test_storage.py index e518e4d2..ca047e95 100644 --- a/gluon/tests/test_storage.py +++ b/gluon/tests/test_storage.py @@ -120,17 +120,14 @@ class TestStorageList(unittest.TestCase): class TestList(unittest.TestCase): + """ Tests Storage.List (fast-check for request.args()) """ def test_listcall(self): a = List((1, 2, 3)) self.assertEqual(a(1), 2) - self.assertEqual(a[1], 2) - self.assertEqual(a(3), None) - self.assertEqual(a[3], None) self.assertEqual(a(-1), 3) self.assertEqual(a(-5), None) - self.assertEqual(a[-5], None) self.assertEqual(a(-5, default='x'), 'x') self.assertEqual(a(-3, cast=str), '1') a.append('1234') @@ -139,8 +136,22 @@ class TestList(unittest.TestCase): a.append('x') self.assertRaises(HTTP, a, 4, cast=int) b = List() + # default is always returned when especified self.assertEqual(b(0, cast=int, default=None), None) - self.assertEqual(b(0, cast=int, default=None, otherwise='something'), None) + self.assertEqual(b(0, cast=int, default=None, otherwise='teste'), None) + self.assertEqual(b(0, cast=int, default='a', otherwise='teste'), 'a') + # if don't have value and otherwise is especified it will called + self.assertEqual(b(0, otherwise=lambda: 'something'), 'something') + self.assertEqual(b(0, cast=int, otherwise=lambda: 'something'), + 'something') + # except if default is especified + self.assertEqual(b(0, default=0, otherwise=lambda: 'something'), 0) + + def test_listgetitem(self): + '''Mantains list behaviour.''' + a = List((1, 2, 3)) + self.assertEqual(a[0], 1) + self.assertEqual(a[::-1], [3, 2, 1]) if __name__ == '__main__':