Skip to content
This repository
Browse code

small performance improvements

--HG--
branch : trunk
  • Loading branch information...
commit 19cf9c20518b04886d95c9cfa7feb61df166c01d 1 parent 7259c76
Armin Ronacher authored
6 docs/api.rst
Source Rendered
@@ -123,13 +123,13 @@ disallows all operations beside testing if it's an undefined object.
123 123 The Context
124 124 -----------
125 125
126   -.. autoclass:: jinja2.runtime.TemplateContext
  126 +.. autoclass:: jinja2.runtime.Context
127 127 :members: super, get, get_exported, get_all
128 128
129 129 .. attribute:: parent
130 130
131 131 A dict of read only, global variables the template looks up. These
132   - can either come from another :class:`TemplateContext`, from the
  132 + can either come from another :class:`Context`, from the
133 133 :attr:`Environment.globals` or :attr:`Template.globals`. It must not
134 134 be altered.
135 135
@@ -279,7 +279,7 @@ enabled::
279 279 return result
280 280
281 281 Context filters work the same just that the first argument is the current
282   -active :class:`TemplateContext` rather then the environment.
  282 +active :class:`Context` rather then the environment.
283 283
284 284
285 285 .. _writing-tests:
13 docs/templates.rst
Source Rendered
@@ -797,6 +797,19 @@ The following functions are available in the global scope by default:
797 797 For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
798 798 These are exactly the valid indices for a list of 4 elements.
799 799
  800 + This is useful to repeat a template block multiple times for example
  801 + to fill a list. Imagine you have 7 users in the list but you want to
  802 + render three empty items to enforce a height with CSS::
  803 +
  804 + <ul>
  805 + {% for user in users %}
  806 + <li>{{ user.username }}</li>
  807 + {% endfor %}
  808 + {% for number in range(10 - users|count) %}
  809 + <li class="empty"><span>...</span></li>
  810 + {% endfor %}
  811 + </ul>
  812 +
800 813 .. function:: lipsum(n=5, html=True, min=20, max=100)
801 814
802 815 Generates some lorem ipsum for the template. Per default five paragraphs
2  examples/bench.py
@@ -305,7 +305,7 @@ def test_spitfire():
305 305 stmt='bench()')
306 306 sys.stdout.write(' >> %-20s<running>' % test)
307 307 sys.stdout.flush()
308   - sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=20) / 20))
  308 + sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
