Mercurial > genshi > genshi-test
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:]): |