Chris McDonough
2015-04-12 b527a610f5426bbf63b32fe8865bcbd1b11d4799
Merge branch 'bertjwregeer-bug/request_subclassing'
2 files modified
73 ■■■■■ changed files
pyramid/tests/test_request.py 59 ●●●●● patch | view | raw | blame | history
pyramid/util.py 14 ●●●● patch | view | raw | blame | history
pyramid/tests/test_request.py
@@ -435,6 +435,7 @@
        self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded)
        self.assertEqual(request.environ['PATH_INFO'], '/' + encoded)
<<<<<<< HEAD
class Test_apply_request_extensions(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
@@ -478,6 +479,64 @@
class Dummy(object):
    pass
class Test_subclassing_Request(unittest.TestCase):
    def test_subclass(self):
        from pyramid.interfaces import IRequest
        from pyramid.request import Request
        from zope.interface import providedBy, implementedBy
        class RequestSub(Request):
            pass
        self.assertTrue(hasattr(Request, '__provides__'))
        self.assertTrue(hasattr(Request, '__implemented__'))
        self.assertTrue(hasattr(Request, '__providedBy__'))
        self.assertFalse(hasattr(RequestSub, '__provides__'))
        self.assertTrue(hasattr(RequestSub, '__providedBy__'))
        self.assertTrue(hasattr(RequestSub, '__implemented__'))
        self.assertTrue(IRequest.implementedBy(RequestSub))
        # The call to implementedBy will add __provides__ to the class
        self.assertTrue(hasattr(RequestSub, '__provides__'))
    def test_subclass_with_implementer(self):
        from pyramid.interfaces import IRequest
        from pyramid.request import Request
        from zope.interface import providedBy, implementedBy, implementer
        @implementer(IRequest)
        class RequestSub(Request):
            pass
        self.assertTrue(hasattr(Request, '__provides__'))
        self.assertTrue(hasattr(Request, '__implemented__'))
        self.assertTrue(hasattr(Request, '__providedBy__'))
        self.assertTrue(hasattr(RequestSub, '__provides__'))
        self.assertTrue(hasattr(RequestSub, '__providedBy__'))
        self.assertTrue(hasattr(RequestSub, '__implemented__'))
        req = RequestSub({})
        req._set_properties({'b': 'b'})
        self.assertTrue(IRequest.providedBy(req))
        self.assertTrue(IRequest.implementedBy(RequestSub))
    def test_subclass_mutate_before_providedBy(self):
        from pyramid.interfaces import IRequest
        from pyramid.request import Request
        from zope.interface import providedBy, implementedBy, implementer
        class RequestSub(Request):
            pass
        req = RequestSub({})
        req._set_properties({'b': 'b'})
        self.assertTrue(IRequest.providedBy(req))
        self.assertTrue(IRequest.implementedBy(RequestSub))
class DummyRequest(object):
    def __init__(self, environ=None):
        if environ is None:
pyramid/util.py
@@ -85,19 +85,19 @@
        if attrs:
            parent = target.__class__
            newcls = 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
            # We assign __provides__ and __implemented__ 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__'):
            # instead.  See GitHub issues #1212, #1529 and #1568 for more
            # information.
            for name in ('__implemented__', '__provides__'):
                # we assign these attributes conditionally to make it possible
                # to test this class in isolation without having any interfaces
                # attached to it