309 309 sys.stdout.write('-' * 80 + '\n')
310 310 sys.stdout.write('''\
311 311 WARNING: The results of this benchmark are useless to compare the
13 jinja2/compiler.py
@@ -740,7 +740,8 @@ def visit_FromImport(self, node, frame):
740 740 self.writeline('if l_%s is missing:' % alias)
741 741 self.indent()
742 742 self.writeline('l_%s = environment.undefined(%r %% '
743   - 'included_template.name)' %
  743 + 'included_template.name, '
  744 + 'name=included_template.name)' %
744 745 (alias, 'the template %r does not export '
745 746 'the requested name ' + repr(name)))
746 747 self.outdent()
@@ -770,11 +771,11 @@ def visit_For(self, node, frame):
770 771 # the expression pointing to the parent loop. We make the
771 772 # undefined a bit more debug friendly at the same time.
772 773 parent_loop = 'loop' in aliases and aliases['loop'] \
773   - or "environment.undefined(%r)" % "'loop' is undefined. " \
774   - 'the filter section of a loop as well as the ' \
775   - 'else block doesn\'t have access to the special ' \
776   - "'loop' variable of the current loop. Because " \
777   - 'there is no parent loop it\'s undefined.'
  774 + or "environment.undefined(%r, name='loop')" % "'loop' " \
  775 + 'is undefined. "the filter section of a loop as well ' \
  776 + 'as the else block doesn\'t have access to the ' \
  777 + "special 'loop' variable of the current loop. " \
  778 + "Because there is no parent loop it's undefined."
778 779
779 780 # if we have an extened loop and a node test, we filter in the
780 781 # "outer frame".
43 jinja2/environment.py
@@ -5,7 +5,7 @@
5 5
6 6 Provides a class that holds runtime and parsing time options.
7 7
8   - :copyright: 2007 by Armin Ronacher.
  8 + :copyright: 2008 by Armin Ronacher.
9 9 :license: BSD, see LICENSE for more details.
10 10 """
11 11 import sys
@@ -14,7 +14,7 @@
14 14 from jinja2.parser import Parser
15 15 from jinja2.optimizer import optimize
16 16 from jinja2.compiler import generate
17   -from jinja2.runtime import Undefined, TemplateContext, concat
  17 +from jinja2.runtime import Undefined, Context, concat
18 18 from jinja2.debug import translate_exception
19 19 from jinja2.utils import import_string, LRUCache, Markup, missing
20 20
@@ -68,6 +68,7 @@ def _environment_sanity_check(environment):
68 68 environment.variable_start_string != \
69 69 environment.comment_start_string, 'block, variable and comment ' \
70 70 'start strings must be different'
  71 + return environment
71 72
72 73
73 74 class Environment(object):
@@ -148,6 +149,9 @@ class Environment(object):
148 149 #: True if the environment is just an overlay
149 150 overlay = False
150 151
  152 + #: the environment this environment is linked to if it is an overlay
  153 + linked_to = None
  154 +
151 155 #: shared environments have this set to `True`. A shared environment
152 156 #: must not be modified
153 157 shared = False
@@ -250,8 +254,7 @@ def overlay(self, block_start_string=missing, block_end_string=missing,
250 254 if extensions is not missing:
251 255 rv.extensions.extend(load_extensions(extensions))
252 256
253   - _environment_sanity_check(rv)
254   - return rv
  257 + return _environment_sanity_check(rv)
255 258
256 259 @property
257 260 def lexer(self):
@@ -456,22 +459,16 @@ def render(self, *args, **kwargs):
456 459 This will return the rendered template as unicode string.
457 460 """
458 461 try:
459   - return concat(self.generate(*args, **kwargs))
  462 + return concat(self._generate(*args, **kwargs))
460 463 except:
461   - # hide the `generate` frame
462   - exc_type, exc_value, tb = sys.exc_info()
463   - raise exc_type, exc_value, tb.tb_next
  464 + exc_type, exc_value, tb = translate_exception(sys.exc_info())
  465 + raise exc_type, exc_value, tb
464 466
465 467 def stream(self, *args, **kwargs):
466 468 """Works exactly like :meth:`generate` but returns a
467 469 :class:`TemplateStream`.
468 470 """
469   - try:
470   - return TemplateStream(self.generate(*args, **kwargs))
471   - except:
472   - # hide the `generate` frame
473   - exc_type, exc_value, tb = sys.exc_info()
474   - raise exc_type, exc_value, tb.tb_next
  471 + return TemplateStream(self.generate(*args, **kwargs))
475 472
476 473 def generate(self, *args, **kwargs):
477 474 """For very large templates it can be useful to not render the whole
@@ -481,6 +478,14 @@ def generate(self, *args, **kwargs):
481 478
482 479 It accepts the same arguments as :meth:`render`.
483 480 """
  481 + try:
  482 + for item in self._generate(*args, **kwargs):
  483 + yield item
  484 + except:
  485 + exc_type, exc_value, tb = translate_exception(sys.exc_info())
  486 + raise exc_type, exc_value, tb
  487 +
  488 + def _generate(self, *args, **kwargs):
484 489 # assemble the context
485 490 context = dict(*args, **kwargs)
486 491
@@ -498,12 +503,7 @@ def generate(self, *args, **kwargs):
498 503 'will lead to unexpected results.' %
499 504 (plural, ', '.join(overrides), plural or ' a', plural))
500 505
501   - try:
502   - for event in self.root_render_func(self.new_context(context)):
503   - yield event
504   - except:
505   - exc_type, exc_value, tb = translate_exception(sys.exc_info())
506   - raise exc_type, exc_value, tb
  506 + return self.root_render_func(self.new_context(context))
507 507
508 508 def new_context(self, vars=None, shared=False):
509 509 """Create a new template context for this template. The vars
@@ -519,8 +519,7 @@ def new_context(self, vars=None, shared=False):
519 519 parent = vars
520 520 else:
521 521 parent = dict(self.globals, **vars)
522   - return TemplateContext(self.environment, parent, self.name,
523   - self.blocks)
  522 + return Context(self.environment, parent, self.name, self.blocks)
524 523
525 524 @property
526 525 def module(self):
26 jinja2/runtime.py
@@ -16,8 +16,8 @@
16 16
17 17
18 18 # these variables are exported to the template runtime
19   -__all__ = ['LoopContext', 'TemplateContext', 'TemplateReference', 'Macro',
20   - 'TemplateRuntimeError', 'Markup', 'missing', 'concat', 'escape',
  19 +__all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
  20 + 'TemplateRuntimeError', 'missing', 'concat', 'escape',
21 21 'markup_join', 'unicode_join']
22 22
23 23
@@ -58,7 +58,7 @@ def unicode_join(*args):
58 58 return concat(imap(unicode, args))
59 59
60 60
61   -class TemplateContext(object):
  61 +class Context(object):
62 62 """The template context holds the variables of a template. It stores the
63 63 values passed to the template and also the names the template exports.
64 64 Creating instances is neither supported nor useful as it's created
@@ -105,7 +105,8 @@ def super(self, name, current):
105 105 raise IndexError()
106 106 except LookupError:
107 107 return self.environment.undefined('there is no parent block '
108   - 'called %r.' % name)
  108 + 'called %r.' % name,
  109 + name='super')
109 110 wrap = self.environment.autoescape and Markup or (lambda x: x)
110 111 render = lambda: wrap(concat(blocks[pos](self)))
111 112 render.__name__ = render.name = name
@@ -239,22 +240,19 @@ def __init__(self, environment, func, name, arguments, defaults,
239 240 self.caller = caller
240 241
241 242 def __call__(self, *args, **kwargs):
242   - if not self.catch_varargs and len(args) > self._argument_count:
243   - raise TypeError('macro %r takes not more than %d argument(s)' %
244   - (self.name, len(self.arguments)))
245 243 arguments = []
246 244 for idx, name in enumerate(self.arguments):
247 245 try:
248 246 value = args[idx]
249   - except IndexError:
  247 + except:
250 248 try:
251 249 value = kwargs.pop(name)
252   - except KeyError:
  250 + except:
253 251 try:
254 252 value = self.defaults[idx - self._argument_count]
255   - except IndexError:
  253 + except:
256 254 value = self._environment.undefined(
257   - 'parameter %r was not provided' % name)
  255 + 'parameter %r was not provided' % name, name=name)
258 256 arguments.append(value)
259 257
260 258 # it's important that the order of these arguments does not change
@@ -263,7 +261,8 @@ def __call__(self, *args, **kwargs):
263 261 if self.caller:
264 262 caller = kwargs.pop('caller', None)
265 263 if caller is None:
266   - caller = self._environment.undefined('No caller defined')
  264 + caller = self._environment.undefined('No caller defined',
  265 + name='caller')
267 266 arguments.append(caller)
268 267 if self.catch_kwargs:
269 268 arguments.append(kwargs)
@@ -272,6 +271,9 @@ def __call__(self, *args, **kwargs):
272 271 (self.name, iter(kwargs).next()))
273 272 if self.catch_varargs:
274 273 arguments.append(args[self._argument_count:])
  274 + elif len(args) > self._argument_count:
  275 + raise TypeError('macro %r takes not more than %d argument(s)' %
  276 + (self.name, len(self.arguments)))
275 277 return self._func(*arguments)
276 278
277 279 def __repr__(self):

0 comments on commit 19cf9c2

Please sign in to comment.
Something went wrong with that request. Please try again.