Commit afb7f98d by Chris Jerdonek

Minor docstring and code comment additions and improvements.

parent 4121be33
...@@ -6,9 +6,9 @@ Defines a Context class to represent mustache(5)'s notion of context. ...@@ -6,9 +6,9 @@ Defines a Context class to represent mustache(5)'s notion of context.
""" """
# We use this private global variable as a return value to represent a key # We use this private global variable as a return value to represent a key
# not being found on lookup. This lets us distinguish the case of a key's # not being found on lookup. This lets us distinguish between the case
# value being None with the case of a key not being found -- without having # of a key's value being None with the case of a key not being found --
# to rely on exceptions (e.g. KeyError) for flow control. # without having to rely on exceptions (e.g. KeyError) for flow control.
_NOT_FOUND = object() _NOT_FOUND = object()
...@@ -19,27 +19,26 @@ def _is_callable(obj): ...@@ -19,27 +19,26 @@ def _is_callable(obj):
def _get_item(obj, key): def _get_item(obj, key):
""" """
Look up the given key in the given object, and return the value. Return a key's value, or _NOT_FOUND if the key does not exist.
The obj argument should satisfy the same conditions as those described The obj argument should satisfy the same conditions as those
in Context.__init__'s() docstring. The behavior of this method is described for the obj arguments in Context.__init__'s() docstring.
undefined if obj is None.
The rules for querying are the same as the rules described in The rules for looking up the value of a key are the same as the rules
Context.get()'s docstring for a single item. described in Context.get()'s docstring for querying a single item.
Returns _NOT_FOUND if the key is not found. The behavior of this function is undefined if obj is None.
""" """
if hasattr(obj, '__getitem__'): if hasattr(obj, '__getitem__'):
# We do a membership test to avoid using exceptions for flow # We do a membership test to avoid using exceptions for flow control
# control. In addition, we call __contains__() explicitly as # (e.g. catching KeyError). In addition, we call __contains__()
# opposed to using the membership operator "in" to avoid # explicitly as opposed to using the membership operator "in" to
# triggering the following Python fallback behavior: # avoid triggering the following Python fallback behavior:
# #
# For objects that don’t define __contains__(), the membership test # "For objects that don’t define __contains__(), the membership test
# first tries iteration via __iter__(), then the old sequence # first tries iteration via __iter__(), then the old sequence
# iteration protocol via __getitem__().... # iteration protocol via __getitem__()...."
# #
# (from http://docs.python.org/reference/datamodel.html#object.__contains__ ) # (from http://docs.python.org/reference/datamodel.html#object.__contains__ )
if obj.__contains__(key): if obj.__contains__(key):
...@@ -58,10 +57,15 @@ def _get_item(obj, key): ...@@ -58,10 +57,15 @@ def _get_item(obj, key):
class Context(object): class Context(object):
""" """
Encapsulates a queryable stack of zero or more dictionary-like objects. Provides dictionary-like access to a stack of zero or more objects.
Instances of this class are intended to act as the context when Instances of this class are meant to represent the rendering context
rendering mustache templates in accordance with mustache(5). when rendering mustache templates in accordance with mustache(5).
Querying the stack for the value of a key queries the objects in the
stack in order from last-added objects to first (last in, first out).
See the docstrings of the methods of this class for more information.
""" """
...@@ -69,7 +73,7 @@ class Context(object): ...@@ -69,7 +73,7 @@ class Context(object):
# option for enabling a strict mode). # option for enabling a strict mode).
def __init__(self, *obj): def __init__(self, *obj):
""" """
Construct an instance and initialize the stack. Construct an instance, and initialize the stack.
The variable argument list *obj are the objects with which to The variable argument list *obj are the objects with which to
populate the initial stack. Objects in the argument list are added populate the initial stack. Objects in the argument list are added
......
...@@ -21,6 +21,7 @@ class TestCase(unittest.TestCase): ...@@ -21,6 +21,7 @@ class TestCase(unittest.TestCase):
def assertIs(self, first, second): def assertIs(self, first, second):
self.assertTrue(first is second, msg="%s is not %s" % (repr(first), repr(second))) self.assertTrue(first is second, msg="%s is not %s" % (repr(first), repr(second)))
class SimpleObject(object): class SimpleObject(object):
"""A sample class that does not define __getitem__().""" """A sample class that does not define __getitem__()."""
...@@ -52,6 +53,10 @@ class GetItemTestCase(TestCase): ...@@ -52,6 +53,10 @@ class GetItemTestCase(TestCase):
"""Test context._get_item().""" """Test context._get_item()."""
def assertNotFound(self, obj, key): def assertNotFound(self, obj, key):
"""
Assert that a call to _get_item() returns _NOT_FOUND.
"""
self.assertIs(_get_item(obj, key), _NOT_FOUND) self.assertIs(_get_item(obj, key), _NOT_FOUND)
### Case: obj is a dictionary. ### Case: obj is a dictionary.
...@@ -115,6 +120,8 @@ class GetItemTestCase(TestCase): ...@@ -115,6 +120,8 @@ class GetItemTestCase(TestCase):
""" """
obj = MappingObject() obj = MappingObject()
self.assertEquals(obj.fuzz, "buzz") self.assertEquals(obj.fuzz, "buzz")
# The presence of __getitem__ causes obj.fuzz not to be checked,
# as desired.
self.assertNotFound(obj, "fuzz") self.assertNotFound(obj, "fuzz")
def test_mapping_object__not_implementing_contains(self): def test_mapping_object__not_implementing_contains(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment