diff options
author | Marius Gedminas <marius@gedmin.as> | 2012-12-12 17:26:15 +0000 |
---|---|---|
committer | Marius Gedminas <marius@gedmin.as> | 2012-12-12 17:26:15 +0000 |
commit | e52caace792b6d399525d6f905f27d89415eb0df (patch) | |
tree | b8df96059d45aa81cedcaf80f5efec18d81544d0 /src | |
parent | acafb04f3d7de3e582ddfd17658f2b961e39748b (diff) | |
download | zope-pagetemplate-e52caace792b6d399525d6f905f27d89415eb0df.tar.gz |
Workaround for CPU-burning pt_errors() on a recursive template.
See https://bugs.launchpad.net/zope.pagetemplate/+bug/732972
This implements the short workaround version of the solution mentioned in the
bug: let's skip macro expansion checking while we're formatting an error
traceback (with the default recursion limit of 100 this still burns a lot of
CPU: ~20 seconds on a 2.5 GHz Core i5).
The test can be easily extended for the better suggested solution (some time in
the future): just drop check_macro_expansion=False and make sure METAL silently
stops recursing iff it notices a loop and TAL evaluation is disabled.
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/pagetemplate/pagetemplate.py | 13 | ||||
-rw-r--r-- | src/zope/pagetemplate/tests/input/recursive.html | 7 | ||||
-rw-r--r-- | src/zope/pagetemplate/tests/output/recursive.html | 14 | ||||
-rw-r--r-- | src/zope/pagetemplate/tests/test_htmltests.py | 14 |
4 files changed, 42 insertions, 6 deletions
diff --git a/src/zope/pagetemplate/pagetemplate.py b/src/zope/pagetemplate/pagetemplate.py index 9275737..f69e7b0 100644 --- a/src/zope/pagetemplate/pagetemplate.py +++ b/src/zope/pagetemplate/pagetemplate.py @@ -132,15 +132,16 @@ class PageTemplate(object): strictinsert=0, sourceAnnotations=sourceAnnotations ) - def pt_errors(self, namespace): + def pt_errors(self, namespace, check_macro_expansion=True): self._cook_check() err = self._v_errors if err: return err - try: - self.pt_render(namespace, source=1) - except: - return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2]) + if check_macro_expansion: + try: + self.pt_render(namespace, source=1) + except: + return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2]) def write(self, text): # We accept both, since the text can either come from a file (and the @@ -261,6 +262,6 @@ class PageTemplateTracebackSupplement(object): def __init__(self, pt, namespace): self.manageable_object = pt self.warnings = [] - e = pt.pt_errors(namespace) + e = pt.pt_errors(namespace, check_macro_expansion=False) if e: self.warnings.extend(e) diff --git a/src/zope/pagetemplate/tests/input/recursive.html b/src/zope/pagetemplate/tests/input/recursive.html new file mode 100644 index 0000000..9726867 --- /dev/null +++ b/src/zope/pagetemplate/tests/input/recursive.html @@ -0,0 +1,7 @@ +<!-- See https://bugs.launchpad.net/zope.pagetemplate/+bug/732972 --> +<ul metal:define-macro="tree"> + <li tal:content="context/name" /> + <li tal:repeat="context context/children"> + <ul metal:use-macro="template/macros/tree" /> + </li> +</ul> diff --git a/src/zope/pagetemplate/tests/output/recursive.html b/src/zope/pagetemplate/tests/output/recursive.html new file mode 100644 index 0000000..a251dcf --- /dev/null +++ b/src/zope/pagetemplate/tests/output/recursive.html @@ -0,0 +1,14 @@ +<!-- See https://bugs.launchpad.net/zope.pagetemplate/+bug/732972 --> +<ul> + <li>root</li> + <li> + <ul> + <li>first</li> +</ul> + </li> + <li> + <ul> + <li>second</li> +</ul> + </li> +</ul> diff --git a/src/zope/pagetemplate/tests/test_htmltests.py b/src/zope/pagetemplate/tests/test_htmltests.py index 34895f0..e0dc5ae 100644 --- a/src/zope/pagetemplate/tests/test_htmltests.py +++ b/src/zope/pagetemplate/tests/test_htmltests.py @@ -133,6 +133,20 @@ class HTMLTests(unittest.TestCase): out = t(msg=msg) util.check_html(expect, out) + def test_recursion(self): + t = self.folder.t + t.write(util.read_input('recursive.html')) + expect = util.read_output('recursive.html') + context = dict(name='root', + children=[dict(name='first', children=[]), + dict(name='second', children=[])]) + namespace = dict(template=t, options={}, args=(), + nothing=None, context=context) + out = t.pt_render(namespace) + util.check_html(expect, out) + # https://bugs.launchpad.net/zope.pagetemplate/+bug/732972 + errors = t.pt_errors(namespace, check_macro_expansion=False) + self.assertFalse(errors) def test_suite(): return unittest.makeSuite(HTMLTests) |