From 525c704e14eb62b94c102802a98e92dbc0497329 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 10 Nov 2007 13:47:56 +0100 Subject: [PATCH] looking for a jinja memleak --HG-- branch : trunk --- jdebug.py | 21 ++++----------- jinja/parser.py | 52 +++++++++++++++++++++---------------- jinja/translators/python.py | 3 +-- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/jdebug.py b/jdebug.py index 5c4f781..219c876 100644 --- a/jdebug.py +++ b/jdebug.py @@ -19,21 +19,12 @@ from jinja.translators.python import PythonTranslator __all__ = ['e', 't', 'p', 'l', 'm'] + +_global_frame = sys._getframe() e = Environment() t = e.from_string -if os.environ.get('JDEBUG_SOURCEPRINT'): - original_translate = PythonTranslator.translate - - def debug_translate(self): - rv = original_translate(self) - sys.stderr.write('## GENERATED SOURCE:\n%s\n' % rv) - return rv - - PythonTranslator.translate = debug_translate - - def p(x=None, f=None): if x is None and f is not None: x = e.loader.get_source(f) @@ -53,17 +44,15 @@ class MemoryGuard(object): def freeze(self): self.clear() - self.update() - - def update(self): - self.guarded_objects.clear() for obj in gc.get_objects(): self.guarded_objects[id(obj)] = True def get_delta(self): + frm = sys._getframe() result = [] for obj in gc.get_objects(): - if id(obj) not in self.guarded_objects: + if id(obj) not in self.guarded_objects and \ + obj is not frm and obj is not result: result.append(obj) return result diff --git a/jinja/parser.py b/jinja/parser.py index 44ea954..40dccb2 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -1117,6 +1117,35 @@ class Parser(object): return assemble_list() + def sanitize_tree(self, body, extends): + self._sanitize_tree([body], [body], extends, body) + return body + + def _sanitize_tree(self, nodelist, stack, extends, body): + """ + This is not a closure because python leaks memory if it is. It's used + by `parse()` to make sure blocks do not trigger unexpected behavior. + """ + for node in nodelist: + if extends is not None and \ + node.__class__ is nodes.Block and \ + stack[-1] is not body: + for n in stack: + if n.__class__ is nodes.Block: + break + else: + raise TemplateSyntaxError('misplaced block %r, ' + 'blocks in child ' + 'templates must be ' + 'either top level or ' + 'located in a block ' + 'tag.' % node.name, + node.lineno, + self.filename) + stack.append(node) + self._sanitize_tree(node.get_child_nodes(), stack, extends, body) + stack.pop() + def parse(self): """ Parse the template and return a Template node. This also does some @@ -1142,28 +1171,7 @@ class Parser(object): if leading_whitespace: self.stream.shift(leading_whitespace) - body = self.subparse(None) - def walk(nodelist, stack): - for node in nodelist: - if extends is not None and \ - node.__class__ is nodes.Block and \ - stack[-1] is not body: - for n in stack: - if n.__class__ is nodes.Block: - break - else: - raise TemplateSyntaxError('misplaced block %r, ' - 'blocks in child ' - 'templates must be ' - 'either top level or ' - 'located in a block ' - 'tag.' % node.name, - node.lineno, - self.filename) - stack.append(node) - walk(node.get_child_nodes(), stack) - stack.pop() - walk([body], [body]) + body = self.sanitize_tree(self.subparse(None), extends) return nodes.Template(extends, body, 1, self.filename) finally: self.close() diff --git a/jinja/translators/python.py b/jinja/translators/python.py index f07fdc3..1f48a11 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -269,10 +269,9 @@ class PythonTranslator(Translator): if self.closed: raise RuntimeError('translator is closed') if node.__class__ in self.handlers: - out = self.handlers[node.__class__](node) + return self.handlers[node.__class__](node) else: raise AssertionError('unhandled node %r' % node.__class__) - return out def close(self): """ -- 2.26.2