summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2014-01-22 03:09:29 -0500
committerChris McDonough <chrism@plope.com>2014-01-22 03:09:29 -0500
commitf58977a38ac65dce742dac38fe1179f61bfc3efc (patch)
tree81c7a359e4d8d81cec926636a3f3a8f4e1a6a546
parentdec681201ec50c261bde022ea09d24f09e3588bd (diff)
downloadpyramid-f58977a38ac65dce742dac38fe1179f61bfc3efc.tar.gz
pyramid-f58977a38ac65dce742dac38fe1179f61bfc3efc.tar.bz2
pyramid-f58977a38ac65dce742dac38fe1179f61bfc3efc.zip
- Fix a memory leak when the configurator's ``set_request_property`` method was
used or when the configurator's ``add_request_method`` method was used with the ``property=True`` attribute. See https://github.com/Pylons/pyramid/issues/1212 . Closes #1212
-rw-r--r--CHANGES.txt5
-rw-r--r--pyramid/util.py21
2 files changed, 26 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 9c38bf814..8a340f320 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,6 +15,11 @@ Bug Fixes
- Add a trailing semicolon to the JSONP response. This fixes JavaScript syntax
errors for old IE versions. See https://github.com/Pylons/pyramid/pull/1205
+- Fix a memory leak when the configurator's ``set_request_property`` method was
+ used or when the configurator's ``add_request_method`` method was used with
+ the ``property=True`` attribute. See
+ https://github.com/Pylons/pyramid/issues/1212 .
+
1.5a3 (2013-12-10)
==================
diff --git a/pyramid/util.py b/pyramid/util.py
index 73f3ebdb0..6b92f17fc 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -26,6 +26,8 @@ class DottedNameResolver(_DottedNameResolver):
def __init__(self, package=None): # default to package = None for bw compat
return _DottedNameResolver.__init__(self, package)
+_marker = object()
+
class InstancePropertyMixin(object):
""" Mixin that will allow an instance to add properties at
run-time as if they had been defined via @property or @reify
@@ -80,6 +82,25 @@ class InstancePropertyMixin(object):
if attrs:
parent = self.__class__
cls = type(parent.__name__, (parent, object), attrs)
+ # We assign __provides__, __implemented__ and __providedBy__ below
+ # to prevent a memory leak that results from from the usage of this
+ # instance's eventual use in an adapter lookup. Adapter lookup
+ # results in ``zope.interface.implementedBy`` being called with the
+ # newly-created class as an argument. Because the newly-created
+ # class has no interface specification data of its own, lookup
+ # causes new ClassProvides and Implements instances related to our
+ # just-generated class to be created and set into the newly-created
+ # class' __dict__. We don't want these instances to be created; we
+ # want this new class to behave exactly like it is the parent class
+ # instead. See https://github.com/Pylons/pyramid/issues/1212 for
+ # more information.
+ for name in ('__implemented__', '__providedBy__', '__provides__'):
+ # we assign these attributes conditionally to make it possible
+ # to test this class in isolation without having any interfaces
+ # attached to it
+ val = getattr(parent, name, _marker)
+ if val is not _marker:
+ setattr(cls, name, val)
self.__class__ = cls
def _set_extensions(self, extensions):