comparison markup/template.py @ 95:7d6426183a90

Improve performance of push/pop operations on the context.
author cmlenz
date Fri, 21 Jul 2006 11:35:56 +0000
parents f648152df7fd
children ef6794139671
comparison
equal deleted inserted replaced
94:80c72e936e72 95:7d6426183a90
75 TemplateError.__init__(self, 'Template "%s" not found' % name) 75 TemplateError.__init__(self, 'Template "%s" not found' % name)
76 self.search_path = search_path 76 self.search_path = search_path
77 77
78 78
79 class Context(object): 79 class Context(object):
80 """A container for template input data. 80 """Container for template input data.
81 81
82 A context provides a stack of scopes. Template directives such as loops can 82 A context provides a stack of scopes (represented by dictionaries).
83 push a new scope on the stack with data that should only be available 83
84 inside the loop. When the loop terminates, that scope can get popped off 84 Template directives such as loops can push a new scope on the stack with
85 the stack again. 85 data that should only be available inside the loop. When the loop
86 terminates, that scope can get popped off the stack again.
86 87
87 >>> ctxt = Context(one='foo', other=1) 88 >>> ctxt = Context(one='foo', other=1)
88 >>> ctxt.get('one') 89 >>> ctxt.get('one')
89 'foo' 90 'foo'
90 >>> ctxt.get('other') 91 >>> ctxt.get('other')
91 1 92 1
92 >>> ctxt.push(one='frost') 93 >>> ctxt.push(dict(one='frost'))
93 >>> ctxt.get('one') 94 >>> ctxt.get('one')
94 'frost' 95 'frost'
95 >>> ctxt.get('other') 96 >>> ctxt.get('other')
96 1 97 1
97 >>> ctxt.pop() 98 >>> ctxt.pop()
99 {'one': 'frost'}
98 >>> ctxt.get('one') 100 >>> ctxt.get('one')
99 'foo' 101 'foo'
100 """ 102 """
101 103
102 def __init__(self, **data): 104 def __init__(self, **data):
103 self.frames = deque([data]) 105 self.frames = deque([data])
106 self.pop = self.frames.popleft
107 self.push = self.frames.appendleft
104 108
105 def __repr__(self): 109 def __repr__(self):
106 return repr(self.frames) 110 return repr(self.frames)
107 111
108 def __setitem__(self, key, value): 112 def __setitem__(self, key, value):
109 """Set a variable in the current context.""" 113 """Set a variable in the current scope."""
110 self.frames[0][key] = value 114 self.frames[0][key] = value
111 115
112 def get(self, key): 116 def get(self, key):
113 """Get a variable's value, starting at the current context frame and 117 """Get a variable's value, starting at the current scope and going
114 going upward. 118 upward.
115 """ 119 """
116 for frame in self.frames: 120 for frame in self.frames:
117 if key in frame: 121 if key in frame:
118 return frame[key] 122 return frame[key]
119 __getitem__ = get 123 __getitem__ = get
120 124
121 def push(self, **data): 125 def push(self, data):
122 """Push a new context frame on the stack.""" 126 """Push a new scope on the stack."""
123 self.frames.appendleft(data)
124 127
125 def pop(self): 128 def pop(self):
126 """Pop the top-most context frame from the stack. 129 """Pop the top-most scope from the stack."""
127
128 If the stack is empty, an `AssertionError` is raised.
129 """
130 assert self.frames, 'Pop from empty context stack'
131 self.frames.popleft()
132 130
133 131
134 class Directive(object): 132 class Directive(object):
135 """Abstract base class for template directives. 133 """Abstract base class for template directives.
136 134
333 for name in self.args: 331 for name in self.args:
334 if args: 332 if args:
335 scope[name] = args.pop(0) 333 scope[name] = args.pop(0)
336 else: 334 else:
337 scope[name] = kwargs.pop(name, self.defaults.get(name)) 335 scope[name] = kwargs.pop(name, self.defaults.get(name))
338 ctxt.push(**scope) 336 ctxt.push(scope)
339 for event in _apply_directives(self.stream, ctxt, self.directives): 337 for event in _apply_directives(self.stream, ctxt, self.directives):
340 yield event 338 yield event
341 ctxt.pop() 339 ctxt.pop()
342 340
343 341
373 if len(targets) == 1: 371 if len(targets) == 1:
374 scope[targets[0]] = item 372 scope[targets[0]] = item
375 else: 373 else:
376 for idx, name in enumerate(targets): 374 for idx, name in enumerate(targets):
377 scope[name] = item[idx] 375 scope[name] = item[idx]
378 ctxt.push(**scope) 376 ctxt.push(scope)
379 for event in _apply_directives(stream, ctxt, directives): 377 for event in _apply_directives(stream, ctxt, directives):
380 yield event 378 yield event
381 ctxt.pop() 379 ctxt.pop()
382 380
383 def __repr__(self): 381 def __repr__(self):
572 570
573 def __call__(self, stream, ctxt, directives): 571 def __call__(self, stream, ctxt, directives):
574 if self.expr: 572 if self.expr:
575 self.value = self.expr.evaluate(ctxt) 573 self.value = self.expr.evaluate(ctxt)
576 self.matched = False 574 self.matched = False
577 ctxt.push(_choose=self) 575 ctxt.push(dict(_choose=self))
578 for event in _apply_directives(stream, ctxt, directives): 576 for event in _apply_directives(stream, ctxt, directives):
579 yield event 577 yield event
580 ctxt.pop() 578 ctxt.pop()
581 579
582 580
918 depth -= 1 916 depth -= 1
919 content.append((kind, data, pos)) 917 content.append((kind, data, pos))
920 test(kind, data, pos) 918 test(kind, data, pos)
921 919
922 content = list(self._flatten(content, ctxt)) 920 content = list(self._flatten(content, ctxt))
923 ctxt.push(select=lambda path: Stream(content).select(path)) 921 select = lambda path: Stream(content).select(path)
922 ctxt.push(dict(select=select))
924 923
925 template = _apply_directives(template, ctxt, directives) 924 template = _apply_directives(template, ctxt, directives)
926 for event in self._match(self._eval(template, ctxt), 925 for event in self._match(self._eval(template, ctxt),
927 ctxt, match_templates[:idx] + 926 ctxt, match_templates[:idx] +
928 match_templates[idx + 1:]): 927 match_templates[idx + 1:]):
Copyright (C) 2012-2017 Edgewall Software