From caf08867e1b23047455277abc3f7e697cb0b966a Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 9 Nov 2017 01:16:03 +0200 Subject: [PATCH 1/2] Implement HttpRequest proxying with __getattr__ for optimized access. --- rest_framework/request.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index 4f413e03f..5de6843bb 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -372,19 +372,23 @@ class Request(object): else: self.auth = None - def __getattribute__(self, attr): + def __getattr__(self, attr): """ If an attribute does not exist on this instance, then we also attempt to proxy it to the underlying HttpRequest object. """ try: - return super(Request, self).__getattribute__(attr) + return getattr(self._request, attr) except AttributeError: - info = sys.exc_info() + outer_info = sys.exc_info() + + # raise the 'original' AttributeError for the proxying Request object instead of the underlying + # HttpRequest object. try: - return getattr(self._request, attr) + self.__getattribute__(attr) except AttributeError: - six.reraise(info[0], info[1], info[2].tb_next) + inner_info = sys.exc_info() + six.reraise(inner_info[0], inner_info[1], outer_info[2].tb_next) @property def DATA(self): From 38b676e71a51c6cdc57323a23e4f82123e19f626 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 21 Nov 2017 18:05:16 +0200 Subject: [PATCH 2/2] Add tests for proxying WSGIRequest attributes in Request. --- tests/test_request.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_request.py b/tests/test_request.py index a87060df1..e8c04a01b 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -249,3 +249,28 @@ class TestSecure(TestCase): def test_default_secure_true(self): request = Request(factory.get('/', secure=True)) assert request.scheme == 'https' + + +class TestWSGIRequestProxy(TestCase): + def test_access_inner_property(self): + wsgi_request = factory.get('/') + + sentinel = object() + wsgi_request.__dict__['inner_property'] = sentinel + + request = Request(wsgi_request) + + assert request.inner_property is sentinel + + def test_access_outer_property(self): + wsgi_request = factory.get('/') + + inner_sentinel = object() + wsgi_request.__dict__['inner_property'] = inner_sentinel + + request = Request(wsgi_request) + + outer_sentinel = object() + request.__dict__['inner_property'] = outer_sentinel + + assert request.inner_property is outer_sentinel