From d13c807616030b285589cec2fddf4e34a8e22b4a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 9 Feb 2015 17:02:54 +0000 Subject: Fix misleading AttributeErrors --- rest_framework/request.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index cfbbdecc..38fcf9c0 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -18,6 +18,7 @@ from django.utils.six import BytesIO from rest_framework import HTTP_HEADER_ENCODING from rest_framework import exceptions from rest_framework.settings import api_settings +import sys import warnings @@ -485,8 +486,16 @@ class Request(object): else: self.auth = None - def __getattr__(self, attr): + def __getattribute__(self, attr): """ - Proxy other attributes to the underlying HttpRequest object. + If an attribute does not exist on this instance, then we also attempt + to proxy it to the underlying HttpRequest object. """ - return getattr(self._request, attr) + try: + return super(Request, self).__getattribute__(attr) + except AttributeError: + info = sys.exc_info() + try: + return getattr(self._request, attr) + except AttributeError: + raise info[0], info[1], info[2].tb_next -- cgit v1.2.3 From 54d82f59ed8a5d2ad4c679680dc52b8a94831d50 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 9 Feb 2015 17:19:22 +0000 Subject: Py3 compat fix --- rest_framework/request.py | 8 ++++---- tests/test_request.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index 38fcf9c0..c4de9424 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -12,9 +12,9 @@ from __future__ import unicode_literals from django.conf import settings from django.http import QueryDict from django.http.multipartparser import parse_header +from django.utils import six from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MergeDict as DjangoMergeDict -from django.utils.six import BytesIO from rest_framework import HTTP_HEADER_ENCODING from rest_framework import exceptions from rest_framework.settings import api_settings @@ -363,7 +363,7 @@ class Request(object): elif hasattr(self._request, 'read'): self._stream = self._request else: - self._stream = BytesIO(self.raw_post_data) + self._stream = six.BytesIO(self.raw_post_data) def _perform_form_overloading(self): """ @@ -405,7 +405,7 @@ class Request(object): self._CONTENTTYPE_PARAM in self._data ): self._content_type = self._data[self._CONTENTTYPE_PARAM] - self._stream = BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding'])) + self._stream = six.BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding'])) self._data, self._files, self._full_data = (Empty, Empty, Empty) def _parse(self): @@ -498,4 +498,4 @@ class Request(object): try: return getattr(self._request, attr) except AttributeError: - raise info[0], info[1], info[2].tb_next + six.reraise(info[0], info[1], info[2].tb_next) diff --git a/tests/test_request.py b/tests/test_request.py index 02a9b1e2..06ad8e93 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -249,6 +249,26 @@ class TestUserSetter(TestCase): login(self.request, self.user) self.assertEqual(self.wrapped_request.user, self.user) + def test_calling_user_fails_when_attribute_error_is_raised(self): + """ + This proves that when an AttributeError is raised inside of the request.user + property, that we can handle this and report the true, underlying error. + """ + class AuthRaisesAttributeError(object): + def authenticate(self, request): + import rest_framework + rest_framework.MISSPELLED_NAME_THAT_DOESNT_EXIST + + self.request = Request(factory.get('/'), authenticators=(AuthRaisesAttributeError(),)) + SessionMiddleware().process_request(self.request) + + login(self.request, self.user) + try: + self.request.user + except AttributeError as error: + self.assertEqual(str(error), "'module' object has no attribute 'MISSPELLED_NAME_THAT_DOESNT_EXIST'") + else: + assert False, 'AttributeError not raised' class TestAuthSetter(TestCase): -- cgit v1.2.3 From 0669f507b3a63114cf429f0662b1781f0e1fa5f8 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 9 Feb 2015 17:22:13 +0000 Subject: pep8 fix --- tests/test_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_request.py b/tests/test_request.py index 06ad8e93..c274ab69 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -270,8 +270,8 @@ class TestUserSetter(TestCase): else: assert False, 'AttributeError not raised' -class TestAuthSetter(TestCase): +class TestAuthSetter(TestCase): def test_auth_can_be_set(self): request = Request(factory.get('/')) request.auth = 'DUMMY' -- cgit v1.2.3 From b2939c157d32e604e10099be891e382d8c54bbec Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 9 Feb 2015 17:43:20 +0000 Subject: Fixes for latest version of pep8 --- env/pip-selfcheck.json | 1 + rest_framework/templatetags/rest_framework.py | 4 +++- tests/test_authentication.py | 5 ++++- tests/test_relations_hyperlink.py | 4 +++- tests/test_renderers.py | 9 +++++++-- tests/test_response.py | 9 +++++++-- tests/test_throttling.py | 8 ++++++-- 7 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 env/pip-selfcheck.json diff --git a/env/pip-selfcheck.json b/env/pip-selfcheck.json new file mode 100644 index 00000000..db1087af --- /dev/null +++ b/env/pip-selfcheck.json @@ -0,0 +1 @@ +{"last_check":"2015-02-09T17:34:33Z","pypi_version":"6.0.8"} \ No newline at end of file diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index 69e03af4..d66ffb33 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -154,7 +154,9 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=True, autoescape=Tru If autoescape is True, the link text and URLs will get autoescaped. """ - trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x + def trim_url(x, limit=trim_url_limit): + return limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x + safe_input = isinstance(text, SafeData) words = word_split_re.split(force_text(text)) for i, word in enumerate(words): diff --git a/tests/test_authentication.py b/tests/test_authentication.py index caabcc21..19fe6043 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -205,7 +205,10 @@ class TokenAuthTests(TestCase): def test_post_json_makes_one_db_query(self): """Ensure that authenticating a user using a token performs only one DB query""" auth = "Token " + self.key - func_to_test = lambda: self.csrf_client.post('/token/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth) + + def func_to_test(): + return self.csrf_client.post('/token/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth) + self.assertNumQueries(1, func_to_test) def test_post_form_failing_token_auth(self): diff --git a/tests/test_relations_hyperlink.py b/tests/test_relations_hyperlink.py index f1b882ed..2230c275 100644 --- a/tests/test_relations_hyperlink.py +++ b/tests/test_relations_hyperlink.py @@ -12,7 +12,9 @@ factory = APIRequestFactory() request = factory.get('/') # Just to ensure we have a request in the serializer context -dummy_view = lambda request, pk: None +def dummy_view(request, pk): + pass + urlpatterns = patterns( '', diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 54eea8ce..4f41144e 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -28,8 +28,13 @@ import re DUMMYSTATUS = status.HTTP_200_OK DUMMYCONTENT = 'dummycontent' -RENDERER_A_SERIALIZER = lambda x: ('Renderer A: %s' % x).encode('ascii') -RENDERER_B_SERIALIZER = lambda x: ('Renderer B: %s' % x).encode('ascii') + +def RENDERER_A_SERIALIZER(x): + return ('Renderer A: %s' % x).encode('ascii') + + +def RENDERER_B_SERIALIZER(x): + return ('Renderer B: %s' % x).encode('ascii') expected_results = [ diff --git a/tests/test_response.py b/tests/test_response.py index f233ae33..4a9deaa2 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -38,8 +38,13 @@ class MockTextMediaRenderer(BaseRenderer): DUMMYSTATUS = status.HTTP_200_OK DUMMYCONTENT = 'dummycontent' -RENDERER_A_SERIALIZER = lambda x: ('Renderer A: %s' % x).encode('ascii') -RENDERER_B_SERIALIZER = lambda x: ('Renderer B: %s' % x).encode('ascii') + +def RENDERER_A_SERIALIZER(x): + return ('Renderer A: %s' % x).encode('ascii') + + +def RENDERER_B_SERIALIZER(x): + return ('Renderer B: %s' % x).encode('ascii') class RendererA(BaseRenderer): diff --git a/tests/test_throttling.py b/tests/test_throttling.py index cc36a004..50a53b3e 100644 --- a/tests/test_throttling.py +++ b/tests/test_throttling.py @@ -188,7 +188,9 @@ class ScopedRateThrottleTests(TestCase): class XYScopedRateThrottle(ScopedRateThrottle): TIMER_SECONDS = 0 THROTTLE_RATES = {'x': '3/min', 'y': '1/min'} - timer = lambda self: self.TIMER_SECONDS + + def timer(self): + return self.TIMER_SECONDS class XView(APIView): throttle_classes = (XYScopedRateThrottle,) @@ -290,7 +292,9 @@ class XffTestingBase(TestCase): class Throttle(ScopedRateThrottle): THROTTLE_RATES = {'test_limit': '1/day'} TIMER_SECONDS = 0 - timer = lambda self: self.TIMER_SECONDS + + def timer(self): + return self.TIMER_SECONDS class View(APIView): throttle_classes = (Throttle,) -- cgit v1.2.3 From 1a087c8c5bac6f157979ef9ff540c0eb23848fb4 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 9 Feb 2015 17:47:59 +0000 Subject: Fix .gitignore --- .gitignore | 18 +++++++----------- env/pip-selfcheck.json | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) delete mode 100644 env/pip-selfcheck.json diff --git a/.gitignore b/.gitignore index 2bdf8f7e..3d5f1043 100644 --- a/.gitignore +++ b/.gitignore @@ -3,18 +3,14 @@ *~ .* -site/ -htmlcov/ -coverage/ -build/ -dist/ -*.egg-info/ +/site/ +/htmlcov/ +/coverage/ +/build/ +/dist/ +/*.egg-info/ +/env/ MANIFEST -bin/ -include/ -lib/ -local/ - !.gitignore !.travis.yml diff --git a/env/pip-selfcheck.json b/env/pip-selfcheck.json deleted file mode 100644 index db1087af..00000000 --- a/env/pip-selfcheck.json +++ /dev/null @@ -1 +0,0 @@ -{"last_check":"2015-02-09T17:34:33Z","pypi_version":"6.0.8"} \ No newline at end of file -- cgit v1.2.3