Commit 340c2991 by Chris Jerdonek

Renamed Context to ContextStack.

parent 780cf29c
# coding: utf-8 # coding: utf-8
""" """
Exposes a context class and functions to retrieve names from context. Exposes a ContextStack class and functions to retrieve names from context.
""" """
...@@ -33,7 +33,7 @@ def _get_value(item, key): ...@@ -33,7 +33,7 @@ def _get_value(item, key):
Returns _NOT_FOUND if the key does not exist. Returns _NOT_FOUND if the key does not exist.
The Context.get() docstring documents this function's intended behavior. The ContextStack.get() docstring documents this function's intended behavior.
""" """
if isinstance(item, dict): if isinstance(item, dict):
...@@ -79,7 +79,7 @@ def resolve(context, name): ...@@ -79,7 +79,7 @@ def resolve(context, name):
return context.get(name, '') return context.get(name, '')
class Context(object): class ContextStack(object):
""" """
Provides dictionary-like access to a stack of zero or more items. Provides dictionary-like access to a stack of zero or more items.
...@@ -94,7 +94,7 @@ class Context(object): ...@@ -94,7 +94,7 @@ class Context(object):
(last in, first out). (last in, first out).
Caution: this class does not currently support recursive nesting in Caution: this class does not currently support recursive nesting in
that items in the stack cannot themselves be Context instances. that items in the stack cannot themselves be ContextStack instances.
See the docstrings of the methods of this class for more details. See the docstrings of the methods of this class for more details.
...@@ -111,7 +111,7 @@ class Context(object): ...@@ -111,7 +111,7 @@ class Context(object):
stack in order so that, in particular, items at the end of stack in order so that, in particular, items at the end of
the argument list are queried first when querying the stack. the argument list are queried first when querying the stack.
Caution: items should not themselves be Context instances, as Caution: items should not themselves be ContextStack instances, as
recursive nesting does not behave as one might expect. recursive nesting does not behave as one might expect.
""" """
...@@ -123,9 +123,9 @@ class Context(object): ...@@ -123,9 +123,9 @@ class Context(object):
For example-- For example--
>>> context = Context({'alpha': 'abc'}, {'numeric': 123}) >>> context = ContextStack({'alpha': 'abc'}, {'numeric': 123})
>>> repr(context) >>> repr(context)
"Context({'alpha': 'abc'}, {'numeric': 123})" "ContextStack({'alpha': 'abc'}, {'numeric': 123})"
""" """
return "%s%s" % (self.__class__.__name__, tuple(self._stack)) return "%s%s" % (self.__class__.__name__, tuple(self._stack))
...@@ -133,18 +133,18 @@ class Context(object): ...@@ -133,18 +133,18 @@ class Context(object):
@staticmethod @staticmethod
def create(*context, **kwargs): def create(*context, **kwargs):
""" """
Build a Context instance from a sequence of context-like items. Build a ContextStack instance from a sequence of context-like items.
This factory-style method is more general than the Context class's This factory-style method is more general than the ContextStack class's
constructor in that, unlike the constructor, the argument list constructor in that, unlike the constructor, the argument list
can itself contain Context instances. can itself contain ContextStack instances.
Here is an example illustrating various aspects of this method: Here is an example illustrating various aspects of this method:
>>> obj1 = {'animal': 'cat', 'vegetable': 'carrot', 'mineral': 'copper'} >>> obj1 = {'animal': 'cat', 'vegetable': 'carrot', 'mineral': 'copper'}
>>> obj2 = Context({'vegetable': 'spinach', 'mineral': 'silver'}) >>> obj2 = ContextStack({'vegetable': 'spinach', 'mineral': 'silver'})
>>> >>>
>>> context = Context.create(obj1, None, obj2, mineral='gold') >>> context = ContextStack.create(obj1, None, obj2, mineral='gold')
>>> >>>
>>> context.get('animal') >>> context.get('animal')
'cat' 'cat'
...@@ -155,7 +155,7 @@ class Context(object): ...@@ -155,7 +155,7 @@ class Context(object):
Arguments: Arguments:
*context: zero or more dictionaries, Context instances, or objects *context: zero or more dictionaries, ContextStack instances, or objects
with which to populate the initial context stack. None with which to populate the initial context stack. None
arguments will be skipped. Items in the *context list are arguments will be skipped. Items in the *context list are
added to the stack in order so that later items in the argument added to the stack in order so that later items in the argument
...@@ -171,12 +171,12 @@ class Context(object): ...@@ -171,12 +171,12 @@ class Context(object):
""" """
items = context items = context
context = Context() context = ContextStack()
for item in items: for item in items:
if item is None: if item is None:
continue continue
if isinstance(item, Context): if isinstance(item, ContextStack):
context._stack.extend(item._stack) context._stack.extend(item._stack)
else: else:
context.push(item) context.push(item)
...@@ -245,9 +245,9 @@ class Context(object): ...@@ -245,9 +245,9 @@ class Context(object):
>>> >>>
>>> dct['greet'] is obj.greet >>> dct['greet'] is obj.greet
True True
>>> Context(dct).get('greet') #doctest: +ELLIPSIS >>> ContextStack(dct).get('greet') #doctest: +ELLIPSIS
<function greet at 0x...> <function greet at 0x...>
>>> Context(obj).get('greet') >>> ContextStack(obj).get('greet')
'Hi Bob!' 'Hi Bob!'
TODO: explain the rationale for this difference in treatment. TODO: explain the rationale for this difference in treatment.
...@@ -289,4 +289,4 @@ class Context(object): ...@@ -289,4 +289,4 @@ class Context(object):
Return a copy of this instance. Return a copy of this instance.
""" """
return Context(*self._stack) return ContextStack(*self._stack)
...@@ -17,7 +17,7 @@ class ParsedTemplate(object): ...@@ -17,7 +17,7 @@ class ParsedTemplate(object):
parse_tree: a list, each element of which is either-- parse_tree: a list, each element of which is either--
(1) a unicode string, or (1) a unicode string, or
(2) a "rendering" callable that accepts a Context instance (2) a "rendering" callable that accepts a ContextStack instance
and returns a unicode string. and returns a unicode string.
The possible rendering callables are the return values of the The possible rendering callables are the return values of the
......
...@@ -215,7 +215,7 @@ class RenderEngine(object): ...@@ -215,7 +215,7 @@ class RenderEngine(object):
Arguments: Arguments:
template: a template string of type unicode. template: a template string of type unicode.
context: a Context instance. context: a ContextStack instance.
""" """
# We keep this type-check as an added check because this method is # We keep this type-check as an added check because this method is
...@@ -238,7 +238,7 @@ class RenderEngine(object): ...@@ -238,7 +238,7 @@ class RenderEngine(object):
template: a template string of type unicode (but not a proper template: a template string of type unicode (but not a proper
subclass of unicode). subclass of unicode).
context: a Context instance. context: a ContextStack instance.
""" """
# Be strict but not too strict. In other words, accept str instead # Be strict but not too strict. In other words, accept str instead
......
...@@ -8,7 +8,7 @@ This module provides a Renderer class to render templates. ...@@ -8,7 +8,7 @@ This module provides a Renderer class to render templates.
import sys import sys
from pystache import defaults from pystache import defaults
from pystache.context import Context from pystache.context import ContextStack
from pystache.loader import Loader from pystache.loader import Loader
from pystache.renderengine import RenderEngine from pystache.renderengine import RenderEngine
from pystache.specloader import SpecLoader from pystache.specloader import SpecLoader
...@@ -277,7 +277,7 @@ class Renderer(object): ...@@ -277,7 +277,7 @@ class Renderer(object):
# RenderEngine.render() requires that the template string be unicode. # RenderEngine.render() requires that the template string be unicode.
template = self._to_unicode_hard(template) template = self._to_unicode_hard(template)
context = Context.create(*context, **kwargs) context = ContextStack.create(*context, **kwargs)
self._context = context self._context = context
engine = self._make_render_engine() engine = self._make_render_engine()
...@@ -338,7 +338,7 @@ class Renderer(object): ...@@ -338,7 +338,7 @@ class Renderer(object):
uses the passed object as the first element of the context stack uses the passed object as the first element of the context stack
when rendering. when rendering.
*context: zero or more dictionaries, Context instances, or objects *context: zero or more dictionaries, ContextStack instances, or objects
with which to populate the initial context stack. None with which to populate the initial context stack. None
arguments are skipped. Items in the *context list are added to arguments are skipped. Items in the *context list are added to
the context stack in order so that later items in the argument the context stack in order so that later items in the argument
......
...@@ -10,7 +10,7 @@ import unittest ...@@ -10,7 +10,7 @@ import unittest
from pystache.context import _NOT_FOUND from pystache.context import _NOT_FOUND
from pystache.context import _get_value from pystache.context import _get_value
from pystache.context import Context from pystache.context import ContextStack
from pystache.tests.common import AssertIsMixin from pystache.tests.common import AssertIsMixin
class SimpleObject(object): class SimpleObject(object):
...@@ -204,10 +204,10 @@ class GetValueTests(unittest.TestCase, AssertIsMixin): ...@@ -204,10 +204,10 @@ class GetValueTests(unittest.TestCase, AssertIsMixin):
self.assertNotFound(item2, 'pop') self.assertNotFound(item2, 'pop')
class ContextTests(unittest.TestCase, AssertIsMixin): class ContextStackTests(unittest.TestCase, AssertIsMixin):
""" """
Test the Context class. Test the ContextStack class.
""" """
...@@ -216,34 +216,34 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -216,34 +216,34 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Check that passing nothing to __init__() raises no exception. Check that passing nothing to __init__() raises no exception.
""" """
context = Context() context = ContextStack()
def test_init__many_elements(self): def test_init__many_elements(self):
""" """
Check that passing more than two items to __init__() raises no exception. Check that passing more than two items to __init__() raises no exception.
""" """
context = Context({}, {}, {}) context = ContextStack({}, {}, {})
def test__repr(self): def test__repr(self):
context = Context() context = ContextStack()
self.assertEqual(repr(context), 'Context()') self.assertEqual(repr(context), 'ContextStack()')
context = Context({'foo': 'bar'}) context = ContextStack({'foo': 'bar'})
self.assertEqual(repr(context), "Context({'foo': 'bar'},)") self.assertEqual(repr(context), "ContextStack({'foo': 'bar'},)")
context = Context({'foo': 'bar'}, {'abc': 123}) context = ContextStack({'foo': 'bar'}, {'abc': 123})
self.assertEqual(repr(context), "Context({'foo': 'bar'}, {'abc': 123})") self.assertEqual(repr(context), "ContextStack({'foo': 'bar'}, {'abc': 123})")
def test__str(self): def test__str(self):
context = Context() context = ContextStack()
self.assertEqual(str(context), 'Context()') self.assertEqual(str(context), 'ContextStack()')
context = Context({'foo': 'bar'}) context = ContextStack({'foo': 'bar'})
self.assertEqual(str(context), "Context({'foo': 'bar'},)") self.assertEqual(str(context), "ContextStack({'foo': 'bar'},)")
context = Context({'foo': 'bar'}, {'abc': 123}) context = ContextStack({'foo': 'bar'}, {'abc': 123})
self.assertEqual(str(context), "Context({'foo': 'bar'}, {'abc': 123})") self.assertEqual(str(context), "ContextStack({'foo': 'bar'}, {'abc': 123})")
## Test the static create() method. ## Test the static create() method.
...@@ -252,7 +252,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -252,7 +252,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test passing a dictionary. Test passing a dictionary.
""" """
context = Context.create({'foo': 'bar'}) context = ContextStack.create({'foo': 'bar'})
self.assertEqual(context.get('foo'), 'bar') self.assertEqual(context.get('foo'), 'bar')
def test_create__none(self): def test_create__none(self):
...@@ -260,7 +260,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -260,7 +260,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test passing None. Test passing None.
""" """
context = Context.create({'foo': 'bar'}, None) context = ContextStack.create({'foo': 'bar'}, None)
self.assertEqual(context.get('foo'), 'bar') self.assertEqual(context.get('foo'), 'bar')
def test_create__object(self): def test_create__object(self):
...@@ -270,16 +270,16 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -270,16 +270,16 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
""" """
class Foo(object): class Foo(object):
foo = 'bar' foo = 'bar'
context = Context.create(Foo()) context = ContextStack.create(Foo())
self.assertEqual(context.get('foo'), 'bar') self.assertEqual(context.get('foo'), 'bar')
def test_create__context(self): def test_create__context(self):
""" """
Test passing a Context instance. Test passing a ContextStack instance.
""" """
obj = Context({'foo': 'bar'}) obj = ContextStack({'foo': 'bar'})
context = Context.create(obj) context = ContextStack.create(obj)
self.assertEqual(context.get('foo'), 'bar') self.assertEqual(context.get('foo'), 'bar')
def test_create__kwarg(self): def test_create__kwarg(self):
...@@ -287,7 +287,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -287,7 +287,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test passing a keyword argument. Test passing a keyword argument.
""" """
context = Context.create(foo='bar') context = ContextStack.create(foo='bar')
self.assertEqual(context.get('foo'), 'bar') self.assertEqual(context.get('foo'), 'bar')
def test_create__precedence_positional(self): def test_create__precedence_positional(self):
...@@ -295,7 +295,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -295,7 +295,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test precedence of positional arguments. Test precedence of positional arguments.
""" """
context = Context.create({'foo': 'bar'}, {'foo': 'buzz'}) context = ContextStack.create({'foo': 'bar'}, {'foo': 'buzz'})
self.assertEqual(context.get('foo'), 'buzz') self.assertEqual(context.get('foo'), 'buzz')
def test_create__precedence_keyword(self): def test_create__precedence_keyword(self):
...@@ -303,7 +303,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -303,7 +303,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test precedence of keyword arguments. Test precedence of keyword arguments.
""" """
context = Context.create({'foo': 'bar'}, foo='buzz') context = ContextStack.create({'foo': 'bar'}, foo='buzz')
self.assertEqual(context.get('foo'), 'buzz') self.assertEqual(context.get('foo'), 'buzz')
def test_get__key_present(self): def test_get__key_present(self):
...@@ -311,7 +311,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -311,7 +311,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test getting a key. Test getting a key.
""" """
context = Context({"foo": "bar"}) context = ContextStack({"foo": "bar"})
self.assertEqual(context.get("foo"), "bar") self.assertEqual(context.get("foo"), "bar")
def test_get__key_missing(self): def test_get__key_missing(self):
...@@ -319,7 +319,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -319,7 +319,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test getting a missing key. Test getting a missing key.
""" """
context = Context() context = ContextStack()
self.assertTrue(context.get("foo") is None) self.assertTrue(context.get("foo") is None)
def test_get__default(self): def test_get__default(self):
...@@ -327,7 +327,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -327,7 +327,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test that get() respects the default value. Test that get() respects the default value.
""" """
context = Context() context = ContextStack()
self.assertEqual(context.get("foo", "bar"), "bar") self.assertEqual(context.get("foo", "bar"), "bar")
def test_get__precedence(self): def test_get__precedence(self):
...@@ -335,7 +335,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -335,7 +335,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Test that get() respects the order of precedence (later items first). Test that get() respects the order of precedence (later items first).
""" """
context = Context({"foo": "bar"}, {"foo": "buzz"}) context = ContextStack({"foo": "bar"}, {"foo": "buzz"})
self.assertEqual(context.get("foo"), "buzz") self.assertEqual(context.get("foo"), "buzz")
def test_get__fallback(self): def test_get__fallback(self):
...@@ -343,7 +343,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -343,7 +343,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
Check that first-added stack items are queried on context misses. Check that first-added stack items are queried on context misses.
""" """
context = Context({"fuzz": "buzz"}, {"foo": "bar"}) context = ContextStack({"fuzz": "buzz"}, {"foo": "bar"})
self.assertEqual(context.get("fuzz"), "buzz") self.assertEqual(context.get("fuzz"), "buzz")
def test_push(self): def test_push(self):
...@@ -352,7 +352,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -352,7 +352,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
""" """
key = "foo" key = "foo"
context = Context({key: "bar"}) context = ContextStack({key: "bar"})
self.assertEqual(context.get(key), "bar") self.assertEqual(context.get(key), "bar")
context.push({key: "buzz"}) context.push({key: "buzz"})
...@@ -364,7 +364,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -364,7 +364,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
""" """
key = "foo" key = "foo"
context = Context({key: "bar"}, {key: "buzz"}) context = ContextStack({key: "bar"}, {key: "buzz"})
self.assertEqual(context.get(key), "buzz") self.assertEqual(context.get(key), "buzz")
item = context.pop() item = context.pop()
...@@ -373,7 +373,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -373,7 +373,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
def test_top(self): def test_top(self):
key = "foo" key = "foo"
context = Context({key: "bar"}, {key: "buzz"}) context = ContextStack({key: "bar"}, {key: "buzz"})
self.assertEqual(context.get(key), "buzz") self.assertEqual(context.get(key), "buzz")
top = context.top() top = context.top()
...@@ -383,7 +383,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin): ...@@ -383,7 +383,7 @@ class ContextTests(unittest.TestCase, AssertIsMixin):
def test_copy(self): def test_copy(self):
key = "foo" key = "foo"
original = Context({key: "bar"}, {key: "buzz"}) original = ContextStack({key: "bar"}, {key: "buzz"})
self.assertEqual(original.get(key), "buzz") self.assertEqual(original.get(key), "buzz")
new = original.copy() new = original.copy()
......
...@@ -7,7 +7,7 @@ Unit tests of renderengine.py. ...@@ -7,7 +7,7 @@ Unit tests of renderengine.py.
import unittest import unittest
from pystache.context import Context from pystache.context import ContextStack
from pystache import defaults from pystache import defaults
from pystache.parser import ParsingError from pystache.parser import ParsingError
from pystache.renderengine import RenderEngine from pystache.renderengine import RenderEngine
...@@ -83,7 +83,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin): ...@@ -83,7 +83,7 @@ class RenderTests(unittest.TestCase, AssertStringMixin):
if partials is not None: if partials is not None:
engine.load_partial = lambda key: unicode(partials[key]) engine.load_partial = lambda key: unicode(partials[key])
context = Context(*context) context = ContextStack(*context)
actual = engine.render(template, context) actual = engine.render(template, context)
......
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