From b6e148dc678cad3bc63d64f41385114134e017be Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 11 Feb 2015 00:23:42 -0600 Subject: [PATCH 1/3] clone a new RendererHelper per request --- pyramid/config/views.py | 3 ++- pyramid/tests/test_config/test_views.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 1f69d7e0ba..338021c24f 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -348,7 +348,6 @@ def rendered_view(self, view): def _rendered_view(self, view, view_renderer): def rendered_view(context, request): - renderer = view_renderer result = view(context, request) if result.__class__ is Response: # potential common case response = result @@ -366,6 +365,8 @@ def rendered_view(context, request): name=renderer_name, package=self.kw.get('package'), registry = registry) + else: + renderer = view_renderer.clone() if '__view__' in attrs: view_inst = attrs.pop('__view__') else: diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py index b0d03fb723..ed5426b125 100644 --- a/pyramid/tests/test_config/test_views.py +++ b/pyramid/tests/test_config/test_views.py @@ -2534,6 +2534,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst, view) self.assertEqual(ctx, context) return response + def clone(self): + return self def view(request): return 'OK' deriver = self._makeOne(renderer=moo()) @@ -2571,6 +2573,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst, 'view') self.assertEqual(ctx, context) return response + def clone(self): + return self def view(request): return 'OK' deriver = self._makeOne(renderer=moo()) @@ -3165,6 +3169,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst.__class__, View) self.assertEqual(ctx, context) return response + def clone(self): + return self class View(object): def __init__(self, context, request): pass @@ -3189,6 +3195,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst.__class__, View) self.assertEqual(ctx, context) return response + def clone(self): + return self class View(object): def __init__(self, request): pass @@ -3213,6 +3221,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst.__class__, View) self.assertEqual(ctx, context) return response + def clone(self): + return self class View: def __init__(self, context, request): pass @@ -3237,6 +3247,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst.__class__, View) self.assertEqual(ctx, context) return response + def clone(self): + return self class View: def __init__(self, request): pass @@ -3261,6 +3273,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst, view) self.assertEqual(ctx, context) return response + def clone(self): + return self class View: def index(self, context, request): return {'a':'1'} @@ -3283,6 +3297,8 @@ def render_view(inself, req, resp, view_inst, ctx): self.assertEqual(view_inst, view) self.assertEqual(ctx, context) return response + def clone(self): + return self class View: def index(self, request): return {'a':'1'} From 06bb4a4db67321e7629f4f2438516ba358f226e9 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 11 Feb 2015 00:25:53 -0600 Subject: [PATCH 2/3] update changelog --- CHANGES.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 2dee64a84c..95566a54bf 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -128,6 +128,13 @@ Bug Fixes - Prevent "parameters to load are deprecated" ``DeprecationWarning`` from setuptools>=11.3. See https://github.com/Pylons/pyramid/pull/1541 +- Avoiding sharing the ``IRenderer`` objects across threads when attached to + a view using the `renderer=` argument. These renderers were instantiated + at time of first render and shared between requests, causing potentially + subtle effects like `pyramid.reload_templates = true` failing to work + in `pyramid_mako`. See https://github.com/Pylons/pyramid/pull/1575 + and https://github.com/Pylons/pyramid/issues/1268 + Deprecations ------------ From ec46918c86d4b1e82a1555ed488d453c65663549 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 5 Mar 2015 10:11:56 -0600 Subject: [PATCH 3/3] add clone to the IRendererInfo interface --- pyramid/interfaces.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 4c171f9cc2..bab91b0eed 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -382,6 +382,9 @@ class IRendererInfo(Interface): settings = Attribute('The deployment settings dictionary related ' 'to the current application') + def clone(): + """ Return a shallow copy that does not share any mutable state.""" + class IRendererFactory(Interface): def __call__(info): """ Return an object that implements