From 19f4425cb4ef33113049eeee59b7c42f57d45d0d Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 21 Nov 2017 18:05:16 +0200 Subject: [PATCH 1/3] Add tests for proxying WSGIRequest attributes in Request. --- tests/test_request.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_request.py b/tests/test_request.py index a87060df10..6726fa914b 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -249,3 +249,17 @@ def test_default_secure_false(self): def test_default_secure_true(self): request = Request(factory.get('/', secure=True)) assert request.scheme == 'https' + + +class TestWSGIRequestProxy(TestCase): + def test_attribute_access(self): + wsgi_request = factory.get('/') + request = Request(wsgi_request) + + inner_sentinel = object() + wsgi_request.inner_property = inner_sentinel + assert request.inner_property is inner_sentinel + + outer_sentinel = object() + request.inner_property = outer_sentinel + assert request.inner_property is outer_sentinel From 03c581eee3e0b7b7a9b843337774e5d72d7ee960 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Wed, 22 Nov 2017 01:37:56 -0500 Subject: [PATCH 2/3] Add request attribute exception test --- tests/test_request.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_request.py b/tests/test_request.py index 6726fa914b..cbadb14678 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -263,3 +263,12 @@ def test_attribute_access(self): outer_sentinel = object() request.inner_property = outer_sentinel assert request.inner_property is outer_sentinel + + def test_exception(self): + # ensure the exception message is not for the underlying WSGIRequest + wsgi_request = factory.get('/') + request = Request(wsgi_request) + + message = "'Request' object has no attribute 'inner_property'" + with self.assertRaisesMessage(AttributeError, message): + request.inner_property From 6d397f7a2d542e437d56d47a6d9ecb242a506718 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Wed, 22 Nov 2017 01:41:44 -0500 Subject: [PATCH 3/3] Reimplement request attribute access --- rest_framework/request.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index f9503cd593..9446910399 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -10,8 +10,6 @@ """ from __future__ import unicode_literals -import sys - from django.conf import settings from django.http import QueryDict from django.http.multipartparser import parse_header @@ -373,19 +371,15 @@ def _not_authenticated(self): 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() - try: - return getattr(self._request, attr) - except AttributeError: - six.reraise(info[0], info[1], info[2].tb_next) + return self.__getattribute__(attr) @property def DATA(self):