diff --git a/pystache/context.py b/pystache/context.py index 67159160..744c492a 100644 --- a/pystache/context.py +++ b/pystache/context.py @@ -50,7 +50,17 @@ def _get_value(context, key): # (e.g. catching KeyError). if key in context: return context[key] - elif type(context).__module__ != _BUILTIN_MODULE: + if isinstance(context, list): + # If we're dealing with a list or a list subclass attempt to use the key + # as an index on the list. + # + # We pass on ValueError (the key is not an int) or IndexError (the key/int + # is not in the list). And continue with normal processing. + try: + return context[int(key)] + except (ValueError, IndexError): + pass + if type(context).__module__ != _BUILTIN_MODULE: # Then we consider the argument an "object" for the purposes of # the spec. # diff --git a/pystache/tests/test_context.py b/pystache/tests/test_context.py index 238e4b00..bcc7f4b8 100644 --- a/pystache/tests/test_context.py +++ b/pystache/tests/test_context.py @@ -221,6 +221,12 @@ class MyList(list): pass self.assertEqual(_get_value(item1, 'pop'), 2) self.assertNotFound(item2, 'pop') + # get list items by index + self.assertEqual(_get_value(item2, '0'), 1) + + # Don't throw errors if we pass a non-int to a list. + self.assertNotFound(item2, 'numberone') + class ContextStackTestCase(unittest.TestCase, AssertIsMixin, AssertStringMixin, AssertExceptionMixin): @@ -497,3 +503,10 @@ def bar(self): stack = ContextStack({"foo": Foo()}) self.assertEqual(stack.get(name), "Baz") + + def test_dot_notation__list(self): + name = "foo.1" + + # When any element in the path is callable, it should be automatically invoked + stack = ContextStack({"foo": ['Ignore me.', 'Choose me!']}) + self.assertEqual(stack.get(name), "Choose me!")