From e569144910e336d2f76a3a31998ec672377d31cc Mon Sep 17 00:00:00 2001 From: Hiroki KIYOHARA Date: Sat, 26 Jul 2014 12:01:44 +0200 Subject: [PATCH 1/2] Added test for the #23070 problem --- tests/view_tests/tests/test_debug.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 7d800ae5913c9..b41ce8b75c9af 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -660,6 +660,21 @@ def callable_setting(): response = self.client.get('/raises500/') self.assertNotContains(response, "This should not be displayed", status_code=500) + def test_callable_settings_forbidding_to_set_attributes(self): + """ + Callable settings which forbid to set attributes should not break + the debug page (#23070). + """ + class CallableSettingWithSlots(object): + __slots__ = [] + + def __call__(self): + return "This should not be displayed" + + with self.settings(DEBUG=True, WITH_SLOTS=CallableSettingWithSlots()): + response = self.client.get('/raises500/') + self.assertNotContains(response, "This should not be displayed", status_code=500) + def test_dict_setting_with_non_str_key(self): """ A dict setting containing a non-string key should not break the From d0889863de50d65659f56f0b9ea0672a8b6482a1 Mon Sep 17 00:00:00 2001 From: Hiroki KIYOHARA Date: Sat, 26 Jul 2014 12:06:48 +0200 Subject: [PATCH 2/2] Fixed code to solve #23070 problem Added a class to wrap callable in settings: * Not to call in the debug page (#21345). * Not to break the debug page if the callable forbidding to set attributes (#23070). Thanks @bmispelon for giving me some advice. --- django/views/debug.py | 16 +++++++++++++++- tests/view_tests/tests/test_debug.py | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/django/views/debug.py b/django/views/debug.py index ac81ecaf9e526..23bf16604dce4 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -33,6 +33,19 @@ def linebreak_iter(template_source): yield len(template_source) + 1 +class CallableSettingWrapper(object): + """ Object to wrap callable appearing in settings + + * Not to call in the debug page (#21345). + * Not to break the debug page if the callable forbidding to set attributes (#23070). + """ + def __init__(self, callable_setting): + self._wrapped = callable_setting + + def __repr__(self): + return repr(self._wrapped) + + def cleanse_setting(key, value): """Cleanse an individual setting key/value of sensitive content. @@ -52,7 +65,8 @@ def cleanse_setting(key, value): cleansed = value if callable(cleansed): - cleansed.do_not_call_in_templates = True + # For fixing #21345 and #23070 + cleansed = CallableSettingWrapper(cleansed) return cleansed diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index b41ce8b75c9af..3d51da9f94861 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -20,7 +20,7 @@ from django.test.utils import override_with_test_loader from django.utils.encoding import force_text, force_bytes from django.utils import six -from django.views.debug import ExceptionReporter +from django.views.debug import CallableSettingWrapper, ExceptionReporter from .. import BrokenException, except_args from ..views import (sensitive_view, non_sensitive_view, paranoid_view, @@ -29,6 +29,21 @@ multivalue_dict_key_error) +class CallableSettingWrapperTests(TestCase): + """ Unittests for CallableSettingWrapper + """ + def test_repr(self): + class WrappedCallable(object): + def __repr__(self): + return "repr from the wrapped callable" + + def __call__(self): + pass + + actual = repr(CallableSettingWrapper(WrappedCallable())) + self.assertEqual(actual, "repr from the wrapped callable") + + @override_settings(DEBUG=True, TEMPLATE_DEBUG=True, ROOT_URLCONF="view_tests.urls") class DebugViewTests(TestCase):