diff options
| -rw-r--r-- | pyramid/tests/test_request.py | 59 | ||||
| -rw-r--r-- | pyramid/util.py | 14 |
2 files changed, 66 insertions, 7 deletions
diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index 79cf1abb8..257e70435 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -435,6 +435,7 @@ class Test_call_app_with_subpath_as_path_info(unittest.TestCase): 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 Test_apply_request_extensions(unittest.TestCase): 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: diff --git a/pyramid/util.py b/pyramid/util.py index 7a8af4899..4a722b381 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -85,19 +85,19 @@ class InstancePropertyHelper(object): 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 |
