diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 4d7565ce9c..de6f8490eb 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -377,6 +377,14 @@ class ClearableFileInput(FileInput): """ Return whether value is considered to be initial value. """ + # hasattr() masks exceptions on Python 2. + if six.PY2: + try: + getattr(value, 'url') + except AttributeError: + return False + else: + return bool(value) return bool(value and hasattr(value, 'url')) def get_template_substitution_values(self, value): diff --git a/tests/forms_tests/tests/test_widgets.py b/tests/forms_tests/tests/test_widgets.py index 62a14dfa5c..5f552b03fd 100644 --- a/tests/forms_tests/tests/test_widgets.py +++ b/tests/forms_tests/tests/test_widgets.py @@ -1345,6 +1345,25 @@ class ClearableFileInputTests(TestCase): self.assertIn('my<div>file', output) self.assertNotIn('my
file', output) + def test_html_does_not_mask_exceptions(self): + """ + A ClearableFileInput should not mask exceptions produced while + checking that it has a value. + """ + @python_2_unicode_compatible + class FailingURLFieldFile(object): + @property + def url(self): + raise RuntimeError('Canary') + + def __str__(self): + return 'value' + + widget = ClearableFileInput() + field = FailingURLFieldFile() + with self.assertRaisesMessage(RuntimeError, 'Canary'): + widget.render('myfile', field) + def test_clear_input_renders_only_if_not_required(self): """ A ClearableFileInput with is_required=False does not render a clear