# HG changeset patch # User cmlenz # Date 1152639641 0 # Node ID 0498da8e5de75c1082691a4a78492b8ad984887d # Parent e9a3930f8823737d32214c4202c84ba545c42daf Use `collections.deque` for the template context stack on Python 2.4, which improves performance if there are many context frame pop/push operations. diff --git a/markup/path.py b/markup/path.py --- a/markup/path.py +++ b/markup/path.py @@ -15,7 +15,7 @@ import re -from markup.core import QName, Stream +from markup.core import QName, Stream, START, END, TEXT __all__ = ['Path'] @@ -114,8 +114,6 @@ @param stream: the stream to select from @return: the substream matching the path, or an empty stream """ - from markup.core import END, START - stream = iter(stream) def _generate(): test = self.test() @@ -212,7 +210,7 @@ """Node test that matches the context node.""" axis = 'self' def __call__(self, kind, *_): - if kind is Stream.START: + if kind is START: return True return None @@ -220,7 +218,7 @@ """Node test that matches any child element.""" axis = 'child' def __call__(self, kind, *_): - if kind is Stream.START: + if kind is START: return True return None @@ -230,7 +228,7 @@ def __init__(self, name): self.name = QName(name) def __call__(self, kind, data, _): - if kind is Stream.START: + if kind is START: return data[0].localname == self.name return None def __repr__(self): @@ -240,10 +238,10 @@ """Node test that matches any attribute.""" axis = 'attribute' def __call__(self, kind, data, pos): - if kind is Stream.START: + if kind is START: text = ''.join([val for _, val in data[1]]) if text: - return Stream.TEXT, text, pos + return TEXT, text, pos return None return None @@ -253,9 +251,9 @@ def __init__(self, name): self.name = QName(name) def __call__(self, kind, data, pos): - if kind is Stream.START: + if kind is START: if self.name in data[1]: - return Stream.TEXT, data[1].get(self.name), pos + return TEXT, data[1].get(self.name), pos return None return None def __repr__(self): @@ -267,7 +265,7 @@ class _FunctionText(_Function): """Function that returns text content.""" def __call__(self, kind, data, pos): - if kind is Stream.TEXT: + if kind is TEXT: return kind, data, pos return None @@ -276,7 +274,7 @@ def __init__(self, value): self.value = value def __call__(self, *_): - return Stream.TEXT, self.value, (-1, -1) + return TEXT, self.value, (-1, -1) class _OperatorEq(_NodeTest): """Equality comparison operator.""" diff --git a/markup/template.py b/markup/template.py --- a/markup/template.py +++ b/markup/template.py @@ -38,6 +38,12 @@ * Could we generate byte code from expressions? """ +try: + from collections import deque +except ImportError: + class deque(list): + def appendleft(self, x): self.insert(0, x) + def popleft(self): return self.pop(0) import compiler import os import posixpath @@ -117,40 +123,35 @@ """ def __init__(self, **data): - self.stack = [data] - - def __getitem__(self, key): - """Get a variable's value, starting at the current context frame and - going upward. - """ - return self.get(key) + self.frames = deque([data]) def __repr__(self): - return repr(self.stack) + return repr(self.frames) def __setitem__(self, key, value): """Set a variable in the current context.""" - self.stack[0][key] = value + self.frames[0][key] = value def get(self, key): """Get a variable's value, starting at the current context frame and going upward. """ - for frame in self.stack: + for frame in self.frames: if key in frame: return frame[key] + __getitem__ = get def push(self, **data): """Push a new context frame on the stack.""" - self.stack.insert(0, data) + self.frames.appendleft(data) def pop(self): """Pop the top-most context frame from the stack. If the stack is empty, an `AssertionError` is raised. """ - assert self.stack, 'Pop from empty context stack' - self.stack.pop(0) + #assert self.frames, 'Pop from empty context stack' + self.frames.popleft() class Directive(object):