diff options
| author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
| commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
| tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/forms_tests | |
| parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/forms_tests')
69 files changed, 5883 insertions, 4062 deletions
diff --git a/tests/forms_tests/field_tests/__init__.py b/tests/forms_tests/field_tests/__init__.py index 4aae30282b..94b2a91242 100644 --- a/tests/forms_tests/field_tests/__init__.py +++ b/tests/forms_tests/field_tests/__init__.py @@ -2,8 +2,8 @@ from django import forms class FormFieldAssertionsMixin: - def assertWidgetRendersTo(self, field, to): class Form(forms.Form): f = field - self.assertHTMLEqual(str(Form()['f']), to) + + self.assertHTMLEqual(str(Form()["f"]), to) diff --git a/tests/forms_tests/field_tests/test_base.py b/tests/forms_tests/field_tests/test_base.py index 4ddbea3414..201e05e47e 100644 --- a/tests/forms_tests/field_tests/test_base.py +++ b/tests/forms_tests/field_tests/test_base.py @@ -3,7 +3,6 @@ from django.test import SimpleTestCase class BasicFieldsTests(SimpleTestCase): - def test_field_sets_widget_is_required(self): self.assertTrue(Field(required=True).widget.is_required) self.assertFalse(Field(required=False).widget.is_required) @@ -23,20 +22,20 @@ class BasicFieldsTests(SimpleTestCase): def test_field_deepcopies_widget_instance(self): class CustomChoiceField(ChoiceField): - widget = Select(attrs={'class': 'my-custom-class'}) + widget = Select(attrs={"class": "my-custom-class"}) class TestForm(Form): field1 = CustomChoiceField(choices=[]) field2 = CustomChoiceField(choices=[]) f = TestForm() - f.fields['field1'].choices = [('1', '1')] - f.fields['field2'].choices = [('2', '2')] - self.assertEqual(f.fields['field1'].widget.choices, [('1', '1')]) - self.assertEqual(f.fields['field2'].widget.choices, [('2', '2')]) + f.fields["field1"].choices = [("1", "1")] + f.fields["field2"].choices = [("2", "2")] + self.assertEqual(f.fields["field1"].widget.choices, [("1", "1")]) + self.assertEqual(f.fields["field2"].widget.choices, [("2", "2")]) class DisabledFieldTests(SimpleTestCase): def test_disabled_field_has_changed_always_false(self): disabled_field = Field(disabled=True) - self.assertFalse(disabled_field.has_changed('x', 'y')) + self.assertFalse(disabled_field.has_changed("x", "y")) diff --git a/tests/forms_tests/field_tests/test_booleanfield.py b/tests/forms_tests/field_tests/test_booleanfield.py index b0153e9e0b..560a0f473b 100644 --- a/tests/forms_tests/field_tests/test_booleanfield.py +++ b/tests/forms_tests/field_tests/test_booleanfield.py @@ -6,11 +6,10 @@ from django.test import SimpleTestCase class BooleanFieldTest(SimpleTestCase): - def test_booleanfield_clean_1(self): f = BooleanField() with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) self.assertTrue(f.clean(True)) @@ -19,25 +18,25 @@ class BooleanFieldTest(SimpleTestCase): self.assertTrue(f.clean(1)) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(0) - self.assertTrue(f.clean('Django rocks')) - self.assertTrue(f.clean('True')) + self.assertTrue(f.clean("Django rocks")) + self.assertTrue(f.clean("True")) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('False') + f.clean("False") def test_booleanfield_clean_2(self): f = BooleanField(required=False) - self.assertIs(f.clean(''), False) + self.assertIs(f.clean(""), False) self.assertIs(f.clean(None), False) self.assertIs(f.clean(True), True) self.assertIs(f.clean(False), False) self.assertIs(f.clean(1), True) self.assertIs(f.clean(0), False) - self.assertIs(f.clean('1'), True) - self.assertIs(f.clean('0'), False) - self.assertIs(f.clean('Django rocks'), True) - self.assertIs(f.clean('False'), False) - self.assertIs(f.clean('false'), False) - self.assertIs(f.clean('FaLsE'), False) + self.assertIs(f.clean("1"), True) + self.assertIs(f.clean("0"), False) + self.assertIs(f.clean("Django rocks"), True) + self.assertIs(f.clean("False"), False) + self.assertIs(f.clean("false"), False) + self.assertIs(f.clean("FaLsE"), False) def test_boolean_picklable(self): self.assertIsInstance(pickle.loads(pickle.dumps(BooleanField())), BooleanField) @@ -45,20 +44,20 @@ class BooleanFieldTest(SimpleTestCase): def test_booleanfield_changed(self): f = BooleanField() self.assertFalse(f.has_changed(None, None)) - self.assertFalse(f.has_changed(None, '')) - self.assertFalse(f.has_changed('', None)) - self.assertFalse(f.has_changed('', '')) - self.assertTrue(f.has_changed(False, 'on')) - self.assertFalse(f.has_changed(True, 'on')) - self.assertTrue(f.has_changed(True, '')) + self.assertFalse(f.has_changed(None, "")) + self.assertFalse(f.has_changed("", None)) + self.assertFalse(f.has_changed("", "")) + self.assertTrue(f.has_changed(False, "on")) + self.assertFalse(f.has_changed(True, "on")) + self.assertTrue(f.has_changed(True, "")) # Initial value may have mutated to a string due to show_hidden_initial (#19537) - self.assertTrue(f.has_changed('False', 'on')) + self.assertTrue(f.has_changed("False", "on")) # HiddenInput widget sends string values for boolean but doesn't clean them in value_from_datadict - self.assertFalse(f.has_changed(False, 'False')) - self.assertFalse(f.has_changed(True, 'True')) - self.assertTrue(f.has_changed(False, 'True')) - self.assertTrue(f.has_changed(True, 'False')) + self.assertFalse(f.has_changed(False, "False")) + self.assertFalse(f.has_changed(True, "True")) + self.assertTrue(f.has_changed(False, "True")) + self.assertTrue(f.has_changed(True, "False")) def test_disabled_has_changed(self): f = BooleanField(disabled=True) - self.assertIs(f.has_changed('True', 'False'), False) + self.assertIs(f.has_changed("True", "False"), False) diff --git a/tests/forms_tests/field_tests/test_charfield.py b/tests/forms_tests/field_tests/test_charfield.py index 352761deec..2c3f9b7ebe 100644 --- a/tests/forms_tests/field_tests/test_charfield.py +++ b/tests/forms_tests/field_tests/test_charfield.py @@ -1,66 +1,63 @@ from django.core.exceptions import ValidationError -from django.forms import ( - CharField, HiddenInput, PasswordInput, Textarea, TextInput, -) +from django.forms import CharField, HiddenInput, PasswordInput, Textarea, TextInput from django.test import SimpleTestCase from . import FormFieldAssertionsMixin class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_charfield_1(self): f = CharField() - self.assertEqual('1', f.clean(1)) - self.assertEqual('hello', f.clean('hello')) + self.assertEqual("1", f.clean(1)) + self.assertEqual("hello", f.clean("hello")) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') - self.assertEqual('[1, 2, 3]', f.clean([1, 2, 3])) + f.clean("") + self.assertEqual("[1, 2, 3]", f.clean([1, 2, 3])) self.assertIsNone(f.max_length) self.assertIsNone(f.min_length) def test_charfield_2(self): f = CharField(required=False) - self.assertEqual('1', f.clean(1)) - self.assertEqual('hello', f.clean('hello')) - self.assertEqual('', f.clean(None)) - self.assertEqual('', f.clean('')) - self.assertEqual('[1, 2, 3]', f.clean([1, 2, 3])) + self.assertEqual("1", f.clean(1)) + self.assertEqual("hello", f.clean("hello")) + self.assertEqual("", f.clean(None)) + self.assertEqual("", f.clean("")) + self.assertEqual("[1, 2, 3]", f.clean([1, 2, 3])) self.assertIsNone(f.max_length) self.assertIsNone(f.min_length) def test_charfield_3(self): f = CharField(max_length=10, required=False) - self.assertEqual('12345', f.clean('12345')) - self.assertEqual('1234567890', f.clean('1234567890')) + self.assertEqual("12345", f.clean("12345")) + self.assertEqual("1234567890", f.clean("1234567890")) msg = "'Ensure this value has at most 10 characters (it has 11).'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('1234567890a') + f.clean("1234567890a") self.assertEqual(f.max_length, 10) self.assertIsNone(f.min_length) def test_charfield_4(self): f = CharField(min_length=10, required=False) - self.assertEqual('', f.clean('')) + self.assertEqual("", f.clean("")) msg = "'Ensure this value has at least 10 characters (it has 5).'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('12345') - self.assertEqual('1234567890', f.clean('1234567890')) - self.assertEqual('1234567890a', f.clean('1234567890a')) + f.clean("12345") + self.assertEqual("1234567890", f.clean("1234567890")) + self.assertEqual("1234567890a", f.clean("1234567890a")) self.assertIsNone(f.max_length) self.assertEqual(f.min_length, 10) def test_charfield_5(self): f = CharField(min_length=10, required=True) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") msg = "'Ensure this value has at least 10 characters (it has 5).'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('12345') - self.assertEqual('1234567890', f.clean('1234567890')) - self.assertEqual('1234567890a', f.clean('1234567890a')) + f.clean("12345") + self.assertEqual("1234567890", f.clean("1234567890")) + self.assertEqual("1234567890a", f.clean("1234567890a")) self.assertIsNone(f.max_length) self.assertEqual(f.min_length, 10) @@ -70,12 +67,12 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): raises an exception. """ with self.assertRaises(ValueError): - CharField(min_length='a') + CharField(min_length="a") with self.assertRaises(ValueError): - CharField(max_length='a') - msg = '__init__() takes 1 positional argument but 2 were given' + CharField(max_length="a") + msg = "__init__() takes 1 positional argument but 2 were given" with self.assertRaisesMessage(TypeError, msg): - CharField('a') + CharField("a") def test_charfield_widget_attrs(self): """ @@ -90,22 +87,28 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): # Return a maxlength attribute equal to max_length. f = CharField(max_length=10) - self.assertEqual(f.widget_attrs(TextInput()), {'maxlength': '10'}) - self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10'}) - self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10'}) + self.assertEqual(f.widget_attrs(TextInput()), {"maxlength": "10"}) + self.assertEqual(f.widget_attrs(PasswordInput()), {"maxlength": "10"}) + self.assertEqual(f.widget_attrs(Textarea()), {"maxlength": "10"}) # Return a minlength attribute equal to min_length. f = CharField(min_length=5) - self.assertEqual(f.widget_attrs(TextInput()), {'minlength': '5'}) - self.assertEqual(f.widget_attrs(PasswordInput()), {'minlength': '5'}) - self.assertEqual(f.widget_attrs(Textarea()), {'minlength': '5'}) + self.assertEqual(f.widget_attrs(TextInput()), {"minlength": "5"}) + self.assertEqual(f.widget_attrs(PasswordInput()), {"minlength": "5"}) + self.assertEqual(f.widget_attrs(Textarea()), {"minlength": "5"}) # Return both maxlength and minlength when both max_length and # min_length are set. f = CharField(max_length=10, min_length=5) - self.assertEqual(f.widget_attrs(TextInput()), {'maxlength': '10', 'minlength': '5'}) - self.assertEqual(f.widget_attrs(PasswordInput()), {'maxlength': '10', 'minlength': '5'}) - self.assertEqual(f.widget_attrs(Textarea()), {'maxlength': '10', 'minlength': '5'}) + self.assertEqual( + f.widget_attrs(TextInput()), {"maxlength": "10", "minlength": "5"} + ) + self.assertEqual( + f.widget_attrs(PasswordInput()), {"maxlength": "10", "minlength": "5"} + ) + self.assertEqual( + f.widget_attrs(Textarea()), {"maxlength": "10", "minlength": "5"} + ) self.assertEqual(f.widget_attrs(HiddenInput()), {}) def test_charfield_strip(self): @@ -113,12 +116,12 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): Values have whitespace stripped but not if strip=False. """ f = CharField() - self.assertEqual(f.clean(' 1'), '1') - self.assertEqual(f.clean('1 '), '1') + self.assertEqual(f.clean(" 1"), "1") + self.assertEqual(f.clean("1 "), "1") f = CharField(strip=False) - self.assertEqual(f.clean(' 1'), ' 1') - self.assertEqual(f.clean('1 '), '1 ') + self.assertEqual(f.clean(" 1"), " 1") + self.assertEqual(f.clean("1 "), "1 ") def test_strip_before_checking_empty(self): """ @@ -126,10 +129,11 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): converted to the empty value, None. """ f = CharField(required=False, empty_value=None) - self.assertIsNone(f.clean(' ')) + self.assertIsNone(f.clean(" ")) def test_clean_non_string(self): """CharField.clean() calls str(value) before stripping it.""" + class StringWrapper: def __init__(self, v): self.v = v @@ -137,18 +141,20 @@ class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def __str__(self): return self.v - value = StringWrapper(' ') + value = StringWrapper(" ") f1 = CharField(required=False, empty_value=None) self.assertIsNone(f1.clean(value)) f2 = CharField(strip=False) - self.assertEqual(f2.clean(value), ' ') + self.assertEqual(f2.clean(value), " ") def test_charfield_disabled(self): f = CharField(disabled=True) - self.assertWidgetRendersTo(f, '<input type="text" name="f" id="id_f" disabled required>') + self.assertWidgetRendersTo( + f, '<input type="text" name="f" id="id_f" disabled required>' + ) def test_null_characters_prohibited(self): f = CharField() - msg = 'Null characters are not allowed.' + msg = "Null characters are not allowed." with self.assertRaisesMessage(ValidationError, msg): - f.clean('\x00something') + f.clean("\x00something") diff --git a/tests/forms_tests/field_tests/test_choicefield.py b/tests/forms_tests/field_tests/test_choicefield.py index f25e2cedfd..bc580bbf02 100644 --- a/tests/forms_tests/field_tests/test_choicefield.py +++ b/tests/forms_tests/field_tests/test_choicefield.py @@ -7,52 +7,52 @@ from . import FormFieldAssertionsMixin class ChoiceFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_choicefield_1(self): - f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')]) + f = ChoiceField(choices=[("1", "One"), ("2", "Two")]) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual('1', f.clean(1)) - self.assertEqual('1', f.clean('1')) + self.assertEqual("1", f.clean(1)) + self.assertEqual("1", f.clean("1")) msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('3') + f.clean("3") def test_choicefield_2(self): - f = ChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False) - self.assertEqual('', f.clean('')) - self.assertEqual('', f.clean(None)) - self.assertEqual('1', f.clean(1)) - self.assertEqual('1', f.clean('1')) + f = ChoiceField(choices=[("1", "One"), ("2", "Two")], required=False) + self.assertEqual("", f.clean("")) + self.assertEqual("", f.clean(None)) + self.assertEqual("1", f.clean(1)) + self.assertEqual("1", f.clean("1")) msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('3') + f.clean("3") def test_choicefield_3(self): - f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')]) - self.assertEqual('J', f.clean('J')) + f = ChoiceField(choices=[("J", "John"), ("P", "Paul")]) + self.assertEqual("J", f.clean("J")) msg = "'Select a valid choice. John is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('John') + f.clean("John") def test_choicefield_4(self): f = ChoiceField( choices=[ - ('Numbers', (('1', 'One'), ('2', 'Two'))), - ('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other'), + ("Numbers", (("1", "One"), ("2", "Two"))), + ("Letters", (("3", "A"), ("4", "B"))), + ("5", "Other"), ] ) - self.assertEqual('1', f.clean(1)) - self.assertEqual('1', f.clean('1')) - self.assertEqual('3', f.clean(3)) - self.assertEqual('3', f.clean('3')) - self.assertEqual('5', f.clean(5)) - self.assertEqual('5', f.clean('5')) + self.assertEqual("1", f.clean(1)) + self.assertEqual("1", f.clean("1")) + self.assertEqual("3", f.clean(3)) + self.assertEqual("3", f.clean("3")) + self.assertEqual("5", f.clean(5)) + self.assertEqual("5", f.clean("5")) msg = "'Select a valid choice. 6 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('6') + f.clean("6") def test_choicefield_choices_default(self): f = ChoiceField() @@ -60,9 +60,10 @@ class ChoiceFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_choicefield_callable(self): def choices(): - return [('J', 'John'), ('P', 'Paul')] + return [("J", "John"), ("P", "Paul")] + f = ChoiceField(choices=choices) - self.assertEqual('J', f.clean('J')) + self.assertEqual("J", f.clean("J")) def test_choicefield_callable_may_evaluate_to_different_values(self): choices = [] @@ -73,29 +74,29 @@ class ChoiceFieldTest(FormFieldAssertionsMixin, SimpleTestCase): class ChoiceFieldForm(Form): choicefield = ChoiceField(choices=choices_as_callable) - choices = [('J', 'John')] + choices = [("J", "John")] form = ChoiceFieldForm() - self.assertEqual([('J', 'John')], list(form.fields['choicefield'].choices)) + self.assertEqual([("J", "John")], list(form.fields["choicefield"].choices)) - choices = [('P', 'Paul')] + choices = [("P", "Paul")] form = ChoiceFieldForm() - self.assertEqual([('P', 'Paul')], list(form.fields['choicefield'].choices)) + self.assertEqual([("P", "Paul")], list(form.fields["choicefield"].choices)) def test_choicefield_disabled(self): - f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')], disabled=True) + f = ChoiceField(choices=[("J", "John"), ("P", "Paul")], disabled=True) self.assertWidgetRendersTo( f, '<select id="id_f" name="f" disabled><option value="J">John</option>' - '<option value="P">Paul</option></select>' + '<option value="P">Paul</option></select>', ) def test_choicefield_enumeration(self): class FirstNames(models.TextChoices): - JOHN = 'J', 'John' - PAUL = 'P', 'Paul' + JOHN = "J", "John" + PAUL = "P", "Paul" f = ChoiceField(choices=FirstNames.choices) - self.assertEqual(f.clean('J'), 'J') + self.assertEqual(f.clean("J"), "J") msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('3') + f.clean("3") diff --git a/tests/forms_tests/field_tests/test_combofield.py b/tests/forms_tests/field_tests/test_combofield.py index 481783fe2e..d433fdf2b3 100644 --- a/tests/forms_tests/field_tests/test_combofield.py +++ b/tests/forms_tests/field_tests/test_combofield.py @@ -4,25 +4,34 @@ from django.test import SimpleTestCase class ComboFieldTest(SimpleTestCase): - def test_combofield_1(self): f = ComboField(fields=[CharField(max_length=20), EmailField()]) - self.assertEqual('test@example.com', f.clean('test@example.com')) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 28).'"): - f.clean('longemailaddress@example.com') - with self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'"): - f.clean('not an email') + self.assertEqual("test@example.com", f.clean("test@example.com")) + with self.assertRaisesMessage( + ValidationError, + "'Ensure this value has at most 20 characters (it has 28).'", + ): + f.clean("longemailaddress@example.com") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid email address.'" + ): + f.clean("not an email") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) def test_combofield_2(self): f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False) - self.assertEqual('test@example.com', f.clean('test@example.com')) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 28).'"): - f.clean('longemailaddress@example.com') - with self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'"): - f.clean('not an email') - self.assertEqual('', f.clean('')) - self.assertEqual('', f.clean(None)) + self.assertEqual("test@example.com", f.clean("test@example.com")) + with self.assertRaisesMessage( + ValidationError, + "'Ensure this value has at most 20 characters (it has 28).'", + ): + f.clean("longemailaddress@example.com") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid email address.'" + ): + f.clean("not an email") + self.assertEqual("", f.clean("")) + self.assertEqual("", f.clean(None)) diff --git a/tests/forms_tests/field_tests/test_datefield.py b/tests/forms_tests/field_tests/test_datefield.py index 10d77bf1bb..a9f93f40ed 100644 --- a/tests/forms_tests/field_tests/test_datefield.py +++ b/tests/forms_tests/field_tests/test_datefield.py @@ -11,174 +11,195 @@ class GetDate(Form): class DateFieldTest(SimpleTestCase): - def test_form_field(self): - a = GetDate({'mydate_month': '4', 'mydate_day': '1', 'mydate_year': '2008'}) + a = GetDate({"mydate_month": "4", "mydate_day": "1", "mydate_year": "2008"}) self.assertTrue(a.is_valid()) - self.assertEqual(a.cleaned_data['mydate'], date(2008, 4, 1)) + self.assertEqual(a.cleaned_data["mydate"], date(2008, 4, 1)) # As with any widget that implements get_value_from_datadict(), we must # accept the input from the "as_hidden" rendering as well. self.assertHTMLEqual( - a['mydate'].as_hidden(), + a["mydate"].as_hidden(), '<input type="hidden" name="mydate" value="2008-04-01" id="id_mydate">', ) - b = GetDate({'mydate': '2008-4-1'}) + b = GetDate({"mydate": "2008-4-1"}) self.assertTrue(b.is_valid()) - self.assertEqual(b.cleaned_data['mydate'], date(2008, 4, 1)) + self.assertEqual(b.cleaned_data["mydate"], date(2008, 4, 1)) # Invalid dates shouldn't be allowed - c = GetDate({'mydate_month': '2', 'mydate_day': '31', 'mydate_year': '2010'}) + c = GetDate({"mydate_month": "2", "mydate_day": "31", "mydate_year": "2010"}) self.assertFalse(c.is_valid()) - self.assertEqual(c.errors, {'mydate': ['Enter a valid date.']}) + self.assertEqual(c.errors, {"mydate": ["Enter a valid date."]}) # label tag is correctly associated with month dropdown - d = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'}) + d = GetDate({"mydate_month": "1", "mydate_day": "1", "mydate_year": "2010"}) self.assertIn('<label for="id_mydate_month">', d.as_p()) - @translation.override('nl') + @translation.override("nl") def test_l10n_date_changed(self): """ DateField.has_changed() with SelectDateWidget works with a localized date format (#17165). """ # With Field.show_hidden_initial=False - b = GetDate({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '1', - }, initial={'mydate': date(2008, 4, 1)}) + b = GetDate( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "1", + }, + initial={"mydate": date(2008, 4, 1)}, + ) self.assertFalse(b.has_changed()) - b = GetDate({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '2', - }, initial={'mydate': date(2008, 4, 1)}) + b = GetDate( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "2", + }, + initial={"mydate": date(2008, 4, 1)}, + ) self.assertTrue(b.has_changed()) # With Field.show_hidden_initial=True class GetDateShowHiddenInitial(Form): mydate = DateField(widget=SelectDateWidget, show_hidden_initial=True) - b = GetDateShowHiddenInitial({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '1', - 'initial-mydate': HiddenInput().format_value(date(2008, 4, 1)), - }, initial={'mydate': date(2008, 4, 1)}) + b = GetDateShowHiddenInitial( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "1", + "initial-mydate": HiddenInput().format_value(date(2008, 4, 1)), + }, + initial={"mydate": date(2008, 4, 1)}, + ) self.assertFalse(b.has_changed()) - b = GetDateShowHiddenInitial({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '22', - 'initial-mydate': HiddenInput().format_value(date(2008, 4, 1)), - }, initial={'mydate': date(2008, 4, 1)}) + b = GetDateShowHiddenInitial( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "22", + "initial-mydate": HiddenInput().format_value(date(2008, 4, 1)), + }, + initial={"mydate": date(2008, 4, 1)}, + ) self.assertTrue(b.has_changed()) - b = GetDateShowHiddenInitial({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '22', - 'initial-mydate': HiddenInput().format_value(date(2008, 4, 1)), - }, initial={'mydate': date(2008, 4, 22)}) + b = GetDateShowHiddenInitial( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "22", + "initial-mydate": HiddenInput().format_value(date(2008, 4, 1)), + }, + initial={"mydate": date(2008, 4, 22)}, + ) self.assertTrue(b.has_changed()) - b = GetDateShowHiddenInitial({ - 'mydate_year': '2008', - 'mydate_month': '4', - 'mydate_day': '22', - 'initial-mydate': HiddenInput().format_value(date(2008, 4, 22)), - }, initial={'mydate': date(2008, 4, 1)}) + b = GetDateShowHiddenInitial( + { + "mydate_year": "2008", + "mydate_month": "4", + "mydate_day": "22", + "initial-mydate": HiddenInput().format_value(date(2008, 4, 22)), + }, + initial={"mydate": date(2008, 4, 1)}, + ) self.assertFalse(b.has_changed()) - @translation.override('nl') + @translation.override("nl") def test_l10n_invalid_date_in(self): # Invalid dates shouldn't be allowed - a = GetDate({'mydate_month': '2', 'mydate_day': '31', 'mydate_year': '2010'}) + a = GetDate({"mydate_month": "2", "mydate_day": "31", "mydate_year": "2010"}) self.assertFalse(a.is_valid()) # 'Geef een geldige datum op.' = 'Enter a valid date.' - self.assertEqual(a.errors, {'mydate': ['Voer een geldige datum in.']}) + self.assertEqual(a.errors, {"mydate": ["Voer een geldige datum in."]}) - @translation.override('nl') + @translation.override("nl") def test_form_label_association(self): # label tag is correctly associated with first rendered dropdown - a = GetDate({'mydate_month': '1', 'mydate_day': '1', 'mydate_year': '2010'}) + a = GetDate({"mydate_month": "1", "mydate_day": "1", "mydate_year": "2010"}) self.assertIn('<label for="id_mydate_day">', a.as_p()) def test_datefield_1(self): f = DateField() self.assertEqual(date(2006, 10, 25), f.clean(date(2006, 10, 25))) self.assertEqual(date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30))) - self.assertEqual(date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30, 59))) - self.assertEqual(date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30, 59, 200))) - self.assertEqual(date(2006, 10, 25), f.clean('2006-10-25')) - self.assertEqual(date(2006, 10, 25), f.clean('10/25/2006')) - self.assertEqual(date(2006, 10, 25), f.clean('10/25/06')) - self.assertEqual(date(2006, 10, 25), f.clean('Oct 25 2006')) - self.assertEqual(date(2006, 10, 25), f.clean('October 25 2006')) - self.assertEqual(date(2006, 10, 25), f.clean('October 25, 2006')) - self.assertEqual(date(2006, 10, 25), f.clean('25 October 2006')) - self.assertEqual(date(2006, 10, 25), f.clean('25 October, 2006')) + self.assertEqual( + date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30, 59)) + ) + self.assertEqual( + date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30, 59, 200)) + ) + self.assertEqual(date(2006, 10, 25), f.clean("2006-10-25")) + self.assertEqual(date(2006, 10, 25), f.clean("10/25/2006")) + self.assertEqual(date(2006, 10, 25), f.clean("10/25/06")) + self.assertEqual(date(2006, 10, 25), f.clean("Oct 25 2006")) + self.assertEqual(date(2006, 10, 25), f.clean("October 25 2006")) + self.assertEqual(date(2006, 10, 25), f.clean("October 25, 2006")) + self.assertEqual(date(2006, 10, 25), f.clean("25 October 2006")) + self.assertEqual(date(2006, 10, 25), f.clean("25 October, 2006")) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('2006-4-31') + f.clean("2006-4-31") with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('200a-10-25') + f.clean("200a-10-25") with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('25/10/06') + f.clean("25/10/06") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) def test_datefield_2(self): f = DateField(required=False) self.assertIsNone(f.clean(None)) - self.assertEqual('None', repr(f.clean(None))) - self.assertIsNone(f.clean('')) - self.assertEqual('None', repr(f.clean(''))) + self.assertEqual("None", repr(f.clean(None))) + self.assertIsNone(f.clean("")) + self.assertEqual("None", repr(f.clean(""))) def test_datefield_3(self): - f = DateField(input_formats=['%Y %m %d']) + f = DateField(input_formats=["%Y %m %d"]) self.assertEqual(date(2006, 10, 25), f.clean(date(2006, 10, 25))) self.assertEqual(date(2006, 10, 25), f.clean(datetime(2006, 10, 25, 14, 30))) - self.assertEqual(date(2006, 10, 25), f.clean('2006 10 25')) + self.assertEqual(date(2006, 10, 25), f.clean("2006 10 25")) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('2006-10-25') + f.clean("2006-10-25") with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('10/25/2006') + f.clean("10/25/2006") with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('10/25/06') + f.clean("10/25/06") def test_datefield_4(self): # Test whitespace stripping behavior (#5714) f = DateField() - self.assertEqual(date(2006, 10, 25), f.clean(' 10/25/2006 ')) - self.assertEqual(date(2006, 10, 25), f.clean(' 10/25/06 ')) - self.assertEqual(date(2006, 10, 25), f.clean(' Oct 25 2006 ')) - self.assertEqual(date(2006, 10, 25), f.clean(' October 25 2006 ')) - self.assertEqual(date(2006, 10, 25), f.clean(' October 25, 2006 ')) - self.assertEqual(date(2006, 10, 25), f.clean(' 25 October 2006 ')) + self.assertEqual(date(2006, 10, 25), f.clean(" 10/25/2006 ")) + self.assertEqual(date(2006, 10, 25), f.clean(" 10/25/06 ")) + self.assertEqual(date(2006, 10, 25), f.clean(" Oct 25 2006 ")) + self.assertEqual(date(2006, 10, 25), f.clean(" October 25 2006 ")) + self.assertEqual(date(2006, 10, 25), f.clean(" October 25, 2006 ")) + self.assertEqual(date(2006, 10, 25), f.clean(" 25 October 2006 ")) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean(' ') + f.clean(" ") def test_datefield_5(self): # Test null bytes (#18982) f = DateField() with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean('a\x00b') + f.clean("a\x00b") def test_datefield_changed(self): - format = '%d/%m/%Y' + format = "%d/%m/%Y" f = DateField(input_formats=[format]) d = date(2007, 9, 17) - self.assertFalse(f.has_changed(d, '17/09/2007')) + self.assertFalse(f.has_changed(d, "17/09/2007")) def test_datefield_strptime(self): """field.strptime() doesn't raise a UnicodeEncodeError (#16123)""" f = DateField() try: - f.strptime('31 мая 2011', '%d-%b-%y') + f.strptime("31 мая 2011", "%d-%b-%y") except Exception as e: # assertIsInstance or assertRaises cannot be used because UnicodeEncodeError # is a subclass of ValueError diff --git a/tests/forms_tests/field_tests/test_datetimefield.py b/tests/forms_tests/field_tests/test_datetimefield.py index 5d118cfdd2..3d266da6b7 100644 --- a/tests/forms_tests/field_tests/test_datetimefield.py +++ b/tests/forms_tests/field_tests/test_datetimefield.py @@ -7,7 +7,6 @@ from django.utils.timezone import get_fixed_timezone, utc class DateTimeFieldTest(SimpleTestCase): - def test_datetimefield_clean(self): tests = [ (date(2006, 10, 25), datetime(2006, 10, 25, 0, 0)), @@ -17,48 +16,48 @@ class DateTimeFieldTest(SimpleTestCase): datetime(2006, 10, 25, 14, 30, 59, 200), datetime(2006, 10, 25, 14, 30, 59, 200), ), - ('2006-10-25 14:30:45.000200', datetime(2006, 10, 25, 14, 30, 45, 200)), - ('2006-10-25 14:30:45.0002', datetime(2006, 10, 25, 14, 30, 45, 200)), - ('2006-10-25 14:30:45', datetime(2006, 10, 25, 14, 30, 45)), - ('2006-10-25 14:30:00', datetime(2006, 10, 25, 14, 30)), - ('2006-10-25 14:30', datetime(2006, 10, 25, 14, 30)), - ('2006-10-25', datetime(2006, 10, 25, 0, 0)), - ('10/25/2006 14:30:45.000200', datetime(2006, 10, 25, 14, 30, 45, 200)), - ('10/25/2006 14:30:45', datetime(2006, 10, 25, 14, 30, 45)), - ('10/25/2006 14:30:00', datetime(2006, 10, 25, 14, 30)), - ('10/25/2006 14:30', datetime(2006, 10, 25, 14, 30)), - ('10/25/2006', datetime(2006, 10, 25, 0, 0)), - ('10/25/06 14:30:45.000200', datetime(2006, 10, 25, 14, 30, 45, 200)), - ('10/25/06 14:30:45', datetime(2006, 10, 25, 14, 30, 45)), - ('10/25/06 14:30:00', datetime(2006, 10, 25, 14, 30)), - ('10/25/06 14:30', datetime(2006, 10, 25, 14, 30)), - ('10/25/06', datetime(2006, 10, 25, 0, 0)), + ("2006-10-25 14:30:45.000200", datetime(2006, 10, 25, 14, 30, 45, 200)), + ("2006-10-25 14:30:45.0002", datetime(2006, 10, 25, 14, 30, 45, 200)), + ("2006-10-25 14:30:45", datetime(2006, 10, 25, 14, 30, 45)), + ("2006-10-25 14:30:00", datetime(2006, 10, 25, 14, 30)), + ("2006-10-25 14:30", datetime(2006, 10, 25, 14, 30)), + ("2006-10-25", datetime(2006, 10, 25, 0, 0)), + ("10/25/2006 14:30:45.000200", datetime(2006, 10, 25, 14, 30, 45, 200)), + ("10/25/2006 14:30:45", datetime(2006, 10, 25, 14, 30, 45)), + ("10/25/2006 14:30:00", datetime(2006, 10, 25, 14, 30)), + ("10/25/2006 14:30", datetime(2006, 10, 25, 14, 30)), + ("10/25/2006", datetime(2006, 10, 25, 0, 0)), + ("10/25/06 14:30:45.000200", datetime(2006, 10, 25, 14, 30, 45, 200)), + ("10/25/06 14:30:45", datetime(2006, 10, 25, 14, 30, 45)), + ("10/25/06 14:30:00", datetime(2006, 10, 25, 14, 30)), + ("10/25/06 14:30", datetime(2006, 10, 25, 14, 30)), + ("10/25/06", datetime(2006, 10, 25, 0, 0)), # ISO 8601 formats. ( - '2014-09-23T22:34:41.614804', + "2014-09-23T22:34:41.614804", datetime(2014, 9, 23, 22, 34, 41, 614804), ), - ('2014-09-23T22:34:41', datetime(2014, 9, 23, 22, 34, 41)), - ('2014-09-23T22:34', datetime(2014, 9, 23, 22, 34)), - ('2014-09-23', datetime(2014, 9, 23, 0, 0)), - ('2014-09-23T22:34Z', datetime(2014, 9, 23, 22, 34, tzinfo=utc)), + ("2014-09-23T22:34:41", datetime(2014, 9, 23, 22, 34, 41)), + ("2014-09-23T22:34", datetime(2014, 9, 23, 22, 34)), + ("2014-09-23", datetime(2014, 9, 23, 0, 0)), + ("2014-09-23T22:34Z", datetime(2014, 9, 23, 22, 34, tzinfo=utc)), ( - '2014-09-23T22:34+07:00', + "2014-09-23T22:34+07:00", datetime(2014, 9, 23, 22, 34, tzinfo=get_fixed_timezone(420)), ), # Whitespace stripping. - (' 2006-10-25 14:30:45 ', datetime(2006, 10, 25, 14, 30, 45)), - (' 2006-10-25 ', datetime(2006, 10, 25, 0, 0)), - (' 10/25/2006 14:30:45 ', datetime(2006, 10, 25, 14, 30, 45)), - (' 10/25/2006 14:30 ', datetime(2006, 10, 25, 14, 30)), - (' 10/25/2006 ', datetime(2006, 10, 25, 0, 0)), - (' 10/25/06 14:30:45 ', datetime(2006, 10, 25, 14, 30, 45)), - (' 10/25/06 ', datetime(2006, 10, 25, 0, 0)), + (" 2006-10-25 14:30:45 ", datetime(2006, 10, 25, 14, 30, 45)), + (" 2006-10-25 ", datetime(2006, 10, 25, 0, 0)), + (" 10/25/2006 14:30:45 ", datetime(2006, 10, 25, 14, 30, 45)), + (" 10/25/2006 14:30 ", datetime(2006, 10, 25, 14, 30)), + (" 10/25/2006 ", datetime(2006, 10, 25, 0, 0)), + (" 10/25/06 14:30:45 ", datetime(2006, 10, 25, 14, 30, 45)), + (" 10/25/06 ", datetime(2006, 10, 25, 0, 0)), ( - ' 2014-09-23T22:34:41.614804 ', + " 2014-09-23T22:34:41.614804 ", datetime(2014, 9, 23, 22, 34, 41, 614804), ), - (' 2014-09-23T22:34Z ', datetime(2014, 9, 23, 22, 34, tzinfo=utc)), + (" 2014-09-23T22:34Z ", datetime(2014, 9, 23, 22, 34, tzinfo=utc)), ] f = DateTimeField() for value, expected_datetime in tests: @@ -69,40 +68,46 @@ class DateTimeFieldTest(SimpleTestCase): f = DateTimeField() msg = "'Enter a valid date/time.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('hello') + f.clean("hello") with self.assertRaisesMessage(ValidationError, msg): - f.clean('2006-10-25 4:30 p.m.') + f.clean("2006-10-25 4:30 p.m.") with self.assertRaisesMessage(ValidationError, msg): - f.clean(' ') + f.clean(" ") with self.assertRaisesMessage(ValidationError, msg): - f.clean('2014-09-23T28:23') - f = DateTimeField(input_formats=['%Y %m %d %I:%M %p']) + f.clean("2014-09-23T28:23") + f = DateTimeField(input_formats=["%Y %m %d %I:%M %p"]) with self.assertRaisesMessage(ValidationError, msg): - f.clean('2006.10.25 14:30:45') + f.clean("2006.10.25 14:30:45") def test_datetimefield_clean_input_formats(self): tests = [ - ('%Y %m %d %I:%M %p', ( - (date(2006, 10, 25), datetime(2006, 10, 25, 0, 0)), - (datetime(2006, 10, 25, 14, 30), datetime(2006, 10, 25, 14, 30)), - ( - datetime(2006, 10, 25, 14, 30, 59), - datetime(2006, 10, 25, 14, 30, 59), - ), + ( + "%Y %m %d %I:%M %p", ( - datetime(2006, 10, 25, 14, 30, 59, 200), - datetime(2006, 10, 25, 14, 30, 59, 200), + (date(2006, 10, 25), datetime(2006, 10, 25, 0, 0)), + (datetime(2006, 10, 25, 14, 30), datetime(2006, 10, 25, 14, 30)), + ( + datetime(2006, 10, 25, 14, 30, 59), + datetime(2006, 10, 25, 14, 30, 59), + ), + ( + datetime(2006, 10, 25, 14, 30, 59, 200), + datetime(2006, 10, 25, 14, 30, 59, 200), + ), + ("2006 10 25 2:30 PM", datetime(2006, 10, 25, 14, 30)), + # ISO-like formats are always accepted. + ("2006-10-25 14:30:45", datetime(2006, 10, 25, 14, 30, 45)), ), - ('2006 10 25 2:30 PM', datetime(2006, 10, 25, 14, 30)), - # ISO-like formats are always accepted. - ('2006-10-25 14:30:45', datetime(2006, 10, 25, 14, 30, 45)), - )), - ('%Y.%m.%d %H:%M:%S.%f', ( + ), + ( + "%Y.%m.%d %H:%M:%S.%f", ( - '2006.10.25 14:30:45.0002', - datetime(2006, 10, 25, 14, 30, 45, 200), + ( + "2006.10.25 14:30:45.0002", + datetime(2006, 10, 25, 14, 30, 45, 200), + ), ), - )), + ), ] for input_format, values in tests: f = DateTimeField(input_formats=[input_format]) @@ -113,11 +118,11 @@ class DateTimeFieldTest(SimpleTestCase): def test_datetimefield_not_required(self): f = DateTimeField(required=False) self.assertIsNone(f.clean(None)) - self.assertEqual('None', repr(f.clean(None))) - self.assertIsNone(f.clean('')) - self.assertEqual('None', repr(f.clean(''))) + self.assertEqual("None", repr(f.clean(None))) + self.assertIsNone(f.clean("")) + self.assertEqual("None", repr(f.clean(""))) def test_datetimefield_changed(self): - f = DateTimeField(input_formats=['%Y %m %d %I:%M %p']) + f = DateTimeField(input_formats=["%Y %m %d %I:%M %p"]) d = datetime(2006, 9, 17, 14, 30, 0) - self.assertFalse(f.has_changed(d, '2006 09 17 2:30 PM')) + self.assertFalse(f.has_changed(d, "2006 09 17 2:30 PM")) diff --git a/tests/forms_tests/field_tests/test_decimalfield.py b/tests/forms_tests/field_tests/test_decimalfield.py index 1dd0984ac7..6e49a41341 100644 --- a/tests/forms_tests/field_tests/test_decimalfield.py +++ b/tests/forms_tests/field_tests/test_decimalfield.py @@ -10,40 +10,51 @@ from . import FormFieldAssertionsMixin class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_decimalfield_1(self): f = DecimalField(max_digits=4, decimal_places=2) - self.assertWidgetRendersTo(f, '<input id="id_f" step="0.01" type="number" name="f" required>') + self.assertWidgetRendersTo( + f, '<input id="id_f" step="0.01" type="number" name="f" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(f.clean('1'), decimal.Decimal("1")) - self.assertIsInstance(f.clean('1'), decimal.Decimal) - self.assertEqual(f.clean('23'), decimal.Decimal("23")) - self.assertEqual(f.clean('3.14'), decimal.Decimal("3.14")) + self.assertEqual(f.clean("1"), decimal.Decimal("1")) + self.assertIsInstance(f.clean("1"), decimal.Decimal) + self.assertEqual(f.clean("23"), decimal.Decimal("23")) + self.assertEqual(f.clean("3.14"), decimal.Decimal("3.14")) self.assertEqual(f.clean(3.14), decimal.Decimal("3.14")) - self.assertEqual(f.clean(decimal.Decimal('3.14')), decimal.Decimal("3.14")) - self.assertEqual(f.clean('1.0 '), decimal.Decimal("1.0")) - self.assertEqual(f.clean(' 1.0'), decimal.Decimal("1.0")) - self.assertEqual(f.clean(' 1.0 '), decimal.Decimal("1.0")) - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'"): - f.clean('123.45') - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'"): - f.clean('1.234') + self.assertEqual(f.clean(decimal.Decimal("3.14")), decimal.Decimal("3.14")) + self.assertEqual(f.clean("1.0 "), decimal.Decimal("1.0")) + self.assertEqual(f.clean(" 1.0"), decimal.Decimal("1.0")) + self.assertEqual(f.clean(" 1.0 "), decimal.Decimal("1.0")) + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 4 digits in total.'" + ): + f.clean("123.45") + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 2 decimal places.'" + ): + f.clean("1.234") msg = "'Ensure that there are no more than 2 digits before the decimal point.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('123.4') - self.assertEqual(f.clean('-12.34'), decimal.Decimal("-12.34")) - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'"): - f.clean('-123.45') - self.assertEqual(f.clean('-.12'), decimal.Decimal("-0.12")) - self.assertEqual(f.clean('-00.12'), decimal.Decimal("-0.12")) - self.assertEqual(f.clean('-000.12'), decimal.Decimal("-0.12")) - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'"): - f.clean('-000.123') - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 4 digits in total.'"): - f.clean('-000.12345') + f.clean("123.4") + self.assertEqual(f.clean("-12.34"), decimal.Decimal("-12.34")) + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 4 digits in total.'" + ): + f.clean("-123.45") + self.assertEqual(f.clean("-.12"), decimal.Decimal("-0.12")) + self.assertEqual(f.clean("-00.12"), decimal.Decimal("-0.12")) + self.assertEqual(f.clean("-000.12"), decimal.Decimal("-0.12")) + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 2 decimal places.'" + ): + f.clean("-000.123") + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 4 digits in total.'" + ): + f.clean("-000.12345") self.assertEqual(f.max_digits, 4) self.assertEqual(f.decimal_places, 2) self.assertIsNone(f.max_value) @@ -52,21 +63,34 @@ class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_enter_a_number_error(self): f = DecimalField(max_value=1, max_digits=4, decimal_places=2) values = ( - '-NaN', 'NaN', '+NaN', - '-sNaN', 'sNaN', '+sNaN', - '-Inf', 'Inf', '+Inf', - '-Infinity', 'Infinity', '+Infinity', - 'a', 'łąść', '1.0a', '--0.12', + "-NaN", + "NaN", + "+NaN", + "-sNaN", + "sNaN", + "+sNaN", + "-Inf", + "Inf", + "+Inf", + "-Infinity", + "Infinity", + "+Infinity", + "a", + "łąść", + "1.0a", + "--0.12", ) for value in values: - with self.subTest(value=value), self.assertRaisesMessage(ValidationError, "'Enter a number.'"): + with self.subTest(value=value), self.assertRaisesMessage( + ValidationError, "'Enter a number.'" + ): f.clean(value) def test_decimalfield_2(self): f = DecimalField(max_digits=4, decimal_places=2, required=False) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) - self.assertEqual(f.clean('1'), decimal.Decimal("1")) + self.assertEqual(f.clean("1"), decimal.Decimal("1")) self.assertEqual(f.max_digits, 4) self.assertEqual(f.decimal_places, 2) self.assertIsNone(f.max_value) @@ -74,71 +98,82 @@ class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_decimalfield_3(self): f = DecimalField( - max_digits=4, decimal_places=2, - max_value=decimal.Decimal('1.5'), - min_value=decimal.Decimal('0.5') + max_digits=4, + decimal_places=2, + max_value=decimal.Decimal("1.5"), + min_value=decimal.Decimal("0.5"), ) self.assertWidgetRendersTo( f, '<input step="0.01" name="f" min="0.5" max="1.5" type="number" id="id_f" required>', ) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'"): - f.clean('1.6') - with self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'"): - f.clean('0.4') - self.assertEqual(f.clean('1.5'), decimal.Decimal("1.5")) - self.assertEqual(f.clean('0.5'), decimal.Decimal("0.5")) - self.assertEqual(f.clean('.5'), decimal.Decimal("0.5")) - self.assertEqual(f.clean('00.50'), decimal.Decimal("0.50")) + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is less than or equal to 1.5.'" + ): + f.clean("1.6") + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is greater than or equal to 0.5.'" + ): + f.clean("0.4") + self.assertEqual(f.clean("1.5"), decimal.Decimal("1.5")) + self.assertEqual(f.clean("0.5"), decimal.Decimal("0.5")) + self.assertEqual(f.clean(".5"), decimal.Decimal("0.5")) + self.assertEqual(f.clean("00.50"), decimal.Decimal("0.50")) self.assertEqual(f.max_digits, 4) self.assertEqual(f.decimal_places, 2) - self.assertEqual(f.max_value, decimal.Decimal('1.5')) - self.assertEqual(f.min_value, decimal.Decimal('0.5')) + self.assertEqual(f.max_value, decimal.Decimal("1.5")) + self.assertEqual(f.min_value, decimal.Decimal("0.5")) def test_decimalfield_4(self): f = DecimalField(decimal_places=2) - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 2 decimal places.'"): - f.clean('0.00000001') + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 2 decimal places.'" + ): + f.clean("0.00000001") def test_decimalfield_5(self): f = DecimalField(max_digits=3) # Leading whole zeros "collapse" to one digit. - self.assertEqual(f.clean('0000000.10'), decimal.Decimal("0.1")) + self.assertEqual(f.clean("0000000.10"), decimal.Decimal("0.1")) # But a leading 0 before the . doesn't count toward max_digits - self.assertEqual(f.clean('0000000.100'), decimal.Decimal("0.100")) + self.assertEqual(f.clean("0000000.100"), decimal.Decimal("0.100")) # Only leading whole zeros "collapse" to one digit. - self.assertEqual(f.clean('000000.02'), decimal.Decimal('0.02')) - with self.assertRaisesMessage(ValidationError, "'Ensure that there are no more than 3 digits in total.'"): - f.clean('000000.0002') - self.assertEqual(f.clean('.002'), decimal.Decimal("0.002")) + self.assertEqual(f.clean("000000.02"), decimal.Decimal("0.02")) + with self.assertRaisesMessage( + ValidationError, "'Ensure that there are no more than 3 digits in total.'" + ): + f.clean("000000.0002") + self.assertEqual(f.clean(".002"), decimal.Decimal("0.002")) def test_decimalfield_6(self): f = DecimalField(max_digits=2, decimal_places=2) - self.assertEqual(f.clean('.01'), decimal.Decimal(".01")) + self.assertEqual(f.clean(".01"), decimal.Decimal(".01")) msg = "'Ensure that there are no more than 0 digits before the decimal point.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('1.1') + f.clean("1.1") def test_decimalfield_scientific(self): f = DecimalField(max_digits=4, decimal_places=2) with self.assertRaisesMessage(ValidationError, "Ensure that there are no more"): - f.clean('1E+2') - self.assertEqual(f.clean('1E+1'), decimal.Decimal('10')) - self.assertEqual(f.clean('1E-1'), decimal.Decimal('0.1')) - self.assertEqual(f.clean('0.546e+2'), decimal.Decimal('54.6')) + f.clean("1E+2") + self.assertEqual(f.clean("1E+1"), decimal.Decimal("10")) + self.assertEqual(f.clean("1E-1"), decimal.Decimal("0.1")) + self.assertEqual(f.clean("0.546e+2"), decimal.Decimal("54.6")) def test_decimalfield_widget_attrs(self): f = DecimalField(max_digits=6, decimal_places=2) self.assertEqual(f.widget_attrs(Widget()), {}) - self.assertEqual(f.widget_attrs(NumberInput()), {'step': '0.01'}) + self.assertEqual(f.widget_attrs(NumberInput()), {"step": "0.01"}) f = DecimalField(max_digits=10, decimal_places=0) - self.assertEqual(f.widget_attrs(NumberInput()), {'step': '1'}) + self.assertEqual(f.widget_attrs(NumberInput()), {"step": "1"}) f = DecimalField(max_digits=19, decimal_places=19) - self.assertEqual(f.widget_attrs(NumberInput()), {'step': '1e-19'}) + self.assertEqual(f.widget_attrs(NumberInput()), {"step": "1e-19"}) f = DecimalField(max_digits=20) - self.assertEqual(f.widget_attrs(NumberInput()), {'step': 'any'}) - f = DecimalField(max_digits=6, widget=NumberInput(attrs={'step': '0.01'})) - self.assertWidgetRendersTo(f, '<input step="0.01" name="f" type="number" id="id_f" required>') + self.assertEqual(f.widget_attrs(NumberInput()), {"step": "any"}) + f = DecimalField(max_digits=6, widget=NumberInput(attrs={"step": "0.01"})) + self.assertWidgetRendersTo( + f, '<input step="0.01" name="f" type="number" id="id_f" required>' + ) def test_decimalfield_localized(self): """ @@ -151,10 +186,10 @@ class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_decimalfield_changed(self): f = DecimalField(max_digits=2, decimal_places=2) d = decimal.Decimal("0.1") - self.assertFalse(f.has_changed(d, '0.10')) - self.assertTrue(f.has_changed(d, '0.101')) + self.assertFalse(f.has_changed(d, "0.10")) + self.assertTrue(f.has_changed(d, "0.101")) - with translation.override('fr'): + with translation.override("fr"): f = DecimalField(max_digits=2, decimal_places=2, localize=True) localized_d = formats.localize_input(d) # -> '0,1' in French self.assertFalse(f.has_changed(d, localized_d)) @@ -164,22 +199,26 @@ class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase): # format-related settings will take precedence over locale-dictated # formats. @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',') + @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=",") def test_decimalfield_support_decimal_separator(self): f = DecimalField(localize=True) - self.assertEqual(f.clean('1001,10'), decimal.Decimal("1001.10")) - self.assertEqual(f.clean('1001.10'), decimal.Decimal("1001.10")) + self.assertEqual(f.clean("1001,10"), decimal.Decimal("1001.10")) + self.assertEqual(f.clean("1001.10"), decimal.Decimal("1001.10")) # RemovedInDjango50Warning: When the deprecation ends, remove # @ignore_warnings and USE_L10N=False. The test should remain because # format-related settings will take precedence over locale-dictated # formats. @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',', USE_THOUSAND_SEPARATOR=True, - THOUSAND_SEPARATOR='.') + @override_settings( + USE_L10N=False, + DECIMAL_SEPARATOR=",", + USE_THOUSAND_SEPARATOR=True, + THOUSAND_SEPARATOR=".", + ) def test_decimalfield_support_thousands_separator(self): f = DecimalField(localize=True) - self.assertEqual(f.clean('1.001,10'), decimal.Decimal("1001.10")) + self.assertEqual(f.clean("1.001,10"), decimal.Decimal("1001.10")) msg = "'Enter a number.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('1,001.1') + f.clean("1,001.1") diff --git a/tests/forms_tests/field_tests/test_durationfield.py b/tests/forms_tests/field_tests/test_durationfield.py index dae139446d..834638354c 100644 --- a/tests/forms_tests/field_tests/test_durationfield.py +++ b/tests/forms_tests/field_tests/test_durationfield.py @@ -10,32 +10,35 @@ from . import FormFieldAssertionsMixin class DurationFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_durationfield_clean(self): f = DurationField() - self.assertEqual(datetime.timedelta(seconds=30), f.clean('30')) - self.assertEqual(datetime.timedelta(minutes=15, seconds=30), f.clean('15:30')) - self.assertEqual(datetime.timedelta(hours=1, minutes=15, seconds=30), f.clean('1:15:30')) + self.assertEqual(datetime.timedelta(seconds=30), f.clean("30")) + self.assertEqual(datetime.timedelta(minutes=15, seconds=30), f.clean("15:30")) + self.assertEqual( + datetime.timedelta(hours=1, minutes=15, seconds=30), f.clean("1:15:30") + ) self.assertEqual( - datetime.timedelta(days=1, hours=1, minutes=15, seconds=30, milliseconds=300), - f.clean('1 1:15:30.3') + datetime.timedelta( + days=1, hours=1, minutes=15, seconds=30, milliseconds=300 + ), + f.clean("1 1:15:30.3"), ) self.assertEqual( datetime.timedelta(0, 10800), f.clean(datetime.timedelta(0, 10800)), ) - msg = 'This field is required.' + msg = "This field is required." with self.assertRaisesMessage(ValidationError, msg): - f.clean('') - msg = 'Enter a valid duration.' + f.clean("") + msg = "Enter a valid duration." with self.assertRaisesMessage(ValidationError, msg): - f.clean('not_a_time') + f.clean("not_a_time") with self.assertRaisesMessage(ValidationError, msg): - DurationField().clean('P3(3D') + DurationField().clean("P3(3D") def test_durationfield_clean_not_required(self): f = DurationField(required=False) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) def test_overflow(self): msg = "The number of days must be between {min_days} and {max_days}.".format( @@ -44,18 +47,18 @@ class DurationFieldTest(FormFieldAssertionsMixin, SimpleTestCase): ) f = DurationField() with self.assertRaisesMessage(ValidationError, msg): - f.clean('1000000000 00:00:00') + f.clean("1000000000 00:00:00") with self.assertRaisesMessage(ValidationError, msg): - f.clean('-1000000000 00:00:00') + f.clean("-1000000000 00:00:00") def test_overflow_translation(self): msg = "Le nombre de jours doit être entre {min_days} et {max_days}.".format( min_days=datetime.timedelta.min.days, max_days=datetime.timedelta.max.days, ) - with translation.override('fr'): + with translation.override("fr"): with self.assertRaisesMessage(ValidationError, msg): - DurationField().clean('1000000000 00:00:00') + DurationField().clean("1000000000 00:00:00") def test_durationfield_render(self): self.assertWidgetRendersTo( @@ -71,5 +74,5 @@ class DurationFieldTest(FormFieldAssertionsMixin, SimpleTestCase): field = DurationField() td = datetime.timedelta(minutes=15, seconds=30) self.assertEqual(field.prepare_value(td), duration_string(td)) - self.assertEqual(field.prepare_value('arbitrary'), 'arbitrary') + self.assertEqual(field.prepare_value("arbitrary"), "arbitrary") self.assertIsNone(field.prepare_value(None)) diff --git a/tests/forms_tests/field_tests/test_emailfield.py b/tests/forms_tests/field_tests/test_emailfield.py index 8b85e4dcc1..d1d52dd608 100644 --- a/tests/forms_tests/field_tests/test_emailfield.py +++ b/tests/forms_tests/field_tests/test_emailfield.py @@ -6,37 +6,44 @@ from . import FormFieldAssertionsMixin class EmailFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_emailfield_1(self): f = EmailField() - self.assertWidgetRendersTo(f, '<input type="email" name="f" id="id_f" required>') + self.assertWidgetRendersTo( + f, '<input type="email" name="f" id="id_f" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual('person@example.com', f.clean('person@example.com')) - with self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'"): - f.clean('foo') + self.assertEqual("person@example.com", f.clean("person@example.com")) + with self.assertRaisesMessage( + ValidationError, "'Enter a valid email address.'" + ): + f.clean("foo") self.assertEqual( - 'local@domain.with.idn.xyz\xe4\xf6\xfc\xdfabc.part.com', - f.clean('local@domain.with.idn.xyzäöüßabc.part.com') + "local@domain.with.idn.xyz\xe4\xf6\xfc\xdfabc.part.com", + f.clean("local@domain.with.idn.xyzäöüßabc.part.com"), ) def test_email_regexp_for_performance(self): f = EmailField() # Check for runaway regex security problem. This will take a long time # if the security fix isn't in place. - addr = 'viewx3dtextx26qx3d@yahoo.comx26latlngx3d15854521645943074058' + addr = "viewx3dtextx26qx3d@yahoo.comx26latlngx3d15854521645943074058" self.assertEqual(addr, f.clean(addr)) def test_emailfield_not_required(self): f = EmailField(required=False) - self.assertEqual('', f.clean('')) - self.assertEqual('', f.clean(None)) - self.assertEqual('person@example.com', f.clean('person@example.com')) - self.assertEqual('example@example.com', f.clean(' example@example.com \t \t ')) - with self.assertRaisesMessage(ValidationError, "'Enter a valid email address.'"): - f.clean('foo') + self.assertEqual("", f.clean("")) + self.assertEqual("", f.clean(None)) + self.assertEqual("person@example.com", f.clean("person@example.com")) + self.assertEqual( + "example@example.com", f.clean(" example@example.com \t \t ") + ) + with self.assertRaisesMessage( + ValidationError, "'Enter a valid email address.'" + ): + f.clean("foo") def test_emailfield_min_max_length(self): f = EmailField(min_length=10, max_length=15) @@ -44,15 +51,21 @@ class EmailFieldTest(FormFieldAssertionsMixin, SimpleTestCase): f, '<input id="id_f" type="email" name="f" maxlength="15" minlength="10" required>', ) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 9).'"): - f.clean('a@foo.com') - self.assertEqual('alf@foo.com', f.clean('alf@foo.com')) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 15 characters (it has 20).'"): - f.clean('alf123456788@foo.com') + with self.assertRaisesMessage( + ValidationError, + "'Ensure this value has at least 10 characters (it has 9).'", + ): + f.clean("a@foo.com") + self.assertEqual("alf@foo.com", f.clean("alf@foo.com")) + with self.assertRaisesMessage( + ValidationError, + "'Ensure this value has at most 15 characters (it has 20).'", + ): + f.clean("alf123456788@foo.com") def test_emailfield_strip_on_none_value(self): f = EmailField(required=False, empty_value=None) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) def test_emailfield_unable_to_set_strip_kwarg(self): diff --git a/tests/forms_tests/field_tests/test_filefield.py b/tests/forms_tests/field_tests/test_filefield.py index 2db106e4a0..56aaa311e0 100644 --- a/tests/forms_tests/field_tests/test_filefield.py +++ b/tests/forms_tests/field_tests/test_filefield.py @@ -7,54 +7,74 @@ from django.test import SimpleTestCase class FileFieldTest(SimpleTestCase): - def test_filefield_1(self): f = FileField() with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('', '') - self.assertEqual('files/test1.pdf', f.clean('', 'files/test1.pdf')) + f.clean("", "") + self.assertEqual("files/test1.pdf", f.clean("", "files/test1.pdf")) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean(None, '') - self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf')) + f.clean(None, "") + self.assertEqual("files/test2.pdf", f.clean(None, "files/test2.pdf")) no_file_msg = "'No file was submitted. Check the encoding type on the form.'" - file = SimpleUploadedFile(None, b'') - file._name = '' + file = SimpleUploadedFile(None, b"") + file._name = "" with self.assertRaisesMessage(ValidationError, no_file_msg): f.clean(file) with self.assertRaisesMessage(ValidationError, no_file_msg): - f.clean(file, '') - self.assertEqual('files/test3.pdf', f.clean(None, 'files/test3.pdf')) + f.clean(file, "") + self.assertEqual("files/test3.pdf", f.clean(None, "files/test3.pdf")) with self.assertRaisesMessage(ValidationError, no_file_msg): - f.clean('some content that is not a file') - with self.assertRaisesMessage(ValidationError, "'The submitted file is empty.'"): - f.clean(SimpleUploadedFile('name', None)) - with self.assertRaisesMessage(ValidationError, "'The submitted file is empty.'"): - f.clean(SimpleUploadedFile('name', b'')) - self.assertEqual(SimpleUploadedFile, type(f.clean(SimpleUploadedFile('name', b'Some File Content')))) + f.clean("some content that is not a file") + with self.assertRaisesMessage( + ValidationError, "'The submitted file is empty.'" + ): + f.clean(SimpleUploadedFile("name", None)) + with self.assertRaisesMessage( + ValidationError, "'The submitted file is empty.'" + ): + f.clean(SimpleUploadedFile("name", b"")) + self.assertEqual( + SimpleUploadedFile, + type(f.clean(SimpleUploadedFile("name", b"Some File Content"))), + ) self.assertIsInstance( - f.clean(SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode())), - SimpleUploadedFile + f.clean( + SimpleUploadedFile( + "我隻氣墊船裝滿晒鱔.txt", "मेरी मँडराने वाली नाव सर्पमीनों से भरी ह".encode() + ) + ), + SimpleUploadedFile, ) self.assertIsInstance( - f.clean(SimpleUploadedFile('name', b'Some File Content'), 'files/test4.pdf'), - SimpleUploadedFile + f.clean( + SimpleUploadedFile("name", b"Some File Content"), "files/test4.pdf" + ), + SimpleUploadedFile, ) def test_filefield_2(self): f = FileField(max_length=5) - with self.assertRaisesMessage(ValidationError, "'Ensure this filename has at most 5 characters (it has 18).'"): - f.clean(SimpleUploadedFile('test_maxlength.txt', b'hello world')) - self.assertEqual('files/test1.pdf', f.clean('', 'files/test1.pdf')) - self.assertEqual('files/test2.pdf', f.clean(None, 'files/test2.pdf')) - self.assertIsInstance(f.clean(SimpleUploadedFile('name', b'Some File Content')), SimpleUploadedFile) + with self.assertRaisesMessage( + ValidationError, + "'Ensure this filename has at most 5 characters (it has 18).'", + ): + f.clean(SimpleUploadedFile("test_maxlength.txt", b"hello world")) + self.assertEqual("files/test1.pdf", f.clean("", "files/test1.pdf")) + self.assertEqual("files/test2.pdf", f.clean(None, "files/test2.pdf")) + self.assertIsInstance( + f.clean(SimpleUploadedFile("name", b"Some File Content")), + SimpleUploadedFile, + ) def test_filefield_3(self): f = FileField(allow_empty_file=True) - self.assertIsInstance(f.clean(SimpleUploadedFile('name', b'')), SimpleUploadedFile) + self.assertIsInstance( + f.clean(SimpleUploadedFile("name", b"")), SimpleUploadedFile + ) def test_filefield_changed(self): """ @@ -65,21 +85,27 @@ class FileFieldTest(SimpleTestCase): f = FileField() # No file was uploaded and no initial data. - self.assertFalse(f.has_changed('', None)) + self.assertFalse(f.has_changed("", None)) # A file was uploaded and no initial data. - self.assertTrue(f.has_changed('', {'filename': 'resume.txt', 'content': 'My resume'})) + self.assertTrue( + f.has_changed("", {"filename": "resume.txt", "content": "My resume"}) + ) # A file was not uploaded, but there is initial data - self.assertFalse(f.has_changed('resume.txt', None)) + self.assertFalse(f.has_changed("resume.txt", None)) # A file was uploaded and there is initial data (file identity is not dealt # with here) - self.assertTrue(f.has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'})) + self.assertTrue( + f.has_changed( + "resume.txt", {"filename": "resume.txt", "content": "My resume"} + ) + ) def test_disabled_has_changed(self): f = FileField(disabled=True) - self.assertIs(f.has_changed('x', 'y'), False) + self.assertIs(f.has_changed("x", "y"), False) def test_file_picklable(self): self.assertIsInstance(pickle.loads(pickle.dumps(FileField())), FileField) diff --git a/tests/forms_tests/field_tests/test_filepathfield.py b/tests/forms_tests/field_tests/test_filepathfield.py index bdd55c32a5..ca0f6f3a7a 100644 --- a/tests/forms_tests/field_tests/test_filepathfield.py +++ b/tests/forms_tests/field_tests/test_filepathfield.py @@ -10,8 +10,8 @@ PATH = os.path.dirname(os.path.abspath(__file__)) def fix_os_paths(x): if isinstance(x, str): if x.startswith(PATH): - x = x[len(PATH):] - return x.replace('\\', '/') + x = x[len(PATH) :] + return x.replace("\\", "/") elif isinstance(x, tuple): return tuple(fix_os_paths(list(x))) elif isinstance(x, list): @@ -22,34 +22,34 @@ def fix_os_paths(x): class FilePathFieldTest(SimpleTestCase): expected_choices = [ - ('/filepathfield_test_dir/__init__.py', '__init__.py'), - ('/filepathfield_test_dir/a.py', 'a.py'), - ('/filepathfield_test_dir/ab.py', 'ab.py'), - ('/filepathfield_test_dir/b.py', 'b.py'), - ('/filepathfield_test_dir/c/__init__.py', '__init__.py'), - ('/filepathfield_test_dir/c/d.py', 'd.py'), - ('/filepathfield_test_dir/c/e.py', 'e.py'), - ('/filepathfield_test_dir/c/f/__init__.py', '__init__.py'), - ('/filepathfield_test_dir/c/f/g.py', 'g.py'), - ('/filepathfield_test_dir/h/__init__.py', '__init__.py'), - ('/filepathfield_test_dir/j/__init__.py', '__init__.py'), + ("/filepathfield_test_dir/__init__.py", "__init__.py"), + ("/filepathfield_test_dir/a.py", "a.py"), + ("/filepathfield_test_dir/ab.py", "ab.py"), + ("/filepathfield_test_dir/b.py", "b.py"), + ("/filepathfield_test_dir/c/__init__.py", "__init__.py"), + ("/filepathfield_test_dir/c/d.py", "d.py"), + ("/filepathfield_test_dir/c/e.py", "e.py"), + ("/filepathfield_test_dir/c/f/__init__.py", "__init__.py"), + ("/filepathfield_test_dir/c/f/g.py", "g.py"), + ("/filepathfield_test_dir/h/__init__.py", "__init__.py"), + ("/filepathfield_test_dir/j/__init__.py", "__init__.py"), ] - path = os.path.join(PATH, 'filepathfield_test_dir') + '/' + path = os.path.join(PATH, "filepathfield_test_dir") + "/" def assertChoices(self, field, expected_choices): self.assertEqual(fix_os_paths(field.choices), expected_choices) def test_fix_os_paths(self): - self.assertEqual(fix_os_paths(self.path), ('/filepathfield_test_dir/')) + self.assertEqual(fix_os_paths(self.path), ("/filepathfield_test_dir/")) def test_nonexistent_path(self): - with self.assertRaisesMessage(FileNotFoundError, 'nonexistent'): - FilePathField(path='nonexistent') + with self.assertRaisesMessage(FileNotFoundError, "nonexistent"): + FilePathField(path="nonexistent") def test_no_options(self): f = FilePathField(path=self.path) expected = [ - ('/filepathfield_test_dir/README', 'README'), + ("/filepathfield_test_dir/README", "README"), ] + self.expected_choices[:4] self.assertChoices(f, expected) @@ -57,48 +57,59 @@ class FilePathFieldTest(SimpleTestCase): f = FilePathField(path=self.path) msg = "'Select a valid choice. a.py is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('a.py') - self.assertEqual(fix_os_paths(f.clean(self.path + 'a.py')), '/filepathfield_test_dir/a.py') + f.clean("a.py") + self.assertEqual( + fix_os_paths(f.clean(self.path + "a.py")), "/filepathfield_test_dir/a.py" + ) def test_match(self): - f = FilePathField(path=self.path, match=r'^.*?\.py$') + f = FilePathField(path=self.path, match=r"^.*?\.py$") self.assertChoices(f, self.expected_choices[:4]) def test_recursive(self): - f = FilePathField(path=self.path, recursive=True, match=r'^.*?\.py$') + f = FilePathField(path=self.path, recursive=True, match=r"^.*?\.py$") expected = [ - ('/filepathfield_test_dir/__init__.py', '__init__.py'), - ('/filepathfield_test_dir/a.py', 'a.py'), - ('/filepathfield_test_dir/ab.py', 'ab.py'), - ('/filepathfield_test_dir/b.py', 'b.py'), - ('/filepathfield_test_dir/c/__init__.py', 'c/__init__.py'), - ('/filepathfield_test_dir/c/d.py', 'c/d.py'), - ('/filepathfield_test_dir/c/e.py', 'c/e.py'), - ('/filepathfield_test_dir/c/f/__init__.py', 'c/f/__init__.py'), - ('/filepathfield_test_dir/c/f/g.py', 'c/f/g.py'), - ('/filepathfield_test_dir/h/__init__.py', 'h/__init__.py'), - ('/filepathfield_test_dir/j/__init__.py', 'j/__init__.py'), - + ("/filepathfield_test_dir/__init__.py", "__init__.py"), + ("/filepathfield_test_dir/a.py", "a.py"), + ("/filepathfield_test_dir/ab.py", "ab.py"), + ("/filepathfield_test_dir/b.py", "b.py"), + ("/filepathfield_test_dir/c/__init__.py", "c/__init__.py"), + ("/filepathfield_test_dir/c/d.py", "c/d.py"), + ("/filepathfield_test_dir/c/e.py", "c/e.py"), + ("/filepathfield_test_dir/c/f/__init__.py", "c/f/__init__.py"), + ("/filepathfield_test_dir/c/f/g.py", "c/f/g.py"), + ("/filepathfield_test_dir/h/__init__.py", "h/__init__.py"), + ("/filepathfield_test_dir/j/__init__.py", "j/__init__.py"), ] self.assertChoices(f, expected) def test_allow_folders(self): f = FilePathField(path=self.path, allow_folders=True, allow_files=False) - self.assertChoices(f, [ - ('/filepathfield_test_dir/c', 'c'), - ('/filepathfield_test_dir/h', 'h'), - ('/filepathfield_test_dir/j', 'j'), - ]) + self.assertChoices( + f, + [ + ("/filepathfield_test_dir/c", "c"), + ("/filepathfield_test_dir/h", "h"), + ("/filepathfield_test_dir/j", "j"), + ], + ) def test_recursive_no_folders_or_files(self): - f = FilePathField(path=self.path, recursive=True, allow_folders=False, allow_files=False) + f = FilePathField( + path=self.path, recursive=True, allow_folders=False, allow_files=False + ) self.assertChoices(f, []) def test_recursive_folders_without_files(self): - f = FilePathField(path=self.path, recursive=True, allow_folders=True, allow_files=False) - self.assertChoices(f, [ - ('/filepathfield_test_dir/c', 'c'), - ('/filepathfield_test_dir/h', 'h'), - ('/filepathfield_test_dir/j', 'j'), - ('/filepathfield_test_dir/c/f', 'c/f'), - ]) + f = FilePathField( + path=self.path, recursive=True, allow_folders=True, allow_files=False + ) + self.assertChoices( + f, + [ + ("/filepathfield_test_dir/c", "c"), + ("/filepathfield_test_dir/h", "h"), + ("/filepathfield_test_dir/j", "j"), + ("/filepathfield_test_dir/c/f", "c/f"), + ], + ) diff --git a/tests/forms_tests/field_tests/test_floatfield.py b/tests/forms_tests/field_tests/test_floatfield.py index 7330c33503..365684c2db 100644 --- a/tests/forms_tests/field_tests/test_floatfield.py +++ b/tests/forms_tests/field_tests/test_floatfield.py @@ -11,41 +11,42 @@ from . import FormFieldAssertionsMixin class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_floatfield_1(self): f = FloatField() - self.assertWidgetRendersTo(f, '<input step="any" type="number" name="f" id="id_f" required>') + self.assertWidgetRendersTo( + f, '<input step="any" type="number" name="f" id="id_f" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(1.0, f.clean('1')) - self.assertIsInstance(f.clean('1'), float) - self.assertEqual(23.0, f.clean('23')) - self.assertEqual(3.1400000000000001, f.clean('3.14')) + self.assertEqual(1.0, f.clean("1")) + self.assertIsInstance(f.clean("1"), float) + self.assertEqual(23.0, f.clean("23")) + self.assertEqual(3.1400000000000001, f.clean("3.14")) self.assertEqual(3.1400000000000001, f.clean(3.14)) self.assertEqual(42.0, f.clean(42)) with self.assertRaisesMessage(ValidationError, "'Enter a number.'"): - f.clean('a') - self.assertEqual(1.0, f.clean('1.0 ')) - self.assertEqual(1.0, f.clean(' 1.0')) - self.assertEqual(1.0, f.clean(' 1.0 ')) + f.clean("a") + self.assertEqual(1.0, f.clean("1.0 ")) + self.assertEqual(1.0, f.clean(" 1.0")) + self.assertEqual(1.0, f.clean(" 1.0 ")) with self.assertRaisesMessage(ValidationError, "'Enter a number.'"): - f.clean('1.0a') + f.clean("1.0a") self.assertIsNone(f.max_value) self.assertIsNone(f.min_value) with self.assertRaisesMessage(ValidationError, "'Enter a number.'"): - f.clean('Infinity') + f.clean("Infinity") with self.assertRaisesMessage(ValidationError, "'Enter a number.'"): - f.clean('NaN') + f.clean("NaN") with self.assertRaisesMessage(ValidationError, "'Enter a number.'"): - f.clean('-Inf') + f.clean("-Inf") def test_floatfield_2(self): f = FloatField(required=False) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) - self.assertEqual(1.0, f.clean('1')) + self.assertEqual(1.0, f.clean("1")) self.assertIsNone(f.max_value) self.assertIsNone(f.min_value) @@ -55,17 +56,21 @@ class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase): f, '<input step="any" name="f" min="0.5" max="1.5" type="number" id="id_f" required>', ) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'"): - f.clean('1.6') - with self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'"): - f.clean('0.4') - self.assertEqual(1.5, f.clean('1.5')) - self.assertEqual(0.5, f.clean('0.5')) + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is less than or equal to 1.5.'" + ): + f.clean("1.6") + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is greater than or equal to 0.5.'" + ): + f.clean("0.4") + self.assertEqual(1.5, f.clean("1.5")) + self.assertEqual(0.5, f.clean("0.5")) self.assertEqual(f.max_value, 1.5) self.assertEqual(f.min_value, 0.5) def test_floatfield_widget_attrs(self): - f = FloatField(widget=NumberInput(attrs={'step': 0.01, 'max': 1.0, 'min': 0.0})) + f = FloatField(widget=NumberInput(attrs={"step": 0.01, "max": 1.0, "min": 0.0})) self.assertWidgetRendersTo( f, '<input step="0.01" name="f" min="0.0" max="1.0" type="number" id="id_f" required>', @@ -82,9 +87,9 @@ class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_floatfield_changed(self): f = FloatField() n = 4.35 - self.assertFalse(f.has_changed(n, '4.3500')) + self.assertFalse(f.has_changed(n, "4.3500")) - with translation.override('fr'): + with translation.override("fr"): f = FloatField(localize=True) localized_n = formats.localize_input(n) # -> '4,35' in French self.assertFalse(f.has_changed(n, localized_n)) @@ -94,31 +99,35 @@ class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase): # format-related settings will take precedence over locale-dictated # formats. @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',') + @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=",") def test_decimalfield_support_decimal_separator(self): f = FloatField(localize=True) - self.assertEqual(f.clean('1001,10'), 1001.10) - self.assertEqual(f.clean('1001.10'), 1001.10) + self.assertEqual(f.clean("1001,10"), 1001.10) + self.assertEqual(f.clean("1001.10"), 1001.10) # RemovedInDjango50Warning: When the deprecation ends, remove # @ignore_warnings and USE_L10N=False. The test should remain because # format-related settings will take precedence over locale-dictated # formats. @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings(USE_L10N=False, DECIMAL_SEPARATOR=',', USE_THOUSAND_SEPARATOR=True, - THOUSAND_SEPARATOR='.') + @override_settings( + USE_L10N=False, + DECIMAL_SEPARATOR=",", + USE_THOUSAND_SEPARATOR=True, + THOUSAND_SEPARATOR=".", + ) def test_decimalfield_support_thousands_separator(self): f = FloatField(localize=True) - self.assertEqual(f.clean('1.001,10'), 1001.10) + self.assertEqual(f.clean("1.001,10"), 1001.10) msg = "'Enter a number.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('1,001.1') + f.clean("1,001.1") -@override_settings(ROOT_URLCONF='forms_tests.urls') +@override_settings(ROOT_URLCONF="forms_tests.urls") class FloatFieldHTMLTest(SeleniumTestCase): - available_apps = ['forms_tests'] + available_apps = ["forms_tests"] def test_float_field_rendering_passes_client_side_validation(self): """ @@ -127,9 +136,9 @@ class FloatFieldHTMLTest(SeleniumTestCase): """ from selenium.webdriver.common.by import By - self.selenium.get(self.live_server_url + reverse('form_view')) - number_input = self.selenium.find_element(By.ID, 'id_number') - number_input.send_keys('0.5') + self.selenium.get(self.live_server_url + reverse("form_view")) + number_input = self.selenium.find_element(By.ID, "id_number") + number_input.send_keys("0.5") is_valid = self.selenium.execute_script( "return document.getElementById('id_number').checkValidity()" ) diff --git a/tests/forms_tests/field_tests/test_genericipaddressfield.py b/tests/forms_tests/field_tests/test_genericipaddressfield.py index 92dbd71a28..80722f5c65 100644 --- a/tests/forms_tests/field_tests/test_genericipaddressfield.py +++ b/tests/forms_tests/field_tests/test_genericipaddressfield.py @@ -4,125 +4,186 @@ from django.test import SimpleTestCase class GenericIPAddressFieldTest(SimpleTestCase): - def test_generic_ipaddress_invalid_arguments(self): with self.assertRaises(ValueError): - GenericIPAddressField(protocol='hamster') + GenericIPAddressField(protocol="hamster") with self.assertRaises(ValueError): - GenericIPAddressField(protocol='ipv4', unpack_ipv4=True) + GenericIPAddressField(protocol="ipv4", unpack_ipv4=True) def test_generic_ipaddress_as_generic(self): # The edge cases of the IPv6 validation code are not deeply tested # here, they are covered in the tests for django.utils.ipv6 f = GenericIPAddressField() with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(f.clean(' 127.0.0.1 '), '127.0.0.1') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('foo') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('127.0.0.') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('1.2.3.4.5') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('256.125.1.5') - self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') - self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('12345:2:3:4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3::4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('foo::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3:4:5:6:7:8') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1:2') + self.assertEqual(f.clean(" 127.0.0.1 "), "127.0.0.1") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("foo") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("127.0.0.") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("1.2.3.4.5") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("256.125.1.5") + self.assertEqual( + f.clean(" fe80::223:6cff:fe8a:2e8a "), "fe80::223:6cff:fe8a:2e8a" + ) + self.assertEqual( + f.clean(" 2a02::223:6cff:fe8a:2e8a "), "2a02::223:6cff:fe8a:2e8a" + ) + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("12345:2:3:4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3::4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("foo::223:6cff:fe8a:2e8a") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3:4:5:6:7:8") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1:2") def test_generic_ipaddress_as_ipv4_only(self): f = GenericIPAddressField(protocol="IPv4") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(f.clean(' 127.0.0.1 '), '127.0.0.1') + self.assertEqual(f.clean(" 127.0.0.1 "), "127.0.0.1") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('foo') + f.clean("foo") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('127.0.0.') + f.clean("127.0.0.") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('1.2.3.4.5') + f.clean("1.2.3.4.5") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('256.125.1.5') + f.clean("256.125.1.5") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('fe80::223:6cff:fe8a:2e8a') + f.clean("fe80::223:6cff:fe8a:2e8a") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 address.'"): - f.clean('2a02::223:6cff:fe8a:2e8a') + f.clean("2a02::223:6cff:fe8a:2e8a") def test_generic_ipaddress_as_ipv6_only(self): f = GenericIPAddressField(protocol="IPv6") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv6 address.'"): - f.clean('127.0.0.1') + f.clean("127.0.0.1") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv6 address.'"): - f.clean('foo') + f.clean("foo") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv6 address.'"): - f.clean('127.0.0.') + f.clean("127.0.0.") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv6 address.'"): - f.clean('1.2.3.4.5') + f.clean("1.2.3.4.5") with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv6 address.'"): - f.clean('256.125.1.5') - self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') - self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('12345:2:3:4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3::4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('foo::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3:4:5:6:7:8') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1:2') + f.clean("256.125.1.5") + self.assertEqual( + f.clean(" fe80::223:6cff:fe8a:2e8a "), "fe80::223:6cff:fe8a:2e8a" + ) + self.assertEqual( + f.clean(" 2a02::223:6cff:fe8a:2e8a "), "2a02::223:6cff:fe8a:2e8a" + ) + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("12345:2:3:4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3::4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("foo::223:6cff:fe8a:2e8a") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3:4:5:6:7:8") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1:2") def test_generic_ipaddress_as_generic_not_required(self): f = GenericIPAddressField(required=False) - self.assertEqual(f.clean(''), '') - self.assertEqual(f.clean(None), '') - self.assertEqual(f.clean('127.0.0.1'), '127.0.0.1') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('foo') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('127.0.0.') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('1.2.3.4.5') - with self.assertRaisesMessage(ValidationError, "'Enter a valid IPv4 or IPv6 address.'"): - f.clean('256.125.1.5') - self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a') - self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('12345:2:3:4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3::4') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('foo::223:6cff:fe8a:2e8a') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1::2:3:4:5:6:7:8') - with self.assertRaisesMessage(ValidationError, "'This is not a valid IPv6 address.'"): - f.clean('1:2') + self.assertEqual(f.clean(""), "") + self.assertEqual(f.clean(None), "") + self.assertEqual(f.clean("127.0.0.1"), "127.0.0.1") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("foo") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("127.0.0.") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("1.2.3.4.5") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid IPv4 or IPv6 address.'" + ): + f.clean("256.125.1.5") + self.assertEqual( + f.clean(" fe80::223:6cff:fe8a:2e8a "), "fe80::223:6cff:fe8a:2e8a" + ) + self.assertEqual( + f.clean(" 2a02::223:6cff:fe8a:2e8a "), "2a02::223:6cff:fe8a:2e8a" + ) + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("12345:2:3:4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3::4") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("foo::223:6cff:fe8a:2e8a") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1::2:3:4:5:6:7:8") + with self.assertRaisesMessage( + ValidationError, "'This is not a valid IPv6 address.'" + ): + f.clean("1:2") def test_generic_ipaddress_normalization(self): # Test the normalizing code f = GenericIPAddressField() - self.assertEqual(f.clean(' ::ffff:0a0a:0a0a '), '::ffff:10.10.10.10') - self.assertEqual(f.clean(' ::ffff:10.10.10.10 '), '::ffff:10.10.10.10') - self.assertEqual(f.clean(' 2001:000:a:0000:0:fe:fe:beef '), '2001:0:a::fe:fe:beef') - self.assertEqual(f.clean(' 2001::a:0000:0:fe:fe:beef '), '2001:0:a::fe:fe:beef') + self.assertEqual(f.clean(" ::ffff:0a0a:0a0a "), "::ffff:10.10.10.10") + self.assertEqual(f.clean(" ::ffff:10.10.10.10 "), "::ffff:10.10.10.10") + self.assertEqual( + f.clean(" 2001:000:a:0000:0:fe:fe:beef "), "2001:0:a::fe:fe:beef" + ) + self.assertEqual( + f.clean(" 2001::a:0000:0:fe:fe:beef "), "2001:0:a::fe:fe:beef" + ) f = GenericIPAddressField(unpack_ipv4=True) - self.assertEqual(f.clean(' ::ffff:0a0a:0a0a'), '10.10.10.10') + self.assertEqual(f.clean(" ::ffff:0a0a:0a0a"), "10.10.10.10") diff --git a/tests/forms_tests/field_tests/test_imagefield.py b/tests/forms_tests/field_tests/test_imagefield.py index 1cb34bf058..c138ee5c09 100644 --- a/tests/forms_tests/field_tests/test_imagefield.py +++ b/tests/forms_tests/field_tests/test_imagefield.py @@ -2,9 +2,7 @@ import os import unittest from django.core.exceptions import ValidationError -from django.core.files.uploadedfile import ( - SimpleUploadedFile, TemporaryUploadedFile, -) +from django.core.files.uploadedfile import SimpleUploadedFile, TemporaryUploadedFile from django.forms import ClearableFileInput, FileInput, ImageField, Widget from django.test import SimpleTestCase @@ -17,26 +15,27 @@ except ImportError: def get_img_path(path): - return os.path.join(os.path.abspath(os.path.join(__file__, '..', '..')), 'tests', path) + return os.path.join( + os.path.abspath(os.path.join(__file__, "..", "..")), "tests", path + ) @unittest.skipUnless(Image, "Pillow is required to test ImageField") class ImageFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_imagefield_annotate_with_image_after_clean(self): f = ImageField() - img_path = get_img_path('filepath_test_files/1x1.png') - with open(img_path, 'rb') as img_file: + img_path = get_img_path("filepath_test_files/1x1.png") + with open(img_path, "rb") as img_file: img_data = img_file.read() - img_file = SimpleUploadedFile('1x1.png', img_data) - img_file.content_type = 'text/plain' + img_file = SimpleUploadedFile("1x1.png", img_data) + img_file.content_type = "text/plain" uploaded_file = f.clean(img_file) - self.assertEqual('PNG', uploaded_file.image.format) - self.assertEqual('image/png', uploaded_file.content_type) + self.assertEqual("PNG", uploaded_file.image.format) + self.assertEqual("image/png", uploaded_file.content_type) def test_imagefield_annotate_with_bitmap_image_after_clean(self): """ @@ -44,42 +43,47 @@ class ImageFieldTest(FormFieldAssertionsMixin, SimpleTestCase): of the image (#24948). """ from PIL.BmpImagePlugin import BmpImageFile + try: Image.register_mime(BmpImageFile.format, None) f = ImageField() - img_path = get_img_path('filepath_test_files/1x1.bmp') - with open(img_path, 'rb') as img_file: + img_path = get_img_path("filepath_test_files/1x1.bmp") + with open(img_path, "rb") as img_file: img_data = img_file.read() - img_file = SimpleUploadedFile('1x1.bmp', img_data) - img_file.content_type = 'text/plain' + img_file = SimpleUploadedFile("1x1.bmp", img_data) + img_file.content_type = "text/plain" uploaded_file = f.clean(img_file) - self.assertEqual('BMP', uploaded_file.image.format) + self.assertEqual("BMP", uploaded_file.image.format) self.assertIsNone(uploaded_file.content_type) finally: - Image.register_mime(BmpImageFile.format, 'image/bmp') + Image.register_mime(BmpImageFile.format, "image/bmp") def test_file_extension_validation(self): f = ImageField() - img_path = get_img_path('filepath_test_files/1x1.png') - with open(img_path, 'rb') as img_file: + img_path = get_img_path("filepath_test_files/1x1.png") + with open(img_path, "rb") as img_file: img_data = img_file.read() - img_file = SimpleUploadedFile('1x1.txt', img_data) - with self.assertRaisesMessage(ValidationError, 'File extension “txt” is not allowed.'): + img_file = SimpleUploadedFile("1x1.txt", img_data) + with self.assertRaisesMessage( + ValidationError, "File extension “txt” is not allowed." + ): f.clean(img_file) def test_corrupted_image(self): f = ImageField() - img_file = SimpleUploadedFile('not_an_image.jpg', b'not an image') + img_file = SimpleUploadedFile("not_an_image.jpg", b"not an image") msg = ( - 'Upload a valid image. The file you uploaded was either not an ' - 'image or a corrupted image.' + "Upload a valid image. The file you uploaded was either not an " + "image or a corrupted image." ) with self.assertRaisesMessage(ValidationError, msg): f.clean(img_file) - with TemporaryUploadedFile('not_an_image_tmp.png', 'text/plain', 1, 'utf-8') as tmp_file: + with TemporaryUploadedFile( + "not_an_image_tmp.png", "text/plain", 1, "utf-8" + ) as tmp_file: with self.assertRaisesMessage(ValidationError, msg): f.clean(tmp_file) @@ -87,16 +91,22 @@ class ImageFieldTest(FormFieldAssertionsMixin, SimpleTestCase): f = ImageField() # Nothing added for non-FileInput widgets. self.assertEqual(f.widget_attrs(Widget()), {}) - self.assertEqual(f.widget_attrs(FileInput()), {'accept': 'image/*'}) - self.assertEqual(f.widget_attrs(ClearableFileInput()), {'accept': 'image/*'}) - self.assertWidgetRendersTo(f, '<input type="file" name="f" accept="image/*" required id="id_f" />') + self.assertEqual(f.widget_attrs(FileInput()), {"accept": "image/*"}) + self.assertEqual(f.widget_attrs(ClearableFileInput()), {"accept": "image/*"}) + self.assertWidgetRendersTo( + f, '<input type="file" name="f" accept="image/*" required id="id_f" />' + ) def test_widget_attrs_accept_specified(self): - f = ImageField(widget=FileInput(attrs={'accept': 'image/png'})) + f = ImageField(widget=FileInput(attrs={"accept": "image/png"})) self.assertEqual(f.widget_attrs(f.widget), {}) - self.assertWidgetRendersTo(f, '<input type="file" name="f" accept="image/png" required id="id_f" />') + self.assertWidgetRendersTo( + f, '<input type="file" name="f" accept="image/png" required id="id_f" />' + ) def test_widget_attrs_accept_false(self): - f = ImageField(widget=FileInput(attrs={'accept': False})) + f = ImageField(widget=FileInput(attrs={"accept": False})) self.assertEqual(f.widget_attrs(f.widget), {}) - self.assertWidgetRendersTo(f, '<input type="file" name="f" required id="id_f" />') + self.assertWidgetRendersTo( + f, '<input type="file" name="f" required id="id_f" />' + ) diff --git a/tests/forms_tests/field_tests/test_integerfield.py b/tests/forms_tests/field_tests/test_integerfield.py index 0dde7ff488..15314d53a4 100644 --- a/tests/forms_tests/field_tests/test_integerfield.py +++ b/tests/forms_tests/field_tests/test_integerfield.py @@ -6,91 +6,108 @@ from . import FormFieldAssertionsMixin class IntegerFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_integerfield_1(self): f = IntegerField() - self.assertWidgetRendersTo(f, '<input type="number" name="f" id="id_f" required>') + self.assertWidgetRendersTo( + f, '<input type="number" name="f" id="id_f" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(1, f.clean('1')) - self.assertIsInstance(f.clean('1'), int) - self.assertEqual(23, f.clean('23')) + self.assertEqual(1, f.clean("1")) + self.assertIsInstance(f.clean("1"), int) + self.assertEqual(23, f.clean("23")) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('a') + f.clean("a") self.assertEqual(42, f.clean(42)) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): f.clean(3.14) - self.assertEqual(1, f.clean('1 ')) - self.assertEqual(1, f.clean(' 1')) - self.assertEqual(1, f.clean(' 1 ')) + self.assertEqual(1, f.clean("1 ")) + self.assertEqual(1, f.clean(" 1")) + self.assertEqual(1, f.clean(" 1 ")) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('1a') + f.clean("1a") self.assertIsNone(f.max_value) self.assertIsNone(f.min_value) def test_integerfield_2(self): f = IntegerField(required=False) - self.assertIsNone(f.clean('')) - self.assertEqual('None', repr(f.clean(''))) + self.assertIsNone(f.clean("")) + self.assertEqual("None", repr(f.clean(""))) self.assertIsNone(f.clean(None)) - self.assertEqual('None', repr(f.clean(None))) - self.assertEqual(1, f.clean('1')) - self.assertIsInstance(f.clean('1'), int) - self.assertEqual(23, f.clean('23')) + self.assertEqual("None", repr(f.clean(None))) + self.assertEqual(1, f.clean("1")) + self.assertIsInstance(f.clean("1"), int) + self.assertEqual(23, f.clean("23")) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('a') - self.assertEqual(1, f.clean('1 ')) - self.assertEqual(1, f.clean(' 1')) - self.assertEqual(1, f.clean(' 1 ')) + f.clean("a") + self.assertEqual(1, f.clean("1 ")) + self.assertEqual(1, f.clean(" 1")) + self.assertEqual(1, f.clean(" 1 ")) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('1a') + f.clean("1a") self.assertIsNone(f.max_value) self.assertIsNone(f.min_value) def test_integerfield_3(self): f = IntegerField(max_value=10) - self.assertWidgetRendersTo(f, '<input max="10" type="number" name="f" id="id_f" required>') + self.assertWidgetRendersTo( + f, '<input max="10" type="number" name="f" id="id_f" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) self.assertEqual(1, f.clean(1)) self.assertEqual(10, f.clean(10)) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 10.'"): + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is less than or equal to 10.'" + ): f.clean(11) - self.assertEqual(10, f.clean('10')) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 10.'"): - f.clean('11') + self.assertEqual(10, f.clean("10")) + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is less than or equal to 10.'" + ): + f.clean("11") self.assertEqual(f.max_value, 10) self.assertIsNone(f.min_value) def test_integerfield_4(self): f = IntegerField(min_value=10) - self.assertWidgetRendersTo(f, '<input id="id_f" type="number" name="f" min="10" required>') + self.assertWidgetRendersTo( + f, '<input id="id_f" type="number" name="f" min="10" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'"): + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is greater than or equal to 10.'" + ): f.clean(1) self.assertEqual(10, f.clean(10)) self.assertEqual(11, f.clean(11)) - self.assertEqual(10, f.clean('10')) - self.assertEqual(11, f.clean('11')) + self.assertEqual(10, f.clean("10")) + self.assertEqual(11, f.clean("11")) self.assertIsNone(f.max_value) self.assertEqual(f.min_value, 10) def test_integerfield_5(self): f = IntegerField(min_value=10, max_value=20) - self.assertWidgetRendersTo(f, '<input id="id_f" max="20" type="number" name="f" min="10" required>') + self.assertWidgetRendersTo( + f, '<input id="id_f" max="20" type="number" name="f" min="10" required>' + ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'"): + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is greater than or equal to 10.'" + ): f.clean(1) self.assertEqual(10, f.clean(10)) self.assertEqual(11, f.clean(11)) - self.assertEqual(10, f.clean('10')) - self.assertEqual(11, f.clean('11')) + self.assertEqual(10, f.clean("10")) + self.assertEqual(11, f.clean("11")) self.assertEqual(20, f.clean(20)) - with self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 20.'"): + with self.assertRaisesMessage( + ValidationError, "'Ensure this value is less than or equal to 20.'" + ): f.clean(21) self.assertEqual(f.max_value, 20) self.assertEqual(f.min_value, 10) @@ -101,34 +118,37 @@ class IntegerFieldTest(FormFieldAssertionsMixin, SimpleTestCase): number input specific attributes. """ f1 = IntegerField(localize=True) - self.assertWidgetRendersTo(f1, '<input id="id_f" name="f" type="text" required>') + self.assertWidgetRendersTo( + f1, '<input id="id_f" name="f" type="text" required>' + ) def test_integerfield_float(self): f = IntegerField() self.assertEqual(1, f.clean(1.0)) - self.assertEqual(1, f.clean('1.0')) - self.assertEqual(1, f.clean(' 1.0 ')) - self.assertEqual(1, f.clean('1.')) - self.assertEqual(1, f.clean(' 1. ')) + self.assertEqual(1, f.clean("1.0")) + self.assertEqual(1, f.clean(" 1.0 ")) + self.assertEqual(1, f.clean("1.")) + self.assertEqual(1, f.clean(" 1. ")) with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('1.5') + f.clean("1.5") with self.assertRaisesMessage(ValidationError, "'Enter a whole number.'"): - f.clean('…') + f.clean("…") def test_integerfield_big_num(self): f = IntegerField() self.assertEqual(9223372036854775808, f.clean(9223372036854775808)) - self.assertEqual(9223372036854775808, f.clean('9223372036854775808')) - self.assertEqual(9223372036854775808, f.clean('9223372036854775808.0')) + self.assertEqual(9223372036854775808, f.clean("9223372036854775808")) + self.assertEqual(9223372036854775808, f.clean("9223372036854775808.0")) def test_integerfield_unicode_number(self): f = IntegerField() - self.assertEqual(50, f.clean('50')) + self.assertEqual(50, f.clean("50")) def test_integerfield_subclass(self): """ Class-defined widget is not overwritten by __init__() (#22245). """ + class MyIntegerField(IntegerField): widget = Textarea diff --git a/tests/forms_tests/field_tests/test_jsonfield.py b/tests/forms_tests/field_tests/test_jsonfield.py index b4f3e74f6a..be2b077e64 100644 --- a/tests/forms_tests/field_tests/test_jsonfield.py +++ b/tests/forms_tests/field_tests/test_jsonfield.py @@ -3,7 +3,12 @@ import uuid from django.core.serializers.json import DjangoJSONEncoder from django.forms import ( - CharField, Form, JSONField, Textarea, TextInput, ValidationError, + CharField, + Form, + JSONField, + Textarea, + TextInput, + ValidationError, ) from django.test import SimpleTestCase @@ -12,25 +17,25 @@ class JSONFieldTest(SimpleTestCase): def test_valid(self): field = JSONField() value = field.clean('{"a": "b"}') - self.assertEqual(value, {'a': 'b'}) + self.assertEqual(value, {"a": "b"}) def test_valid_empty(self): field = JSONField(required=False) - self.assertIsNone(field.clean('')) + self.assertIsNone(field.clean("")) self.assertIsNone(field.clean(None)) def test_invalid(self): field = JSONField() - with self.assertRaisesMessage(ValidationError, 'Enter a valid JSON.'): - field.clean('{some badly formed: json}') + with self.assertRaisesMessage(ValidationError, "Enter a valid JSON."): + field.clean("{some badly formed: json}") def test_prepare_value(self): field = JSONField() - self.assertEqual(field.prepare_value({'a': 'b'}), '{"a": "b"}') - self.assertEqual(field.prepare_value(None), 'null') - self.assertEqual(field.prepare_value('foo'), '"foo"') - self.assertEqual(field.prepare_value('你好,世界'), '"你好,世界"') - self.assertEqual(field.prepare_value({'a': '😀🐱'}), '{"a": "😀🐱"}') + self.assertEqual(field.prepare_value({"a": "b"}), '{"a": "b"}') + self.assertEqual(field.prepare_value(None), "null") + self.assertEqual(field.prepare_value("foo"), '"foo"') + self.assertEqual(field.prepare_value("你好,世界"), '"你好,世界"') + self.assertEqual(field.prepare_value({"a": "😀🐱"}), '{"a": "😀🐱"}') self.assertEqual( field.prepare_value(["你好,世界", "jaźń"]), '["你好,世界", "jaźń"]', @@ -46,6 +51,7 @@ class JSONFieldTest(SimpleTestCase): def test_custom_widget_attribute(self): """The widget can be overridden with an attribute.""" + class CustomJSONField(JSONField): widget = TextInput @@ -57,12 +63,12 @@ class JSONFieldTest(SimpleTestCase): tests = [ '["a", "b", "c"]', '{"a": 1, "b": 2}', - '1', - '1.5', + "1", + "1.5", '"foo"', - 'true', - 'false', - 'null', + "true", + "false", + "null", ] for json_string in tests: with self.subTest(json_string=json_string): @@ -71,8 +77,8 @@ class JSONFieldTest(SimpleTestCase): def test_has_changed(self): field = JSONField() - self.assertIs(field.has_changed({'a': True}, '{"a": 1}'), True) - self.assertIs(field.has_changed({'a': 1, 'b': 2}, '{"b": 2, "a": 1}'), False) + self.assertIs(field.has_changed({"a": True}, '{"a": 1}'), True) + self.assertIs(field.has_changed({"a": 1, "b": 2}, '{"b": 2, "a": 1}'), False) def test_custom_encoder_decoder(self): class CustomDecoder(json.JSONDecoder): @@ -80,11 +86,11 @@ class JSONFieldTest(SimpleTestCase): return super().__init__(object_hook=self.as_uuid, *args, **kwargs) def as_uuid(self, dct): - if 'uuid' in dct: - dct['uuid'] = uuid.UUID(dct['uuid']) + if "uuid" in dct: + dct["uuid"] = uuid.UUID(dct["uuid"]) return dct - value = {'uuid': uuid.UUID('{c141e152-6550-4172-a784-05448d98204b}')} + value = {"uuid": uuid.UUID("{c141e152-6550-4172-a784-05448d98204b}")} encoded_value = '{"uuid": "c141e152-6550-4172-a784-05448d98204b"}' field = JSONField(encoder=DjangoJSONEncoder, decoder=CustomDecoder) self.assertEqual(field.prepare_value(value), encoded_value) @@ -94,8 +100,8 @@ class JSONFieldTest(SimpleTestCase): class JSONForm(Form): json_field = JSONField(disabled=True) - form = JSONForm({'json_field': '["bar"]'}, initial={'json_field': ['foo']}) - self.assertIn('["foo"]</textarea>', form.as_p()) + form = JSONForm({"json_field": '["bar"]'}, initial={"json_field": ["foo"]}) + self.assertIn("["foo"]</textarea>", form.as_p()) def test_redisplay_none_input(self): class JSONForm(Form): @@ -103,29 +109,30 @@ class JSONFieldTest(SimpleTestCase): tests = [ {}, - {'json_field': None}, + {"json_field": None}, ] for data in tests: with self.subTest(data=data): form = JSONForm(data) - self.assertEqual(form['json_field'].value(), 'null') - self.assertIn('null</textarea>', form.as_p()) - self.assertEqual(form.errors['json_field'], ['This field is required.']) + self.assertEqual(form["json_field"].value(), "null") + self.assertIn("null</textarea>", form.as_p()) + self.assertEqual(form.errors["json_field"], ["This field is required."]) def test_redisplay_wrong_input(self): """ Displaying a bound form (typically due to invalid input). The form should not overquote JSONField inputs. """ + class JSONForm(Form): name = CharField(max_length=2) json_field = JSONField() # JSONField input is valid, name is too long. - form = JSONForm({'name': 'xyz', 'json_field': '["foo"]'}) - self.assertNotIn('json_field', form.errors) - self.assertIn('["foo"]</textarea>', form.as_p()) + form = JSONForm({"name": "xyz", "json_field": '["foo"]'}) + self.assertNotIn("json_field", form.errors) + self.assertIn("["foo"]</textarea>", form.as_p()) # Invalid JSONField. - form = JSONForm({'name': 'xy', 'json_field': '{"foo"}'}) - self.assertEqual(form.errors['json_field'], ['Enter a valid JSON.']) - self.assertIn('{"foo"}</textarea>', form.as_p()) + form = JSONForm({"name": "xy", "json_field": '{"foo"}'}) + self.assertEqual(form.errors["json_field"], ["Enter a valid JSON."]) + self.assertIn("{"foo"}</textarea>", form.as_p()) diff --git a/tests/forms_tests/field_tests/test_multiplechoicefield.py b/tests/forms_tests/field_tests/test_multiplechoicefield.py index 6dbeee2685..f316e1de8e 100644 --- a/tests/forms_tests/field_tests/test_multiplechoicefield.py +++ b/tests/forms_tests/field_tests/test_multiplechoicefield.py @@ -4,72 +4,75 @@ from django.test import SimpleTestCase class MultipleChoiceFieldTest(SimpleTestCase): - def test_multiplechoicefield_1(self): - f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two')]) + f = MultipleChoiceField(choices=[("1", "One"), ("2", "Two")]) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) - self.assertEqual(['1'], f.clean([1])) - self.assertEqual(['1'], f.clean(['1'])) - self.assertEqual(['1', '2'], f.clean(['1', '2'])) - self.assertEqual(['1', '2'], f.clean([1, '2'])) - self.assertEqual(['1', '2'], f.clean((1, '2'))) + self.assertEqual(["1"], f.clean([1])) + self.assertEqual(["1"], f.clean(["1"])) + self.assertEqual(["1", "2"], f.clean(["1", "2"])) + self.assertEqual(["1", "2"], f.clean([1, "2"])) + self.assertEqual(["1", "2"], f.clean((1, "2"))) with self.assertRaisesMessage(ValidationError, "'Enter a list of values.'"): - f.clean('hello') + f.clean("hello") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean([]) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(()) msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['3']) + f.clean(["3"]) def test_multiplechoicefield_2(self): - f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two')], required=False) - self.assertEqual([], f.clean('')) + f = MultipleChoiceField(choices=[("1", "One"), ("2", "Two")], required=False) + self.assertEqual([], f.clean("")) self.assertEqual([], f.clean(None)) - self.assertEqual(['1'], f.clean([1])) - self.assertEqual(['1'], f.clean(['1'])) - self.assertEqual(['1', '2'], f.clean(['1', '2'])) - self.assertEqual(['1', '2'], f.clean([1, '2'])) - self.assertEqual(['1', '2'], f.clean((1, '2'))) + self.assertEqual(["1"], f.clean([1])) + self.assertEqual(["1"], f.clean(["1"])) + self.assertEqual(["1", "2"], f.clean(["1", "2"])) + self.assertEqual(["1", "2"], f.clean([1, "2"])) + self.assertEqual(["1", "2"], f.clean((1, "2"))) with self.assertRaisesMessage(ValidationError, "'Enter a list of values.'"): - f.clean('hello') + f.clean("hello") self.assertEqual([], f.clean([])) self.assertEqual([], f.clean(())) msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['3']) + f.clean(["3"]) def test_multiplechoicefield_3(self): f = MultipleChoiceField( - choices=[('Numbers', (('1', 'One'), ('2', 'Two'))), ('Letters', (('3', 'A'), ('4', 'B'))), ('5', 'Other')] + choices=[ + ("Numbers", (("1", "One"), ("2", "Two"))), + ("Letters", (("3", "A"), ("4", "B"))), + ("5", "Other"), + ] ) - self.assertEqual(['1'], f.clean([1])) - self.assertEqual(['1'], f.clean(['1'])) - self.assertEqual(['1', '5'], f.clean([1, 5])) - self.assertEqual(['1', '5'], f.clean([1, '5'])) - self.assertEqual(['1', '5'], f.clean(['1', 5])) - self.assertEqual(['1', '5'], f.clean(['1', '5'])) + self.assertEqual(["1"], f.clean([1])) + self.assertEqual(["1"], f.clean(["1"])) + self.assertEqual(["1", "5"], f.clean([1, 5])) + self.assertEqual(["1", "5"], f.clean([1, "5"])) + self.assertEqual(["1", "5"], f.clean(["1", 5])) + self.assertEqual(["1", "5"], f.clean(["1", "5"])) msg = "'Select a valid choice. 6 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['6']) + f.clean(["6"]) msg = "'Select a valid choice. 6 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['1', '6']) + f.clean(["1", "6"]) def test_multiplechoicefield_changed(self): - f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two'), ('3', 'Three')]) + f = MultipleChoiceField(choices=[("1", "One"), ("2", "Two"), ("3", "Three")]) self.assertFalse(f.has_changed(None, None)) self.assertFalse(f.has_changed([], None)) - self.assertTrue(f.has_changed(None, ['1'])) - self.assertFalse(f.has_changed([1, 2], ['1', '2'])) - self.assertFalse(f.has_changed([2, 1], ['1', '2'])) - self.assertTrue(f.has_changed([1, 2], ['1'])) - self.assertTrue(f.has_changed([1, 2], ['1', '3'])) + self.assertTrue(f.has_changed(None, ["1"])) + self.assertFalse(f.has_changed([1, 2], ["1", "2"])) + self.assertFalse(f.has_changed([2, 1], ["1", "2"])) + self.assertTrue(f.has_changed([1, 2], ["1"])) + self.assertTrue(f.has_changed([1, 2], ["1", "3"])) def test_disabled_has_changed(self): - f = MultipleChoiceField(choices=[('1', 'One'), ('2', 'Two')], disabled=True) - self.assertIs(f.has_changed('x', 'y'), False) + f = MultipleChoiceField(choices=[("1", "One"), ("2", "Two")], disabled=True) + self.assertIs(f.has_changed("x", "y"), False) diff --git a/tests/forms_tests/field_tests/test_multivaluefield.py b/tests/forms_tests/field_tests/test_multivaluefield.py index 449bf16d19..88f7490013 100644 --- a/tests/forms_tests/field_tests/test_multivaluefield.py +++ b/tests/forms_tests/field_tests/test_multivaluefield.py @@ -2,17 +2,24 @@ from datetime import datetime from django.core.exceptions import ValidationError from django.forms import ( - CharField, Form, MultipleChoiceField, MultiValueField, MultiWidget, - SelectMultiple, SplitDateTimeField, SplitDateTimeWidget, TextInput, + CharField, + Form, + MultipleChoiceField, + MultiValueField, + MultiWidget, + SelectMultiple, + SplitDateTimeField, + SplitDateTimeWidget, + TextInput, ) from django.test import SimpleTestCase -beatles = (('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')) +beatles = (("J", "John"), ("P", "Paul"), ("G", "George"), ("R", "Ringo")) class PartiallyRequiredField(MultiValueField): def compress(self, data_list): - return ','.join(data_list) if data_list else None + return ",".join(data_list) if data_list else None class PartiallyRequiredForm(Form): @@ -35,7 +42,7 @@ class ComplexMultiWidget(MultiWidget): def decompress(self, value): if value: - data = value.split(',') + data = value.split(",") return [ data[0], list(data[1]), @@ -55,7 +62,7 @@ class ComplexField(MultiValueField): def compress(self, data_list): if data_list: - return '%s,%s,%s' % (data_list[0], ''.join(data_list[1]), data_list[2]) + return "%s,%s,%s" % (data_list[0], "".join(data_list[1]), data_list[2]) return None @@ -64,7 +71,6 @@ class ComplexFieldForm(Form): class MultiValueFieldTest(SimpleTestCase): - @classmethod def setUpClass(cls): cls.field = ComplexField(widget=ComplexMultiWidget()) @@ -72,8 +78,8 @@ class MultiValueFieldTest(SimpleTestCase): def test_clean(self): self.assertEqual( - self.field.clean(['some text', ['J', 'P'], ['2007-04-25', '6:24:00']]), - 'some text,JP,2007-04-25 06:24:00', + self.field.clean(["some text", ["J", "P"], ["2007-04-25", "6:24:00"]]), + "some text,JP,2007-04-25 06:24:00", ) def test_clean_disabled_multivalue(self): @@ -81,20 +87,20 @@ class MultiValueFieldTest(SimpleTestCase): f = ComplexField(disabled=True, widget=ComplexMultiWidget) inputs = ( - 'some text,JP,2007-04-25 06:24:00', - ['some text', ['J', 'P'], ['2007-04-25', '6:24:00']], + "some text,JP,2007-04-25 06:24:00", + ["some text", ["J", "P"], ["2007-04-25", "6:24:00"]], ) for data in inputs: with self.subTest(data=data): - form = ComplexFieldForm({}, initial={'f': data}) + form = ComplexFieldForm({}, initial={"f": data}) form.full_clean() self.assertEqual(form.errors, {}) - self.assertEqual(form.cleaned_data, {'f': inputs[0]}) + self.assertEqual(form.cleaned_data, {"f": inputs[0]}) def test_bad_choice(self): msg = "'Select a valid choice. X is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - self.field.clean(['some text', ['X'], ['2007-04-25', '6:24:00']]) + self.field.clean(["some text", ["X"], ["2007-04-25", "6:24:00"]]) def test_no_value(self): """ @@ -102,39 +108,49 @@ class MultiValueFieldTest(SimpleTestCase): """ msg = "'This field is required.'" with self.assertRaisesMessage(ValidationError, msg): - self.field.clean(['some text', ['JP']]) + self.field.clean(["some text", ["JP"]]) def test_has_changed_no_initial(self): - self.assertTrue(self.field.has_changed(None, ['some text', ['J', 'P'], ['2007-04-25', '6:24:00']])) + self.assertTrue( + self.field.has_changed( + None, ["some text", ["J", "P"], ["2007-04-25", "6:24:00"]] + ) + ) def test_has_changed_same(self): - self.assertFalse(self.field.has_changed( - 'some text,JP,2007-04-25 06:24:00', - ['some text', ['J', 'P'], ['2007-04-25', '6:24:00']], - )) + self.assertFalse( + self.field.has_changed( + "some text,JP,2007-04-25 06:24:00", + ["some text", ["J", "P"], ["2007-04-25", "6:24:00"]], + ) + ) def test_has_changed_first_widget(self): """ Test when the first widget's data has changed. """ - self.assertTrue(self.field.has_changed( - 'some text,JP,2007-04-25 06:24:00', - ['other text', ['J', 'P'], ['2007-04-25', '6:24:00']], - )) + self.assertTrue( + self.field.has_changed( + "some text,JP,2007-04-25 06:24:00", + ["other text", ["J", "P"], ["2007-04-25", "6:24:00"]], + ) + ) def test_has_changed_last_widget(self): """ Test when the last widget's data has changed. This ensures that it is not short circuiting while testing the widgets. """ - self.assertTrue(self.field.has_changed( - 'some text,JP,2007-04-25 06:24:00', - ['some text', ['J', 'P'], ['2009-04-25', '11:44:00']], - )) + self.assertTrue( + self.field.has_changed( + "some text,JP,2007-04-25 06:24:00", + ["some text", ["J", "P"], ["2009-04-25", "11:44:00"]], + ) + ) def test_disabled_has_changed(self): f = MultiValueField(fields=(CharField(), CharField()), disabled=True) - self.assertIs(f.has_changed(['x', 'x'], ['y', 'y']), False) + self.assertIs(f.has_changed(["x", "x"], ["y", "y"]), False) def test_form_as_table(self): form = ComplexFieldForm() @@ -155,12 +171,14 @@ class MultiValueFieldTest(SimpleTestCase): ) def test_form_as_table_data(self): - form = ComplexFieldForm({ - 'field1_0': 'some text', - 'field1_1': ['J', 'P'], - 'field1_2_0': '2007-04-25', - 'field1_2_1': '06:24:00', - }) + form = ComplexFieldForm( + { + "field1_0": "some text", + "field1_1": ["J", "P"], + "field1_2_0": "2007-04-25", + "field1_2_1": "06:24:00", + } + ) self.assertHTMLEqual( form.as_table(), """ @@ -178,19 +196,26 @@ class MultiValueFieldTest(SimpleTestCase): ) def test_form_cleaned_data(self): - form = ComplexFieldForm({ - 'field1_0': 'some text', - 'field1_1': ['J', 'P'], - 'field1_2_0': '2007-04-25', - 'field1_2_1': '06:24:00', - }) + form = ComplexFieldForm( + { + "field1_0": "some text", + "field1_1": ["J", "P"], + "field1_2_0": "2007-04-25", + "field1_2_1": "06:24:00", + } + ) form.is_valid() - self.assertEqual(form.cleaned_data['field1'], 'some text,JP,2007-04-25 06:24:00') + self.assertEqual( + form.cleaned_data["field1"], "some text,JP,2007-04-25 06:24:00" + ) def test_render_required_attributes(self): - form = PartiallyRequiredForm({'f_0': 'Hello', 'f_1': ''}) + form = PartiallyRequiredForm({"f_0": "Hello", "f_1": ""}) self.assertTrue(form.is_valid()) - self.assertInHTML('<input type="text" name="f_0" value="Hello" required id="id_f_0">', form.as_p()) + self.assertInHTML( + '<input type="text" name="f_0" value="Hello" required id="id_f_0">', + form.as_p(), + ) self.assertInHTML('<input type="text" name="f_1" id="id_f_1">', form.as_p()) - form = PartiallyRequiredForm({'f_0': '', 'f_1': ''}) + form = PartiallyRequiredForm({"f_0": "", "f_1": ""}) self.assertFalse(form.is_valid()) diff --git a/tests/forms_tests/field_tests/test_nullbooleanfield.py b/tests/forms_tests/field_tests/test_nullbooleanfield.py index 55812612c9..5b632c8de3 100644 --- a/tests/forms_tests/field_tests/test_nullbooleanfield.py +++ b/tests/forms_tests/field_tests/test_nullbooleanfield.py @@ -5,56 +5,60 @@ from . import FormFieldAssertionsMixin class NullBooleanFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_nullbooleanfield_clean(self): f = NullBooleanField() - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertTrue(f.clean(True)) self.assertFalse(f.clean(False)) self.assertIsNone(f.clean(None)) - self.assertFalse(f.clean('0')) - self.assertTrue(f.clean('1')) - self.assertIsNone(f.clean('2')) - self.assertIsNone(f.clean('3')) - self.assertIsNone(f.clean('hello')) - self.assertTrue(f.clean('true')) - self.assertFalse(f.clean('false')) + self.assertFalse(f.clean("0")) + self.assertTrue(f.clean("1")) + self.assertIsNone(f.clean("2")) + self.assertIsNone(f.clean("3")) + self.assertIsNone(f.clean("hello")) + self.assertTrue(f.clean("true")) + self.assertFalse(f.clean("false")) def test_nullbooleanfield_2(self): # The internal value is preserved if using HiddenInput (#7753). class HiddenNullBooleanForm(Form): hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True) hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False) + f = HiddenNullBooleanForm() self.assertHTMLEqual( '<input type="hidden" name="hidden_nullbool1" value="True" id="id_hidden_nullbool1">' '<input type="hidden" name="hidden_nullbool2" value="False" id="id_hidden_nullbool2">', - str(f) + str(f), ) def test_nullbooleanfield_3(self): class HiddenNullBooleanForm(Form): hidden_nullbool1 = NullBooleanField(widget=HiddenInput, initial=True) hidden_nullbool2 = NullBooleanField(widget=HiddenInput, initial=False) - f = HiddenNullBooleanForm({'hidden_nullbool1': 'True', 'hidden_nullbool2': 'False'}) + + f = HiddenNullBooleanForm( + {"hidden_nullbool1": "True", "hidden_nullbool2": "False"} + ) self.assertIsNone(f.full_clean()) - self.assertTrue(f.cleaned_data['hidden_nullbool1']) - self.assertFalse(f.cleaned_data['hidden_nullbool2']) + self.assertTrue(f.cleaned_data["hidden_nullbool1"]) + self.assertFalse(f.cleaned_data["hidden_nullbool2"]) def test_nullbooleanfield_4(self): # Make sure we're compatible with MySQL, which uses 0 and 1 for its # boolean values (#9609). - NULLBOOL_CHOICES = (('1', 'Yes'), ('0', 'No'), ('', 'Unknown')) + NULLBOOL_CHOICES = (("1", "Yes"), ("0", "No"), ("", "Unknown")) class MySQLNullBooleanForm(Form): nullbool0 = NullBooleanField(widget=RadioSelect(choices=NULLBOOL_CHOICES)) nullbool1 = NullBooleanField(widget=RadioSelect(choices=NULLBOOL_CHOICES)) nullbool2 = NullBooleanField(widget=RadioSelect(choices=NULLBOOL_CHOICES)) - f = MySQLNullBooleanForm({'nullbool0': '1', 'nullbool1': '0', 'nullbool2': ''}) + + f = MySQLNullBooleanForm({"nullbool0": "1", "nullbool1": "0", "nullbool2": ""}) self.assertIsNone(f.full_clean()) - self.assertTrue(f.cleaned_data['nullbool0']) - self.assertFalse(f.cleaned_data['nullbool1']) - self.assertIsNone(f.cleaned_data['nullbool2']) + self.assertTrue(f.cleaned_data["nullbool0"]) + self.assertFalse(f.cleaned_data["nullbool1"]) + self.assertIsNone(f.cleaned_data["nullbool2"]) def test_nullbooleanfield_changed(self): f = NullBooleanField() @@ -66,9 +70,9 @@ class NullBooleanFieldTest(FormFieldAssertionsMixin, SimpleTestCase): self.assertTrue(f.has_changed(True, None)) self.assertTrue(f.has_changed(True, False)) # HiddenInput widget sends string values for boolean but doesn't clean them in value_from_datadict - self.assertFalse(f.has_changed(False, 'False')) - self.assertFalse(f.has_changed(True, 'True')) - self.assertFalse(f.has_changed(None, '')) - self.assertTrue(f.has_changed(False, 'True')) - self.assertTrue(f.has_changed(True, 'False')) - self.assertTrue(f.has_changed(None, 'False')) + self.assertFalse(f.has_changed(False, "False")) + self.assertFalse(f.has_changed(True, "True")) + self.assertFalse(f.has_changed(None, "")) + self.assertTrue(f.has_changed(False, "True")) + self.assertTrue(f.has_changed(True, "False")) + self.assertTrue(f.has_changed(None, "False")) diff --git a/tests/forms_tests/field_tests/test_regexfield.py b/tests/forms_tests/field_tests/test_regexfield.py index 80d0f1c7cd..9a2b1387f6 100644 --- a/tests/forms_tests/field_tests/test_regexfield.py +++ b/tests/forms_tests/field_tests/test_regexfield.py @@ -6,80 +6,84 @@ from django.test import SimpleTestCase class RegexFieldTest(SimpleTestCase): - def test_regexfield_1(self): - f = RegexField('^[0-9][A-F][0-9]$') - self.assertEqual('2A2', f.clean('2A2')) - self.assertEqual('3F3', f.clean('3F3')) + f = RegexField("^[0-9][A-F][0-9]$") + self.assertEqual("2A2", f.clean("2A2")) + self.assertEqual("3F3", f.clean("3F3")) with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('3G3') + f.clean("3G3") with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean(' 2A2') + f.clean(" 2A2") with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('2A2 ') + f.clean("2A2 ") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") def test_regexfield_2(self): - f = RegexField('^[0-9][A-F][0-9]$', required=False) - self.assertEqual('2A2', f.clean('2A2')) - self.assertEqual('3F3', f.clean('3F3')) + f = RegexField("^[0-9][A-F][0-9]$", required=False) + self.assertEqual("2A2", f.clean("2A2")) + self.assertEqual("3F3", f.clean("3F3")) with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('3G3') - self.assertEqual('', f.clean('')) + f.clean("3G3") + self.assertEqual("", f.clean("")) def test_regexfield_3(self): - f = RegexField(re.compile('^[0-9][A-F][0-9]$')) - self.assertEqual('2A2', f.clean('2A2')) - self.assertEqual('3F3', f.clean('3F3')) + f = RegexField(re.compile("^[0-9][A-F][0-9]$")) + self.assertEqual("2A2", f.clean("2A2")) + self.assertEqual("3F3", f.clean("3F3")) with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('3G3') + f.clean("3G3") with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean(' 2A2') + f.clean(" 2A2") with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('2A2 ') + f.clean("2A2 ") def test_regexfield_4(self): - f = RegexField('^[0-9]+$', min_length=5, max_length=10) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 5 characters (it has 3).'"): - f.clean('123') + f = RegexField("^[0-9]+$", min_length=5, max_length=10) + with self.assertRaisesMessage( + ValidationError, "'Ensure this value has at least 5 characters (it has 3).'" + ): + f.clean("123") with self.assertRaisesMessage( ValidationError, "'Ensure this value has at least 5 characters (it has 3).', " "'Enter a valid value.'", ): - f.clean('abc') - self.assertEqual('12345', f.clean('12345')) - self.assertEqual('1234567890', f.clean('1234567890')) - with self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 10 characters (it has 11).'"): - f.clean('12345678901') + f.clean("abc") + self.assertEqual("12345", f.clean("12345")) + self.assertEqual("1234567890", f.clean("1234567890")) + with self.assertRaisesMessage( + ValidationError, + "'Ensure this value has at most 10 characters (it has 11).'", + ): + f.clean("12345678901") with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('12345a') + f.clean("12345a") def test_regexfield_unicode_characters(self): - f = RegexField(r'^\w+$') - self.assertEqual('éèøçÎÎ你好', f.clean('éèøçÎÎ你好')) + f = RegexField(r"^\w+$") + self.assertEqual("éèøçÎÎ你好", f.clean("éèøçÎÎ你好")) def test_change_regex_after_init(self): - f = RegexField('^[a-z]+$') - f.regex = '^[0-9]+$' - self.assertEqual('1234', f.clean('1234')) + f = RegexField("^[a-z]+$") + f.regex = "^[0-9]+$" + self.assertEqual("1234", f.clean("1234")) with self.assertRaisesMessage(ValidationError, "'Enter a valid value.'"): - f.clean('abcd') + f.clean("abcd") def test_get_regex(self): - f = RegexField('^[a-z]+$') - self.assertEqual(f.regex, re.compile('^[a-z]+$')) + f = RegexField("^[a-z]+$") + self.assertEqual(f.regex, re.compile("^[a-z]+$")) def test_regexfield_strip(self): - f = RegexField('^[a-z]+$', strip=True) - self.assertEqual(f.clean(' a'), 'a') - self.assertEqual(f.clean('a '), 'a') + f = RegexField("^[a-z]+$", strip=True) + self.assertEqual(f.clean(" a"), "a") + self.assertEqual(f.clean("a "), "a") def test_empty_value(self): - f = RegexField('', required=False) - self.assertEqual(f.clean(''), '') - self.assertEqual(f.clean(None), '') - f = RegexField('', empty_value=None, required=False) - self.assertIsNone(f.clean('')) + f = RegexField("", required=False) + self.assertEqual(f.clean(""), "") + self.assertEqual(f.clean(None), "") + f = RegexField("", empty_value=None, required=False) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) diff --git a/tests/forms_tests/field_tests/test_slugfield.py b/tests/forms_tests/field_tests/test_slugfield.py index 6d766e8af5..d796a2c3aa 100644 --- a/tests/forms_tests/field_tests/test_slugfield.py +++ b/tests/forms_tests/field_tests/test_slugfield.py @@ -3,25 +3,24 @@ from django.test import SimpleTestCase class SlugFieldTest(SimpleTestCase): - def test_slugfield_normalization(self): f = SlugField() - self.assertEqual(f.clean(' aa-bb-cc '), 'aa-bb-cc') + self.assertEqual(f.clean(" aa-bb-cc "), "aa-bb-cc") def test_slugfield_unicode_normalization(self): f = SlugField(allow_unicode=True) - self.assertEqual(f.clean('a'), 'a') - self.assertEqual(f.clean('1'), '1') - self.assertEqual(f.clean('a1'), 'a1') - self.assertEqual(f.clean('你好'), '你好') - self.assertEqual(f.clean(' 你-好 '), '你-好') - self.assertEqual(f.clean('ıçğüş'), 'ıçğüş') - self.assertEqual(f.clean('foo-ıç-bar'), 'foo-ıç-bar') + self.assertEqual(f.clean("a"), "a") + self.assertEqual(f.clean("1"), "1") + self.assertEqual(f.clean("a1"), "a1") + self.assertEqual(f.clean("你好"), "你好") + self.assertEqual(f.clean(" 你-好 "), "你-好") + self.assertEqual(f.clean("ıçğüş"), "ıçğüş") + self.assertEqual(f.clean("foo-ıç-bar"), "foo-ıç-bar") def test_empty_value(self): f = SlugField(required=False) - self.assertEqual(f.clean(''), '') - self.assertEqual(f.clean(None), '') + self.assertEqual(f.clean(""), "") + self.assertEqual(f.clean(None), "") f = SlugField(required=False, empty_value=None) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) diff --git a/tests/forms_tests/field_tests/test_splitdatetimefield.py b/tests/forms_tests/field_tests/test_splitdatetimefield.py index bf20587682..788ca592fa 100644 --- a/tests/forms_tests/field_tests/test_splitdatetimefield.py +++ b/tests/forms_tests/field_tests/test_splitdatetimefield.py @@ -7,59 +7,78 @@ from django.test import SimpleTestCase class SplitDateTimeFieldTest(SimpleTestCase): - def test_splitdatetimefield_1(self): f = SplitDateTimeField() self.assertIsInstance(f.widget, SplitDateTimeWidget) self.assertEqual( datetime.datetime(2006, 1, 10, 7, 30), - f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) + f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]), ) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'Enter a list of values.'"): - f.clean('hello') - with self.assertRaisesMessage(ValidationError, "'Enter a valid date.', 'Enter a valid time.'"): - f.clean(['hello', 'there']) + f.clean("hello") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid date.', 'Enter a valid time.'" + ): + f.clean(["hello", "there"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean(['2006-01-10', 'there']) + f.clean(["2006-01-10", "there"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean(['hello', '07:30']) + f.clean(["hello", "07:30"]) def test_splitdatetimefield_2(self): f = SplitDateTimeField(required=False) self.assertEqual( datetime.datetime(2006, 1, 10, 7, 30), - f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]) + f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)]), + ) + self.assertEqual( + datetime.datetime(2006, 1, 10, 7, 30), f.clean(["2006-01-10", "07:30"]) ) - self.assertEqual(datetime.datetime(2006, 1, 10, 7, 30), f.clean(['2006-01-10', '07:30'])) self.assertIsNone(f.clean(None)) - self.assertIsNone(f.clean('')) - self.assertIsNone(f.clean([''])) - self.assertIsNone(f.clean(['', ''])) + self.assertIsNone(f.clean("")) + self.assertIsNone(f.clean([""])) + self.assertIsNone(f.clean(["", ""])) with self.assertRaisesMessage(ValidationError, "'Enter a list of values.'"): - f.clean('hello') - with self.assertRaisesMessage(ValidationError, "'Enter a valid date.', 'Enter a valid time.'"): - f.clean(['hello', 'there']) + f.clean("hello") + with self.assertRaisesMessage( + ValidationError, "'Enter a valid date.', 'Enter a valid time.'" + ): + f.clean(["hello", "there"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean(['2006-01-10', 'there']) + f.clean(["2006-01-10", "there"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean(['hello', '07:30']) + f.clean(["hello", "07:30"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean(['2006-01-10', '']) + f.clean(["2006-01-10", ""]) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean(['2006-01-10']) + f.clean(["2006-01-10"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid date.'"): - f.clean(['', '07:30']) + f.clean(["", "07:30"]) def test_splitdatetimefield_changed(self): - f = SplitDateTimeField(input_date_formats=['%d/%m/%Y']) - self.assertFalse(f.has_changed(['11/01/2012', '09:18:15'], ['11/01/2012', '09:18:15'])) - self.assertTrue(f.has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['2008-05-06', '12:40:00'])) - self.assertFalse(f.has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['06/05/2008', '12:40'])) - self.assertTrue(f.has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['06/05/2008', '12:41'])) + f = SplitDateTimeField(input_date_formats=["%d/%m/%Y"]) + self.assertFalse( + f.has_changed(["11/01/2012", "09:18:15"], ["11/01/2012", "09:18:15"]) + ) + self.assertTrue( + f.has_changed( + datetime.datetime(2008, 5, 6, 12, 40, 00), ["2008-05-06", "12:40:00"] + ) + ) + self.assertFalse( + f.has_changed( + datetime.datetime(2008, 5, 6, 12, 40, 00), ["06/05/2008", "12:40"] + ) + ) + self.assertTrue( + f.has_changed( + datetime.datetime(2008, 5, 6, 12, 40, 00), ["06/05/2008", "12:41"] + ) + ) def test_form_as_table(self): class TestForm(Form): @@ -68,8 +87,8 @@ class SplitDateTimeFieldTest(SimpleTestCase): f = TestForm() self.assertHTMLEqual( f.as_table(), - '<tr><th><label>Datetime:</label></th><td>' + "<tr><th><label>Datetime:</label></th><td>" '<input type="text" name="datetime_0" required id="id_datetime_0">' '<input type="text" name="datetime_1" required id="id_datetime_1">' - '</td></tr>', + "</td></tr>", ) diff --git a/tests/forms_tests/field_tests/test_timefield.py b/tests/forms_tests/field_tests/test_timefield.py index a44b10fa07..fbe6a3cf31 100644 --- a/tests/forms_tests/field_tests/test_timefield.py +++ b/tests/forms_tests/field_tests/test_timefield.py @@ -8,39 +8,38 @@ from . import FormFieldAssertionsMixin class TimeFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_timefield_1(self): f = TimeField() self.assertEqual(datetime.time(14, 25), f.clean(datetime.time(14, 25))) self.assertEqual(datetime.time(14, 25, 59), f.clean(datetime.time(14, 25, 59))) - self.assertEqual(datetime.time(14, 25), f.clean('14:25')) - self.assertEqual(datetime.time(14, 25, 59), f.clean('14:25:59')) + self.assertEqual(datetime.time(14, 25), f.clean("14:25")) + self.assertEqual(datetime.time(14, 25, 59), f.clean("14:25:59")) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean('hello') + f.clean("hello") with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean('1:24 p.m.') + f.clean("1:24 p.m.") def test_timefield_2(self): - f = TimeField(input_formats=['%I:%M %p']) + f = TimeField(input_formats=["%I:%M %p"]) self.assertEqual(datetime.time(14, 25), f.clean(datetime.time(14, 25))) self.assertEqual(datetime.time(14, 25, 59), f.clean(datetime.time(14, 25, 59))) - self.assertEqual(datetime.time(4, 25), f.clean('4:25 AM')) - self.assertEqual(datetime.time(16, 25), f.clean('4:25 PM')) + self.assertEqual(datetime.time(4, 25), f.clean("4:25 AM")) + self.assertEqual(datetime.time(16, 25), f.clean("4:25 PM")) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean('14:30:45') + f.clean("14:30:45") def test_timefield_3(self): f = TimeField() # Test whitespace stripping behavior (#5714) - self.assertEqual(datetime.time(14, 25), f.clean(' 14:25 ')) - self.assertEqual(datetime.time(14, 25, 59), f.clean(' 14:25:59 ')) + self.assertEqual(datetime.time(14, 25), f.clean(" 14:25 ")) + self.assertEqual(datetime.time(14, 25, 59), f.clean(" 14:25:59 ")) with self.assertRaisesMessage(ValidationError, "'Enter a valid time.'"): - f.clean(' ') + f.clean(" ") def test_timefield_changed(self): t1 = datetime.time(12, 51, 34, 482548) t2 = datetime.time(12, 51) - f = TimeField(input_formats=['%H:%M', '%H:%M %p']) - self.assertTrue(f.has_changed(t1, '12:51')) - self.assertFalse(f.has_changed(t2, '12:51')) - self.assertFalse(f.has_changed(t2, '12:51 PM')) + f = TimeField(input_formats=["%H:%M", "%H:%M %p"]) + self.assertTrue(f.has_changed(t1, "12:51")) + self.assertFalse(f.has_changed(t2, "12:51")) + self.assertFalse(f.has_changed(t2, "12:51 PM")) diff --git a/tests/forms_tests/field_tests/test_typedchoicefield.py b/tests/forms_tests/field_tests/test_typedchoicefield.py index 2c6cd265b5..52a83eca37 100644 --- a/tests/forms_tests/field_tests/test_typedchoicefield.py +++ b/tests/forms_tests/field_tests/test_typedchoicefield.py @@ -6,72 +6,84 @@ from django.test import SimpleTestCase class TypedChoiceFieldTest(SimpleTestCase): - def test_typedchoicefield_1(self): f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) - self.assertEqual(1, f.clean('1')) + self.assertEqual(1, f.clean("1")) msg = "'Select a valid choice. 2 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('2') + f.clean("2") def test_typedchoicefield_2(self): # Different coercion, same validation. f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=float) - self.assertEqual(1.0, f.clean('1')) + self.assertEqual(1.0, f.clean("1")) def test_typedchoicefield_3(self): # This can also cause weirdness: be careful (bool(-1) == True, remember) f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=bool) - self.assertTrue(f.clean('-1')) + self.assertTrue(f.clean("-1")) def test_typedchoicefield_4(self): # Even more weirdness: if you have a valid choice but your coercion function # can't coerce, you'll still get a validation error. Don't do this! - f = TypedChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int) + f = TypedChoiceField(choices=[("A", "A"), ("B", "B")], coerce=int) msg = "'Select a valid choice. B is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('B') + f.clean("B") # Required fields require values with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") def test_typedchoicefield_5(self): # Non-required fields aren't required - f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False) - self.assertEqual('', f.clean('')) + f = TypedChoiceField( + choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False + ) + self.assertEqual("", f.clean("")) # If you want cleaning an empty value to return a different type, tell the field def test_typedchoicefield_6(self): - f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None) - self.assertIsNone(f.clean('')) + f = TypedChoiceField( + choices=[(1, "+1"), (-1, "-1")], + coerce=int, + required=False, + empty_value=None, + ) + self.assertIsNone(f.clean("")) def test_typedchoicefield_has_changed(self): # has_changed should not trigger required validation f = TypedChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=True) - self.assertFalse(f.has_changed(None, '')) - self.assertFalse(f.has_changed(1, '1')) - self.assertFalse(f.has_changed('1', '1')) + self.assertFalse(f.has_changed(None, "")) + self.assertFalse(f.has_changed(1, "1")) + self.assertFalse(f.has_changed("1", "1")) f = TypedChoiceField( - choices=[('', '---------'), ('a', "a"), ('b', "b")], coerce=str, - required=False, initial=None, empty_value=None, + choices=[("", "---------"), ("a", "a"), ("b", "b")], + coerce=str, + required=False, + initial=None, + empty_value=None, ) - self.assertFalse(f.has_changed(None, '')) - self.assertTrue(f.has_changed('', 'a')) - self.assertFalse(f.has_changed('a', 'a')) + self.assertFalse(f.has_changed(None, "")) + self.assertTrue(f.has_changed("", "a")) + self.assertFalse(f.has_changed("a", "a")) def test_typedchoicefield_special_coerce(self): """ A coerce function which results in a value not present in choices should raise an appropriate error (#21397). """ + def coerce_func(val): - return decimal.Decimal('1.%s' % val) + return decimal.Decimal("1.%s" % val) - f = TypedChoiceField(choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True) - self.assertEqual(decimal.Decimal('1.2'), f.clean('2')) + f = TypedChoiceField( + choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True + ) + self.assertEqual(decimal.Decimal("1.2"), f.clean("2")) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('3') + f.clean("3") diff --git a/tests/forms_tests/field_tests/test_typedmultiplechoicefield.py b/tests/forms_tests/field_tests/test_typedmultiplechoicefield.py index 1c97676a87..6810f1ed19 100644 --- a/tests/forms_tests/field_tests/test_typedmultiplechoicefield.py +++ b/tests/forms_tests/field_tests/test_typedmultiplechoicefield.py @@ -6,70 +6,80 @@ from django.test import SimpleTestCase class TypedMultipleChoiceFieldTest(SimpleTestCase): - def test_typedmultiplechoicefield_1(self): f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) - self.assertEqual([1], f.clean(['1'])) + self.assertEqual([1], f.clean(["1"])) msg = "'Select a valid choice. 2 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['2']) + f.clean(["2"]) def test_typedmultiplechoicefield_2(self): # Different coercion, same validation. f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=float) - self.assertEqual([1.0], f.clean(['1'])) + self.assertEqual([1.0], f.clean(["1"])) def test_typedmultiplechoicefield_3(self): # This can also cause weirdness: be careful (bool(-1) == True, remember) f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=bool) - self.assertEqual([True], f.clean(['-1'])) + self.assertEqual([True], f.clean(["-1"])) def test_typedmultiplechoicefield_4(self): f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int) - self.assertEqual([1, -1], f.clean(['1', '-1'])) + self.assertEqual([1, -1], f.clean(["1", "-1"])) msg = "'Select a valid choice. 2 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['1', '2']) + f.clean(["1", "2"]) def test_typedmultiplechoicefield_5(self): # Even more weirdness: if you have a valid choice but your coercion function # can't coerce, you'll still get a validation error. Don't do this! - f = TypedMultipleChoiceField(choices=[('A', 'A'), ('B', 'B')], coerce=int) + f = TypedMultipleChoiceField(choices=[("A", "A"), ("B", "B")], coerce=int) msg = "'Select a valid choice. B is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['B']) + f.clean(["B"]) # Required fields require values with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean([]) def test_typedmultiplechoicefield_6(self): # Non-required fields aren't required - f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False) + f = TypedMultipleChoiceField( + choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False + ) self.assertEqual([], f.clean([])) def test_typedmultiplechoicefield_7(self): # If you want cleaning an empty value to return a different type, tell the field - f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=False, empty_value=None) + f = TypedMultipleChoiceField( + choices=[(1, "+1"), (-1, "-1")], + coerce=int, + required=False, + empty_value=None, + ) self.assertIsNone(f.clean([])) def test_typedmultiplechoicefield_has_changed(self): # has_changed should not trigger required validation - f = TypedMultipleChoiceField(choices=[(1, "+1"), (-1, "-1")], coerce=int, required=True) - self.assertFalse(f.has_changed(None, '')) + f = TypedMultipleChoiceField( + choices=[(1, "+1"), (-1, "-1")], coerce=int, required=True + ) + self.assertFalse(f.has_changed(None, "")) def test_typedmultiplechoicefield_special_coerce(self): """ A coerce function which results in a value not present in choices should raise an appropriate error (#21397). """ + def coerce_func(val): - return decimal.Decimal('1.%s' % val) + return decimal.Decimal("1.%s" % val) f = TypedMultipleChoiceField( - choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True) - self.assertEqual([decimal.Decimal('1.2')], f.clean(['2'])) + choices=[(1, "1"), (2, "2")], coerce=coerce_func, required=True + ) + self.assertEqual([decimal.Decimal("1.2")], f.clean(["2"])) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean([]) msg = "'Select a valid choice. 3 is not one of the available choices.'" with self.assertRaisesMessage(ValidationError, msg): - f.clean(['3']) + f.clean(["3"]) diff --git a/tests/forms_tests/field_tests/test_urlfield.py b/tests/forms_tests/field_tests/test_urlfield.py index 187d44a050..042a3bf586 100644 --- a/tests/forms_tests/field_tests/test_urlfield.py +++ b/tests/forms_tests/field_tests/test_urlfield.py @@ -6,14 +6,13 @@ from . import FormFieldAssertionsMixin class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): - def test_urlfield_widget(self): f = URLField() self.assertWidgetRendersTo(f, '<input type="url" name="f" id="id_f" required>') def test_urlfield_widget_max_min_length(self): f = URLField(min_length=15, max_length=20) - self.assertEqual('http://example.com', f.clean('http://example.com')) + self.assertEqual("http://example.com", f.clean("http://example.com")) self.assertWidgetRendersTo( f, '<input id="id_f" type="url" name="f" maxlength="20" ' @@ -21,55 +20,58 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): ) msg = "'Ensure this value has at least 15 characters (it has 12).'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('http://f.com') + f.clean("http://f.com") msg = "'Ensure this value has at most 20 characters (it has 37).'" with self.assertRaisesMessage(ValidationError, msg): - f.clean('http://abcdefghijklmnopqrstuvwxyz.com') + f.clean("http://abcdefghijklmnopqrstuvwxyz.com") def test_urlfield_clean(self): f = URLField(required=False) tests = [ - ('http://localhost', 'http://localhost'), - ('http://example.com', 'http://example.com'), - ('http://example.com/test', 'http://example.com/test'), - ('http://example.com.', 'http://example.com.'), - ('http://www.example.com', 'http://www.example.com'), - ('http://www.example.com:8000/test', 'http://www.example.com:8000/test'), + ("http://localhost", "http://localhost"), + ("http://example.com", "http://example.com"), + ("http://example.com/test", "http://example.com/test"), + ("http://example.com.", "http://example.com."), + ("http://www.example.com", "http://www.example.com"), + ("http://www.example.com:8000/test", "http://www.example.com:8000/test"), ( - 'http://example.com?some_param=some_value', - 'http://example.com?some_param=some_value', + "http://example.com?some_param=some_value", + "http://example.com?some_param=some_value", ), - ('valid-with-hyphens.com', 'http://valid-with-hyphens.com'), - ('subdomain.domain.com', 'http://subdomain.domain.com'), - ('http://200.8.9.10', 'http://200.8.9.10'), - ('http://200.8.9.10:8000/test', 'http://200.8.9.10:8000/test'), - ('http://valid-----hyphens.com', 'http://valid-----hyphens.com'), + ("valid-with-hyphens.com", "http://valid-with-hyphens.com"), + ("subdomain.domain.com", "http://subdomain.domain.com"), + ("http://200.8.9.10", "http://200.8.9.10"), + ("http://200.8.9.10:8000/test", "http://200.8.9.10:8000/test"), + ("http://valid-----hyphens.com", "http://valid-----hyphens.com"), ( - 'http://some.idn.xyzäöüßabc.domain.com:123/blah', - 'http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah', + "http://some.idn.xyzäöüßabc.domain.com:123/blah", + "http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah", ), ( - 'www.example.com/s/http://code.djangoproject.com/ticket/13804', - 'http://www.example.com/s/http://code.djangoproject.com/ticket/13804', + "www.example.com/s/http://code.djangoproject.com/ticket/13804", + "http://www.example.com/s/http://code.djangoproject.com/ticket/13804", ), # Normalization. - ('http://example.com/ ', 'http://example.com/'), + ("http://example.com/ ", "http://example.com/"), # Valid IDN. - ('http://עברית.idn.icann.org/', 'http://עברית.idn.icann.org/'), - ('http://sãopaulo.com/', 'http://sãopaulo.com/'), - ('http://sãopaulo.com.br/', 'http://sãopaulo.com.br/'), - ('http://пример.испытание/', 'http://пример.испытание/'), - ('http://مثال.إختبار/', 'http://مثال.إختبار/'), - ('http://例子.测试/', 'http://例子.测试/'), - ('http://例子.測試/', 'http://例子.測試/'), - ('http://उदाहरण.परीक्षा/', 'http://उदाहरण.परीक्षा/',), - ('http://例え.テスト/', 'http://例え.テスト/'), - ('http://مثال.آزمایشی/', 'http://مثال.آزمایشی/'), - ('http://실례.테스트/', 'http://실례.테스트/'), - ('http://العربية.idn.icann.org/', 'http://العربية.idn.icann.org/'), + ("http://עברית.idn.icann.org/", "http://עברית.idn.icann.org/"), + ("http://sãopaulo.com/", "http://sãopaulo.com/"), + ("http://sãopaulo.com.br/", "http://sãopaulo.com.br/"), + ("http://пример.испытание/", "http://пример.испытание/"), + ("http://مثال.إختبار/", "http://مثال.إختبار/"), + ("http://例子.测试/", "http://例子.测试/"), + ("http://例子.測試/", "http://例子.測試/"), + ( + "http://उदाहरण.परीक्षा/", + "http://उदाहरण.परीक्षा/", + ), + ("http://例え.テスト/", "http://例え.テスト/"), + ("http://مثال.آزمایشی/", "http://مثال.آزمایشی/"), + ("http://실례.테스트/", "http://실례.테스트/"), + ("http://العربية.idn.icann.org/", "http://العربية.idn.icann.org/"), # IPv6. - ('http://[12:34::3a53]/', 'http://[12:34::3a53]/'), - ('http://[a34:9238::]:8080/', 'http://[a34:9238::]:8080/'), + ("http://[12:34::3a53]/", "http://[12:34::3a53]/"), + ("http://[a34:9238::]:8080/", "http://[a34:9238::]:8080/"), ] for url, expected in tests: with self.subTest(url=url): @@ -78,32 +80,32 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): def test_urlfield_clean_invalid(self): f = URLField() tests = [ - 'foo', - 'com.', - '.', - 'http://', - 'http://example', - 'http://example.', - 'http://.com', - 'http://invalid-.com', - 'http://-invalid.com', - 'http://inv-.alid-.com', - 'http://inv-.-alid.com', - '[a', - 'http://[a', + "foo", + "com.", + ".", + "http://", + "http://example", + "http://example.", + "http://.com", + "http://invalid-.com", + "http://-invalid.com", + "http://inv-.alid-.com", + "http://inv-.-alid.com", + "[a", + "http://[a", # Non-string. 23, # Hangs "forever" before fixing a catastrophic backtracking, # see #11198. - 'http://%s' % ('X' * 60,), + "http://%s" % ("X" * 60,), # A second example, to make sure the problem is really addressed, # even on domains that don't fail the domain label length check in # the regex. - 'http://%s' % ("X" * 200,), + "http://%s" % ("X" * 200,), # urlsplit() raises ValueError. - '////]@N.AN', + "////]@N.AN", # Empty hostname. - '#@A.bO', + "#@A.bO", ] msg = "'Enter a valid URL.'" for value in tests: @@ -117,16 +119,16 @@ class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase): with self.assertRaisesMessage(ValidationError, msg): f.clean(None) with self.assertRaisesMessage(ValidationError, msg): - f.clean('') + f.clean("") def test_urlfield_clean_not_required(self): f = URLField(required=False) - self.assertEqual(f.clean(None), '') - self.assertEqual(f.clean(''), '') + self.assertEqual(f.clean(None), "") + self.assertEqual(f.clean(""), "") def test_urlfield_strip_on_none_value(self): f = URLField(required=False, empty_value=None) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) def test_urlfield_unable_to_set_strip_kwarg(self): diff --git a/tests/forms_tests/field_tests/test_uuidfield.py b/tests/forms_tests/field_tests/test_uuidfield.py index e1c1698d02..b039c4a0c3 100644 --- a/tests/forms_tests/field_tests/test_uuidfield.py +++ b/tests/forms_tests/field_tests/test_uuidfield.py @@ -6,28 +6,27 @@ from django.test import SimpleTestCase class UUIDFieldTest(SimpleTestCase): - def test_uuidfield_1(self): field = UUIDField() - value = field.clean('550e8400e29b41d4a716446655440000') - self.assertEqual(value, uuid.UUID('550e8400e29b41d4a716446655440000')) + value = field.clean("550e8400e29b41d4a716446655440000") + self.assertEqual(value, uuid.UUID("550e8400e29b41d4a716446655440000")) def test_clean_value_with_dashes(self): field = UUIDField() - value = field.clean('550e8400-e29b-41d4-a716-446655440000') - self.assertEqual(value, uuid.UUID('550e8400e29b41d4a716446655440000')) + value = field.clean("550e8400-e29b-41d4-a716-446655440000") + self.assertEqual(value, uuid.UUID("550e8400e29b41d4a716446655440000")) def test_uuidfield_2(self): field = UUIDField(required=False) - self.assertIsNone(field.clean('')) + self.assertIsNone(field.clean("")) self.assertIsNone(field.clean(None)) def test_uuidfield_3(self): field = UUIDField() - with self.assertRaisesMessage(ValidationError, 'Enter a valid UUID.'): - field.clean('550e8400') + with self.assertRaisesMessage(ValidationError, "Enter a valid UUID."): + field.clean("550e8400") def test_uuidfield_4(self): field = UUIDField() - value = field.prepare_value(uuid.UUID('550e8400e29b41d4a716446655440000')) - self.assertEqual(value, '550e8400-e29b-41d4-a716-446655440000') + value = field.prepare_value(uuid.UUID("550e8400e29b41d4a716446655440000")) + self.assertEqual(value, "550e8400-e29b-41d4-a716-446655440000") diff --git a/tests/forms_tests/models.py b/tests/forms_tests/models.py index 23cabc2d84..ae212f332d 100644 --- a/tests/forms_tests/models.py +++ b/tests/forms_tests/models.py @@ -20,7 +20,7 @@ class BoundaryModel(models.Model): class Defaults(models.Model): - name = models.CharField(max_length=255, default='class default value') + name = models.CharField(max_length=255, default="class default value") def_date = models.DateField(default=datetime.date(1980, 1, 1)) value = models.IntegerField(default=42) callable_default = models.IntegerField(default=callable_default) @@ -28,45 +28,48 @@ class Defaults(models.Model): class ChoiceModel(models.Model): """For ModelChoiceField and ModelMultipleChoiceField tests.""" + CHOICES = [ - ('', 'No Preference'), - ('f', 'Foo'), - ('b', 'Bar'), + ("", "No Preference"), + ("f", "Foo"), + ("b", "Bar"), ] INTEGER_CHOICES = [ - (None, 'No Preference'), - (1, 'Foo'), - (2, 'Bar'), + (None, "No Preference"), + (1, "Foo"), + (2, "Bar"), ] STRING_CHOICES_WITH_NONE = [ - (None, 'No Preference'), - ('f', 'Foo'), - ('b', 'Bar'), + (None, "No Preference"), + ("f", "Foo"), + ("b", "Bar"), ] name = models.CharField(max_length=10) choice = models.CharField(max_length=2, blank=True, choices=CHOICES) choice_string_w_none = models.CharField( - max_length=2, blank=True, null=True, choices=STRING_CHOICES_WITH_NONE) + max_length=2, blank=True, null=True, choices=STRING_CHOICES_WITH_NONE + ) choice_integer = models.IntegerField(choices=INTEGER_CHOICES, blank=True, null=True) class ChoiceOptionModel(models.Model): """Destination for ChoiceFieldModel's ForeignKey. Can't reuse ChoiceModel because error_message tests require that it have no instances.""" + name = models.CharField(max_length=10) class Meta: - ordering = ('name',) + ordering = ("name",) def __str__(self): - return 'ChoiceOption %d' % self.pk + return "ChoiceOption %d" % self.pk def choice_default(): - return ChoiceOptionModel.objects.get_or_create(name='default')[0].pk + return ChoiceOptionModel.objects.get_or_create(name="default")[0].pk def choice_default_list(): @@ -84,6 +87,7 @@ def int_list_default(): class ChoiceFieldModel(models.Model): """Model with ForeignKey to another model, for testing ModelForm generation with ModelChoiceField.""" + choice = models.ForeignKey( ChoiceOptionModel, models.CASCADE, @@ -94,19 +98,19 @@ class ChoiceFieldModel(models.Model): ChoiceOptionModel, models.CASCADE, blank=False, - related_name='choice_int', + related_name="choice_int", default=int_default, ) multi_choice = models.ManyToManyField( ChoiceOptionModel, blank=False, - related_name='multi_choice', + related_name="multi_choice", default=choice_default_list, ) multi_choice_int = models.ManyToManyField( ChoiceOptionModel, blank=False, - related_name='multi_choice_int', + related_name="multi_choice_int", default=int_list_default, ) @@ -115,18 +119,18 @@ class OptionalMultiChoiceModel(models.Model): multi_choice = models.ManyToManyField( ChoiceOptionModel, blank=False, - related_name='not_relevant', + related_name="not_relevant", default=choice_default, ) multi_choice_optional = models.ManyToManyField( ChoiceOptionModel, blank=True, - related_name='not_relevant2', + related_name="not_relevant2", ) class FileModel(models.Model): - file = models.FileField(storage=temp_storage, upload_to='tests') + file = models.FileField(storage=temp_storage, upload_to="tests") class Article(models.Model): diff --git a/tests/forms_tests/tests/__init__.py b/tests/forms_tests/tests/__init__.py index 3d1d8eefa4..193a7149a1 100644 --- a/tests/forms_tests/tests/__init__.py +++ b/tests/forms_tests/tests/__init__.py @@ -9,8 +9,8 @@ except ImportError: def jinja2_tests(test_func): - test_func = skipIf(jinja2 is None, 'this test requires jinja2')(test_func) + test_func = skipIf(jinja2 is None, "this test requires jinja2")(test_func) return override_settings( - FORM_RENDERER='django.forms.renderers.Jinja2', - TEMPLATES={'BACKEND': 'django.template.backends.jinja2.Jinja2'}, + FORM_RENDERER="django.forms.renderers.Jinja2", + TEMPLATES={"BACKEND": "django.template.backends.jinja2.Jinja2"}, )(test_func) diff --git a/tests/forms_tests/tests/test_deprecation_forms.py b/tests/forms_tests/tests/test_deprecation_forms.py index 6bdb595602..2a4fb6b0e1 100644 --- a/tests/forms_tests/tests/test_deprecation_forms.py +++ b/tests/forms_tests/tests/test_deprecation_forms.py @@ -13,8 +13,8 @@ class DivErrorList(ErrorList): def as_divs(self): if not self: - return '' - return '<div class="errorlist">%s</div>' % ''.join( + return "" + return '<div class="errorlist">%s</div>' % "".join( f'<div class="error">{error}</div>' for error in self ) @@ -22,16 +22,16 @@ class DivErrorList(ErrorList): class DeprecationTests(SimpleTestCase): def test_deprecation_warning_html_output(self): msg = ( - 'django.forms.BaseForm._html_output() is deprecated. Please use ' - '.render() and .get_context() instead.' + "django.forms.BaseForm._html_output() is deprecated. Please use " + ".render() and .get_context() instead." ) with self.assertRaisesMessage(RemovedInDjango50Warning, msg): form = Person() form._html_output( normal_row='<p id="p_%(field_name)s"></p>', - error_row='%s', - row_ender='</p>', - help_text_html=' %s', + error_row="%s", + row_ender="</p>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -40,11 +40,11 @@ class DeprecationTests(SimpleTestCase): email = EmailField() comment = CharField() - data = {'email': 'invalid'} + data = {"email": "invalid"} f = EmailForm(data, error_class=DivErrorList) msg = ( - 'Returning a plain string from DivErrorList is deprecated. Please ' - 'customize via the template system instead.' + "Returning a plain string from DivErrorList is deprecated. Please " + "customize via the template system instead." ) with self.assertRaisesMessage(RemovedInDjango50Warning, msg): f.as_p() @@ -58,7 +58,7 @@ class DeprecatedTests(SimpleTestCase): email = EmailField() comment = CharField() - data = {'email': 'invalid'} + data = {"email": "invalid"} f = CommentForm(data, auto_id=False, error_class=DivErrorList) self.assertHTMLEqual( f.as_p(), @@ -73,15 +73,16 @@ class DeprecatedTests(SimpleTestCase): def test_field_name(self): """#5749 - `field_name` may be used as a key in _html_output().""" + class SomeForm(Form): some_field = CharField() def as_p(self): return self._html_output( normal_row='<p id="p_%(field_name)s"></p>', - error_row='%s', - row_ender='</p>', - help_text_html=' %s', + error_row="%s", + row_ender="</p>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -92,15 +93,16 @@ class DeprecatedTests(SimpleTestCase): """ `css_classes` may be used as a key in _html_output() (empty classes). """ + class SomeForm(Form): some_field = CharField() def as_p(self): return self._html_output( normal_row='<p class="%(css_classes)s"></p>', - error_row='%s', - row_ender='</p>', - help_text_html=' %s', + error_row="%s", + row_ender="</p>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -112,16 +114,17 @@ class DeprecatedTests(SimpleTestCase): `css_classes` may be used as a key in _html_output() (class comes from required_css_class in this case). """ + class SomeForm(Form): some_field = CharField() - required_css_class = 'foo' + required_css_class = "foo" def as_p(self): return self._html_output( normal_row='<p class="%(css_classes)s"></p>', - error_row='%s', - row_ender='</p>', - help_text_html=' %s', + error_row="%s", + row_ender="</p>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -133,6 +136,7 @@ class DeprecatedTests(SimpleTestCase): BaseForm._html_output() should merge all the hidden input fields and put them in the last row. """ + class SomeForm(Form): hidden1 = CharField(widget=HiddenInput) custom = CharField() @@ -140,10 +144,10 @@ class DeprecatedTests(SimpleTestCase): def as_p(self): return self._html_output( - normal_row='<p%(html_class_attr)s>%(field)s %(field_name)s</p>', - error_row='%s', - row_ender='</p>', - help_text_html=' %s', + normal_row="<p%(html_class_attr)s>%(field)s %(field_name)s</p>", + error_row="%s", + row_ender="</p>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -152,7 +156,7 @@ class DeprecatedTests(SimpleTestCase): form.as_p(), '<p><input id="id_custom" name="custom" type="text" required> custom' '<input id="id_hidden1" name="hidden1" type="hidden">' - '<input id="id_hidden2" name="hidden2" type="hidden"></p>' + '<input id="id_hidden2" name="hidden2" type="hidden"></p>', ) def test_field_name_with_hidden_input_and_non_matching_row_ender(self): @@ -160,6 +164,7 @@ class DeprecatedTests(SimpleTestCase): BaseForm._html_output() should merge all the hidden input fields and put them in the last row ended with the specific row ender. """ + class SomeForm(Form): hidden1 = CharField(widget=HiddenInput) custom = CharField() @@ -167,10 +172,10 @@ class DeprecatedTests(SimpleTestCase): def as_p(self): return self._html_output( - normal_row='<p%(html_class_attr)s>%(field)s %(field_name)s</p>', - error_row='%s', - row_ender='<hr><hr>', - help_text_html=' %s', + normal_row="<p%(html_class_attr)s>%(field)s %(field_name)s</p>", + error_row="%s", + row_ender="<hr><hr>", + help_text_html=" %s", errors_on_separate_row=True, ) @@ -179,5 +184,5 @@ class DeprecatedTests(SimpleTestCase): form.as_p(), '<p><input id="id_custom" name="custom" type="text" required> custom</p>\n' '<input id="id_hidden1" name="hidden1" type="hidden">' - '<input id="id_hidden2" name="hidden2" type="hidden"><hr><hr>' + '<input id="id_hidden2" name="hidden2" type="hidden"><hr><hr>', ) diff --git a/tests/forms_tests/tests/test_error_messages.py b/tests/forms_tests/tests/test_error_messages.py index 340c39546c..2ad356858f 100644 --- a/tests/forms_tests/tests/test_error_messages.py +++ b/tests/forms_tests/tests/test_error_messages.py @@ -1,11 +1,26 @@ from django.core.exceptions import ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.forms import ( - BooleanField, CharField, ChoiceField, DateField, DateTimeField, - DecimalField, EmailField, FileField, FloatField, Form, - GenericIPAddressField, IntegerField, ModelChoiceField, - ModelMultipleChoiceField, MultipleChoiceField, RegexField, - SplitDateTimeField, TimeField, URLField, utils, + BooleanField, + CharField, + ChoiceField, + DateField, + DateTimeField, + DecimalField, + EmailField, + FileField, + FloatField, + Form, + GenericIPAddressField, + IntegerField, + ModelChoiceField, + ModelMultipleChoiceField, + MultipleChoiceField, + RegexField, + SplitDateTimeField, + TimeField, + URLField, + utils, ) from django.template import Context, Template from django.test import SimpleTestCase, TestCase @@ -24,188 +39,188 @@ class AssertFormErrorsMixin: class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin): def test_charfield(self): e = { - 'required': 'REQUIRED', - 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s', - 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s', + "required": "REQUIRED", + "min_length": "LENGTH %(show_value)s, MIN LENGTH %(limit_value)s", + "max_length": "LENGTH %(show_value)s, MAX LENGTH %(limit_value)s", } f = CharField(min_length=5, max_length=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['LENGTH 4, MIN LENGTH 5'], f.clean, '1234') - self.assertFormErrors(['LENGTH 11, MAX LENGTH 10'], f.clean, '12345678901') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["LENGTH 4, MIN LENGTH 5"], f.clean, "1234") + self.assertFormErrors(["LENGTH 11, MAX LENGTH 10"], f.clean, "12345678901") def test_integerfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'min_value': 'MIN VALUE IS %(limit_value)s', - 'max_value': 'MAX VALUE IS %(limit_value)s', + "required": "REQUIRED", + "invalid": "INVALID", + "min_value": "MIN VALUE IS %(limit_value)s", + "max_value": "MAX VALUE IS %(limit_value)s", } f = IntegerField(min_value=5, max_value=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') - self.assertFormErrors(['MIN VALUE IS 5'], f.clean, '4') - self.assertFormErrors(['MAX VALUE IS 10'], f.clean, '11') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") + self.assertFormErrors(["MIN VALUE IS 5"], f.clean, "4") + self.assertFormErrors(["MAX VALUE IS 10"], f.clean, "11") def test_floatfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'min_value': 'MIN VALUE IS %(limit_value)s', - 'max_value': 'MAX VALUE IS %(limit_value)s', + "required": "REQUIRED", + "invalid": "INVALID", + "min_value": "MIN VALUE IS %(limit_value)s", + "max_value": "MAX VALUE IS %(limit_value)s", } f = FloatField(min_value=5, max_value=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') - self.assertFormErrors(['MIN VALUE IS 5'], f.clean, '4') - self.assertFormErrors(['MAX VALUE IS 10'], f.clean, '11') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") + self.assertFormErrors(["MIN VALUE IS 5"], f.clean, "4") + self.assertFormErrors(["MAX VALUE IS 10"], f.clean, "11") def test_decimalfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'min_value': 'MIN VALUE IS %(limit_value)s', - 'max_value': 'MAX VALUE IS %(limit_value)s', - 'max_digits': 'MAX DIGITS IS %(max)s', - 'max_decimal_places': 'MAX DP IS %(max)s', - 'max_whole_digits': 'MAX DIGITS BEFORE DP IS %(max)s', + "required": "REQUIRED", + "invalid": "INVALID", + "min_value": "MIN VALUE IS %(limit_value)s", + "max_value": "MAX VALUE IS %(limit_value)s", + "max_digits": "MAX DIGITS IS %(max)s", + "max_decimal_places": "MAX DP IS %(max)s", + "max_whole_digits": "MAX DIGITS BEFORE DP IS %(max)s", } f = DecimalField(min_value=5, max_value=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') - self.assertFormErrors(['MIN VALUE IS 5'], f.clean, '4') - self.assertFormErrors(['MAX VALUE IS 10'], f.clean, '11') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") + self.assertFormErrors(["MIN VALUE IS 5"], f.clean, "4") + self.assertFormErrors(["MAX VALUE IS 10"], f.clean, "11") f2 = DecimalField(max_digits=4, decimal_places=2, error_messages=e) - self.assertFormErrors(['MAX DIGITS IS 4'], f2.clean, '123.45') - self.assertFormErrors(['MAX DP IS 2'], f2.clean, '1.234') - self.assertFormErrors(['MAX DIGITS BEFORE DP IS 2'], f2.clean, '123.4') + self.assertFormErrors(["MAX DIGITS IS 4"], f2.clean, "123.45") + self.assertFormErrors(["MAX DP IS 2"], f2.clean, "1.234") + self.assertFormErrors(["MAX DIGITS BEFORE DP IS 2"], f2.clean, "123.4") def test_datefield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', + "required": "REQUIRED", + "invalid": "INVALID", } f = DateField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") def test_timefield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', + "required": "REQUIRED", + "invalid": "INVALID", } f = TimeField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") def test_datetimefield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', + "required": "REQUIRED", + "invalid": "INVALID", } f = DateTimeField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") def test_regexfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s', - 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s', + "required": "REQUIRED", + "invalid": "INVALID", + "min_length": "LENGTH %(show_value)s, MIN LENGTH %(limit_value)s", + "max_length": "LENGTH %(show_value)s, MAX LENGTH %(limit_value)s", } - f = RegexField(r'^[0-9]+$', min_length=5, max_length=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abcde') - self.assertFormErrors(['LENGTH 4, MIN LENGTH 5'], f.clean, '1234') - self.assertFormErrors(['LENGTH 11, MAX LENGTH 10'], f.clean, '12345678901') + f = RegexField(r"^[0-9]+$", min_length=5, max_length=10, error_messages=e) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abcde") + self.assertFormErrors(["LENGTH 4, MIN LENGTH 5"], f.clean, "1234") + self.assertFormErrors(["LENGTH 11, MAX LENGTH 10"], f.clean, "12345678901") def test_emailfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'min_length': 'LENGTH %(show_value)s, MIN LENGTH %(limit_value)s', - 'max_length': 'LENGTH %(show_value)s, MAX LENGTH %(limit_value)s', + "required": "REQUIRED", + "invalid": "INVALID", + "min_length": "LENGTH %(show_value)s, MIN LENGTH %(limit_value)s", + "max_length": "LENGTH %(show_value)s, MAX LENGTH %(limit_value)s", } f = EmailField(min_length=8, max_length=10, error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abcdefgh') - self.assertFormErrors(['LENGTH 7, MIN LENGTH 8'], f.clean, 'a@b.com') - self.assertFormErrors(['LENGTH 11, MAX LENGTH 10'], f.clean, 'aye@bee.com') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abcdefgh") + self.assertFormErrors(["LENGTH 7, MIN LENGTH 8"], f.clean, "a@b.com") + self.assertFormErrors(["LENGTH 11, MAX LENGTH 10"], f.clean, "aye@bee.com") def test_filefield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'missing': 'MISSING', - 'empty': 'EMPTY FILE', + "required": "REQUIRED", + "invalid": "INVALID", + "missing": "MISSING", + "empty": "EMPTY FILE", } f = FileField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc') - self.assertFormErrors(['EMPTY FILE'], f.clean, SimpleUploadedFile('name', None)) - self.assertFormErrors(['EMPTY FILE'], f.clean, SimpleUploadedFile('name', '')) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc") + self.assertFormErrors(["EMPTY FILE"], f.clean, SimpleUploadedFile("name", None)) + self.assertFormErrors(["EMPTY FILE"], f.clean, SimpleUploadedFile("name", "")) def test_urlfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID', - 'max_length': '"%(value)s" has more than %(limit_value)d characters.', + "required": "REQUIRED", + "invalid": "INVALID", + "max_length": '"%(value)s" has more than %(limit_value)d characters.', } f = URLField(error_messages=e, max_length=17) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID'], f.clean, 'abc.c') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID"], f.clean, "abc.c") self.assertFormErrors( ['"http://djangoproject.com" has more than 17 characters.'], f.clean, - 'djangoproject.com' + "djangoproject.com", ) def test_booleanfield(self): e = { - 'required': 'REQUIRED', + "required": "REQUIRED", } f = BooleanField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') + self.assertFormErrors(["REQUIRED"], f.clean, "") def test_choicefield(self): e = { - 'required': 'REQUIRED', - 'invalid_choice': '%(value)s IS INVALID CHOICE', + "required": "REQUIRED", + "invalid_choice": "%(value)s IS INVALID CHOICE", } - f = ChoiceField(choices=[('a', 'aye')], error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['b IS INVALID CHOICE'], f.clean, 'b') + f = ChoiceField(choices=[("a", "aye")], error_messages=e) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["b IS INVALID CHOICE"], f.clean, "b") def test_multiplechoicefield(self): e = { - 'required': 'REQUIRED', - 'invalid_choice': '%(value)s IS INVALID CHOICE', - 'invalid_list': 'NOT A LIST', + "required": "REQUIRED", + "invalid_choice": "%(value)s IS INVALID CHOICE", + "invalid_list": "NOT A LIST", } - f = MultipleChoiceField(choices=[('a', 'aye')], error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['NOT A LIST'], f.clean, 'b') - self.assertFormErrors(['b IS INVALID CHOICE'], f.clean, ['b']) + f = MultipleChoiceField(choices=[("a", "aye")], error_messages=e) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["NOT A LIST"], f.clean, "b") + self.assertFormErrors(["b IS INVALID CHOICE"], f.clean, ["b"]) def test_splitdatetimefield(self): e = { - 'required': 'REQUIRED', - 'invalid_date': 'INVALID DATE', - 'invalid_time': 'INVALID TIME', + "required": "REQUIRED", + "invalid_date": "INVALID DATE", + "invalid_time": "INVALID TIME", } f = SplitDateTimeField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID DATE', 'INVALID TIME'], f.clean, ['a', 'b']) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID DATE", "INVALID TIME"], f.clean, ["a", "b"]) def test_generic_ipaddressfield(self): e = { - 'required': 'REQUIRED', - 'invalid': 'INVALID IP ADDRESS', + "required": "REQUIRED", + "invalid": "INVALID IP ADDRESS", } f = GenericIPAddressField(error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID IP ADDRESS'], f.clean, '127.0.0') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID IP ADDRESS"], f.clean, "127.0.0") def test_subclassing_errorlist(self): class TestForm(Form): @@ -222,102 +237,113 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin): def as_divs(self): if not self: - return '' - return mark_safe('<div class="error">%s</div>' % ''.join('<p>%s</p>' % e for e in self)) + return "" + return mark_safe( + '<div class="error">%s</div>' + % "".join("<p>%s</p>" % e for e in self) + ) # This form should print errors the default way. - form1 = TestForm({'first_name': 'John'}) + form1 = TestForm({"first_name": "John"}) self.assertHTMLEqual( - str(form1['last_name'].errors), - '<ul class="errorlist"><li>This field is required.</li></ul>' + str(form1["last_name"].errors), + '<ul class="errorlist"><li>This field is required.</li></ul>', ) self.assertHTMLEqual( - str(form1.errors['__all__']), - '<ul class="errorlist nonfield"><li>I like to be awkward.</li></ul>' + str(form1.errors["__all__"]), + '<ul class="errorlist nonfield"><li>I like to be awkward.</li></ul>', ) # This one should wrap error groups in the customized way. - form2 = TestForm({'first_name': 'John'}, error_class=CustomErrorList) - self.assertHTMLEqual(str(form2['last_name'].errors), '<div class="error"><p>This field is required.</p></div>') - self.assertHTMLEqual(str(form2.errors['__all__']), '<div class="error"><p>I like to be awkward.</p></div>') + form2 = TestForm({"first_name": "John"}, error_class=CustomErrorList) + self.assertHTMLEqual( + str(form2["last_name"].errors), + '<div class="error"><p>This field is required.</p></div>', + ) + self.assertHTMLEqual( + str(form2.errors["__all__"]), + '<div class="error"><p>I like to be awkward.</p></div>', + ) def test_error_messages_escaping(self): # The forms layer doesn't escape input values directly because error # messages might be presented in non-HTML contexts. Instead, the # message is marked for escaping by the template engine, so a template # is needed to trigger the escaping. - t = Template('{{ form.errors }}') + t = Template("{{ form.errors }}") class SomeForm(Form): - field = ChoiceField(choices=[('one', 'One')]) + field = ChoiceField(choices=[("one", "One")]) - f = SomeForm({'field': '<script>'}) + f = SomeForm({"field": "<script>"}) self.assertHTMLEqual( - t.render(Context({'form': f})), + t.render(Context({"form": f})), '<ul class="errorlist"><li>field<ul class="errorlist">' - '<li>Select a valid choice. <script> is not one of the ' - 'available choices.</li></ul></li></ul>' + "<li>Select a valid choice. <script> is not one of the " + "available choices.</li></ul></li></ul>", ) class SomeForm(Form): - field = MultipleChoiceField(choices=[('one', 'One')]) + field = MultipleChoiceField(choices=[("one", "One")]) - f = SomeForm({'field': ['<script>']}) + f = SomeForm({"field": ["<script>"]}) self.assertHTMLEqual( - t.render(Context({'form': f})), + t.render(Context({"form": f})), '<ul class="errorlist"><li>field<ul class="errorlist">' - '<li>Select a valid choice. <script> is not one of the ' - 'available choices.</li></ul></li></ul>' + "<li>Select a valid choice. <script> is not one of the " + "available choices.</li></ul></li></ul>", ) class SomeForm(Form): field = ModelMultipleChoiceField(ChoiceModel.objects.all()) - f = SomeForm({'field': ['<script>']}) + f = SomeForm({"field": ["<script>"]}) self.assertHTMLEqual( - t.render(Context({'form': f})), + t.render(Context({"form": f})), '<ul class="errorlist"><li>field<ul class="errorlist">' - '<li>“<script>” is not a valid value.</li>' - '</ul></li></ul>' + "<li>“<script>” is not a valid value.</li>" + "</ul></li></ul>", ) class ModelChoiceFieldErrorMessagesTestCase(TestCase, AssertFormErrorsMixin): def test_modelchoicefield(self): # Create choices for the model choice field tests below. - ChoiceModel.objects.create(pk=1, name='a') - ChoiceModel.objects.create(pk=2, name='b') - ChoiceModel.objects.create(pk=3, name='c') + ChoiceModel.objects.create(pk=1, name="a") + ChoiceModel.objects.create(pk=2, name="b") + ChoiceModel.objects.create(pk=3, name="c") # ModelChoiceField e = { - 'required': 'REQUIRED', - 'invalid_choice': 'INVALID CHOICE', + "required": "REQUIRED", + "invalid_choice": "INVALID CHOICE", } f = ModelChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['INVALID CHOICE'], f.clean, '4') + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["INVALID CHOICE"], f.clean, "4") # ModelMultipleChoiceField e = { - 'required': 'REQUIRED', - 'invalid_choice': '%(value)s IS INVALID CHOICE', - 'invalid_list': 'NOT A LIST OF VALUES', + "required": "REQUIRED", + "invalid_choice": "%(value)s IS INVALID CHOICE", + "invalid_list": "NOT A LIST OF VALUES", } - f = ModelMultipleChoiceField(queryset=ChoiceModel.objects.all(), error_messages=e) - self.assertFormErrors(['REQUIRED'], f.clean, '') - self.assertFormErrors(['NOT A LIST OF VALUES'], f.clean, '3') - self.assertFormErrors(['4 IS INVALID CHOICE'], f.clean, ['4']) + f = ModelMultipleChoiceField( + queryset=ChoiceModel.objects.all(), error_messages=e + ) + self.assertFormErrors(["REQUIRED"], f.clean, "") + self.assertFormErrors(["NOT A LIST OF VALUES"], f.clean, "3") + self.assertFormErrors(["4 IS INVALID CHOICE"], f.clean, ["4"]) def test_modelchoicefield_value_placeholder(self): f = ModelChoiceField( queryset=ChoiceModel.objects.all(), error_messages={ - 'invalid_choice': '"%(value)s" is not one of the available choices.', + "invalid_choice": '"%(value)s" is not one of the available choices.', }, ) self.assertFormErrors( ['"invalid" is not one of the available choices.'], f.clean, - 'invalid', + "invalid", ) diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py index aa47481998..5467cee9ad 100644 --- a/tests/forms_tests/tests/test_forms.py +++ b/tests/forms_tests/tests/test_forms.py @@ -7,12 +7,34 @@ from django.core.exceptions import NON_FIELD_ERRORS from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import MaxValueValidator, RegexValidator from django.forms import ( - BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField, - DateTimeField, EmailField, FileField, FileInput, FloatField, Form, - HiddenInput, ImageField, IntegerField, MultipleChoiceField, - MultipleHiddenInput, MultiValueField, MultiWidget, NullBooleanField, - PasswordInput, RadioSelect, Select, SplitDateTimeField, - SplitHiddenDateTimeWidget, Textarea, TextInput, TimeField, ValidationError, + BooleanField, + CharField, + CheckboxSelectMultiple, + ChoiceField, + DateField, + DateTimeField, + EmailField, + FileField, + FileInput, + FloatField, + Form, + HiddenInput, + ImageField, + IntegerField, + MultipleChoiceField, + MultipleHiddenInput, + MultiValueField, + MultiWidget, + NullBooleanField, + PasswordInput, + RadioSelect, + Select, + SplitDateTimeField, + SplitHiddenDateTimeWidget, + Textarea, + TextInput, + TimeField, + ValidationError, forms, ) from django.forms.renderers import DjangoTemplates, get_default_renderer @@ -29,7 +51,7 @@ from . import jinja2_tests class FrameworkForm(Form): name = CharField() - language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect) + language = ChoiceField(choices=[("P", "Python"), ("J", "Java")], widget=RadioSelect) class Person(Form): @@ -39,7 +61,7 @@ class Person(Form): class PersonNew(Form): - first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'})) + first_name = CharField(widget=TextInput(attrs={"id": "first_name_id"})) last_name = CharField() birthday = DateField() @@ -47,7 +69,7 @@ class PersonNew(Form): class SongForm(Form): name = CharField() composers = MultipleChoiceField( - choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], + choices=[("J", "John Lennon"), ("P", "Paul McCartney")], widget=CheckboxSelectMultiple, ) @@ -64,33 +86,35 @@ class FormsTestCase(SimpleTestCase): def test_form(self): # Pass a dictionary to a Form's __init__(). - p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}) + p = Person( + {"first_name": "John", "last_name": "Lennon", "birthday": "1940-10-9"} + ) self.assertTrue(p.is_bound) self.assertEqual(p.errors, {}) self.assertIsInstance(p.errors, dict) self.assertTrue(p.is_valid()) - self.assertHTMLEqual(p.errors.as_ul(), '') - self.assertEqual(p.errors.as_text(), '') - self.assertEqual(p.cleaned_data["first_name"], 'John') - self.assertEqual(p.cleaned_data["last_name"], 'Lennon') + self.assertHTMLEqual(p.errors.as_ul(), "") + self.assertEqual(p.errors.as_text(), "") + self.assertEqual(p.cleaned_data["first_name"], "John") + self.assertEqual(p.cleaned_data["last_name"], "Lennon") self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9)) self.assertHTMLEqual( - str(p['first_name']), - '<input type="text" name="first_name" value="John" id="id_first_name" required>' + str(p["first_name"]), + '<input type="text" name="first_name" value="John" id="id_first_name" required>', ) self.assertHTMLEqual( - str(p['last_name']), - '<input type="text" name="last_name" value="Lennon" id="id_last_name" required>' + str(p["last_name"]), + '<input type="text" name="last_name" value="Lennon" id="id_last_name" required>', ) self.assertHTMLEqual( - str(p['birthday']), - '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required>' + str(p["birthday"]), + '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required>', ) msg = "Key 'nonexistentfield' not found in 'Person'. Choices are: birthday, first_name, last_name." with self.assertRaisesMessage(KeyError, msg): - p['nonexistentfield'] + p["nonexistentfield"] form_output = [] @@ -98,10 +122,10 @@ class FormsTestCase(SimpleTestCase): form_output.append(str(boundfield)) self.assertHTMLEqual( - '\n'.join(form_output), + "\n".join(form_output), """<input type="text" name="first_name" value="John" id="id_first_name" required> <input type="text" name="last_name" value="Lennon" id="id_last_name" required> -<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required>""" +<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required>""", ) form_output = [] @@ -109,11 +133,14 @@ class FormsTestCase(SimpleTestCase): for boundfield in p: form_output.append([boundfield.label, boundfield.data]) - self.assertEqual(form_output, [ - ['First name', 'John'], - ['Last name', 'Lennon'], - ['Birthday', '1940-10-9'] - ]) + self.assertEqual( + form_output, + [ + ["First name", "John"], + ["Last name", "Lennon"], + ["Birthday", "1940-10-9"], + ], + ) self.assertHTMLEqual( str(p), """<tr><th><label for="id_first_name">First name:</label></th><td> @@ -121,16 +148,16 @@ class FormsTestCase(SimpleTestCase): <tr><th><label for="id_last_name">Last name:</label></th><td> <input type="text" name="last_name" value="Lennon" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th><td> -<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></td></tr>""" +<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></td></tr>""", ) def test_empty_dict(self): # Empty dictionaries are valid, too. p = Person({}) self.assertTrue(p.is_bound) - self.assertEqual(p.errors['first_name'], ['This field is required.']) - self.assertEqual(p.errors['last_name'], ['This field is required.']) - self.assertEqual(p.errors['birthday'], ['This field is required.']) + self.assertEqual(p.errors["first_name"], ["This field is required."]) + self.assertEqual(p.errors["last_name"], ["This field is required."]) + self.assertEqual(p.errors["birthday"], ["This field is required."]) self.assertFalse(p.is_valid()) self.assertEqual(p.cleaned_data, {}) self.assertHTMLEqual( @@ -143,7 +170,7 @@ class FormsTestCase(SimpleTestCase): <input type="text" name="last_name" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th><td> <ul class="errorlist"><li>This field is required.</li></ul> -<input type="text" name="birthday" id="id_birthday" required></td></tr>""" +<input type="text" name="birthday" id="id_birthday" required></td></tr>""", ) self.assertHTMLEqual( p.as_table(), @@ -155,7 +182,7 @@ class FormsTestCase(SimpleTestCase): <input type="text" name="last_name" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th> <td><ul class="errorlist"><li>This field is required.</li></ul> -<input type="text" name="birthday" id="id_birthday" required></td></tr>""" +<input type="text" name="birthday" id="id_birthday" required></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), @@ -167,7 +194,7 @@ class FormsTestCase(SimpleTestCase): <input type="text" name="last_name" id="id_last_name" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> <label for="id_birthday">Birthday:</label> -<input type="text" name="birthday" id="id_birthday" required></li>""" +<input type="text" name="birthday" id="id_birthday" required></li>""", ) self.assertHTMLEqual( p.as_p(), @@ -179,7 +206,7 @@ class FormsTestCase(SimpleTestCase): <input type="text" name="last_name" id="id_last_name" required></p> <ul class="errorlist"><li>This field is required.</li></ul> <p><label for="id_birthday">Birthday:</label> -<input type="text" name="birthday" id="id_birthday" required></p>""" +<input type="text" name="birthday" id="id_birthday" required></p>""", ) def test_empty_querydict_args(self): @@ -207,7 +234,7 @@ class FormsTestCase(SimpleTestCase): <tr><th><label for="id_last_name">Last name:</label></th><td> <input type="text" name="last_name" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th><td> -<input type="text" name="birthday" id="id_birthday" required></td></tr>""" +<input type="text" name="birthday" id="id_birthday" required></td></tr>""", ) self.assertHTMLEqual( p.as_table(), @@ -216,7 +243,7 @@ class FormsTestCase(SimpleTestCase): <tr><th><label for="id_last_name">Last name:</label></th><td> <input type="text" name="last_name" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th><td> -<input type="text" name="birthday" id="id_birthday" required></td></tr>""" +<input type="text" name="birthday" id="id_birthday" required></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), @@ -225,7 +252,7 @@ class FormsTestCase(SimpleTestCase): <li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" required></li> <li><label for="id_birthday">Birthday:</label> -<input type="text" name="birthday" id="id_birthday" required></li>""" +<input type="text" name="birthday" id="id_birthday" required></li>""", ) self.assertHTMLEqual( p.as_p(), @@ -234,16 +261,18 @@ class FormsTestCase(SimpleTestCase): <p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" required></p> <p><label for="id_birthday">Birthday:</label> -<input type="text" name="birthday" id="id_birthday" required></p>""" +<input type="text" name="birthday" id="id_birthday" required></p>""", ) def test_unicode_values(self): # Unicode values are handled properly. - p = Person({ - 'first_name': 'John', - 'last_name': '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', - 'birthday': '1940-10-9' - }) + p = Person( + { + "first_name": "John", + "last_name": "\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111", + "birthday": "1940-10-9", + } + ) self.assertHTMLEqual( p.as_table(), '<tr><th><label for="id_first_name">First name:</label></th><td>' @@ -253,7 +282,7 @@ class FormsTestCase(SimpleTestCase): 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111"' 'id="id_last_name" required></td></tr>\n' '<tr><th><label for="id_birthday">Birthday:</label></th><td>' - '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></td></tr>' + '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></td></tr>', ) self.assertHTMLEqual( p.as_ul(), @@ -263,7 +292,7 @@ class FormsTestCase(SimpleTestCase): '<input type="text" name="last_name" ' 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" required></li>\n' '<li><label for="id_birthday">Birthday:</label> ' - '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></li>' + '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></li>', ) self.assertHTMLEqual( p.as_p(), @@ -273,32 +302,41 @@ class FormsTestCase(SimpleTestCase): '<input type="text" name="last_name" ' 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" required></p>\n' '<p><label for="id_birthday">Birthday:</label> ' - '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></p>' + '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required></p>', ) - p = Person({'last_name': 'Lennon'}) - self.assertEqual(p.errors['first_name'], ['This field is required.']) - self.assertEqual(p.errors['birthday'], ['This field is required.']) + p = Person({"last_name": "Lennon"}) + self.assertEqual(p.errors["first_name"], ["This field is required."]) + self.assertEqual(p.errors["birthday"], ["This field is required."]) self.assertFalse(p.is_valid()) self.assertEqual( p.errors, - {'birthday': ['This field is required.'], 'first_name': ['This field is required.']} + { + "birthday": ["This field is required."], + "first_name": ["This field is required."], + }, ) - self.assertEqual(p.cleaned_data, {'last_name': 'Lennon'}) - self.assertEqual(p['first_name'].errors, ['This field is required.']) + self.assertEqual(p.cleaned_data, {"last_name": "Lennon"}) + self.assertEqual(p["first_name"].errors, ["This field is required."]) self.assertHTMLEqual( - p['first_name'].errors.as_ul(), - '<ul class="errorlist"><li>This field is required.</li></ul>' + p["first_name"].errors.as_ul(), + '<ul class="errorlist"><li>This field is required.</li></ul>', ) - self.assertEqual(p['first_name'].errors.as_text(), '* This field is required.') + self.assertEqual(p["first_name"].errors.as_text(), "* This field is required.") p = Person() self.assertHTMLEqual( - str(p['first_name']), + str(p["first_name"]), '<input type="text" name="first_name" id="id_first_name" required>', ) - self.assertHTMLEqual(str(p['last_name']), '<input type="text" name="last_name" id="id_last_name" required>') - self.assertHTMLEqual(str(p['birthday']), '<input type="text" name="birthday" id="id_birthday" required>') + self.assertHTMLEqual( + str(p["last_name"]), + '<input type="text" name="last_name" id="id_last_name" required>', + ) + self.assertHTMLEqual( + str(p["birthday"]), + '<input type="text" name="birthday" id="id_birthday" required>', + ) def test_cleaned_data_only_fields(self): # cleaned_data will always *only* contain a key for fields defined in the @@ -306,17 +344,17 @@ class FormsTestCase(SimpleTestCase): # example, we pass a bunch of extra fields to the form constructor, # but cleaned_data contains only the form's fields. data = { - 'first_name': 'John', - 'last_name': 'Lennon', - 'birthday': '1940-10-9', - 'extra1': 'hello', - 'extra2': 'hello', + "first_name": "John", + "last_name": "Lennon", + "birthday": "1940-10-9", + "extra1": "hello", + "extra2": "hello", } p = Person(data) self.assertTrue(p.is_valid()) - self.assertEqual(p.cleaned_data['first_name'], 'John') - self.assertEqual(p.cleaned_data['last_name'], 'Lennon') - self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9)) + self.assertEqual(p.cleaned_data["first_name"], "John") + self.assertEqual(p.cleaned_data["last_name"], "Lennon") + self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9)) def test_optional_data(self): # cleaned_data will include a key and value for *all* fields defined in the Form, @@ -329,12 +367,12 @@ class FormsTestCase(SimpleTestCase): last_name = CharField() nick_name = CharField(required=False) - data = {'first_name': 'John', 'last_name': 'Lennon'} + data = {"first_name": "John", "last_name": "Lennon"} f = OptionalPersonForm(data) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['nick_name'], '') - self.assertEqual(f.cleaned_data['first_name'], 'John') - self.assertEqual(f.cleaned_data['last_name'], 'Lennon') + self.assertEqual(f.cleaned_data["nick_name"], "") + self.assertEqual(f.cleaned_data["first_name"], "John") + self.assertEqual(f.cleaned_data["last_name"], "Lennon") # For DateFields, it's set to None. class OptionalPersonForm(Form): @@ -342,19 +380,19 @@ class FormsTestCase(SimpleTestCase): last_name = CharField() birth_date = DateField(required=False) - data = {'first_name': 'John', 'last_name': 'Lennon'} + data = {"first_name": "John", "last_name": "Lennon"} f = OptionalPersonForm(data) self.assertTrue(f.is_valid()) - self.assertIsNone(f.cleaned_data['birth_date']) - self.assertEqual(f.cleaned_data['first_name'], 'John') - self.assertEqual(f.cleaned_data['last_name'], 'Lennon') + self.assertIsNone(f.cleaned_data["birth_date"]) + self.assertEqual(f.cleaned_data["first_name"], "John") + self.assertEqual(f.cleaned_data["last_name"], "Lennon") def test_auto_id(self): # "auto_id" tells the Form to add an "id" attribute to each form element. # If it's a string that contains '%s', Django will use that as a format string # into which the field's name will be inserted. It will also put a <label> around # the human-readable labels for a field. - p = Person(auto_id='%s_id') + p = Person(auto_id="%s_id") self.assertHTMLEqual( p.as_table(), """<tr><th><label for="first_name_id">First name:</label></th><td> @@ -362,7 +400,7 @@ class FormsTestCase(SimpleTestCase): <tr><th><label for="last_name_id">Last name:</label></th><td> <input type="text" name="last_name" id="last_name_id" required></td></tr> <tr><th><label for="birthday_id">Birthday:</label></th><td> -<input type="text" name="birthday" id="birthday_id" required></td></tr>""" +<input type="text" name="birthday" id="birthday_id" required></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), @@ -371,7 +409,7 @@ class FormsTestCase(SimpleTestCase): <li><label for="last_name_id">Last name:</label> <input type="text" name="last_name" id="last_name_id" required></li> <li><label for="birthday_id">Birthday:</label> -<input type="text" name="birthday" id="birthday_id" required></li>""" +<input type="text" name="birthday" id="birthday_id" required></li>""", ) self.assertHTMLEqual( p.as_p(), @@ -380,7 +418,7 @@ class FormsTestCase(SimpleTestCase): <p><label for="last_name_id">Last name:</label> <input type="text" name="last_name" id="last_name_id" required></p> <p><label for="birthday_id">Birthday:</label> -<input type="text" name="birthday" id="birthday_id" required></p>""" +<input type="text" name="birthday" id="birthday_id" required></p>""", ) def test_auto_id_true(self): @@ -394,7 +432,7 @@ class FormsTestCase(SimpleTestCase): <li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" required></li> <li><label for="birthday">Birthday:</label> -<input type="text" name="birthday" id="birthday" required></li>""" +<input type="text" name="birthday" id="birthday" required></li>""", ) def test_auto_id_false(self): @@ -405,7 +443,7 @@ class FormsTestCase(SimpleTestCase): p.as_ul(), """<li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> -<li>Birthday: <input type="text" name="birthday" required></li>""" +<li>Birthday: <input type="text" name="birthday" required></li>""", ) def test_id_on_field(self): @@ -417,7 +455,7 @@ class FormsTestCase(SimpleTestCase): """<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> -<li>Birthday: <input type="text" name="birthday" required></li>""" +<li>Birthday: <input type="text" name="birthday" required></li>""", ) def test_auto_id_on_form_and_field(self): @@ -431,7 +469,7 @@ class FormsTestCase(SimpleTestCase): <li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" required></li> <li><label for="birthday">Birthday:</label> -<input type="text" name="birthday" id="birthday" required></li>""" +<input type="text" name="birthday" id="birthday" required></li>""", ) def test_various_boolean_values(self): @@ -440,38 +478,55 @@ class FormsTestCase(SimpleTestCase): get_spam = BooleanField() f = SignupForm(auto_id=False) - self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" required>') - self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required>') + self.assertHTMLEqual( + str(f["email"]), '<input type="email" name="email" required>' + ) + self.assertHTMLEqual( + str(f["get_spam"]), '<input type="checkbox" name="get_spam" required>' + ) - f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False) - self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" value="test@example.com" required>') + f = SignupForm({"email": "test@example.com", "get_spam": True}, auto_id=False) + self.assertHTMLEqual( + str(f["email"]), + '<input type="email" name="email" value="test@example.com" required>', + ) self.assertHTMLEqual( - str(f['get_spam']), + str(f["get_spam"]), '<input checked type="checkbox" name="get_spam" required>', ) # 'True' or 'true' should be rendered without a value attribute - f = SignupForm({'email': 'test@example.com', 'get_spam': 'True'}, auto_id=False) + f = SignupForm({"email": "test@example.com", "get_spam": "True"}, auto_id=False) self.assertHTMLEqual( - str(f['get_spam']), + str(f["get_spam"]), '<input checked type="checkbox" name="get_spam" required>', ) - f = SignupForm({'email': 'test@example.com', 'get_spam': 'true'}, auto_id=False) + f = SignupForm({"email": "test@example.com", "get_spam": "true"}, auto_id=False) self.assertHTMLEqual( - str(f['get_spam']), '<input checked type="checkbox" name="get_spam" required>') + str(f["get_spam"]), + '<input checked type="checkbox" name="get_spam" required>', + ) # A value of 'False' or 'false' should be rendered unchecked - f = SignupForm({'email': 'test@example.com', 'get_spam': 'False'}, auto_id=False) - self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required>') + f = SignupForm( + {"email": "test@example.com", "get_spam": "False"}, auto_id=False + ) + self.assertHTMLEqual( + str(f["get_spam"]), '<input type="checkbox" name="get_spam" required>' + ) - f = SignupForm({'email': 'test@example.com', 'get_spam': 'false'}, auto_id=False) - self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required>') + f = SignupForm( + {"email": "test@example.com", "get_spam": "false"}, auto_id=False + ) + self.assertHTMLEqual( + str(f["get_spam"]), '<input type="checkbox" name="get_spam" required>' + ) # A value of '0' should be interpreted as a True value (#16820) - f = SignupForm({'email': 'test@example.com', 'get_spam': '0'}) + f = SignupForm({"email": "test@example.com", "get_spam": "0"}) self.assertTrue(f.is_valid()) - self.assertTrue(f.cleaned_data.get('get_spam')) + self.assertTrue(f.cleaned_data.get("get_spam")) def test_widget_output(self): # Any Field can have a Widget class passed to its constructor: @@ -480,85 +535,122 @@ class FormsTestCase(SimpleTestCase): message = CharField(widget=Textarea) f = ContactForm(auto_id=False) - self.assertHTMLEqual(str(f['subject']), '<input type="text" name="subject" required>') - self.assertHTMLEqual(str(f['message']), '<textarea name="message" rows="10" cols="40" required></textarea>') + self.assertHTMLEqual( + str(f["subject"]), '<input type="text" name="subject" required>' + ) + self.assertHTMLEqual( + str(f["message"]), + '<textarea name="message" rows="10" cols="40" required></textarea>', + ) # as_textarea(), as_text() and as_hidden() are shortcuts for changing the output # widget type: self.assertHTMLEqual( - f['subject'].as_textarea(), + f["subject"].as_textarea(), '<textarea name="subject" rows="10" cols="40" required></textarea>', ) - self.assertHTMLEqual(f['message'].as_text(), '<input type="text" name="message" required>') - self.assertHTMLEqual(f['message'].as_hidden(), '<input type="hidden" name="message">') + self.assertHTMLEqual( + f["message"].as_text(), '<input type="text" name="message" required>' + ) + self.assertHTMLEqual( + f["message"].as_hidden(), '<input type="hidden" name="message">' + ) # The 'widget' parameter to a Field can also be an instance: class ContactForm(Form): subject = CharField() - message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20})) + message = CharField(widget=Textarea(attrs={"rows": 80, "cols": 20})) f = ContactForm(auto_id=False) - self.assertHTMLEqual(str(f['message']), '<textarea name="message" rows="80" cols="20" required></textarea>') + self.assertHTMLEqual( + str(f["message"]), + '<textarea name="message" rows="80" cols="20" required></textarea>', + ) # Instance-level attrs are *not* carried over to as_textarea(), as_text() and # as_hidden(): - self.assertHTMLEqual(f['message'].as_text(), '<input type="text" name="message" required>') - f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False) self.assertHTMLEqual( - f['subject'].as_textarea(), - '<textarea rows="10" cols="40" name="subject" required>Hello</textarea>' + f["message"].as_text(), '<input type="text" name="message" required>' + ) + f = ContactForm({"subject": "Hello", "message": "I love you."}, auto_id=False) + self.assertHTMLEqual( + f["subject"].as_textarea(), + '<textarea rows="10" cols="40" name="subject" required>Hello</textarea>', ) self.assertHTMLEqual( - f['message'].as_text(), + f["message"].as_text(), '<input type="text" name="message" value="I love you." required>', ) - self.assertHTMLEqual(f['message'].as_hidden(), '<input type="hidden" name="message" value="I love you.">') + self.assertHTMLEqual( + f["message"].as_hidden(), + '<input type="hidden" name="message" value="I love you.">', + ) def test_forms_with_choices(self): # For a form with a <select>, use ChoiceField: class FrameworkForm(Form): name = CharField() - language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')]) + language = ChoiceField(choices=[("P", "Python"), ("J", "Java")]) f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select name="language"> + self.assertHTMLEqual( + str(f["language"]), + """<select name="language"> <option value="P">Python</option> <option value="J">Java</option> -</select>""") - f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select name="language"> +</select>""", + ) + f = FrameworkForm({"name": "Django", "language": "P"}, auto_id=False) + self.assertHTMLEqual( + str(f["language"]), + """<select name="language"> <option value="P" selected>Python</option> <option value="J">Java</option> -</select>""") +</select>""", + ) # A subtlety: If one of the choices' value is the empty string and the form is # unbound, then the <option> for the empty-string choice will get selected. class FrameworkForm(Form): name = CharField() - language = ChoiceField(choices=[('', '------'), ('P', 'Python'), ('J', 'Java')]) + language = ChoiceField( + choices=[("", "------"), ("P", "Python"), ("J", "Java")] + ) f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select name="language" required> + self.assertHTMLEqual( + str(f["language"]), + """<select name="language" required> <option value="" selected>------</option> <option value="P">Python</option> <option value="J">Java</option> -</select>""") +</select>""", + ) # You can specify widget attributes in the Widget constructor. class FrameworkForm(Form): name = CharField() - language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(attrs={'class': 'foo'})) + language = ChoiceField( + choices=[("P", "Python"), ("J", "Java")], + widget=Select(attrs={"class": "foo"}), + ) f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language"> + self.assertHTMLEqual( + str(f["language"]), + """<select class="foo" name="language"> <option value="P">Python</option> <option value="J">Java</option> -</select>""") - f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language"> +</select>""", + ) + f = FrameworkForm({"name": "Django", "language": "P"}, auto_id=False) + self.assertHTMLEqual( + str(f["language"]), + """<select class="foo" name="language"> <option value="P" selected>Python</option> <option value="J">Java</option> -</select>""") +</select>""", + ) # When passing a custom widget instance to ChoiceField, note that setting # 'choices' on the widget is meaningless. The widget will use the choices @@ -566,20 +658,28 @@ class FormsTestCase(SimpleTestCase): class FrameworkForm(Form): name = CharField() language = ChoiceField( - choices=[('P', 'Python'), ('J', 'Java')], - widget=Select(choices=[('R', 'Ruby'), ('P', 'Perl')], attrs={'class': 'foo'}), + choices=[("P", "Python"), ("J", "Java")], + widget=Select( + choices=[("R", "Ruby"), ("P", "Perl")], attrs={"class": "foo"} + ), ) f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language"> + self.assertHTMLEqual( + str(f["language"]), + """<select class="foo" name="language"> <option value="P">Python</option> <option value="J">Java</option> -</select>""") - f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language"> +</select>""", + ) + f = FrameworkForm({"name": "Django", "language": "P"}, auto_id=False) + self.assertHTMLEqual( + str(f["language"]), + """<select class="foo" name="language"> <option value="P" selected>Python</option> <option value="J">Java</option> -</select>""") +</select>""", + ) # You can set a ChoiceField's choices after the fact. class FrameworkForm(Form): @@ -587,44 +687,59 @@ class FormsTestCase(SimpleTestCase): language = ChoiceField() f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<select name="language"> -</select>""") - f.fields['language'].choices = [('P', 'Python'), ('J', 'Java')] - self.assertHTMLEqual(str(f['language']), """<select name="language"> + self.assertHTMLEqual( + str(f["language"]), + """<select name="language"> +</select>""", + ) + f.fields["language"].choices = [("P", "Python"), ("J", "Java")] + self.assertHTMLEqual( + str(f["language"]), + """<select name="language"> <option value="P">Python</option> <option value="J">Java</option> -</select>""") +</select>""", + ) def test_forms_with_radio(self): # Add widget=RadioSelect to use that widget with a ChoiceField. f = FrameworkForm(auto_id=False) - self.assertHTMLEqual(str(f['language']), """<div> + self.assertHTMLEqual( + str(f["language"]), + """<div> <div><label><input type="radio" name="language" value="P" required> Python</label></div> <div><label><input type="radio" name="language" value="J" required> Java</label></div> -</div>""") - self.assertHTMLEqual(f.as_table(), """<tr><th>Name:</th><td><input type="text" name="name" required></td></tr> +</div>""", + ) + self.assertHTMLEqual( + f.as_table(), + """<tr><th>Name:</th><td><input type="text" name="name" required></td></tr> <tr><th>Language:</th><td><div> <div><label><input type="radio" name="language" value="P" required> Python</label></div> <div><label><input type="radio" name="language" value="J" required> Java</label></div> -</div></td></tr>""") - self.assertHTMLEqual(f.as_ul(), """<li>Name: <input type="text" name="name" required></li> +</div></td></tr>""", + ) + self.assertHTMLEqual( + f.as_ul(), + """<li>Name: <input type="text" name="name" required></li> <li>Language: <div> <div><label><input type="radio" name="language" value="P" required> Python</label></div> <div><label><input type="radio" name="language" value="J" required> Java</label></div> -</div></li>""") +</div></li>""", + ) # Regarding auto_id and <label>, RadioSelect is a special case. Each radio button # gets a distinct ID, formed by appending an underscore plus the button's # zero-based index. - f = FrameworkForm(auto_id='id_%s') + f = FrameworkForm(auto_id="id_%s") self.assertHTMLEqual( - str(f['language']), + str(f["language"]), """<div id="id_language"> <div><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required> Python</label></div> <div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required> Java</label></div> -</div>""" +</div>""", ) # When RadioSelect is used with auto_id, and the whole form is printed @@ -639,7 +754,7 @@ Java</label></div> Python</label></div> <div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required> Java</label></div> -</div></td></tr>""" +</div></td></tr>""", ) self.assertHTMLEqual( f.as_ul(), @@ -649,7 +764,7 @@ Java</label></div> Python</label></div> <div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required> Java</label></div> -</div></li>""" +</div></li>""", ) self.assertHTMLEqual( f.as_p(), @@ -659,73 +774,92 @@ Java</label></div> Python</label></div> <div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required> Java</label></div> -</div></p>""" +</div></p>""", ) def test_form_with_iterable_boundfield(self): class BeatleForm(Form): name = ChoiceField( - choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')], + choices=[ + ("john", "John"), + ("paul", "Paul"), + ("george", "George"), + ("ringo", "Ringo"), + ], widget=RadioSelect, ) f = BeatleForm(auto_id=False) self.assertHTMLEqual( - '\n'.join(str(bf) for bf in f['name']), + "\n".join(str(bf) for bf in f["name"]), """<label><input type="radio" name="name" value="john" required> John</label> <label><input type="radio" name="name" value="paul" required> Paul</label> <label><input type="radio" name="name" value="george" required> George</label> -<label><input type="radio" name="name" value="ringo" required> Ringo</label>""" +<label><input type="radio" name="name" value="ringo" required> Ringo</label>""", ) self.assertHTMLEqual( - '\n'.join('<div>%s</div>' % bf for bf in f['name']), + "\n".join("<div>%s</div>" % bf for bf in f["name"]), """<div><label><input type="radio" name="name" value="john" required> John</label></div> <div><label><input type="radio" name="name" value="paul" required> Paul</label></div> <div><label><input type="radio" name="name" value="george" required> George</label></div> -<div><label><input type="radio" name="name" value="ringo" required> Ringo</label></div>""" +<div><label><input type="radio" name="name" value="ringo" required> Ringo</label></div>""", ) def test_form_with_iterable_boundfield_id(self): class BeatleForm(Form): name = ChoiceField( - choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')], + choices=[ + ("john", "John"), + ("paul", "Paul"), + ("george", "George"), + ("ringo", "Ringo"), + ], widget=RadioSelect, ) - fields = list(BeatleForm()['name']) + + fields = list(BeatleForm()["name"]) self.assertEqual(len(fields), 4) - self.assertEqual(fields[0].id_for_label, 'id_name_0') - self.assertEqual(fields[0].choice_label, 'John') + self.assertEqual(fields[0].id_for_label, "id_name_0") + self.assertEqual(fields[0].choice_label, "John") self.assertHTMLEqual( fields[0].tag(), - '<input type="radio" name="name" value="john" id="id_name_0" required>' + '<input type="radio" name="name" value="john" id="id_name_0" required>', ) self.assertHTMLEqual( str(fields[0]), '<label for="id_name_0"><input type="radio" name="name" ' - 'value="john" id="id_name_0" required> John</label>' + 'value="john" id="id_name_0" required> John</label>', ) - self.assertEqual(fields[1].id_for_label, 'id_name_1') - self.assertEqual(fields[1].choice_label, 'Paul') + self.assertEqual(fields[1].id_for_label, "id_name_1") + self.assertEqual(fields[1].choice_label, "Paul") self.assertHTMLEqual( fields[1].tag(), - '<input type="radio" name="name" value="paul" id="id_name_1" required>' + '<input type="radio" name="name" value="paul" id="id_name_1" required>', ) self.assertHTMLEqual( str(fields[1]), '<label for="id_name_1"><input type="radio" name="name" ' - 'value="paul" id="id_name_1" required> Paul</label>' + 'value="paul" id="id_name_1" required> Paul</label>', ) def test_iterable_boundfield_select(self): class BeatleForm(Form): - name = ChoiceField(choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')]) - fields = list(BeatleForm(auto_id=False)['name']) + name = ChoiceField( + choices=[ + ("john", "John"), + ("paul", "Paul"), + ("george", "George"), + ("ringo", "Ringo"), + ] + ) + + fields = list(BeatleForm(auto_id=False)["name"]) self.assertEqual(len(fields), 4) self.assertEqual(fields[0].id_for_label, None) - self.assertEqual(fields[0].choice_label, 'John') + self.assertEqual(fields[0].choice_label, "John") self.assertHTMLEqual(fields[0].tag(), '<option value="john">John</option>') self.assertHTMLEqual(str(fields[0]), '<option value="john">John</option>') @@ -735,17 +869,25 @@ Java</label></div> name = CharField() f = BeatleForm(auto_id=False) - self.assertHTMLEqual('\n'.join(str(bf) for bf in f['name']), '<input type="text" name="name" required>') + self.assertHTMLEqual( + "\n".join(str(bf) for bf in f["name"]), + '<input type="text" name="name" required>', + ) def test_boundfield_slice(self): class BeatleForm(Form): name = ChoiceField( - choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')], + choices=[ + ("john", "John"), + ("paul", "Paul"), + ("george", "George"), + ("ringo", "Ringo"), + ], widget=RadioSelect, ) f = BeatleForm() - bf = f['name'] + bf = f["name"] self.assertEqual( [str(item) for item in bf[1:]], [str(bf[1]), str(bf[2]), str(bf[3])], @@ -755,17 +897,18 @@ Java</label></div> class TestForm(Form): name = ChoiceField(choices=[]) - field = TestForm()['name'] - msg = 'BoundField indices must be integers or slices, not str.' + field = TestForm()["name"] + msg = "BoundField indices must be integers or slices, not str." with self.assertRaisesMessage(TypeError, msg): - field['foo'] + field["foo"] def test_boundfield_bool(self): """BoundField without any choices (subwidgets) evaluates to True.""" + class TestForm(Form): name = ChoiceField(choices=[]) - self.assertIs(bool(TestForm()['name']), True) + self.assertIs(bool(TestForm()["name"]), True) def test_forms_with_multiple_choice(self): # MultipleChoiceField is a special case, as its data is required to be a list: @@ -774,24 +917,37 @@ Java</label></div> composers = MultipleChoiceField() f = SongForm(auto_id=False) - self.assertHTMLEqual(str(f['composers']), """<select multiple name="composers" required> -</select>""") + self.assertHTMLEqual( + str(f["composers"]), + """<select multiple name="composers" required> +</select>""", + ) class SongForm(Form): name = CharField() - composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')]) + composers = MultipleChoiceField( + choices=[("J", "John Lennon"), ("P", "Paul McCartney")] + ) f = SongForm(auto_id=False) - self.assertHTMLEqual(str(f['composers']), """<select multiple name="composers" required> + self.assertHTMLEqual( + str(f["composers"]), + """<select multiple name="composers" required> <option value="J">John Lennon</option> <option value="P">Paul McCartney</option> -</select>""") - f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False) - self.assertHTMLEqual(str(f['name']), '<input type="text" name="name" value="Yesterday" required>') - self.assertHTMLEqual(str(f['composers']), """<select multiple name="composers" required> +</select>""", + ) + f = SongForm({"name": "Yesterday", "composers": ["P"]}, auto_id=False) + self.assertHTMLEqual( + str(f["name"]), '<input type="text" name="name" value="Yesterday" required>' + ) + self.assertHTMLEqual( + str(f["composers"]), + """<select multiple name="composers" required> <option value="J">John Lennon</option> <option value="P" selected>Paul McCartney</option> -</select>""") +</select>""", + ) f = SongForm() self.assertHTMLEqual( f.as_table(), @@ -801,7 +957,7 @@ Java</label></div> '<td><select name="composers" required id="id_composers" multiple>' '<option value="J">John Lennon</option>' '<option value="P">Paul McCartney</option>' - '</select></td></tr>', + "</select></td></tr>", ) self.assertHTMLEqual( f.as_ul(), @@ -811,7 +967,7 @@ Java</label></div> '<select name="composers" required id="id_composers" multiple>' '<option value="J">John Lennon</option>' '<option value="P">Paul McCartney</option>' - '</select></li>', + "</select></li>", ) self.assertHTMLEqual( f.as_p(), @@ -821,7 +977,7 @@ Java</label></div> '<select name="composers" required id="id_composers" multiple>' '<option value="J">John Lennon</option>' '<option value="P">Paul McCartney</option>' - '</select></p>', + "</select></p>", ) def test_multiple_checkbox_render(self): @@ -837,7 +993,7 @@ Java</label></div> '<div><label for="id_composers_1">' '<input type="checkbox" name="composers" value="P" ' 'id="id_composers_1">Paul McCartney</label></div>' - '</div></td></tr>', + "</div></td></tr>", ) self.assertHTMLEqual( f.as_ul(), @@ -850,7 +1006,7 @@ Java</label></div> '<div><label for="id_composers_1">' '<input type="checkbox" name="composers" value="P" ' 'id="id_composers_1">Paul McCartney</label></div>' - '</div></li>', + "</div></li>", ) self.assertHTMLEqual( f.as_p(), @@ -863,7 +1019,7 @@ Java</label></div> '<div><label for="id_composers_1">' '<input type="checkbox" name="composers" value="P" ' 'id="id_composers_1">Paul McCartney</label></div>' - '</div></p>', + "</div></p>", ) def test_form_with_disabled_fields(self): @@ -877,82 +1033,101 @@ Java</label></div> # Disabled fields are generally not transmitted by user agents. # The value from the form's initial data is used. - f1 = PersonForm({'name': 'John Doe'}, initial={'birthday': datetime.date(1974, 8, 16)}) - f2 = PersonFormFieldInitial({'name': 'John Doe'}) + f1 = PersonForm( + {"name": "John Doe"}, initial={"birthday": datetime.date(1974, 8, 16)} + ) + f2 = PersonFormFieldInitial({"name": "John Doe"}) for form in (f1, f2): self.assertTrue(form.is_valid()) self.assertEqual( form.cleaned_data, - {'birthday': datetime.date(1974, 8, 16), 'name': 'John Doe'} + {"birthday": datetime.date(1974, 8, 16), "name": "John Doe"}, ) # Values provided in the form's data are ignored. - data = {'name': 'John Doe', 'birthday': '1984-11-10'} - f1 = PersonForm(data, initial={'birthday': datetime.date(1974, 8, 16)}) + data = {"name": "John Doe", "birthday": "1984-11-10"} + f1 = PersonForm(data, initial={"birthday": datetime.date(1974, 8, 16)}) f2 = PersonFormFieldInitial(data) for form in (f1, f2): self.assertTrue(form.is_valid()) self.assertEqual( form.cleaned_data, - {'birthday': datetime.date(1974, 8, 16), 'name': 'John Doe'} + {"birthday": datetime.date(1974, 8, 16), "name": "John Doe"}, ) # Initial data remains present on invalid forms. data = {} - f1 = PersonForm(data, initial={'birthday': datetime.date(1974, 8, 16)}) + f1 = PersonForm(data, initial={"birthday": datetime.date(1974, 8, 16)}) f2 = PersonFormFieldInitial(data) for form in (f1, f2): self.assertFalse(form.is_valid()) - self.assertEqual(form['birthday'].value(), datetime.date(1974, 8, 16)) + self.assertEqual(form["birthday"].value(), datetime.date(1974, 8, 16)) def test_hidden_data(self): class SongForm(Form): name = CharField() - composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')]) + composers = MultipleChoiceField( + choices=[("J", "John Lennon"), ("P", "Paul McCartney")] + ) # MultipleChoiceField rendered as_hidden() is a special case. Because it can # have multiple values, its as_hidden() renders multiple <input type="hidden"> # tags. - f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False) - self.assertHTMLEqual(f['composers'].as_hidden(), '<input type="hidden" name="composers" value="P">') - f = SongForm({'name': 'From Me To You', 'composers': ['P', 'J']}, auto_id=False) - self.assertHTMLEqual(f['composers'].as_hidden(), """<input type="hidden" name="composers" value="P"> -<input type="hidden" name="composers" value="J">""") + f = SongForm({"name": "Yesterday", "composers": ["P"]}, auto_id=False) + self.assertHTMLEqual( + f["composers"].as_hidden(), + '<input type="hidden" name="composers" value="P">', + ) + f = SongForm({"name": "From Me To You", "composers": ["P", "J"]}, auto_id=False) + self.assertHTMLEqual( + f["composers"].as_hidden(), + """<input type="hidden" name="composers" value="P"> +<input type="hidden" name="composers" value="J">""", + ) # DateTimeField rendered as_hidden() is special too class MessageForm(Form): when = SplitDateTimeField() - f = MessageForm({'when_0': '1992-01-01', 'when_1': '01:01'}) + f = MessageForm({"when_0": "1992-01-01", "when_1": "01:01"}) self.assertTrue(f.is_valid()) self.assertHTMLEqual( - str(f['when']), + str(f["when"]), '<input type="text" name="when_0" value="1992-01-01" id="id_when_0" required>' - '<input type="text" name="when_1" value="01:01" id="id_when_1" required>' + '<input type="text" name="when_1" value="01:01" id="id_when_1" required>', ) self.assertHTMLEqual( - f['when'].as_hidden(), + f["when"].as_hidden(), '<input type="hidden" name="when_0" value="1992-01-01" id="id_when_0">' - '<input type="hidden" name="when_1" value="01:01" id="id_when_1">' + '<input type="hidden" name="when_1" value="01:01" id="id_when_1">', ) def test_multiple_choice_checkbox(self): # MultipleChoiceField can also be used with the CheckboxSelectMultiple widget. f = SongForm(auto_id=False) - self.assertHTMLEqual(str(f['composers']), """<div> + self.assertHTMLEqual( + str(f["composers"]), + """<div> <div><label><input type="checkbox" name="composers" value="J"> John Lennon</label></div> <div><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></div> -</div>""") - f = SongForm({'composers': ['J']}, auto_id=False) - self.assertHTMLEqual(str(f['composers']), """<div> +</div>""", + ) + f = SongForm({"composers": ["J"]}, auto_id=False) + self.assertHTMLEqual( + str(f["composers"]), + """<div> <div><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></div> <div><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></div> -</div>""") - f = SongForm({'composers': ['J', 'P']}, auto_id=False) - self.assertHTMLEqual(str(f['composers']), """<div> +</div>""", + ) + f = SongForm({"composers": ["J", "P"]}, auto_id=False) + self.assertHTMLEqual( + str(f["composers"]), + """<div> <div><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></div> <div><label><input checked type="checkbox" name="composers" value="P"> Paul McCartney</label></div> -</div>""") +</div>""", + ) def test_checkbox_auto_id(self): # Regarding auto_id, CheckboxSelectMultiple is a special case. Each checkbox @@ -961,19 +1136,19 @@ Java</label></div> class SongForm(Form): name = CharField() composers = MultipleChoiceField( - choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], + choices=[("J", "John Lennon"), ("P", "Paul McCartney")], widget=CheckboxSelectMultiple, ) - f = SongForm(auto_id='%s_id') + f = SongForm(auto_id="%s_id") self.assertHTMLEqual( - str(f['composers']), + str(f["composers"]), """<div id="composers_id"> <div><label for="composers_id_0"> <input type="checkbox" name="composers" value="J" id="composers_id_0"> John Lennon</label></div> <div><label for="composers_id_1"> <input type="checkbox" name="composers" value="P" id="composers_id_1"> Paul McCartney</label></div> -</div>""" +</div>""", ) def test_multiple_choice_list_data(self): @@ -982,33 +1157,33 @@ Java</label></div> class SongForm(Form): name = CharField() composers = MultipleChoiceField( - choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], + choices=[("J", "John Lennon"), ("P", "Paul McCartney")], widget=CheckboxSelectMultiple, ) - data = {'name': 'Yesterday', 'composers': ['J', 'P']} + data = {"name": "Yesterday", "composers": ["J", "P"]} f = SongForm(data) self.assertEqual(f.errors, {}) - data = QueryDict('name=Yesterday&composers=J&composers=P') + data = QueryDict("name=Yesterday&composers=J&composers=P") f = SongForm(data) self.assertEqual(f.errors, {}) - data = MultiValueDict({'name': ['Yesterday'], 'composers': ['J', 'P']}) + data = MultiValueDict({"name": ["Yesterday"], "composers": ["J", "P"]}) f = SongForm(data) self.assertEqual(f.errors, {}) # SelectMultiple uses ducktyping so that MultiValueDictLike.getlist() # is called. - f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'})) + f = SongForm(MultiValueDictLike({"name": "Yesterday", "composers": "J"})) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['composers'], ['J']) + self.assertEqual(f.cleaned_data["composers"], ["J"]) def test_multiple_hidden(self): class SongForm(Form): name = CharField() composers = MultipleChoiceField( - choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], + choices=[("J", "John Lennon"), ("P", "Paul McCartney")], widget=CheckboxSelectMultiple, ) @@ -1016,36 +1191,39 @@ Java</label></div> class SongFormHidden(Form): name = CharField() composers = MultipleChoiceField( - choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], + choices=[("J", "John Lennon"), ("P", "Paul McCartney")], widget=MultipleHiddenInput, ) - f = SongFormHidden(MultiValueDict({'name': ['Yesterday'], 'composers': ['J', 'P']}), auto_id=False) + f = SongFormHidden( + MultiValueDict({"name": ["Yesterday"], "composers": ["J", "P"]}), + auto_id=False, + ) self.assertHTMLEqual( f.as_ul(), """<li>Name: <input type="text" name="name" value="Yesterday" required> <input type="hidden" name="composers" value="J"> -<input type="hidden" name="composers" value="P"></li>""" +<input type="hidden" name="composers" value="P"></li>""", ) # When using CheckboxSelectMultiple, the framework expects a list of input and # returns a list of input. - f = SongForm({'name': 'Yesterday'}, auto_id=False) - self.assertEqual(f.errors['composers'], ['This field is required.']) - f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False) + f = SongForm({"name": "Yesterday"}, auto_id=False) + self.assertEqual(f.errors["composers"], ["This field is required."]) + f = SongForm({"name": "Yesterday", "composers": ["J"]}, auto_id=False) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['composers'], ['J']) - self.assertEqual(f.cleaned_data['name'], 'Yesterday') - f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False) + self.assertEqual(f.cleaned_data["composers"], ["J"]) + self.assertEqual(f.cleaned_data["name"], "Yesterday") + f = SongForm({"name": "Yesterday", "composers": ["J", "P"]}, auto_id=False) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['composers'], ['J', 'P']) - self.assertEqual(f.cleaned_data['name'], 'Yesterday') + self.assertEqual(f.cleaned_data["composers"], ["J", "P"]) + self.assertEqual(f.cleaned_data["name"], "Yesterday") # MultipleHiddenInput uses ducktyping so that # MultiValueDictLike.getlist() is called. - f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'})) + f = SongForm(MultiValueDictLike({"name": "Yesterday", "composers": "J"})) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['composers'], ['J']) + self.assertEqual(f.cleaned_data["composers"], ["J"]) def test_escaping(self): # Validation errors are HTML-escaped when output as HTML. @@ -1054,18 +1232,25 @@ Java</label></div> special_safe_name = CharField(label=mark_safe("<em>Special</em> Field")) def clean_special_name(self): - raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name']) + raise ValidationError( + "Something's wrong with '%s'" % self.cleaned_data["special_name"] + ) def clean_special_safe_name(self): raise ValidationError( - mark_safe("'<b>%s</b>' is a safe string" % self.cleaned_data['special_safe_name']) + mark_safe( + "'<b>%s</b>' is a safe string" + % self.cleaned_data["special_safe_name"] + ) ) - f = EscapingForm({ - 'special_name': - "Nothing to escape", - 'special_safe_name': "Nothing to escape", - }, auto_id=False) + f = EscapingForm( + { + "special_name": "Nothing to escape", + "special_safe_name": "Nothing to escape", + }, + auto_id=False, + ) self.assertHTMLEqual( f.as_table(), """<tr><th><em>Special</em> Field:</th><td> @@ -1073,12 +1258,15 @@ Java</label></div> <input type="text" name="special_name" value="Nothing to escape" required></td></tr> <tr><th><em>Special</em> Field:</th><td> <ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul> -<input type="text" name="special_safe_name" value="Nothing to escape" required></td></tr>""" +<input type="text" name="special_safe_name" value="Nothing to escape" required></td></tr>""", + ) + f = EscapingForm( + { + "special_name": "Should escape < & > and <script>alert('xss')</script>", + "special_safe_name": "<i>Do not escape</i>", + }, + auto_id=False, ) - f = EscapingForm({ - 'special_name': "Should escape < & > and <script>alert('xss')</script>", - 'special_safe_name': "<i>Do not escape</i>" - }, auto_id=False) self.assertHTMLEqual( f.as_table(), """<tr><th><em>Special</em> Field:</th><td> @@ -1088,7 +1276,7 @@ Java</label></div> value="Should escape < & > and <script>alert('xss')</script>" required></td></tr> <tr><th><em>Special</em> Field:</th><td> <ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul> -<input type="text" name="special_safe_name" value="<i>Do not escape</i>" required></td></tr>""" +<input type="text" name="special_safe_name" value="<i>Do not escape</i>" required></td></tr>""", ) def test_validating_multiple_fields(self): @@ -1105,25 +1293,36 @@ value="Should escape < & > and <script>alert('xss')< password2 = CharField(widget=PasswordInput) def clean_password2(self): - if (self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and - self.cleaned_data['password1'] != self.cleaned_data['password2']): - raise ValidationError('Please make sure your passwords match.') + if ( + self.cleaned_data.get("password1") + and self.cleaned_data.get("password2") + and self.cleaned_data["password1"] != self.cleaned_data["password2"] + ): + raise ValidationError("Please make sure your passwords match.") - return self.cleaned_data['password2'] + return self.cleaned_data["password2"] f = UserRegistration(auto_id=False) self.assertEqual(f.errors, {}) f = UserRegistration({}, auto_id=False) - self.assertEqual(f.errors['username'], ['This field is required.']) - self.assertEqual(f.errors['password1'], ['This field is required.']) - self.assertEqual(f.errors['password2'], ['This field is required.']) - f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) - self.assertEqual(f.errors['password2'], ['Please make sure your passwords match.']) - f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) + self.assertEqual(f.errors["username"], ["This field is required."]) + self.assertEqual(f.errors["password1"], ["This field is required."]) + self.assertEqual(f.errors["password2"], ["This field is required."]) + f = UserRegistration( + {"username": "adrian", "password1": "foo", "password2": "bar"}, + auto_id=False, + ) + self.assertEqual( + f.errors["password2"], ["Please make sure your passwords match."] + ) + f = UserRegistration( + {"username": "adrian", "password1": "foo", "password2": "foo"}, + auto_id=False, + ) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['username'], 'adrian') - self.assertEqual(f.cleaned_data['password1'], 'foo') - self.assertEqual(f.cleaned_data['password2'], 'foo') + self.assertEqual(f.cleaned_data["username"], "adrian") + self.assertEqual(f.cleaned_data["password1"], "foo") + self.assertEqual(f.cleaned_data["password2"], "foo") # Another way of doing multiple-field validation is by implementing the # Form's clean() method. Usually ValidationError raised by that method @@ -1144,26 +1343,29 @@ value="Should escape < & > and <script>alert('xss')< def clean(self): # Test raising a ValidationError as NON_FIELD_ERRORS. - if (self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and - self.cleaned_data['password1'] != self.cleaned_data['password2']): - raise ValidationError('Please make sure your passwords match.') + if ( + self.cleaned_data.get("password1") + and self.cleaned_data.get("password2") + and self.cleaned_data["password1"] != self.cleaned_data["password2"] + ): + raise ValidationError("Please make sure your passwords match.") # Test raising ValidationError that targets multiple fields. errors = {} - if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE': - errors['password1'] = 'Forbidden value.' - if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE': - errors['password2'] = ['Forbidden value.'] + if self.cleaned_data.get("password1") == "FORBIDDEN_VALUE": + errors["password1"] = "Forbidden value." + if self.cleaned_data.get("password2") == "FORBIDDEN_VALUE": + errors["password2"] = ["Forbidden value."] if errors: raise ValidationError(errors) # Test Form.add_error() - if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE2': - self.add_error(None, 'Non-field error 1.') - self.add_error('password1', 'Forbidden value 2.') - if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE2': - self.add_error('password2', 'Forbidden value 2.') - raise ValidationError('Non-field error 2.') + if self.cleaned_data.get("password1") == "FORBIDDEN_VALUE2": + self.add_error(None, "Non-field error 1.") + self.add_error("password1", "Forbidden value 2.") + if self.cleaned_data.get("password2") == "FORBIDDEN_VALUE2": + self.add_error("password2", "Forbidden value 2.") + raise ValidationError("Non-field error 2.") return self.cleaned_data @@ -1179,21 +1381,26 @@ value="Should escape < & > and <script>alert('xss')< <tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul> <input type="password" name="password1" required></td></tr> <tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul> -<input type="password" name="password2" required></td></tr>""" +<input type="password" name="password2" required></td></tr>""", ) - self.assertEqual(f.errors['username'], ['This field is required.']) - self.assertEqual(f.errors['password1'], ['This field is required.']) - self.assertEqual(f.errors['password2'], ['This field is required.']) + self.assertEqual(f.errors["username"], ["This field is required."]) + self.assertEqual(f.errors["password1"], ["This field is required."]) + self.assertEqual(f.errors["password2"], ["This field is required."]) - f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) - self.assertEqual(f.errors['__all__'], ['Please make sure your passwords match.']) + f = UserRegistration( + {"username": "adrian", "password1": "foo", "password2": "bar"}, + auto_id=False, + ) + self.assertEqual( + f.errors["__all__"], ["Please make sure your passwords match."] + ) self.assertHTMLEqual( f.as_table(), """<tr><td colspan="2"> <ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul></td></tr> <tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" required></td></tr> <tr><th>Password1:</th><td><input type="password" name="password1" required></td></tr> -<tr><th>Password2:</th><td><input type="password" name="password2" required></td></tr>""" +<tr><th>Password2:</th><td><input type="password" name="password2" required></td></tr>""", ) self.assertHTMLEqual( f.as_ul(), @@ -1201,34 +1408,45 @@ value="Should escape < & > and <script>alert('xss')< <li>Please make sure your passwords match.</li></ul></li> <li>Username: <input type="text" name="username" value="adrian" maxlength="10" required></li> <li>Password1: <input type="password" name="password1" required></li> -<li>Password2: <input type="password" name="password2" required></li>""" +<li>Password2: <input type="password" name="password2" required></li>""", ) - f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) + f = UserRegistration( + {"username": "adrian", "password1": "foo", "password2": "foo"}, + auto_id=False, + ) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['username'], 'adrian') - self.assertEqual(f.cleaned_data['password1'], 'foo') - self.assertEqual(f.cleaned_data['password2'], 'foo') + self.assertEqual(f.cleaned_data["username"], "adrian") + self.assertEqual(f.cleaned_data["password1"], "foo") + self.assertEqual(f.cleaned_data["password2"], "foo") - f = UserRegistration({ - 'username': 'adrian', - 'password1': 'FORBIDDEN_VALUE', - 'password2': 'FORBIDDEN_VALUE', - }, auto_id=False) - self.assertEqual(f.errors['password1'], ['Forbidden value.']) - self.assertEqual(f.errors['password2'], ['Forbidden value.']) + f = UserRegistration( + { + "username": "adrian", + "password1": "FORBIDDEN_VALUE", + "password2": "FORBIDDEN_VALUE", + }, + auto_id=False, + ) + self.assertEqual(f.errors["password1"], ["Forbidden value."]) + self.assertEqual(f.errors["password2"], ["Forbidden value."]) - f = UserRegistration({ - 'username': 'adrian', - 'password1': 'FORBIDDEN_VALUE2', - 'password2': 'FORBIDDEN_VALUE2', - }, auto_id=False) - self.assertEqual(f.errors['__all__'], ['Non-field error 1.', 'Non-field error 2.']) - self.assertEqual(f.errors['password1'], ['Forbidden value 2.']) - self.assertEqual(f.errors['password2'], ['Forbidden value 2.']) + f = UserRegistration( + { + "username": "adrian", + "password1": "FORBIDDEN_VALUE2", + "password2": "FORBIDDEN_VALUE2", + }, + auto_id=False, + ) + self.assertEqual( + f.errors["__all__"], ["Non-field error 1.", "Non-field error 2."] + ) + self.assertEqual(f.errors["password1"], ["Forbidden value 2."]) + self.assertEqual(f.errors["password2"], ["Forbidden value 2."]) with self.assertRaisesMessage(ValueError, "has no field named"): - f.add_error('missing_field', 'Some error.') + f.add_error("missing_field", "Some error.") def test_update_error_dict(self): class CodeForm(Form): @@ -1236,27 +1454,27 @@ value="Should escape < & > and <script>alert('xss')< def clean(self): try: - raise ValidationError({'code': [ValidationError('Code error 1.')]}) + raise ValidationError({"code": [ValidationError("Code error 1.")]}) except ValidationError as e: self._errors = e.update_error_dict(self._errors) try: - raise ValidationError({'code': [ValidationError('Code error 2.')]}) + raise ValidationError({"code": [ValidationError("Code error 2.")]}) except ValidationError as e: self._errors = e.update_error_dict(self._errors) try: - raise ValidationError({'code': forms.ErrorList(['Code error 3.'])}) + raise ValidationError({"code": forms.ErrorList(["Code error 3."])}) except ValidationError as e: self._errors = e.update_error_dict(self._errors) try: - raise ValidationError('Non-field error 1.') + raise ValidationError("Non-field error 1.") except ValidationError as e: self._errors = e.update_error_dict(self._errors) try: - raise ValidationError([ValidationError('Non-field error 2.')]) + raise ValidationError([ValidationError("Non-field error 2.")]) except ValidationError as e: self._errors = e.update_error_dict(self._errors) @@ -1265,17 +1483,20 @@ value="Should escape < & > and <script>alert('xss')< if not isinstance(error_list, self.error_class): self._errors[field] = self.error_class(error_list) - form = CodeForm({'code': 'hello'}) + form = CodeForm({"code": "hello"}) # Trigger validation. self.assertFalse(form.is_valid()) # update_error_dict didn't lose track of the ErrorDict type. self.assertIsInstance(form._errors, forms.ErrorDict) - self.assertEqual(dict(form.errors), { - 'code': ['Code error 1.', 'Code error 2.', 'Code error 3.'], - NON_FIELD_ERRORS: ['Non-field error 1.', 'Non-field error 2.'], - }) + self.assertEqual( + dict(form.errors), + { + "code": ["Code error 1.", "Code error 2.", "Code error 3."], + NON_FIELD_ERRORS: ["Non-field error 1.", "Non-field error 2."], + }, + ) def test_has_error(self): class UserRegistration(Form): @@ -1284,43 +1505,46 @@ value="Should escape < & > and <script>alert('xss')< password2 = CharField(widget=PasswordInput) def clean(self): - if (self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and - self.cleaned_data['password1'] != self.cleaned_data['password2']): + if ( + self.cleaned_data.get("password1") + and self.cleaned_data.get("password2") + and self.cleaned_data["password1"] != self.cleaned_data["password2"] + ): raise ValidationError( - 'Please make sure your passwords match.', - code='password_mismatch', + "Please make sure your passwords match.", + code="password_mismatch", ) f = UserRegistration(data={}) - self.assertTrue(f.has_error('password1')) - self.assertTrue(f.has_error('password1', 'required')) - self.assertFalse(f.has_error('password1', 'anything')) + self.assertTrue(f.has_error("password1")) + self.assertTrue(f.has_error("password1", "required")) + self.assertFalse(f.has_error("password1", "anything")) - f = UserRegistration(data={'password1': 'Hi', 'password2': 'Hi'}) - self.assertTrue(f.has_error('password1')) - self.assertTrue(f.has_error('password1', 'min_length')) - self.assertFalse(f.has_error('password1', 'anything')) - self.assertFalse(f.has_error('password2')) - self.assertFalse(f.has_error('password2', 'anything')) + f = UserRegistration(data={"password1": "Hi", "password2": "Hi"}) + self.assertTrue(f.has_error("password1")) + self.assertTrue(f.has_error("password1", "min_length")) + self.assertFalse(f.has_error("password1", "anything")) + self.assertFalse(f.has_error("password2")) + self.assertFalse(f.has_error("password2", "anything")) - f = UserRegistration(data={'password1': 'Bonjour', 'password2': 'Hello'}) - self.assertFalse(f.has_error('password1')) - self.assertFalse(f.has_error('password1', 'required')) + f = UserRegistration(data={"password1": "Bonjour", "password2": "Hello"}) + self.assertFalse(f.has_error("password1")) + self.assertFalse(f.has_error("password1", "required")) self.assertTrue(f.has_error(NON_FIELD_ERRORS)) - self.assertTrue(f.has_error(NON_FIELD_ERRORS, 'password_mismatch')) - self.assertFalse(f.has_error(NON_FIELD_ERRORS, 'anything')) + self.assertTrue(f.has_error(NON_FIELD_ERRORS, "password_mismatch")) + self.assertFalse(f.has_error(NON_FIELD_ERRORS, "anything")) def test_html_output_with_hidden_input_field_errors(self): class TestForm(Form): hidden_input = CharField(widget=HiddenInput) def clean(self): - self.add_error(None, 'Form error') + self.add_error(None, "Form error") f = TestForm(data={}) error_dict = { - 'hidden_input': ['This field is required.'], - '__all__': ['Form error'], + "hidden_input": ["This field is required."], + "__all__": ["Form error"], } self.assertEqual(f.errors, error_dict) f.as_table() @@ -1328,19 +1552,19 @@ value="Should escape < & > and <script>alert('xss')< self.assertHTMLEqual( f.as_table(), '<tr><td colspan="2"><ul class="errorlist nonfield"><li>Form error</li>' - '<li>(Hidden field hidden_input) This field is required.</li></ul>' + "<li>(Hidden field hidden_input) This field is required.</li></ul>" '<input type="hidden" name="hidden_input" id="id_hidden_input"></td></tr>', ) self.assertHTMLEqual( f.as_ul(), '<li><ul class="errorlist nonfield"><li>Form error</li>' - '<li>(Hidden field hidden_input) This field is required.</li></ul>' + "<li>(Hidden field hidden_input) This field is required.</li></ul>" '<input type="hidden" name="hidden_input" id="id_hidden_input"></li>', ) self.assertHTMLEqual( f.as_p(), '<ul class="errorlist nonfield"><li>Form error</li>' - '<li>(Hidden field hidden_input) This field is required.</li></ul>' + "<li>(Hidden field hidden_input) This field is required.</li></ul>" '<p><input type="hidden" name="hidden_input" id="id_hidden_input"></p>', ) @@ -1354,14 +1578,14 @@ value="Should escape < & > and <script>alert('xss')< def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['birthday'] = DateField() + self.fields["birthday"] = DateField() p = Person(auto_id=False) self.assertHTMLEqual( p.as_table(), """<tr><th>First name:</th><td><input type="text" name="first_name" required></td></tr> <tr><th>Last name:</th><td><input type="text" name="last_name" required></td></tr> -<tr><th>Birthday:</th><td><input type="text" name="birthday" required></td></tr>""" +<tr><th>Birthday:</th><td><input type="text" name="birthday" required></td></tr>""", ) # Instances of a dynamic Form do not persist fields from one Form instance to @@ -1373,19 +1597,19 @@ value="Should escape < & > and <script>alert('xss')< for field in field_list: self.fields[field[0]] = field[1] - field_list = [('field1', CharField()), ('field2', CharField())] + field_list = [("field1", CharField()), ("field2", CharField())] my_form = MyForm(field_list=field_list) self.assertHTMLEqual( my_form.as_table(), """<tr><th>Field1:</th><td><input type="text" name="field1" required></td></tr> -<tr><th>Field2:</th><td><input type="text" name="field2" required></td></tr>""" +<tr><th>Field2:</th><td><input type="text" name="field2" required></td></tr>""", ) - field_list = [('field3', CharField()), ('field4', CharField())] + field_list = [("field3", CharField()), ("field4", CharField())] my_form = MyForm(field_list=field_list) self.assertHTMLEqual( my_form.as_table(), """<tr><th>Field3:</th><td><input type="text" name="field3" required></td></tr> -<tr><th>Field4:</th><td><input type="text" name="field4" required></td></tr>""" +<tr><th>Field4:</th><td><input type="text" name="field4" required></td></tr>""", ) class MyForm(Form): @@ -1398,23 +1622,23 @@ value="Should escape < & > and <script>alert('xss')< for field in field_list: self.fields[field[0]] = field[1] - field_list = [('field1', CharField()), ('field2', CharField())] + field_list = [("field1", CharField()), ("field2", CharField())] my_form = MyForm(field_list=field_list) self.assertHTMLEqual( my_form.as_table(), """<tr><th>Default field 1:</th><td><input type="text" name="default_field_1" required></td></tr> <tr><th>Default field 2:</th><td><input type="text" name="default_field_2" required></td></tr> <tr><th>Field1:</th><td><input type="text" name="field1" required></td></tr> -<tr><th>Field2:</th><td><input type="text" name="field2" required></td></tr>""" +<tr><th>Field2:</th><td><input type="text" name="field2" required></td></tr>""", ) - field_list = [('field3', CharField()), ('field4', CharField())] + field_list = [("field3", CharField()), ("field4", CharField())] my_form = MyForm(field_list=field_list) self.assertHTMLEqual( my_form.as_table(), """<tr><th>Default field 1:</th><td><input type="text" name="default_field_1" required></td></tr> <tr><th>Default field 2:</th><td><input type="text" name="default_field_2" required></td></tr> <tr><th>Field3:</th><td><input type="text" name="field3" required></td></tr> -<tr><th>Field4:</th><td><input type="text" name="field4" required></td></tr>""" +<tr><th>Field4:</th><td><input type="text" name="field4" required></td></tr>""", ) # Similarly, changes to field attributes do not persist from one Form instance @@ -1427,24 +1651,42 @@ value="Should escape < & > and <script>alert('xss')< super().__init__(*args, **kwargs) if names_required: - self.fields['first_name'].required = True - self.fields['first_name'].widget.attrs['class'] = 'required' - self.fields['last_name'].required = True - self.fields['last_name'].widget.attrs['class'] = 'required' + self.fields["first_name"].required = True + self.fields["first_name"].widget.attrs["class"] = "required" + self.fields["last_name"].required = True + self.fields["last_name"].widget.attrs["class"] = "required" f = Person(names_required=False) - self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (False, False)) - self.assertEqual(f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs, ({}, {})) + self.assertEqual( + f["first_name"].field.required, + f["last_name"].field.required, + (False, False), + ) + self.assertEqual( + f["first_name"].field.widget.attrs, + f["last_name"].field.widget.attrs, + ({}, {}), + ) f = Person(names_required=True) - self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (True, True)) self.assertEqual( - f['first_name'].field.widget.attrs, - f['last_name'].field.widget.attrs, - ({'class': 'reuired'}, {'class': 'required'}) + f["first_name"].field.required, f["last_name"].field.required, (True, True) + ) + self.assertEqual( + f["first_name"].field.widget.attrs, + f["last_name"].field.widget.attrs, + ({"class": "reuired"}, {"class": "required"}), ) f = Person(names_required=False) - self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (False, False)) - self.assertEqual(f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs, ({}, {})) + self.assertEqual( + f["first_name"].field.required, + f["last_name"].field.required, + (False, False), + ) + self.assertEqual( + f["first_name"].field.widget.attrs, + f["last_name"].field.widget.attrs, + ({}, {}), + ) class Person(Form): first_name = CharField(max_length=30) @@ -1454,49 +1696,61 @@ value="Should escape < & > and <script>alert('xss')< super().__init__(*args, **kwargs) if name_max_length: - self.fields['first_name'].max_length = name_max_length - self.fields['last_name'].max_length = name_max_length + self.fields["first_name"].max_length = name_max_length + self.fields["last_name"].max_length = name_max_length f = Person(name_max_length=None) - self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (30, 30)) + self.assertEqual( + f["first_name"].field.max_length, f["last_name"].field.max_length, (30, 30) + ) f = Person(name_max_length=20) - self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (20, 20)) + self.assertEqual( + f["first_name"].field.max_length, f["last_name"].field.max_length, (20, 20) + ) f = Person(name_max_length=None) - self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (30, 30)) + self.assertEqual( + f["first_name"].field.max_length, f["last_name"].field.max_length, (30, 30) + ) # Similarly, choices do not persist from one Form instance to the next. # Refs #15127. class Person(Form): first_name = CharField(required=False) last_name = CharField(required=False) - gender = ChoiceField(choices=(('f', 'Female'), ('m', 'Male'))) + gender = ChoiceField(choices=(("f", "Female"), ("m", "Male"))) def __init__(self, allow_unspec_gender=False, *args, **kwargs): super().__init__(*args, **kwargs) if allow_unspec_gender: - self.fields['gender'].choices += (('u', 'Unspecified'),) + self.fields["gender"].choices += (("u", "Unspecified"),) f = Person() - self.assertEqual(f['gender'].field.choices, [('f', 'Female'), ('m', 'Male')]) + self.assertEqual(f["gender"].field.choices, [("f", "Female"), ("m", "Male")]) f = Person(allow_unspec_gender=True) - self.assertEqual(f['gender'].field.choices, [('f', 'Female'), ('m', 'Male'), ('u', 'Unspecified')]) + self.assertEqual( + f["gender"].field.choices, + [("f", "Female"), ("m", "Male"), ("u", "Unspecified")], + ) f = Person() - self.assertEqual(f['gender'].field.choices, [('f', 'Female'), ('m', 'Male')]) + self.assertEqual(f["gender"].field.choices, [("f", "Female"), ("m", "Male")]) def test_validators_independence(self): """ The list of form field validators can be modified without polluting other forms. """ + class MyForm(Form): myfield = CharField(max_length=25) f1 = MyForm() f2 = MyForm() - f1.fields['myfield'].validators[0] = MaxValueValidator(12) - self.assertNotEqual(f1.fields['myfield'].validators[0], f2.fields['myfield'].validators[0]) + f1.fields["myfield"].validators[0] = MaxValueValidator(12) + self.assertNotEqual( + f1.fields["myfield"].validators[0], f2.fields["myfield"].validators[0] + ) def test_hidden_widget(self): # HiddenInput widgets are displayed differently in the as_table(), as_ul()) @@ -1515,22 +1769,23 @@ value="Should escape < & > and <script>alert('xss')< """<tr><th>First name:</th><td><input type="text" name="first_name" required></td></tr> <tr><th>Last name:</th><td><input type="text" name="last_name" required></td></tr> <tr><th>Birthday:</th> -<td><input type="text" name="birthday" required><input type="hidden" name="hidden_text"></td></tr>""" +<td><input type="text" name="birthday" required><input type="hidden" name="hidden_text"></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), """<li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> -<li>Birthday: <input type="text" name="birthday" required><input type="hidden" name="hidden_text"></li>""" +<li>Birthday: <input type="text" name="birthday" required><input type="hidden" name="hidden_text"></li>""", ) self.assertHTMLEqual( - p.as_p(), """<p>First name: <input type="text" name="first_name" required></p> + p.as_p(), + """<p>First name: <input type="text" name="first_name" required></p> <p>Last name: <input type="text" name="last_name" required></p> -<p>Birthday: <input type="text" name="birthday" required><input type="hidden" name="hidden_text"></p>""" +<p>Birthday: <input type="text" name="birthday" required><input type="hidden" name="hidden_text"></p>""", ) # With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label. - p = Person(auto_id='id_%s') + p = Person(auto_id="id_%s") self.assertHTMLEqual( p.as_table(), """<tr><th><label for="id_first_name">First name:</label></th><td> @@ -1539,7 +1794,7 @@ value="Should escape < & > and <script>alert('xss')< <input type="text" name="last_name" id="id_last_name" required></td></tr> <tr><th><label for="id_birthday">Birthday:</label></th><td> <input type="text" name="birthday" id="id_birthday" required> -<input type="hidden" name="hidden_text" id="id_hidden_text"></td></tr>""" +<input type="hidden" name="hidden_text" id="id_hidden_text"></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), @@ -1549,7 +1804,7 @@ value="Should escape < & > and <script>alert('xss')< <input type="text" name="last_name" id="id_last_name" required></li> <li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" required> -<input type="hidden" name="hidden_text" id="id_hidden_text"></li>""" +<input type="hidden" name="hidden_text" id="id_hidden_text"></li>""", ) self.assertHTMLEqual( p.as_p(), @@ -1559,14 +1814,17 @@ value="Should escape < & > and <script>alert('xss')< <input type="text" name="last_name" id="id_last_name" required></p> <p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" required> -<input type="hidden" name="hidden_text" id="id_hidden_text"></p>""" +<input type="hidden" name="hidden_text" id="id_hidden_text"></p>""", ) # If a field with a HiddenInput has errors, the as_table() and as_ul() output # will include the error message(s) with the text "(Hidden field [fieldname]) " # prepended. This message is displayed at the top of the output, regardless of # its field's order in the form. - p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}, auto_id=False) + p = Person( + {"first_name": "John", "last_name": "Lennon", "birthday": "1940-10-9"}, + auto_id=False, + ) self.assertHTMLEqual( p.as_table(), """<tr><td colspan="2"> @@ -1574,7 +1832,7 @@ value="Should escape < & > and <script>alert('xss')< <tr><th>First name:</th><td><input type="text" name="first_name" value="John" required></td></tr> <tr><th>Last name:</th><td><input type="text" name="last_name" value="Lennon" required></td></tr> <tr><th>Birthday:</th><td><input type="text" name="birthday" value="1940-10-9" required> -<input type="hidden" name="hidden_text"></td></tr>""" +<input type="hidden" name="hidden_text"></td></tr>""", ) self.assertHTMLEqual( p.as_ul(), @@ -1582,7 +1840,7 @@ value="Should escape < & > and <script>alert('xss')< <li>First name: <input type="text" name="first_name" value="John" required></li> <li>Last name: <input type="text" name="last_name" value="Lennon" required></li> <li>Birthday: <input type="text" name="birthday" value="1940-10-9" required> -<input type="hidden" name="hidden_text"></li>""" +<input type="hidden" name="hidden_text"></li>""", ) self.assertHTMLEqual( p.as_p(), @@ -1590,7 +1848,7 @@ value="Should escape < & > and <script>alert('xss')< <p>First name: <input type="text" name="first_name" value="John" required></p> <p>Last name: <input type="text" name="last_name" value="Lennon" required></p> <p>Birthday: <input type="text" name="birthday" value="1940-10-9" required> -<input type="hidden" name="hidden_text"></p>""" +<input type="hidden" name="hidden_text"></p>""", ) # A corner case: It's possible for a form to have only HiddenInputs. @@ -1599,9 +1857,17 @@ value="Should escape < & > and <script>alert('xss')< bar = CharField(widget=HiddenInput) p = TestForm(auto_id=False) - self.assertHTMLEqual(p.as_table(), '<input type="hidden" name="foo"><input type="hidden" name="bar">') - self.assertHTMLEqual(p.as_ul(), '<input type="hidden" name="foo"><input type="hidden" name="bar">') - self.assertHTMLEqual(p.as_p(), '<input type="hidden" name="foo"><input type="hidden" name="bar">') + self.assertHTMLEqual( + p.as_table(), + '<input type="hidden" name="foo"><input type="hidden" name="bar">', + ) + self.assertHTMLEqual( + p.as_ul(), + '<input type="hidden" name="foo"><input type="hidden" name="bar">', + ) + self.assertHTMLEqual( + p.as_p(), '<input type="hidden" name="foo"><input type="hidden" name="bar">' + ) def test_field_order(self): # A Form's fields are displayed in the same order in which they were defined. @@ -1622,7 +1888,9 @@ value="Should escape < & > and <script>alert('xss')< field14 = CharField() p = TestForm(auto_id=False) - self.assertHTMLEqual(p.as_table(), """<tr><th>Field1:</th><td><input type="text" name="field1" required></td></tr> + self.assertHTMLEqual( + p.as_table(), + """<tr><th>Field1:</th><td><input type="text" name="field1" required></td></tr> <tr><th>Field2:</th><td><input type="text" name="field2" required></td></tr> <tr><th>Field3:</th><td><input type="text" name="field3" required></td></tr> <tr><th>Field4:</th><td><input type="text" name="field4" required></td></tr> @@ -1635,7 +1903,8 @@ value="Should escape < & > and <script>alert('xss')< <tr><th>Field11:</th><td><input type="text" name="field11" required></td></tr> <tr><th>Field12:</th><td><input type="text" name="field12" required></td></tr> <tr><th>Field13:</th><td><input type="text" name="field13" required></td></tr> -<tr><th>Field14:</th><td><input type="text" name="field14" required></td></tr>""") +<tr><th>Field14:</th><td><input type="text" name="field14" required></td></tr>""", + ) def test_explicit_field_order(self): class TestFormParent(Form): @@ -1644,17 +1913,17 @@ value="Should escape < & > and <script>alert('xss')< field4 = CharField() field5 = CharField() field6 = CharField() - field_order = ['field6', 'field5', 'field4', 'field2', 'field1'] + field_order = ["field6", "field5", "field4", "field2", "field1"] class TestForm(TestFormParent): field3 = CharField() - field_order = ['field2', 'field4', 'field3', 'field5', 'field6'] + field_order = ["field2", "field4", "field3", "field5", "field6"] class TestFormRemove(TestForm): field1 = None class TestFormMissing(TestForm): - field_order = ['field2', 'field4', 'field3', 'field5', 'field6', 'field1'] + field_order = ["field2", "field4", "field3", "field5", "field6", "field1"] field1 = None class TestFormInit(TestFormParent): @@ -1674,11 +1943,13 @@ value="Should escape < & > and <script>alert('xss')< p = TestForm() self.assertEqual(list(p.fields), TestFormMissing.field_order) p = TestFormInit() - order = [*TestForm.field_order, 'field1'] + order = [*TestForm.field_order, "field1"] self.assertEqual(list(p.fields), order) - TestForm.field_order = ['unknown'] + TestForm.field_order = ["unknown"] p = TestForm() - self.assertEqual(list(p.fields), ['field1', 'field2', 'field4', 'field5', 'field6', 'field3']) + self.assertEqual( + list(p.fields), ["field1", "field2", "field4", "field5", "field6", "field3"] + ) def test_form_html_attributes(self): # Some Field classes have an effect on the HTML attributes of their associated @@ -1686,10 +1957,12 @@ value="Should escape < & > and <script>alert('xss')< # either a TextInput or PasswordInput, then the widget's rendered HTML will # include the "maxlength" attribute. class UserRegistration(Form): - username = CharField(max_length=10) # uses TextInput by default + username = CharField(max_length=10) # uses TextInput by default password = CharField(max_length=10, widget=PasswordInput) - realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test - address = CharField() # no max_length defined here + realname = CharField( + max_length=10, widget=TextInput + ) # redundantly define widget, just to test + address = CharField() # no max_length defined here p = UserRegistration(auto_id=False) self.assertHTMLEqual( @@ -1697,21 +1970,23 @@ value="Should escape < & > and <script>alert('xss')< """<li>Username: <input type="text" name="username" maxlength="10" required></li> <li>Password: <input type="password" name="password" maxlength="10" required></li> <li>Realname: <input type="text" name="realname" maxlength="10" required></li> -<li>Address: <input type="text" name="address" required></li>""" +<li>Address: <input type="text" name="address" required></li>""", ) # If you specify a custom "attrs" that includes the "maxlength" attribute, # the Field's max_length attribute will override whatever "maxlength" you specify # in "attrs". class UserRegistration(Form): - username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20})) + username = CharField( + max_length=10, widget=TextInput(attrs={"maxlength": 20}) + ) password = CharField(max_length=10, widget=PasswordInput) p = UserRegistration(auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" required></li> -<li>Password: <input type="password" name="password" maxlength="10" required></li>""" +<li>Password: <input type="password" name="password" maxlength="10" required></li>""", ) def test_specifying_labels(self): @@ -1719,26 +1994,26 @@ value="Should escape < & > and <script>alert('xss')< # class. If you don't specify 'label', Django will use the field name with # underscores converted to spaces, and the initial letter capitalized. class UserRegistration(Form): - username = CharField(max_length=10, label='Your username') + username = CharField(max_length=10, label="Your username") password1 = CharField(widget=PasswordInput) - password2 = CharField(widget=PasswordInput, label='Contraseña (de nuevo)') + password2 = CharField(widget=PasswordInput, label="Contraseña (de nuevo)") p = UserRegistration(auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Your username: <input type="text" name="username" maxlength="10" required></li> <li>Password1: <input type="password" name="password1" required></li> -<li>Contraseña (de nuevo): <input type="password" name="password2" required></li>""" +<li>Contraseña (de nuevo): <input type="password" name="password2" required></li>""", ) # Labels for as_* methods will only end in a colon if they don't end in other # punctuation already. class Questions(Form): - q1 = CharField(label='The first question') - q2 = CharField(label='What is your name?') - q3 = CharField(label='The answer to life is:') - q4 = CharField(label='Answer this question!') - q5 = CharField(label='The last question. Period.') + q1 = CharField(label="The first question") + q2 = CharField(label="What is your name?") + q3 = CharField(label="The answer to life is:") + q4 = CharField(label="Answer this question!") + q5 = CharField(label="The last question. Period.") self.assertHTMLEqual( Questions(auto_id=False).as_p(), @@ -1746,7 +2021,7 @@ value="Should escape < & > and <script>alert('xss')< <p>What is your name? <input type="text" name="q2" required></p> <p>The answer to life is: <input type="text" name="q3" required></p> <p>Answer this question! <input type="text" name="q4" required></p> -<p>The last question. Period. <input type="text" name="q5" required></p>""" +<p>The last question. Period. <input type="text" name="q5" required></p>""", ) self.assertHTMLEqual( Questions().as_p(), @@ -1754,23 +2029,26 @@ value="Should escape < & > and <script>alert('xss')< <p><label for="id_q2">What is your name?</label> <input type="text" name="q2" id="id_q2" required></p> <p><label for="id_q3">The answer to life is:</label> <input type="text" name="q3" id="id_q3" required></p> <p><label for="id_q4">Answer this question!</label> <input type="text" name="q4" id="id_q4" required></p> -<p><label for="id_q5">The last question. Period.</label> <input type="text" name="q5" id="id_q5" required></p>""" +<p><label for="id_q5">The last question. Period.</label> <input type="text" name="q5" id="id_q5" required></p>""", ) # If a label is set to the empty string for a field, that field won't get a label. class UserRegistration(Form): - username = CharField(max_length=10, label='') + username = CharField(max_length=10, label="") password = CharField(widget=PasswordInput) p = UserRegistration(auto_id=False) - self.assertHTMLEqual(p.as_ul(), """<li> <input type="text" name="username" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""") - p = UserRegistration(auto_id='id_%s') + self.assertHTMLEqual( + p.as_ul(), + """<li> <input type="text" name="username" maxlength="10" required></li> +<li>Password: <input type="password" name="password" required></li>""", + ) + p = UserRegistration(auto_id="id_%s") self.assertHTMLEqual( p.as_ul(), """<li> <input id="id_username" type="text" name="username" maxlength="10" required></li> <li><label for="id_password">Password:</label> -<input type="password" name="password" id="id_password" required></li>""" +<input type="password" name="password" id="id_password" required></li>""", ) # If label is None, Django will auto-create the label from the field name. This @@ -1783,15 +2061,15 @@ value="Should escape < & > and <script>alert('xss')< self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""" +<li>Password: <input type="password" name="password" required></li>""", ) - p = UserRegistration(auto_id='id_%s') + p = UserRegistration(auto_id="id_%s") self.assertHTMLEqual( p.as_ul(), """<li><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" required></li> <li><label for="id_password">Password:</label> -<input type="password" name="password" id="id_password" required></li>""" +<input type="password" name="password" id="id_password" required></li>""", ) def test_label_suffix(self): @@ -1801,31 +2079,40 @@ value="Should escape < & > and <script>alert('xss')< # punctuation symbol: ., !, ? or :. If you specify a different suffix, it will # be appended regardless of the last character of the label. class FavoriteForm(Form): - color = CharField(label='Favorite color?') - animal = CharField(label='Favorite animal') - answer = CharField(label='Secret answer', label_suffix=' =') + color = CharField(label="Favorite color?") + animal = CharField(label="Favorite animal") + answer = CharField(label="Secret answer", label_suffix=" =") f = FavoriteForm(auto_id=False) - self.assertHTMLEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" required></li> + self.assertHTMLEqual( + f.as_ul(), + """<li>Favorite color? <input type="text" name="color" required></li> <li>Favorite animal: <input type="text" name="animal" required></li> -<li>Secret answer = <input type="text" name="answer" required></li>""") +<li>Secret answer = <input type="text" name="answer" required></li>""", + ) - f = FavoriteForm(auto_id=False, label_suffix='?') - self.assertHTMLEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" required></li> + f = FavoriteForm(auto_id=False, label_suffix="?") + self.assertHTMLEqual( + f.as_ul(), + """<li>Favorite color? <input type="text" name="color" required></li> <li>Favorite animal? <input type="text" name="animal" required></li> -<li>Secret answer = <input type="text" name="answer" required></li>""") +<li>Secret answer = <input type="text" name="answer" required></li>""", + ) - f = FavoriteForm(auto_id=False, label_suffix='') - self.assertHTMLEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" required></li> + f = FavoriteForm(auto_id=False, label_suffix="") + self.assertHTMLEqual( + f.as_ul(), + """<li>Favorite color? <input type="text" name="color" required></li> <li>Favorite animal <input type="text" name="animal" required></li> -<li>Secret answer = <input type="text" name="answer" required></li>""") +<li>Secret answer = <input type="text" name="answer" required></li>""", + ) - f = FavoriteForm(auto_id=False, label_suffix='\u2192') + f = FavoriteForm(auto_id=False, label_suffix="\u2192") self.assertHTMLEqual( f.as_ul(), '<li>Favorite color? <input type="text" name="color" required></li>\n' '<li>Favorite animal\u2192 <input type="text" name="animal" required></li>\n' - '<li>Secret answer = <input type="text" name="answer" required></li>' + '<li>Secret answer = <input type="text" name="answer" required></li>', ) def test_initial_data(self): @@ -1835,7 +2122,7 @@ value="Should escape < & > and <script>alert('xss')< # empty dictionary). Also, the initial value is *not* used if data for a # particular required field isn't provided. class UserRegistration(Form): - username = CharField(max_length=10, initial='django') + username = CharField(max_length=10, initial="django") password = CharField(widget=PasswordInput) # Here, we're not submitting any data, so the initial value will be displayed.) @@ -1843,7 +2130,7 @@ value="Should escape < & > and <script>alert('xss')< self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""" +<li>Password: <input type="password" name="password" required></li>""", ) # Here, we're submitting data, so the initial value will *not* be displayed. @@ -1853,29 +2140,29 @@ value="Should escape < & > and <script>alert('xss')< """<li><ul class="errorlist"><li>This field is required.</li></ul> Username: <input type="text" name="username" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", ) - p = UserRegistration({'username': ''}, auto_id=False) + p = UserRegistration({"username": ""}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul> Username: <input type="text" name="username" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", ) - p = UserRegistration({'username': 'foo'}, auto_id=False) + p = UserRegistration({"username": "foo"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", ) # An 'initial' value is *not* used as a fallback if data is not provided. In this # example, we don't provide a value for 'username', and the form raises a # validation error rather than using the initial value for 'username'. - p = UserRegistration({'password': 'secret'}) - self.assertEqual(p.errors['username'], ['This field is required.']) + p = UserRegistration({"password": "secret"}) + self.assertEqual(p.errors["username"], ["This field is required."]) self.assertFalse(p.is_valid()) def test_dynamic_initial_data(self): @@ -1889,61 +2176,66 @@ Password: <input type="password" name="password" required></li>""" password = CharField(widget=PasswordInput) # Here, we're not submitting any data, so the initial value will be displayed.) - p = UserRegistration(initial={'username': 'django'}, auto_id=False) + p = UserRegistration(initial={"username": "django"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""" +<li>Password: <input type="password" name="password" required></li>""", ) - p = UserRegistration(initial={'username': 'stephane'}, auto_id=False) + p = UserRegistration(initial={"username": "stephane"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="stephane" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""" +<li>Password: <input type="password" name="password" required></li>""", ) # The 'initial' parameter is meaningless if you pass data. - p = UserRegistration({}, initial={'username': 'django'}, auto_id=False) + p = UserRegistration({}, initial={"username": "django"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul> Username: <input type="text" name="username" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", + ) + p = UserRegistration( + {"username": ""}, initial={"username": "django"}, auto_id=False ) - p = UserRegistration({'username': ''}, initial={'username': 'django'}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul> Username: <input type="text" name="username" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", + ) + p = UserRegistration( + {"username": "foo"}, initial={"username": "django"}, auto_id=False ) - p = UserRegistration({'username': 'foo'}, initial={'username': 'django'}, auto_id=False) self.assertHTMLEqual( - p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" required></li> + p.as_ul(), + """<li>Username: <input type="text" name="username" value="foo" maxlength="10" required></li> <li><ul class="errorlist"><li>This field is required.</li></ul> -Password: <input type="password" name="password" required></li>""" +Password: <input type="password" name="password" required></li>""", ) # A dynamic 'initial' value is *not* used as a fallback if data is not provided. # In this example, we don't provide a value for 'username', and the form raises a # validation error rather than using the initial value for 'username'. - p = UserRegistration({'password': 'secret'}, initial={'username': 'django'}) - self.assertEqual(p.errors['username'], ['This field is required.']) + p = UserRegistration({"password": "secret"}, initial={"username": "django"}) + self.assertEqual(p.errors["username"], ["This field is required."]) self.assertFalse(p.is_valid()) # If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(), # then the latter will get precedence. class UserRegistration(Form): - username = CharField(max_length=10, initial='django') + username = CharField(max_length=10, initial="django") password = CharField(widget=PasswordInput) - p = UserRegistration(initial={'username': 'babik'}, auto_id=False) + p = UserRegistration(initial={"username": "babik"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="babik" maxlength="10" required></li> -<li>Password: <input type="password" name="password" required></li>""" +<li>Password: <input type="password" name="password" required></li>""", ) def test_callable_initial_data(self): @@ -1952,23 +2244,28 @@ Password: <input type="password" name="password" required></li>""" class UserRegistration(Form): username = CharField(max_length=10) password = CharField(widget=PasswordInput) - options = MultipleChoiceField(choices=[('f', 'foo'), ('b', 'bar'), ('w', 'whiz')]) + options = MultipleChoiceField( + choices=[("f", "foo"), ("b", "bar"), ("w", "whiz")] + ) # We need to define functions that get called later.) def initial_django(): - return 'django' + return "django" def initial_stephane(): - return 'stephane' + return "stephane" def initial_options(): - return ['f', 'b'] + return ["f", "b"] def initial_other_options(): - return ['b', 'w'] + return ["b", "w"] # Here, we're not submitting any data, so the initial value will be displayed.) - p = UserRegistration(initial={'username': initial_django, 'options': initial_options}, auto_id=False) + p = UserRegistration( + initial={"username": initial_django, "options": initial_options}, + auto_id=False, + ) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" required></li> @@ -1977,11 +2274,15 @@ Password: <input type="password" name="password" required></li>""" <option value="f" selected>foo</option> <option value="b" selected>bar</option> <option value="w">whiz</option> -</select></li>""" +</select></li>""", ) # The 'initial' parameter is meaningless if you pass data. - p = UserRegistration({}, initial={'username': initial_django, 'options': initial_options}, auto_id=False) + p = UserRegistration( + {}, + initial={"username": initial_django, "options": initial_options}, + auto_id=False, + ) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul> @@ -1993,9 +2294,11 @@ Options: <select multiple name="options" required> <option value="f">foo</option> <option value="b">bar</option> <option value="w">whiz</option> -</select></li>""" +</select></li>""", + ) + p = UserRegistration( + {"username": ""}, initial={"username": initial_django}, auto_id=False ) - p = UserRegistration({'username': ''}, initial={'username': initial_django}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul> @@ -2007,10 +2310,12 @@ Options: <select multiple name="options" required> <option value="f">foo</option> <option value="b">bar</option> <option value="w">whiz</option> -</select></li>""" +</select></li>""", ) p = UserRegistration( - {'username': 'foo', 'options': ['f', 'b']}, initial={'username': initial_django}, auto_id=False + {"username": "foo", "options": ["f", "b"]}, + initial={"username": initial_django}, + auto_id=False, ) self.assertHTMLEqual( p.as_ul(), @@ -2021,14 +2326,17 @@ Password: <input type="password" name="password" required></li> <option value="f" selected>foo</option> <option value="b" selected>bar</option> <option value="w">whiz</option> -</select></li>""" +</select></li>""", ) # A callable 'initial' value is *not* used as a fallback if data is not provided. # In this example, we don't provide a value for 'username', and the form raises a # validation error rather than using the initial value for 'username'. - p = UserRegistration({'password': 'secret'}, initial={'username': initial_django, 'options': initial_options}) - self.assertEqual(p.errors['username'], ['This field is required.']) + p = UserRegistration( + {"password": "secret"}, + initial={"username": initial_django, "options": initial_options}, + ) + self.assertEqual(p.errors["username"], ["This field is required."]) self.assertFalse(p.is_valid()) # If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(), @@ -2037,7 +2345,7 @@ Password: <input type="password" name="password" required></li> username = CharField(max_length=10, initial=initial_django) password = CharField(widget=PasswordInput) options = MultipleChoiceField( - choices=[('f', 'foo'), ('b', 'bar'), ('w', 'whiz')], + choices=[("f", "foo"), ("b", "bar"), ("w", "whiz")], initial=initial_other_options, ) @@ -2050,9 +2358,12 @@ Password: <input type="password" name="password" required></li> <option value="f">foo</option> <option value="b" selected>bar</option> <option value="w" selected>whiz</option> -</select></li>""" +</select></li>""", + ) + p = UserRegistration( + initial={"username": initial_stephane, "options": initial_options}, + auto_id=False, ) - p = UserRegistration(initial={'username': initial_stephane, 'options': initial_options}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="stephane" maxlength="10" required></li> @@ -2061,31 +2372,31 @@ Password: <input type="password" name="password" required></li> <option value="f" selected>foo</option> <option value="b" selected>bar</option> <option value="w">whiz</option> -</select></li>""" +</select></li>""", ) def test_get_initial_for_field(self): now = datetime.datetime(2006, 10, 25, 14, 30, 45, 123456) class PersonForm(Form): - first_name = CharField(initial='John') - last_name = CharField(initial='Doe') + first_name = CharField(initial="John") + last_name = CharField(initial="Doe") age = IntegerField() - occupation = CharField(initial=lambda: 'Unknown') + occupation = CharField(initial=lambda: "Unknown") dt_fixed = DateTimeField(initial=now) dt_callable = DateTimeField(initial=lambda: now) - form = PersonForm(initial={'first_name': 'Jane'}) + form = PersonForm(initial={"first_name": "Jane"}) cases = [ - ('age', None), - ('last_name', 'Doe'), + ("age", None), + ("last_name", "Doe"), # Form.initial overrides Field.initial. - ('first_name', 'Jane'), + ("first_name", "Jane"), # Callables are evaluated. - ('occupation', 'Unknown'), + ("occupation", "Unknown"), # Microseconds are removed from datetimes. - ('dt_fixed', datetime.datetime(2006, 10, 25, 14, 30, 45)), - ('dt_callable', datetime.datetime(2006, 10, 25, 14, 30, 45)), + ("dt_fixed", datetime.datetime(2006, 10, 25, 14, 30, 45)), + ("dt_callable", datetime.datetime(2006, 10, 25, 14, 30, 45)), ] for field_name, expected in cases: with self.subTest(field_name=field_name): @@ -2095,72 +2406,79 @@ Password: <input type="password" name="password" required></li> def test_changed_data(self): class Person(Form): - first_name = CharField(initial='Hans') - last_name = CharField(initial='Greatel') + first_name = CharField(initial="Hans") + last_name = CharField(initial="Greatel") birthday = DateField(initial=datetime.date(1974, 8, 16)) - p = Person(data={'first_name': 'Hans', 'last_name': 'Scrmbl', 'birthday': '1974-08-16'}) + p = Person( + data={"first_name": "Hans", "last_name": "Scrmbl", "birthday": "1974-08-16"} + ) self.assertTrue(p.is_valid()) - self.assertNotIn('first_name', p.changed_data) - self.assertIn('last_name', p.changed_data) - self.assertNotIn('birthday', p.changed_data) + self.assertNotIn("first_name", p.changed_data) + self.assertIn("last_name", p.changed_data) + self.assertNotIn("birthday", p.changed_data) # A field raising ValidationError is always in changed_data class PedanticField(forms.Field): def to_python(self, value): - raise ValidationError('Whatever') + raise ValidationError("Whatever") class Person2(Person): - pedantic = PedanticField(initial='whatever', show_hidden_initial=True) + pedantic = PedanticField(initial="whatever", show_hidden_initial=True) - p = Person2(data={ - 'first_name': 'Hans', 'last_name': 'Scrmbl', 'birthday': '1974-08-16', - 'initial-pedantic': 'whatever', - }) + p = Person2( + data={ + "first_name": "Hans", + "last_name": "Scrmbl", + "birthday": "1974-08-16", + "initial-pedantic": "whatever", + } + ) self.assertFalse(p.is_valid()) - self.assertIn('pedantic', p.changed_data) + self.assertIn("pedantic", p.changed_data) def test_boundfield_values(self): # It's possible to get to the value which would be used for rendering # the widget for a field by using the BoundField's value method. class UserRegistration(Form): - username = CharField(max_length=10, initial='djangonaut') + username = CharField(max_length=10, initial="djangonaut") password = CharField(widget=PasswordInput) unbound = UserRegistration() - bound = UserRegistration({'password': 'foo'}) - self.assertIsNone(bound['username'].value()) - self.assertEqual(unbound['username'].value(), 'djangonaut') - self.assertEqual(bound['password'].value(), 'foo') - self.assertIsNone(unbound['password'].value()) + bound = UserRegistration({"password": "foo"}) + self.assertIsNone(bound["username"].value()) + self.assertEqual(unbound["username"].value(), "djangonaut") + self.assertEqual(bound["password"].value(), "foo") + self.assertIsNone(unbound["password"].value()) def test_boundfield_initial_called_once(self): """ Multiple calls to BoundField().value() in an unbound form should return the same result each time (#24391). """ + class MyForm(Form): name = CharField(max_length=10, initial=uuid.uuid4) form = MyForm() - name = form['name'] + name = form["name"] self.assertEqual(name.value(), name.value()) # BoundField is also cached - self.assertIs(form['name'], name) + self.assertIs(form["name"], name) def test_boundfield_value_disabled_callable_initial(self): class PersonForm(Form): - name = CharField(initial=lambda: 'John Doe', disabled=True) + name = CharField(initial=lambda: "John Doe", disabled=True) # Without form data. form = PersonForm() - self.assertEqual(form['name'].value(), 'John Doe') + self.assertEqual(form["name"].value(), "John Doe") # With form data. As the field is disabled, the value should not be # affected by the form data. form = PersonForm({}) - self.assertEqual(form['name'].value(), 'John Doe') + self.assertEqual(form["name"].value(), "John Doe") def test_custom_boundfield(self): class CustomField(CharField): @@ -2171,7 +2489,7 @@ Password: <input type="password" name="password" required></li> name = CustomField() f = SampleForm() - self.assertEqual(f['name'], (f, 'name')) + self.assertEqual(f["name"], (f, "name")) def test_initial_datetime_values(self): now = datetime.datetime.now() @@ -2199,18 +2517,22 @@ Password: <input type="password" name="password" required></li> auto_time_only = TimeField(initial=delayed_now_time) supports_microseconds = DateTimeField(initial=delayed_now, widget=TextInput) hi_default_microsec = DateTimeField(initial=delayed_now, widget=HiddenInput) - hi_without_microsec = DateTimeField(initial=delayed_now, widget=HiddenInputWithoutMicrosec) - ti_without_microsec = DateTimeField(initial=delayed_now, widget=TextInputWithoutMicrosec) + hi_without_microsec = DateTimeField( + initial=delayed_now, widget=HiddenInputWithoutMicrosec + ) + ti_without_microsec = DateTimeField( + initial=delayed_now, widget=TextInputWithoutMicrosec + ) unbound = DateTimeForm() cases = [ - ('fixed', now_no_ms), - ('auto_timestamp', now_no_ms), - ('auto_time_only', now_no_ms.time()), - ('supports_microseconds', now), - ('hi_default_microsec', now), - ('hi_without_microsec', now_no_ms), - ('ti_without_microsec', now_no_ms), + ("fixed", now_no_ms), + ("auto_timestamp", now_no_ms), + ("auto_time_only", now_no_ms.time()), + ("supports_microseconds", now), + ("hi_default_microsec", now), + ("hi_without_microsec", now_no_ms), + ("ti_without_microsec", now_no_ms), ] for field_name, expected in cases: with self.subTest(field_name=field_name): @@ -2229,7 +2551,12 @@ Password: <input type="password" name="password" required></li> def now(self): self.elapsed_seconds += 1 return datetime.datetime( - 2006, 10, 25, 14, 30, 45 + self.elapsed_seconds, + 2006, + 10, + 25, + 14, + 30, + 45 + self.elapsed_seconds, microseconds, ) @@ -2244,12 +2571,16 @@ Password: <input type="password" name="password" required></li> removes microseconds. """ form = self.get_datetime_form_with_callable_initial( - disabled=True, microseconds=123456, + disabled=True, + microseconds=123456, ) self.assertEqual(form.errors, {}) - self.assertEqual(form.cleaned_data, { - 'dt': datetime.datetime(2006, 10, 25, 14, 30, 46), - }) + self.assertEqual( + form.cleaned_data, + { + "dt": datetime.datetime(2006, 10, 25, 14, 30, 46), + }, + ) def test_datetime_clean_disabled_callable_initial_bound_field(self): """ @@ -2258,23 +2589,28 @@ Password: <input type="password" name="password" required></li> """ form = self.get_datetime_form_with_callable_initial(disabled=True) self.assertEqual(form.errors, {}) - cleaned = form.cleaned_data['dt'] + cleaned = form.cleaned_data["dt"] self.assertEqual(cleaned, datetime.datetime(2006, 10, 25, 14, 30, 46)) - bf = form['dt'] + bf = form["dt"] self.assertEqual(cleaned, bf.initial) def test_datetime_changed_data_callable_with_microseconds(self): class DateTimeForm(forms.Form): - dt = DateTimeField(initial=lambda: datetime.datetime(2006, 10, 25, 14, 30, 45, 123456), disabled=True) + dt = DateTimeField( + initial=lambda: datetime.datetime(2006, 10, 25, 14, 30, 45, 123456), + disabled=True, + ) - form = DateTimeForm({'dt': '2006-10-25 14:30:45'}) + form = DateTimeForm({"dt": "2006-10-25 14:30:45"}) self.assertEqual(form.changed_data, []) def test_help_text(self): # You can specify descriptive text for a field by using the 'help_text' argument) class UserRegistration(Form): - username = CharField(max_length=10, help_text='e.g., user@example.com') - password = CharField(widget=PasswordInput, help_text='Wählen Sie mit Bedacht.') + username = CharField(max_length=10, help_text="e.g., user@example.com") + password = CharField( + widget=PasswordInput, help_text="Wählen Sie mit Bedacht." + ) p = UserRegistration(auto_id=False) self.assertHTMLEqual( @@ -2282,40 +2618,42 @@ Password: <input type="password" name="password" required></li> """<li>Username: <input type="text" name="username" maxlength="10" required> <span class="helptext">e.g., user@example.com</span></li> <li>Password: <input type="password" name="password" required> -<span class="helptext">Wählen Sie mit Bedacht.</span></li>""" +<span class="helptext">Wählen Sie mit Bedacht.</span></li>""", ) self.assertHTMLEqual( p.as_p(), """<p>Username: <input type="text" name="username" maxlength="10" required> <span class="helptext">e.g., user@example.com</span></p> <p>Password: <input type="password" name="password" required> -<span class="helptext">Wählen Sie mit Bedacht.</span></p>""" +<span class="helptext">Wählen Sie mit Bedacht.</span></p>""", ) self.assertHTMLEqual( p.as_table(), """<tr><th>Username:</th><td><input type="text" name="username" maxlength="10" required><br> <span class="helptext">e.g., user@example.com</span></td></tr> <tr><th>Password:</th><td><input type="password" name="password" required><br> -<span class="helptext">Wählen Sie mit Bedacht.</span></td></tr>""" +<span class="helptext">Wählen Sie mit Bedacht.</span></td></tr>""", ) # The help text is displayed whether or not data is provided for the form. - p = UserRegistration({'username': 'foo'}, auto_id=False) + p = UserRegistration({"username": "foo"}, auto_id=False) self.assertHTMLEqual( p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" required> <span class="helptext">e.g., user@example.com</span></li> <li><ul class="errorlist"><li>This field is required.</li></ul> Password: <input type="password" name="password" required> -<span class="helptext">Wählen Sie mit Bedacht.</span></li>""" +<span class="helptext">Wählen Sie mit Bedacht.</span></li>""", ) # help_text is not displayed for hidden fields. It can be used for documentation # purposes, though. class UserRegistration(Form): - username = CharField(max_length=10, help_text='e.g., user@example.com') + username = CharField(max_length=10, help_text="e.g., user@example.com") password = CharField(widget=PasswordInput) - next = CharField(widget=HiddenInput, initial='/', help_text='Redirect destination') + next = CharField( + widget=HiddenInput, initial="/", help_text="Redirect destination" + ) p = UserRegistration(auto_id=False) self.assertHTMLEqual( @@ -2323,16 +2661,17 @@ Password: <input type="password" name="password" required> """<li>Username: <input type="text" name="username" maxlength="10" required> <span class="helptext">e.g., user@example.com</span></li> <li>Password: <input type="password" name="password" required> -<input type="hidden" name="next" value="/"></li>""" +<input type="hidden" name="next" value="/"></li>""", ) def test_help_text_html_safe(self): """help_text should not be escaped.""" + class UserRegistration(Form): - username = CharField(max_length=10, help_text='e.g., user@example.com') + username = CharField(max_length=10, help_text="e.g., user@example.com") password = CharField( widget=PasswordInput, - help_text='Help text is <strong>escaped</strong>.', + help_text="Help text is <strong>escaped</strong>.", ) p = UserRegistration(auto_id=False) @@ -2341,24 +2680,24 @@ Password: <input type="password" name="password" required> '<li>Username: <input type="text" name="username" maxlength="10" required>' '<span class="helptext">e.g., user@example.com</span></li>' '<li>Password: <input type="password" name="password" required>' - '<span class="helptext">Help text is <strong>escaped</strong>.</span></li>' + '<span class="helptext">Help text is <strong>escaped</strong>.</span></li>', ) self.assertHTMLEqual( p.as_p(), '<p>Username: <input type="text" name="username" maxlength="10" required>' '<span class="helptext">e.g., user@example.com</span></p>' '<p>Password: <input type="password" name="password" required>' - '<span class="helptext">Help text is <strong>escaped</strong>.</span></p>' + '<span class="helptext">Help text is <strong>escaped</strong>.</span></p>', ) self.assertHTMLEqual( p.as_table(), - '<tr><th>Username:</th><td>' + "<tr><th>Username:</th><td>" '<input type="text" name="username" maxlength="10" required><br>' '<span class="helptext">e.g., user@example.com</span></td></tr>' - '<tr><th>Password:</th><td>' + "<tr><th>Password:</th><td>" '<input type="password" name="password" required><br>' '<span class="helptext">Help text is <strong>escaped</strong>.</span>' - '</td></tr>' + "</td></tr>", ) def test_subclassing_forms(self): @@ -2378,7 +2717,7 @@ Password: <input type="password" name="password" required> p.as_ul(), """<li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> -<li>Birthday: <input type="text" name="birthday" required></li>""" +<li>Birthday: <input type="text" name="birthday" required></li>""", ) m = Musician(auto_id=False) self.assertHTMLEqual( @@ -2386,7 +2725,7 @@ Password: <input type="password" name="password" required> """<li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> <li>Birthday: <input type="text" name="birthday" required></li> -<li>Instrument: <input type="text" name="instrument" required></li>""" +<li>Instrument: <input type="text" name="instrument" required></li>""", ) # Yes, you can subclass multiple forms. The fields are added in the order in @@ -2403,11 +2742,14 @@ Password: <input type="password" name="password" required> haircut_type = CharField() b = Beatle(auto_id=False) - self.assertHTMLEqual(b.as_ul(), """<li>Instrument: <input type="text" name="instrument" required></li> + self.assertHTMLEqual( + b.as_ul(), + """<li>Instrument: <input type="text" name="instrument" required></li> <li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> <li>Birthday: <input type="text" name="birthday" required></li> -<li>Haircut type: <input type="text" name="haircut_type" required></li>""") +<li>Haircut type: <input type="text" name="haircut_type" required></li>""", + ) def test_forms_with_prefixes(self): # Sometimes it's necessary to have multiple forms display on the same HTML page, @@ -2423,11 +2765,11 @@ Password: <input type="password" name="password" required> birthday = DateField() data = { - 'person1-first_name': 'John', - 'person1-last_name': 'Lennon', - 'person1-birthday': '1940-10-9' + "person1-first_name": "John", + "person1-last_name": "Lennon", + "person1-birthday": "1940-10-9", } - p = Person(data, prefix='person1') + p = Person(data, prefix="person1") self.assertHTMLEqual( p.as_ul(), """<li><label for="id_person1-first_name">First name:</label> @@ -2435,74 +2777,70 @@ Password: <input type="password" name="password" required> <li><label for="id_person1-last_name">Last name:</label> <input type="text" name="person1-last_name" value="Lennon" id="id_person1-last_name" required></li> <li><label for="id_person1-birthday">Birthday:</label> -<input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" required></li>""" +<input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" required></li>""", ) self.assertHTMLEqual( - str(p['first_name']), - '<input type="text" name="person1-first_name" value="John" id="id_person1-first_name" required>' + str(p["first_name"]), + '<input type="text" name="person1-first_name" value="John" id="id_person1-first_name" required>', ) self.assertHTMLEqual( - str(p['last_name']), - '<input type="text" name="person1-last_name" value="Lennon" id="id_person1-last_name" required>' + str(p["last_name"]), + '<input type="text" name="person1-last_name" value="Lennon" id="id_person1-last_name" required>', ) self.assertHTMLEqual( - str(p['birthday']), - '<input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" required>' + str(p["birthday"]), + '<input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" required>', ) self.assertEqual(p.errors, {}) self.assertTrue(p.is_valid()) - self.assertEqual(p.cleaned_data['first_name'], 'John') - self.assertEqual(p.cleaned_data['last_name'], 'Lennon') - self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9)) + self.assertEqual(p.cleaned_data["first_name"], "John") + self.assertEqual(p.cleaned_data["last_name"], "Lennon") + self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9)) # Let's try submitting some bad data to make sure form.errors and field.errors # work as expected. data = { - 'person1-first_name': '', - 'person1-last_name': '', - 'person1-birthday': '' + "person1-first_name": "", + "person1-last_name": "", + "person1-birthday": "", } - p = Person(data, prefix='person1') - self.assertEqual(p.errors['first_name'], ['This field is required.']) - self.assertEqual(p.errors['last_name'], ['This field is required.']) - self.assertEqual(p.errors['birthday'], ['This field is required.']) - self.assertEqual(p['first_name'].errors, ['This field is required.']) + p = Person(data, prefix="person1") + self.assertEqual(p.errors["first_name"], ["This field is required."]) + self.assertEqual(p.errors["last_name"], ["This field is required."]) + self.assertEqual(p.errors["birthday"], ["This field is required."]) + self.assertEqual(p["first_name"].errors, ["This field is required."]) # Accessing a nonexistent field. with self.assertRaises(KeyError): - p['person1-first_name'].errors + p["person1-first_name"].errors # In this example, the data doesn't have a prefix, but the form requires it, so # the form doesn't "see" the fields. - data = { - 'first_name': 'John', - 'last_name': 'Lennon', - 'birthday': '1940-10-9' - } - p = Person(data, prefix='person1') - self.assertEqual(p.errors['first_name'], ['This field is required.']) - self.assertEqual(p.errors['last_name'], ['This field is required.']) - self.assertEqual(p.errors['birthday'], ['This field is required.']) + data = {"first_name": "John", "last_name": "Lennon", "birthday": "1940-10-9"} + p = Person(data, prefix="person1") + self.assertEqual(p.errors["first_name"], ["This field is required."]) + self.assertEqual(p.errors["last_name"], ["This field is required."]) + self.assertEqual(p.errors["birthday"], ["This field is required."]) # With prefixes, a single data dictionary can hold data for multiple instances # of the same form. data = { - 'person1-first_name': 'John', - 'person1-last_name': 'Lennon', - 'person1-birthday': '1940-10-9', - 'person2-first_name': 'Jim', - 'person2-last_name': 'Morrison', - 'person2-birthday': '1943-12-8' + "person1-first_name": "John", + "person1-last_name": "Lennon", + "person1-birthday": "1940-10-9", + "person2-first_name": "Jim", + "person2-last_name": "Morrison", + "person2-birthday": "1943-12-8", } - p1 = Person(data, prefix='person1') + p1 = Person(data, prefix="person1") self.assertTrue(p1.is_valid()) - self.assertEqual(p1.cleaned_data['first_name'], 'John') - self.assertEqual(p1.cleaned_data['last_name'], 'Lennon') - self.assertEqual(p1.cleaned_data['birthday'], datetime.date(1940, 10, 9)) - p2 = Person(data, prefix='person2') + self.assertEqual(p1.cleaned_data["first_name"], "John") + self.assertEqual(p1.cleaned_data["last_name"], "Lennon") + self.assertEqual(p1.cleaned_data["birthday"], datetime.date(1940, 10, 9)) + p2 = Person(data, prefix="person2") self.assertTrue(p2.is_valid()) - self.assertEqual(p2.cleaned_data['first_name'], 'Jim') - self.assertEqual(p2.cleaned_data['last_name'], 'Morrison') - self.assertEqual(p2.cleaned_data['birthday'], datetime.date(1943, 12, 8)) + self.assertEqual(p2.cleaned_data["first_name"], "Jim") + self.assertEqual(p2.cleaned_data["last_name"], "Morrison") + self.assertEqual(p2.cleaned_data["birthday"], datetime.date(1943, 12, 8)) # By default, forms append a hyphen between the prefix and the field name, but a # form can alter that behavior by implementing the add_prefix() method. This @@ -2514,9 +2852,13 @@ Password: <input type="password" name="password" required> birthday = DateField() def add_prefix(self, field_name): - return '%s-prefix-%s' % (self.prefix, field_name) if self.prefix else field_name + return ( + "%s-prefix-%s" % (self.prefix, field_name) + if self.prefix + else field_name + ) - p = Person(prefix='foo') + p = Person(prefix="foo") self.assertHTMLEqual( p.as_ul(), """<li><label for="id_foo-prefix-first_name">First name:</label> @@ -2524,30 +2866,30 @@ Password: <input type="password" name="password" required> <li><label for="id_foo-prefix-last_name">Last name:</label> <input type="text" name="foo-prefix-last_name" id="id_foo-prefix-last_name" required></li> <li><label for="id_foo-prefix-birthday">Birthday:</label> -<input type="text" name="foo-prefix-birthday" id="id_foo-prefix-birthday" required></li>""" +<input type="text" name="foo-prefix-birthday" id="id_foo-prefix-birthday" required></li>""", ) data = { - 'foo-prefix-first_name': 'John', - 'foo-prefix-last_name': 'Lennon', - 'foo-prefix-birthday': '1940-10-9' + "foo-prefix-first_name": "John", + "foo-prefix-last_name": "Lennon", + "foo-prefix-birthday": "1940-10-9", } - p = Person(data, prefix='foo') + p = Person(data, prefix="foo") self.assertTrue(p.is_valid()) - self.assertEqual(p.cleaned_data['first_name'], 'John') - self.assertEqual(p.cleaned_data['last_name'], 'Lennon') - self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9)) + self.assertEqual(p.cleaned_data["first_name"], "John") + self.assertEqual(p.cleaned_data["last_name"], "Lennon") + self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9)) def test_class_prefix(self): # Prefix can be also specified at the class level. class Person(Form): first_name = CharField() - prefix = 'foo' + prefix = "foo" p = Person() - self.assertEqual(p.prefix, 'foo') + self.assertEqual(p.prefix, "foo") - p = Person(prefix='bar') - self.assertEqual(p.prefix, 'bar') + p = Person(prefix="bar") + self.assertEqual(p.prefix, "bar") def test_forms_with_null_boolean(self): # NullBooleanField is a bit of a special case because its presentation (widget) @@ -2556,60 +2898,87 @@ Password: <input type="password" name="password" required> name = CharField() is_cool = NullBooleanField() - p = Person({'name': 'Joe'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> + p = Person({"name": "Joe"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': '1'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "1"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': '2'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "2"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': '3'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "3"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': True}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": True}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': False}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": False}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': 'unknown'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "unknown"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': 'true'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "true"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> -</select>""") - p = Person({'name': 'Joe', 'is_cool': 'false'}, auto_id=False) - self.assertHTMLEqual(str(p['is_cool']), """<select name="is_cool"> +</select>""", + ) + p = Person({"name": "Joe", "is_cool": "false"}, auto_id=False) + self.assertHTMLEqual( + str(p["is_cool"]), + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> -</select>""") +</select>""", + ) def test_forms_with_file_fields(self): # FileFields are a special case because they take their data from the request.FILES, @@ -2626,37 +2995,47 @@ Password: <input type="password" name="password" required> f = FileForm(data={}, files={}, auto_id=False) self.assertHTMLEqual( f.as_table(), - '<tr><th>File1:</th><td>' + "<tr><th>File1:</th><td>" '<ul class="errorlist"><li>This field is required.</li></ul>' - '<input type="file" name="file1" required></td></tr>' + '<input type="file" name="file1" required></td></tr>', ) - f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', b'')}, auto_id=False) + f = FileForm( + data={}, files={"file1": SimpleUploadedFile("name", b"")}, auto_id=False + ) self.assertHTMLEqual( f.as_table(), - '<tr><th>File1:</th><td>' + "<tr><th>File1:</th><td>" '<ul class="errorlist"><li>The submitted file is empty.</li></ul>' - '<input type="file" name="file1" required></td></tr>' + '<input type="file" name="file1" required></td></tr>', ) - f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False) + f = FileForm( + data={}, files={"file1": "something that is not a file"}, auto_id=False + ) self.assertHTMLEqual( f.as_table(), - '<tr><th>File1:</th><td>' + "<tr><th>File1:</th><td>" '<ul class="errorlist"><li>No file was submitted. Check the ' - 'encoding type on the form.</li></ul>' - '<input type="file" name="file1" required></td></tr>' + "encoding type on the form.</li></ul>" + '<input type="file" name="file1" required></td></tr>', ) - f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', b'some content')}, auto_id=False) + f = FileForm( + data={}, + files={"file1": SimpleUploadedFile("name", b"some content")}, + auto_id=False, + ) self.assertHTMLEqual( f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1" required></td></tr>', ) self.assertTrue(f.is_valid()) - file1 = SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode()) - f = FileForm(data={}, files={'file1': file1}, auto_id=False) + file1 = SimpleUploadedFile( + "我隻氣墊船裝滿晒鱔.txt", "मेरी मँडराने वाली नाव सर्पमीनों से भरी ह".encode() + ) + f = FileForm(data={}, files={"file1": file1}, auto_id=False) self.assertHTMLEqual( f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1" required></td></tr>', @@ -2665,7 +3044,7 @@ Password: <input type="password" name="password" required> # A required file field with initial data should not contain the # required HTML attribute. The file input is left blank by the user to # keep the existing, initial value. - f = FileForm(initial={'file1': 'resume.txt'}, auto_id=False) + f = FileForm(initial={"file1": "resume.txt"}, auto_id=False) self.assertHTMLEqual( f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1"></td></tr>', @@ -2673,11 +3052,11 @@ Password: <input type="password" name="password" required> def test_filefield_initial_callable(self): class FileForm(forms.Form): - file1 = forms.FileField(initial=lambda: 'resume.txt') + file1 = forms.FileField(initial=lambda: "resume.txt") f = FileForm({}) self.assertEqual(f.errors, {}) - self.assertEqual(f.cleaned_data['file1'], 'resume.txt') + self.assertEqual(f.cleaned_data["file1"], "resume.txt") def test_filefield_with_fileinput_required(self): class FileForm(Form): @@ -2686,13 +3065,13 @@ Password: <input type="password" name="password" required> f = FileForm(auto_id=False) self.assertHTMLEqual( f.as_table(), - '<tr><th>File1:</th><td>' + "<tr><th>File1:</th><td>" '<input type="file" name="file1" required></td></tr>', ) # A required file field with initial data doesn't contain the required # HTML attribute. The file input is left blank by the user to keep the # existing, initial value. - f = FileForm(initial={'file1': 'resume.txt'}, auto_id=False) + f = FileForm(initial={"file1": "resume.txt"}, auto_id=False) self.assertHTMLEqual( f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1"></td></tr>', @@ -2707,10 +3086,16 @@ Password: <input type="password" name="password" required> name = CharField() # First let's show what happens id empty_permitted=False (the default): - data = {'artist': '', 'song': ''} + data = {"artist": "", "song": ""} form = SongForm(data, empty_permitted=False) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors, {'name': ['This field is required.'], 'artist': ['This field is required.']}) + self.assertEqual( + form.errors, + { + "name": ["This field is required."], + "artist": ["This field is required."], + }, + ) self.assertEqual(form.cleaned_data, {}) # Now let's show what happens when empty_permitted=True and the form is empty. @@ -2721,16 +3106,16 @@ Password: <input type="password" name="password" required> # But if we fill in data for one of the fields, the form is no longer empty and # the whole thing must pass validation. - data = {'artist': 'The Doors', 'song': ''} + data = {"artist": "The Doors", "song": ""} form = SongForm(data, empty_permitted=False) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors, {'name': ['This field is required.']}) - self.assertEqual(form.cleaned_data, {'artist': 'The Doors'}) + self.assertEqual(form.errors, {"name": ["This field is required."]}) + self.assertEqual(form.cleaned_data, {"artist": "The Doors"}) # If a field is not given in the data then None is returned for its data. Lets # make sure that when checking for empty_permitted that None is treated # accordingly. - data = {'artist': None, 'song': ''} + data = {"artist": None, "song": ""} form = SongForm(data, empty_permitted=True, use_required_attribute=False) self.assertTrue(form.is_valid()) @@ -2740,14 +3125,19 @@ Password: <input type="password" name="password" required> amount = FloatField() qty = IntegerField() - data = {'amount': '0.0', 'qty': ''} - form = PriceForm(data, initial={'amount': 0.0}, empty_permitted=True, use_required_attribute=False) + data = {"amount": "0.0", "qty": ""} + form = PriceForm( + data, + initial={"amount": 0.0}, + empty_permitted=True, + use_required_attribute=False, + ) self.assertTrue(form.is_valid()) def test_empty_permitted_and_use_required_attribute(self): msg = ( - 'The empty_permitted and use_required_attribute arguments may not ' - 'both be True.' + "The empty_permitted and use_required_attribute arguments may not " + "both be True." ) with self.assertRaisesMessage(ValueError, msg): Person(empty_permitted=True, use_required_attribute=True) @@ -2759,8 +3149,8 @@ Password: <input type="password" name="password" required> name = CharField() form = SongForm() - self.assertEqual([f.name for f in form.hidden_fields()], ['token']) - self.assertEqual([f.name for f in form.visible_fields()], ['artist', 'name']) + self.assertEqual([f.name for f in form.hidden_fields()], ["token"]) + self.assertEqual([f.name for f in form.visible_fields()], ["artist", "name"]) def test_hidden_initial_gets_id(self): class MyForm(Form): @@ -2770,7 +3160,7 @@ Password: <input type="password" name="password" required> MyForm().as_table(), '<tr><th><label for="id_field1">Field1:</label></th>' '<td><input id="id_field1" type="text" name="field1" maxlength="50" required>' - '<input type="hidden" name="initial-field1" id="initial-id_field1"></td></tr>' + '<input type="hidden" name="initial-field1" id="initial-id_field1"></td></tr>', ) def test_error_html_required_html_classes(self): @@ -2781,8 +3171,8 @@ Password: <input type="password" name="password" required> age = IntegerField() p = Person({}) - p.error_css_class = 'error' - p.required_css_class = 'required' + p.error_css_class = "error" + p.required_css_class = "required" self.assertHTMLEqual( p.as_ul(), @@ -2796,7 +3186,7 @@ Password: <input type="password" name="password" required> </select></li> <li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email"></li> <li class="required error"><ul class="errorlist"><li>This field is required.</li></ul> -<label class="required" for="id_age">Age:</label> <input type="number" name="age" id="id_age" required></li>""" +<label class="required" for="id_age">Age:</label> <input type="number" name="age" id="id_age" required></li>""", ) self.assertHTMLEqual( @@ -2813,7 +3203,7 @@ Password: <input type="password" name="password" required> <p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email"></p> <ul class="errorlist"><li>This field is required.</li></ul> <p class="required error"><label class="required" for="id_age">Age:</label> -<input type="number" name="age" id="id_age" required></p>""" +<input type="number" name="age" id="id_age" required></p>""", ) self.assertHTMLEqual( @@ -2832,7 +3222,7 @@ Password: <input type="password" name="password" required> <input type="email" name="email" id="id_email"></td></tr> <tr class="required error"><th><label class="required" for="id_age">Age:</label></th> <td><ul class="errorlist"><li>This field is required.</li></ul> -<input type="number" name="age" id="id_age" required></td></tr>""" +<input type="number" name="age" id="id_age" required></td></tr>""", ) def test_label_has_required_css_class(self): @@ -2840,28 +3230,34 @@ Password: <input type="password" name="password" required> required_css_class is added to label_tag() and legend_tag() of required fields. """ + class SomeForm(Form): - required_css_class = 'required' + required_css_class = "required" field = CharField(max_length=10) field2 = IntegerField(required=False) - f = SomeForm({'field': 'test'}) - self.assertHTMLEqual(f['field'].label_tag(), '<label for="id_field" class="required">Field:</label>') + f = SomeForm({"field": "test"}) + self.assertHTMLEqual( + f["field"].label_tag(), + '<label for="id_field" class="required">Field:</label>', + ) self.assertHTMLEqual( - f['field'].legend_tag(), + f["field"].legend_tag(), '<legend for="id_field" class="required">Field:</legend>', ) self.assertHTMLEqual( - f['field'].label_tag(attrs={'class': 'foo'}), - '<label for="id_field" class="foo required">Field:</label>' + f["field"].label_tag(attrs={"class": "foo"}), + '<label for="id_field" class="foo required">Field:</label>', + ) + self.assertHTMLEqual( + f["field"].legend_tag(attrs={"class": "foo"}), + '<legend for="id_field" class="foo required">Field:</legend>', ) self.assertHTMLEqual( - f['field'].legend_tag(attrs={'class': 'foo'}), - '<legend for="id_field" class="foo required">Field:</legend>' + f["field2"].label_tag(), '<label for="id_field2">Field2:</label>' ) - self.assertHTMLEqual(f['field2'].label_tag(), '<label for="id_field2">Field2:</label>') self.assertHTMLEqual( - f['field2'].legend_tag(), + f["field2"].legend_tag(), '<legend for="id_field2">Field2:</legend>', ) @@ -2873,54 +3269,58 @@ Password: <input type="password" name="password" required> self.assertHTMLEqual( form.as_ul(), '<input type="hidden" name="happened_at_0" id="id_happened_at_0">' - '<input type="hidden" name="happened_at_1" id="id_happened_at_1">' + '<input type="hidden" name="happened_at_1" id="id_happened_at_1">', ) def test_multivalue_field_validation(self): def bad_names(value): - if value == 'bad value': - raise ValidationError('bad value not allowed') + if value == "bad value": + raise ValidationError("bad value not allowed") class NameField(MultiValueField): def __init__(self, fields=(), *args, **kwargs): - fields = (CharField(label='First name', max_length=10), - CharField(label='Last name', max_length=10)) + fields = ( + CharField(label="First name", max_length=10), + CharField(label="Last name", max_length=10), + ) super().__init__(fields=fields, *args, **kwargs) def compress(self, data_list): - return ' '.join(data_list) + return " ".join(data_list) class NameForm(Form): name = NameField(validators=[bad_names]) - form = NameForm(data={'name': ['bad', 'value']}) + form = NameForm(data={"name": ["bad", "value"]}) form.full_clean() self.assertFalse(form.is_valid()) - self.assertEqual(form.errors, {'name': ['bad value not allowed']}) - form = NameForm(data={'name': ['should be overly', 'long for the field names']}) + self.assertEqual(form.errors, {"name": ["bad value not allowed"]}) + form = NameForm(data={"name": ["should be overly", "long for the field names"]}) self.assertFalse(form.is_valid()) self.assertEqual( - form.errors, { - 'name': [ - 'Ensure this value has at most 10 characters (it has 16).', - 'Ensure this value has at most 10 characters (it has 24).', + form.errors, + { + "name": [ + "Ensure this value has at most 10 characters (it has 16).", + "Ensure this value has at most 10 characters (it has 24).", ], - } + }, ) - form = NameForm(data={'name': ['fname', 'lname']}) + form = NameForm(data={"name": ["fname", "lname"]}) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data, {'name': 'fname lname'}) + self.assertEqual(form.cleaned_data, {"name": "fname lname"}) def test_multivalue_deep_copy(self): """ #19298 -- MultiValueField needs to override the default as it needs to deep-copy subfields: """ + class ChoicesField(MultiValueField): def __init__(self, fields=(), *args, **kwargs): fields = ( - ChoiceField(label='Rank', choices=((1, 1), (2, 2))), - CharField(label='Name', max_length=10), + ChoiceField(label="Rank", choices=((1, 1), (2, 2))), + CharField(label="Name", max_length=10), ) super().__init__(fields=fields, *args, **kwargs) @@ -2934,6 +3334,7 @@ Password: <input type="password" name="password" required> """ #23674 -- invalid initial data should not break form.changed_data() """ + class DateAgeField(MultiValueField): def __init__(self, fields=(), *args, **kwargs): fields = (DateField(label="Date"), IntegerField(label="Age")) @@ -2950,47 +3351,66 @@ Password: <input type="password" name="password" required> class PhoneField(MultiValueField): def __init__(self, *args, **kwargs): fields = ( - CharField(label='Country Code', validators=[ - RegexValidator(r'^\+[0-9]{1,2}$', message='Enter a valid country code.')]), - CharField(label='Phone Number'), - CharField(label='Extension', error_messages={'incomplete': 'Enter an extension.'}), - CharField(label='Label', required=False, help_text='E.g. home, work.'), + CharField( + label="Country Code", + validators=[ + RegexValidator( + r"^\+[0-9]{1,2}$", message="Enter a valid country code." + ) + ], + ), + CharField(label="Phone Number"), + CharField( + label="Extension", + error_messages={"incomplete": "Enter an extension."}, + ), + CharField( + label="Label", required=False, help_text="E.g. home, work." + ), ) super().__init__(fields, *args, **kwargs) def compress(self, data_list): if data_list: - return '%s.%s ext. %s (label: %s)' % tuple(data_list) + return "%s.%s ext. %s (label: %s)" % tuple(data_list) return None # An empty value for any field will raise a `required` error on a # required `MultiValueField`. f = PhoneField() with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean([]) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean(['+61']) + f.clean(["+61"]) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean(['+61', '287654321', '123']) - self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home'])) + f.clean(["+61", "287654321", "123"]) + self.assertEqual( + "+61.287654321 ext. 123 (label: Home)", + f.clean(["+61", "287654321", "123", "Home"]), + ) with self.assertRaisesMessage(ValidationError, "'Enter a valid country code.'"): - f.clean(['61', '287654321', '123', 'Home']) + f.clean(["61", "287654321", "123", "Home"]) # Empty values for fields will NOT raise a `required` error on an # optional `MultiValueField` f = PhoneField(required=False) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) self.assertIsNone(f.clean([])) - self.assertEqual('+61. ext. (label: )', f.clean(['+61'])) - self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123'])) - self.assertEqual('+61.287654321 ext. 123 (label: Home)', f.clean(['+61', '287654321', '123', 'Home'])) + self.assertEqual("+61. ext. (label: )", f.clean(["+61"])) + self.assertEqual( + "+61.287654321 ext. 123 (label: )", f.clean(["+61", "287654321", "123"]) + ) + self.assertEqual( + "+61.287654321 ext. 123 (label: Home)", + f.clean(["+61", "287654321", "123", "Home"]), + ) with self.assertRaisesMessage(ValidationError, "'Enter a valid country code.'"): - f.clean(['61', '287654321', '123', 'Home']) + f.clean(["61", "287654321", "123", "Home"]) # For a required `MultiValueField` with `require_all_fields=False`, a # `required` error will only be raised if all fields are empty. Fields @@ -2998,32 +3418,40 @@ Password: <input type="password" name="password" required> # required field will raise an `incomplete` error. f = PhoneField(require_all_fields=False) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): - f.clean('') + f.clean("") with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean(None) with self.assertRaisesMessage(ValidationError, "'This field is required.'"): f.clean([]) with self.assertRaisesMessage(ValidationError, "'Enter a complete value.'"): - f.clean(['+61']) - self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123'])) - with self.assertRaisesMessage(ValidationError, "'Enter a complete value.', 'Enter an extension.'"): - f.clean(['', '', '', 'Home']) + f.clean(["+61"]) + self.assertEqual( + "+61.287654321 ext. 123 (label: )", f.clean(["+61", "287654321", "123"]) + ) + with self.assertRaisesMessage( + ValidationError, "'Enter a complete value.', 'Enter an extension.'" + ): + f.clean(["", "", "", "Home"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid country code.'"): - f.clean(['61', '287654321', '123', 'Home']) + f.clean(["61", "287654321", "123", "Home"]) # For an optional `MultiValueField` with `require_all_fields=False`, we # don't get any `required` error but we still get `incomplete` errors. f = PhoneField(required=False, require_all_fields=False) - self.assertIsNone(f.clean('')) + self.assertIsNone(f.clean("")) self.assertIsNone(f.clean(None)) self.assertIsNone(f.clean([])) with self.assertRaisesMessage(ValidationError, "'Enter a complete value.'"): - f.clean(['+61']) - self.assertEqual('+61.287654321 ext. 123 (label: )', f.clean(['+61', '287654321', '123'])) - with self.assertRaisesMessage(ValidationError, "'Enter a complete value.', 'Enter an extension.'"): - f.clean(['', '', '', 'Home']) + f.clean(["+61"]) + self.assertEqual( + "+61.287654321 ext. 123 (label: )", f.clean(["+61", "287654321", "123"]) + ) + with self.assertRaisesMessage( + ValidationError, "'Enter a complete value.', 'Enter an extension.'" + ): + f.clean(["", "", "", "Home"]) with self.assertRaisesMessage(ValidationError, "'Enter a valid country code.'"): - f.clean(['61', '287654321', '123', 'Home']) + f.clean(["61", "287654321", "123", "Home"]) def test_multivalue_optional_subfields_rendering(self): class PhoneWidget(MultiWidget): @@ -3044,7 +3472,9 @@ Password: <input type="password" name="password" required> phone2 = PhoneField(widget=PhoneWidget, required=False) phone3 = PhoneField(widget=PhoneWidget, require_all_fields=False) phone4 = PhoneField( - widget=PhoneWidget, required=False, require_all_fields=False, + widget=PhoneWidget, + required=False, + require_all_fields=False, ) form = PhoneForm(auto_id=False) @@ -3063,42 +3493,41 @@ Password: <input type="password" name="password" required> Form fields can customize what is considered as an empty value for themselves (#19997). """ + class CustomJSONField(CharField): - empty_values = [None, ''] + empty_values = [None, ""] def to_python(self, value): # Fake json.loads - if value == '{}': + if value == "{}": return {} return super().to_python(value) class JSONForm(forms.Form): json = CustomJSONField() - form = JSONForm(data={'json': '{}'}) + form = JSONForm(data={"json": "{}"}) form.full_clean() - self.assertEqual(form.cleaned_data, {'json': {}}) + self.assertEqual(form.cleaned_data, {"json": {}}) def test_boundfield_label_tag(self): class SomeForm(Form): field = CharField() - boundfield = SomeForm()['field'] + + boundfield = SomeForm()["field"] testcases = [ # (args, kwargs, expected) # without anything: just print the <label> ((), {}, '<%(tag)s for="id_field">Field:</%(tag)s>'), - # passing just one argument: overrides the field's label - (('custom',), {}, '<%(tag)s for="id_field">custom:</%(tag)s>'), - + (("custom",), {}, '<%(tag)s for="id_field">custom:</%(tag)s>'), # the overridden label is escaped - (('custom&',), {}, '<%(tag)s for="id_field">custom&:</%(tag)s>'), - ((mark_safe('custom&'),), {}, '<%(tag)s for="id_field">custom&:</%(tag)s>'), - + (("custom&",), {}, '<%(tag)s for="id_field">custom&:</%(tag)s>'), + ((mark_safe("custom&"),), {}, '<%(tag)s for="id_field">custom&:</%(tag)s>'), # Passing attrs to add extra attributes on the <label> ( (), - {'attrs': {'class': 'pretty'}}, + {"attrs": {"class": "pretty"}}, '<%(tag)s for="id_field" class="pretty">Field:</%(tag)s>', ), ] @@ -3107,11 +3536,11 @@ Password: <input type="password" name="password" required> with self.subTest(args=args, kwargs=kwargs): self.assertHTMLEqual( boundfield.label_tag(*args, **kwargs), - expected % {'tag': 'label'}, + expected % {"tag": "label"}, ) self.assertHTMLEqual( boundfield.legend_tag(*args, **kwargs), - expected % {'tag': 'legend'}, + expected % {"tag": "legend"}, ) def test_boundfield_label_tag_no_id(self): @@ -3119,19 +3548,21 @@ Password: <input type="password" name="password" required> If a widget has no id, label_tag() and legend_tag() return the text with no surrounding <label>. """ + class SomeForm(Form): field = CharField() - boundfield = SomeForm(auto_id='')['field'] - self.assertHTMLEqual(boundfield.label_tag(), 'Field:') - self.assertHTMLEqual(boundfield.legend_tag(), 'Field:') - self.assertHTMLEqual(boundfield.label_tag('Custom&'), 'Custom&:') - self.assertHTMLEqual(boundfield.legend_tag('Custom&'), 'Custom&:') + boundfield = SomeForm(auto_id="")["field"] + + self.assertHTMLEqual(boundfield.label_tag(), "Field:") + self.assertHTMLEqual(boundfield.legend_tag(), "Field:") + self.assertHTMLEqual(boundfield.label_tag("Custom&"), "Custom&:") + self.assertHTMLEqual(boundfield.legend_tag("Custom&"), "Custom&:") def test_boundfield_label_tag_custom_widget_id_for_label(self): class CustomIdForLabelTextInput(TextInput): def id_for_label(self, id): - return 'custom_' + id + return "custom_" + id class EmptyIdForLabelTextInput(TextInput): def id_for_label(self, id): @@ -3142,18 +3573,21 @@ Password: <input type="password" name="password" required> empty = CharField(widget=EmptyIdForLabelTextInput) form = SomeForm() - self.assertHTMLEqual(form['custom'].label_tag(), '<label for="custom_id_custom">Custom:</label>') self.assertHTMLEqual( - form['custom'].legend_tag(), + form["custom"].label_tag(), '<label for="custom_id_custom">Custom:</label>' + ) + self.assertHTMLEqual( + form["custom"].legend_tag(), '<legend for="custom_id_custom">Custom:</legend>', ) - self.assertHTMLEqual(form['empty'].label_tag(), '<label>Empty:</label>') - self.assertHTMLEqual(form['empty'].legend_tag(), '<legend>Empty:</legend>') + self.assertHTMLEqual(form["empty"].label_tag(), "<label>Empty:</label>") + self.assertHTMLEqual(form["empty"].legend_tag(), "<legend>Empty:</legend>") def test_boundfield_empty_label(self): class SomeForm(Form): - field = CharField(label='') - boundfield = SomeForm()['field'] + field = CharField(label="") + + boundfield = SomeForm()["field"] self.assertHTMLEqual(boundfield.label_tag(), '<label for="id_field"></label>') self.assertHTMLEqual( @@ -3163,38 +3597,40 @@ Password: <input type="password" name="password" required> def test_boundfield_id_for_label(self): class SomeForm(Form): - field = CharField(label='') + field = CharField(label="") - self.assertEqual(SomeForm()['field'].id_for_label, 'id_field') + self.assertEqual(SomeForm()["field"].id_for_label, "id_field") def test_boundfield_id_for_label_override_by_attrs(self): """ If an id is provided in `Widget.attrs`, it overrides the generated ID, unless it is `None`. """ + class SomeForm(Form): - field = CharField(widget=TextInput(attrs={'id': 'myCustomID'})) - field_none = CharField(widget=TextInput(attrs={'id': None})) + field = CharField(widget=TextInput(attrs={"id": "myCustomID"})) + field_none = CharField(widget=TextInput(attrs={"id": None})) form = SomeForm() - self.assertEqual(form['field'].id_for_label, 'myCustomID') - self.assertEqual(form['field_none'].id_for_label, 'id_field_none') + self.assertEqual(form["field"].id_for_label, "myCustomID") + self.assertEqual(form["field_none"].id_for_label, "id_field_none") def test_boundfield_subwidget_id_for_label(self): """ If auto_id is provided when initializing the form, the generated ID in subwidgets must reflect that prefix. """ + class SomeForm(Form): field = MultipleChoiceField( - choices=[('a', 'A'), ('b', 'B')], + choices=[("a", "A"), ("b", "B")], widget=CheckboxSelectMultiple, ) - form = SomeForm(auto_id='prefix_%s') - subwidgets = form['field'].subwidgets - self.assertEqual(subwidgets[0].id_for_label, 'prefix_field_0') - self.assertEqual(subwidgets[1].id_for_label, 'prefix_field_1') + form = SomeForm(auto_id="prefix_%s") + subwidgets = form["field"].subwidgets + self.assertEqual(subwidgets[0].id_for_label, "prefix_field_0") + self.assertEqual(subwidgets[1].id_for_label, "prefix_field_1") def test_boundfield_widget_type(self): class SomeForm(Form): @@ -3202,28 +3638,33 @@ Password: <input type="password" name="password" required> birthday = SplitDateTimeField(widget=SplitHiddenDateTimeWidget) f = SomeForm() - self.assertEqual(f['first_name'].widget_type, 'text') - self.assertEqual(f['birthday'].widget_type, 'splithiddendatetime') + self.assertEqual(f["first_name"].widget_type, "text") + self.assertEqual(f["birthday"].widget_type, "splithiddendatetime") def test_boundfield_css_classes(self): form = Person() - field = form['first_name'] - self.assertEqual(field.css_classes(), '') - self.assertEqual(field.css_classes(extra_classes=''), '') - self.assertEqual(field.css_classes(extra_classes='test'), 'test') - self.assertEqual(field.css_classes(extra_classes='test test'), 'test') + field = form["first_name"] + self.assertEqual(field.css_classes(), "") + self.assertEqual(field.css_classes(extra_classes=""), "") + self.assertEqual(field.css_classes(extra_classes="test"), "test") + self.assertEqual(field.css_classes(extra_classes="test test"), "test") def test_label_suffix_override(self): """ BoundField label_suffix (if provided) overrides Form label_suffix """ + class SomeForm(Form): field = CharField() - boundfield = SomeForm(label_suffix='!')['field'] - self.assertHTMLEqual(boundfield.label_tag(label_suffix='$'), '<label for="id_field">Field$</label>') + boundfield = SomeForm(label_suffix="!")["field"] + + self.assertHTMLEqual( + boundfield.label_tag(label_suffix="$"), + '<label for="id_field">Field$</label>', + ) self.assertHTMLEqual( - boundfield.legend_tag(label_suffix='$'), + boundfield.legend_tag(label_suffix="$"), '<legend for="id_field">Field$</legend>', ) @@ -3233,16 +3674,18 @@ Password: <input type="password" name="password" required> bar = CharField() def clean(self): - raise ValidationError('Non-field error.', code='secret', params={'a': 1, 'b': 2}) + raise ValidationError( + "Non-field error.", code="secret", params={"a": 1, "b": 2} + ) form = MyForm({}) self.assertIs(form.is_valid(), False) errors = form.errors.as_text() control = [ - '* foo\n * This field is required.', - '* bar\n * This field is required.', - '* __all__\n * Non-field error.', + "* foo\n * This field is required.", + "* bar\n * This field is required.", + "* __all__\n * Non-field error.", ] for error in control: self.assertIn(error, errors) @@ -3258,30 +3701,31 @@ Password: <input type="password" name="password" required> errors = form.errors.get_json_data() control = { - 'foo': [{'code': 'required', 'message': 'This field is required.'}], - 'bar': [{'code': 'required', 'message': 'This field is required.'}], - '__all__': [{'code': 'secret', 'message': 'Non-field error.'}] + "foo": [{"code": "required", "message": "This field is required."}], + "bar": [{"code": "required", "message": "This field is required."}], + "__all__": [{"code": "secret", "message": "Non-field error."}], } self.assertEqual(errors, control) self.assertEqual(json.dumps(errors), form.errors.as_json()) def test_error_dict_as_json_escape_html(self): """#21962 - adding html escape flag to ErrorDict""" + class MyForm(Form): foo = CharField() bar = CharField() def clean(self): raise ValidationError( - '<p>Non-field error.</p>', - code='secret', - params={'a': 1, 'b': 2}, + "<p>Non-field error.</p>", + code="secret", + params={"a": 1, "b": 2}, ) control = { - 'foo': [{'code': 'required', 'message': 'This field is required.'}], - 'bar': [{'code': 'required', 'message': 'This field is required.'}], - '__all__': [{'code': 'secret', 'message': '<p>Non-field error.</p>'}] + "foo": [{"code": "required", "message": "This field is required."}], + "bar": [{"code": "required", "message": "This field is required."}], + "__all__": [{"code": "secret", "message": "<p>Non-field error.</p>"}], } form = MyForm({}) @@ -3290,57 +3734,52 @@ Password: <input type="password" name="password" required> errors = json.loads(form.errors.as_json()) self.assertEqual(errors, control) - escaped_error = '<p>Non-field error.</p>' + escaped_error = "<p>Non-field error.</p>" self.assertEqual( - form.errors.get_json_data(escape_html=True)['__all__'][0]['message'], - escaped_error + form.errors.get_json_data(escape_html=True)["__all__"][0]["message"], + escaped_error, ) errors = json.loads(form.errors.as_json(escape_html=True)) - control['__all__'][0]['message'] = escaped_error + control["__all__"][0]["message"] = escaped_error self.assertEqual(errors, control) def test_error_list(self): e = ErrorList() - e.append('Foo') - e.append(ValidationError('Foo%(bar)s', code='foobar', params={'bar': 'bar'})) + e.append("Foo") + e.append(ValidationError("Foo%(bar)s", code="foobar", params={"bar": "bar"})) self.assertIsInstance(e, list) - self.assertIn('Foo', e) - self.assertIn('Foo', ValidationError(e)) + self.assertIn("Foo", e) + self.assertIn("Foo", ValidationError(e)) - self.assertEqual( - e.as_text(), - '* Foo\n* Foobar' - ) + self.assertEqual(e.as_text(), "* Foo\n* Foobar") self.assertEqual( - e.as_ul(), - '<ul class="errorlist"><li>Foo</li><li>Foobar</li></ul>' + e.as_ul(), '<ul class="errorlist"><li>Foo</li><li>Foobar</li></ul>' ) errors = e.get_json_data() self.assertEqual( errors, - [{"message": "Foo", "code": ""}, {"message": "Foobar", "code": "foobar"}] + [{"message": "Foo", "code": ""}, {"message": "Foobar", "code": "foobar"}], ) self.assertEqual(json.dumps(errors), e.as_json()) def test_error_list_class_not_specified(self): e = ErrorList() - e.append('Foo') - e.append(ValidationError('Foo%(bar)s', code='foobar', params={'bar': 'bar'})) + e.append("Foo") + e.append(ValidationError("Foo%(bar)s", code="foobar", params={"bar": "bar"})) self.assertEqual( - e.as_ul(), - '<ul class="errorlist"><li>Foo</li><li>Foobar</li></ul>' + e.as_ul(), '<ul class="errorlist"><li>Foo</li><li>Foobar</li></ul>' ) def test_error_list_class_has_one_class_specified(self): - e = ErrorList(error_class='foobar-error-class') - e.append('Foo') - e.append(ValidationError('Foo%(bar)s', code='foobar', params={'bar': 'bar'})) + e = ErrorList(error_class="foobar-error-class") + e.append("Foo") + e.append(ValidationError("Foo%(bar)s", code="foobar", params={"bar": "bar"})) self.assertEqual( e.as_ul(), - '<ul class="errorlist foobar-error-class"><li>Foo</li><li>Foobar</li></ul>' + '<ul class="errorlist foobar-error-class"><li>Foo</li><li>Foobar</li></ul>', ) def test_error_list_with_hidden_field_errors_has_correct_class(self): @@ -3348,21 +3787,21 @@ Password: <input type="password" name="password" required> first_name = CharField() last_name = CharField(widget=HiddenInput) - p = Person({'first_name': 'John'}) + p = Person({"first_name": "John"}) self.assertHTMLEqual( p.as_ul(), """<li><ul class="errorlist nonfield"> <li>(Hidden field last_name) This field is required.</li></ul></li><li> <label for="id_first_name">First name:</label> <input id="id_first_name" name="first_name" type="text" value="John" required> -<input id="id_last_name" name="last_name" type="hidden"></li>""" +<input id="id_last_name" name="last_name" type="hidden"></li>""", ) self.assertHTMLEqual( p.as_p(), """<ul class="errorlist nonfield"><li>(Hidden field last_name) This field is required.</li></ul> <p><label for="id_first_name">First name:</label> <input id="id_first_name" name="first_name" type="text" value="John" required> -<input id="id_last_name" name="last_name" type="hidden"></p>""" +<input id="id_last_name" name="last_name" type="hidden"></p>""", ) self.assertHTMLEqual( p.as_table(), @@ -3370,7 +3809,7 @@ Password: <input type="password" name="password" required> <li>(Hidden field last_name) This field is required.</li></ul></td></tr> <tr><th><label for="id_first_name">First name:</label></th><td> <input id="id_first_name" name="first_name" type="text" value="John" required> -<input id="id_last_name" name="last_name" type="hidden"></td></tr>""" +<input id="id_last_name" name="last_name" type="hidden"></td></tr>""", ) def test_error_list_with_non_field_errors_has_correct_class(self): @@ -3379,12 +3818,12 @@ Password: <input type="password" name="password" required> last_name = CharField() def clean(self): - raise ValidationError('Generic validation error') + raise ValidationError("Generic validation error") - p = Person({'first_name': 'John', 'last_name': 'Lennon'}) + p = Person({"first_name": "John", "last_name": "Lennon"}) self.assertHTMLEqual( str(p.non_field_errors()), - '<ul class="errorlist nonfield"><li>Generic validation error</li></ul>' + '<ul class="errorlist nonfield"><li>Generic validation error</li></ul>', ) self.assertHTMLEqual( p.as_ul(), @@ -3393,11 +3832,10 @@ Password: <input type="password" name="password" required> <li><label for="id_first_name">First name:</label> <input id="id_first_name" name="first_name" type="text" value="John" required></li> <li><label for="id_last_name">Last name:</label> -<input id="id_last_name" name="last_name" type="text" value="Lennon" required></li>""" +<input id="id_last_name" name="last_name" type="text" value="Lennon" required></li>""", ) self.assertHTMLEqual( - p.non_field_errors().as_text(), - '* Generic validation error' + p.non_field_errors().as_text(), "* Generic validation error" ) self.assertHTMLEqual( p.as_p(), @@ -3405,7 +3843,7 @@ Password: <input type="password" name="password" required> <p><label for="id_first_name">First name:</label> <input id="id_first_name" name="first_name" type="text" value="John" required></p> <p><label for="id_last_name">Last name:</label> -<input id="id_last_name" name="last_name" type="text" value="Lennon" required></p>""" +<input id="id_last_name" name="last_name" type="text" value="Lennon" required></p>""", ) self.assertHTMLEqual( p.as_table(), @@ -3413,7 +3851,7 @@ Password: <input type="password" name="password" required> <tr><th><label for="id_first_name">First name:</label></th><td> <input id="id_first_name" name="first_name" type="text" value="John" required></td></tr> <tr><th><label for="id_last_name">Last name:</label></th><td> -<input id="id_last_name" name="last_name" type="text" value="Lennon" required></td></tr>""" +<input id="id_last_name" name="last_name" type="text" value="Lennon" required></td></tr>""", ) def test_error_escaping(self): @@ -3426,7 +3864,7 @@ Password: <input type="password" name="password" required> clean_visible = clean_hidden - form = TestForm({'hidden': 'a', 'visible': 'b'}) + form = TestForm({"hidden": "a", "visible": "b"}) form.is_valid() self.assertHTMLEqual( form.as_ul(), @@ -3434,7 +3872,7 @@ Password: <input type="password" name="password" required> '<li><ul class="errorlist"><li>Foo & "bar"!</li></ul>' '<label for="id_visible">Visible:</label> ' '<input type="text" name="visible" value="b" id="id_visible" required>' - '<input type="hidden" name="hidden" value="a" id="id_hidden"></li>' + '<input type="hidden" name="hidden" value="a" id="id_hidden"></li>', ) def test_baseform_repr(self): @@ -3443,25 +3881,43 @@ Password: <input type="password" name="password" required> form. """ p = Person() - self.assertEqual(repr(p), "<Person bound=False, valid=Unknown, fields=(first_name;last_name;birthday)>") - p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}) - self.assertEqual(repr(p), "<Person bound=True, valid=Unknown, fields=(first_name;last_name;birthday)>") + self.assertEqual( + repr(p), + "<Person bound=False, valid=Unknown, fields=(first_name;last_name;birthday)>", + ) + p = Person( + {"first_name": "John", "last_name": "Lennon", "birthday": "1940-10-9"} + ) + self.assertEqual( + repr(p), + "<Person bound=True, valid=Unknown, fields=(first_name;last_name;birthday)>", + ) p.is_valid() - self.assertEqual(repr(p), "<Person bound=True, valid=True, fields=(first_name;last_name;birthday)>") - p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': 'fakedate'}) + self.assertEqual( + repr(p), + "<Person bound=True, valid=True, fields=(first_name;last_name;birthday)>", + ) + p = Person( + {"first_name": "John", "last_name": "Lennon", "birthday": "fakedate"} + ) p.is_valid() - self.assertEqual(repr(p), "<Person bound=True, valid=False, fields=(first_name;last_name;birthday)>") + self.assertEqual( + repr(p), + "<Person bound=True, valid=False, fields=(first_name;last_name;birthday)>", + ) def test_baseform_repr_dont_trigger_validation(self): """ BaseForm.__repr__() shouldn't trigger the form validation. """ - p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': 'fakedate'}) + p = Person( + {"first_name": "John", "last_name": "Lennon", "birthday": "fakedate"} + ) repr(p) with self.assertRaises(AttributeError): p.cleaned_data self.assertFalse(p.is_valid()) - self.assertEqual(p.cleaned_data, {'first_name': 'John', 'last_name': 'Lennon'}) + self.assertEqual(p.cleaned_data, {"first_name": "John", "last_name": "Lennon"}) def test_accessing_clean(self): class UserForm(Form): @@ -3472,13 +3928,13 @@ Password: <input type="password" name="password" required> data = self.cleaned_data if not self.errors: - data['username'] = data['username'].lower() + data["username"] = data["username"].lower() return data - f = UserForm({'username': 'SirRobin', 'password': 'blue'}) + f = UserForm({"username": "SirRobin", "password": "blue"}) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['username'], 'sirrobin') + self.assertEqual(f.cleaned_data["username"], "sirrobin") def test_changing_cleaned_data_nothing_returned(self): class UserForm(Form): @@ -3486,12 +3942,12 @@ Password: <input type="password" name="password" required> password = CharField(widget=PasswordInput) def clean(self): - self.cleaned_data['username'] = self.cleaned_data['username'].lower() + self.cleaned_data["username"] = self.cleaned_data["username"].lower() # don't return anything - f = UserForm({'username': 'SirRobin', 'password': 'blue'}) + f = UserForm({"username": "SirRobin", "password": "blue"}) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['username'], 'sirrobin') + self.assertEqual(f.cleaned_data["username"], "sirrobin") def test_changing_cleaned_data_in_clean(self): class UserForm(Form): @@ -3503,13 +3959,13 @@ Password: <input type="password" name="password" required> # Return a different dict. We have not changed self.cleaned_data. return { - 'username': data['username'].lower(), - 'password': 'this_is_not_a_secret', + "username": data["username"].lower(), + "password": "this_is_not_a_secret", } - f = UserForm({'username': 'SirRobin', 'password': 'blue'}) + f = UserForm({"username": "SirRobin", "password": "blue"}) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['username'], 'sirrobin') + self.assertEqual(f.cleaned_data["username"], "sirrobin") def test_multipart_encoded_form(self): class FormWithoutFile(Form): @@ -3531,10 +3987,10 @@ Password: <input type="password" name="password" required> username = CharField() form = SimpleForm() - self.assertTrue(hasattr(SimpleForm, '__html__')) + self.assertTrue(hasattr(SimpleForm, "__html__")) self.assertEqual(str(form), form.__html__()) - self.assertTrue(hasattr(form['username'], '__html__')) - self.assertEqual(str(form['username']), form['username'].__html__()) + self.assertTrue(hasattr(form["username"], "__html__")) + self.assertEqual(str(form["username"]), form["username"].__html__()) def test_use_required_attribute_true(self): class MyForm(Form): @@ -3542,7 +3998,7 @@ Password: <input type="password" name="password" required> f1 = CharField(max_length=30) f2 = CharField(max_length=30, required=False) f3 = CharField(widget=Textarea) - f4 = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')]) + f4 = ChoiceField(choices=[("P", "Python"), ("J", "Java")]) form = MyForm() self.assertHTMLEqual( @@ -3550,11 +4006,11 @@ Password: <input type="password" name="password" required> '<p><label for="id_f1">F1:</label> <input id="id_f1" maxlength="30" name="f1" type="text" required></p>' '<p><label for="id_f2">F2:</label> <input id="id_f2" maxlength="30" name="f2" type="text"></p>' '<p><label for="id_f3">F3:</label> <textarea cols="40" id="id_f3" name="f3" rows="10" required>' - '</textarea></p>' + "</textarea></p>" '<p><label for="id_f4">F4:</label> <select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></p>', + "</select></p>", ) self.assertHTMLEqual( form.as_ul(), @@ -3562,11 +4018,11 @@ Password: <input type="password" name="password" required> '<input id="id_f1" maxlength="30" name="f1" type="text" required></li>' '<li><label for="id_f2">F2:</label> <input id="id_f2" maxlength="30" name="f2" type="text"></li>' '<li><label for="id_f3">F3:</label> <textarea cols="40" id="id_f3" name="f3" rows="10" required>' - '</textarea></li>' + "</textarea></li>" '<li><label for="id_f4">F4:</label> <select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></li>', + "</select></li>", ) self.assertHTMLEqual( form.as_table(), @@ -3576,11 +4032,11 @@ Password: <input type="password" name="password" required> '<td><input id="id_f2" maxlength="30" name="f2" type="text"></td></tr>' '<tr><th><label for="id_f3">F3:</label></th>' '<td><textarea cols="40" id="id_f3" name="f3" rows="10" required>' - '</textarea></td></tr>' + "</textarea></td></tr>" '<tr><th><label for="id_f4">F4:</label></th><td><select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></td></tr>', + "</select></td></tr>", ) def test_use_required_attribute_false(self): @@ -3589,7 +4045,7 @@ Password: <input type="password" name="password" required> f1 = CharField(max_length=30) f2 = CharField(max_length=30, required=False) f3 = CharField(widget=Textarea) - f4 = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')]) + f4 = ChoiceField(choices=[("P", "Python"), ("J", "Java")]) form = MyForm() self.assertHTMLEqual( @@ -3597,22 +4053,22 @@ Password: <input type="password" name="password" required> '<p><label for="id_f1">F1:</label> <input id="id_f1" maxlength="30" name="f1" type="text"></p>' '<p><label for="id_f2">F2:</label> <input id="id_f2" maxlength="30" name="f2" type="text"></p>' '<p><label for="id_f3">F3:</label> <textarea cols="40" id="id_f3" name="f3" rows="10">' - '</textarea></p>' + "</textarea></p>" '<p><label for="id_f4">F4:</label> <select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></p>', + "</select></p>", ) self.assertHTMLEqual( form.as_ul(), '<li><label for="id_f1">F1:</label> <input id="id_f1" maxlength="30" name="f1" type="text"></li>' '<li><label for="id_f2">F2:</label> <input id="id_f2" maxlength="30" name="f2" type="text"></li>' '<li><label for="id_f3">F3:</label> <textarea cols="40" id="id_f3" name="f3" rows="10">' - '</textarea></li>' + "</textarea></li>" '<li><label for="id_f4">F4:</label> <select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></li>', + "</select></li>", ) self.assertHTMLEqual( form.as_table(), @@ -3621,11 +4077,11 @@ Password: <input type="password" name="password" required> '<tr><th><label for="id_f2">F2:</label></th>' '<td><input id="id_f2" maxlength="30" name="f2" type="text"></td></tr>' '<tr><th><label for="id_f3">F3:</label></th><td><textarea cols="40" id="id_f3" name="f3" rows="10">' - '</textarea></td></tr>' + "</textarea></td></tr>" '<tr><th><label for="id_f4">F4:</label></th><td><select id="id_f4" name="f4">' '<option value="P">Python</option>' '<option value="J">Java</option>' - '</select></td></tr>', + "</select></td></tr>", ) def test_only_hidden_fields(self): @@ -3637,23 +4093,23 @@ Password: <input type="password" name="password" required> self.assertHTMLEqual( f.as_p(), '<ul class="errorlist nonfield">' - '<li>(Hidden field data) This field is required.</li></ul>\n<p> ' - '<input type="hidden" name="data" id="id_data"></p>' + "<li>(Hidden field data) This field is required.</li></ul>\n<p> " + '<input type="hidden" name="data" id="id_data"></p>', ) self.assertHTMLEqual( f.as_table(), '<tr><td colspan="2"><ul class="errorlist nonfield">' - '<li>(Hidden field data) This field is required.</li></ul>' - '<input type="hidden" name="data" id="id_data"></td></tr>' + "<li>(Hidden field data) This field is required.</li></ul>" + '<input type="hidden" name="data" id="id_data"></td></tr>', ) def test_field_named_data(self): class DataForm(Form): data = CharField(max_length=10) - f = DataForm({'data': 'xyzzy'}) + f = DataForm({"data": "xyzzy"}) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data, {'data': 'xyzzy'}) + self.assertEqual(f.cleaned_data, {"data": "xyzzy"}) def test_empty_data_files_multi_value_dict(self): p = Person() @@ -3663,7 +4119,7 @@ Password: <input type="password" name="password" required> def test_field_deep_copy_error_messages(self): class CustomCharField(CharField): def __init__(self, **kwargs): - kwargs['error_messages'] = {'invalid': 'Form custom error message.'} + kwargs["error_messages"] = {"invalid": "Form custom error message."} super().__init__(**kwargs) field = CustomCharField() @@ -3673,8 +4129,10 @@ Password: <input type="password" name="password" required> def test_label_does_not_include_new_line(self): form = Person() - field = form['first_name'] - self.assertEqual(field.label_tag(), '<label for="id_first_name">First name:</label>') + field = form["first_name"] + self.assertEqual( + field.label_tag(), '<label for="id_first_name">First name:</label>' + ) self.assertEqual( field.legend_tag(), '<legend for="id_first_name">First name:</legend>', @@ -3683,13 +4141,13 @@ Password: <input type="password" name="password" required> @override_settings(USE_THOUSAND_SEPARATOR=True) def test_label_attrs_not_localized(self): form = Person() - field = form['first_name'] + field = form["first_name"] self.assertHTMLEqual( - field.label_tag(attrs={'number': 9999}), + field.label_tag(attrs={"number": 9999}), '<label number="9999" for="id_first_name">First name:</label>', ) self.assertHTMLEqual( - field.legend_tag(attrs={'number': 9999}), + field.legend_tag(attrs={"number": 9999}), '<legend number="9999" for="id_first_name">First name:</legend>', ) @@ -3704,7 +4162,6 @@ class CustomRenderer(DjangoTemplates): class RendererTests(SimpleTestCase): - def test_default(self): form = Form() self.assertEqual(form.renderer, get_default_renderer()) @@ -3744,54 +4201,55 @@ class RendererTests(SimpleTestCase): class TemplateTests(SimpleTestCase): def test_iterate_radios(self): - f = FrameworkForm(auto_id='id_%s') + f = FrameworkForm(auto_id="id_%s") t = Template( - '{% for radio in form.language %}' + "{% for radio in form.language %}" '<div class="myradio">{{ radio }}</div>' - '{% endfor %}' + "{% endfor %}" ) self.assertHTMLEqual( - t.render(Context({'form': f})), + t.render(Context({"form": f})), '<div class="myradio"><label for="id_language_0">' '<input id="id_language_0" name="language" type="radio" value="P" ' - 'required> Python</label></div>' + "required> Python</label></div>" '<div class="myradio"><label for="id_language_1">' '<input id="id_language_1" name="language" type="radio" value="J" ' - 'required> Java</label></div>', + "required> Java</label></div>", ) def test_iterate_checkboxes(self): - f = SongForm({'composers': ['J', 'P']}, auto_id=False) + f = SongForm({"composers": ["J", "P"]}, auto_id=False) t = Template( - '{% for checkbox in form.composers %}' + "{% for checkbox in form.composers %}" '<div class="mycheckbox">{{ checkbox }}</div>' - '{% endfor %}' + "{% endfor %}" ) self.assertHTMLEqual( - t.render(Context({'form': f})), + t.render(Context({"form": f})), '<div class="mycheckbox"><label>' '<input checked name="composers" type="checkbox" value="J"> ' - 'John Lennon</label></div>' + "John Lennon</label></div>" '<div class="mycheckbox"><label>' '<input checked name="composers" type="checkbox" value="P"> ' - 'Paul McCartney</label></div>', + "Paul McCartney</label></div>", ) def test_templates_with_forms(self): class UserRegistration(Form): - username = CharField(max_length=10, help_text=( - "Good luck picking a username that doesn't already exist." - )) + username = CharField( + max_length=10, + help_text=("Good luck picking a username that doesn't already exist."), + ) password1 = CharField(widget=PasswordInput) password2 = CharField(widget=PasswordInput) def clean(self): if ( - self.cleaned_data.get('password1') and - self.cleaned_data.get('password2') and - self.cleaned_data['password1'] != self.cleaned_data['password2'] + self.cleaned_data.get("password1") + and self.cleaned_data.get("password2") + and self.cleaned_data["password1"] != self.cleaned_data["password2"] ): - raise ValidationError('Please make sure your passwords match.') + raise ValidationError("Please make sure your passwords match.") return self.cleaned_data # There is full flexibility in displaying form fields in a template. @@ -3800,169 +4258,169 @@ class TemplateTests(SimpleTestCase): # responsibility of displaying all the errors, including any that might # not be associated with a particular field. t = Template( - '<form>' - '{{ form.username.errors.as_ul }}' - '<p><label>Your username: {{ form.username }}</label></p>' - '{{ form.password1.errors.as_ul }}' - '<p><label>Password: {{ form.password1 }}</label></p>' - '{{ form.password2.errors.as_ul }}' - '<p><label>Password (again): {{ form.password2 }}</label></p>' + "<form>" + "{{ form.username.errors.as_ul }}" + "<p><label>Your username: {{ form.username }}</label></p>" + "{{ form.password1.errors.as_ul }}" + "<p><label>Password: {{ form.password1 }}</label></p>" + "{{ form.password2.errors.as_ul }}" + "<p><label>Password (again): {{ form.password2 }}</label></p>" '<input type="submit" required>' - '</form>' + "</form>" ) f = UserRegistration(auto_id=False) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p><label>Your username: ' + t.render(Context({"form": f})), + "<form>" + "<p><label>Your username: " '<input type="text" name="username" maxlength="10" required></label></p>' - '<p><label>Password: ' + "<p><label>Password: " '<input type="password" name="password1" required></label></p>' - '<p><label>Password (again): ' + "<p><label>Password (again): " '<input type="password" name="password2" required></label></p>' '<input type="submit" required>' - '</form>', + "</form>", ) - f = UserRegistration({'username': 'django'}, auto_id=False) + f = UserRegistration({"username": "django"}, auto_id=False) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p><label>Your username: ' + t.render(Context({"form": f})), + "<form>" + "<p><label>Your username: " '<input type="text" name="username" value="django" maxlength="10" required>' - '</label></p>' + "</label></p>" '<ul class="errorlist"><li>This field is required.</li></ul><p>' - '<label>Password: ' + "<label>Password: " '<input type="password" name="password1" required></label></p>' '<ul class="errorlist"><li>This field is required.</li></ul>' - '<p><label>Password (again): ' + "<p><label>Password (again): " '<input type="password" name="password2" required></label></p>' '<input type="submit" required>' - '</form>', + "</form>", ) # Use form.[field].label to output a field's label. 'label' for a field # can by specified by using the 'label' argument to a Field class. If # 'label' is not specified, Django will use the field name with # underscores converted to spaces, and the initial letter capitalized. t = Template( - '<form>' - '<p><label>{{ form.username.label }}: {{ form.username }}</label></p>' - '<p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p>' - '<p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p>' + "<form>" + "<p><label>{{ form.username.label }}: {{ form.username }}</label></p>" + "<p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p>" + "<p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p>" '<input type="submit" required>' - '</form>' + "</form>" ) f = UserRegistration(auto_id=False) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p><label>Username: ' + t.render(Context({"form": f})), + "<form>" + "<p><label>Username: " '<input type="text" name="username" maxlength="10" required></label></p>' - '<p><label>Password1: ' + "<p><label>Password1: " '<input type="password" name="password1" required></label></p>' - '<p><label>Password2: ' + "<p><label>Password2: " '<input type="password" name="password2" required></label></p>' '<input type="submit" required>' - '</form>', + "</form>", ) # Use form.[field].label_tag to output a field's label with a <label> # tag wrapped around it, but *only* if the given field has an "id" # attribute. Recall from above that passing the "auto_id" argument to a # Form gives each field an "id" attribute. t = Template( - '<form>' - '<p>{{ form.username.label_tag }} {{ form.username }}</p>' - '<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>' - '<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>' + "<form>" + "<p>{{ form.username.label_tag }} {{ form.username }}</p>" + "<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>" + "<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>" '<input type="submit" required>' - '</form>' + "</form>" ) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p>Username: ' + t.render(Context({"form": f})), + "<form>" + "<p>Username: " '<input type="text" name="username" maxlength="10" required></p>' '<p>Password1: <input type="password" name="password1" required></p>' '<p>Password2: <input type="password" name="password2" required></p>' '<input type="submit" required>' - '</form>', + "</form>", ) - f = UserRegistration(auto_id='id_%s') + f = UserRegistration(auto_id="id_%s") self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' + t.render(Context({"form": f})), + "<form>" '<p><label for="id_username">Username:</label>' '<input id="id_username" type="text" name="username" maxlength="10" ' - 'required></p>' + "required></p>" '<p><label for="id_password1">Password1:</label>' '<input type="password" name="password1" id="id_password1" required></p>' '<p><label for="id_password2">Password2:</label>' '<input type="password" name="password2" id="id_password2" required></p>' '<input type="submit" required>' - '</form>', + "</form>", ) # Use form.[field].legend_tag to output a field's label with a <legend> # tag wrapped around it, but *only* if the given field has an "id" # attribute. Recall from above that passing the "auto_id" argument to a # Form gives each field an "id" attribute. t = Template( - '<form>' - '<p>{{ form.username.legend_tag }} {{ form.username }}</p>' - '<p>{{ form.password1.legend_tag }} {{ form.password1 }}</p>' - '<p>{{ form.password2.legend_tag }} {{ form.password2 }}</p>' + "<form>" + "<p>{{ form.username.legend_tag }} {{ form.username }}</p>" + "<p>{{ form.password1.legend_tag }} {{ form.password1 }}</p>" + "<p>{{ form.password2.legend_tag }} {{ form.password2 }}</p>" '<input type="submit" required>' - '</form>' + "</form>" ) f = UserRegistration(auto_id=False) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p>Username: ' + t.render(Context({"form": f})), + "<form>" + "<p>Username: " '<input type="text" name="username" maxlength="10" required></p>' '<p>Password1: <input type="password" name="password1" required></p>' '<p>Password2: <input type="password" name="password2" required></p>' '<input type="submit" required>' - '</form>', + "</form>", ) - f = UserRegistration(auto_id='id_%s') + f = UserRegistration(auto_id="id_%s") self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' + t.render(Context({"form": f})), + "<form>" '<p><legend for="id_username">Username:</legend>' '<input id="id_username" type="text" name="username" maxlength="10" ' - 'required></p>' + "required></p>" '<p><legend for="id_password1">Password1:</legend>' '<input type="password" name="password1" id="id_password1" required></p>' '<p><legend for="id_password2">Password2:</legend>' '<input type="password" name="password2" id="id_password2" required></p>' '<input type="submit" required>' - '</form>', + "</form>", ) # Use form.[field].help_text to output a field's help text. If the # given field does not have help text, nothing will be output. t = Template( - '<form>' - '<p>{{ form.username.label_tag }} {{ form.username }}<br>' - '{{ form.username.help_text }}</p>' - '<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>' - '<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>' + "<form>" + "<p>{{ form.username.label_tag }} {{ form.username }}<br>" + "{{ form.username.help_text }}</p>" + "<p>{{ form.password1.label_tag }} {{ form.password1 }}</p>" + "<p>{{ form.password2.label_tag }} {{ form.password2 }}</p>" '<input type="submit" required>' - '</form>' + "</form>" ) f = UserRegistration(auto_id=False) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p>Username: ' + t.render(Context({"form": f})), + "<form>" + "<p>Username: " '<input type="text" name="username" maxlength="10" required><br>' - 'Good luck picking a username that doesn't already exist.</p>' + "Good luck picking a username that doesn't already exist.</p>" '<p>Password1: <input type="password" name="password1" required></p>' '<p>Password2: <input type="password" name="password2" required></p>' '<input type="submit" required>' - '</form>', + "</form>", ) self.assertEqual( - Template('{{ form.password1.help_text }}').render(Context({'form': f})), - '', + Template("{{ form.password1.help_text }}").render(Context({"form": f})), + "", ) # To display the errors that aren't associated with a particular field # e.g. the errors caused by Form.clean() -- use @@ -3970,59 +4428,59 @@ class TemplateTests(SimpleTestCase): # is displayed as a <ul> (or an empty string, if the list of errors is # empty). t = Template( - '<form>' - '{{ form.username.errors.as_ul }}' - '<p><label>Your username: {{ form.username }}</label></p>' - '{{ form.password1.errors.as_ul }}' - '<p><label>Password: {{ form.password1 }}</label></p>' - '{{ form.password2.errors.as_ul }}' - '<p><label>Password (again): {{ form.password2 }}</label></p>' + "<form>" + "{{ form.username.errors.as_ul }}" + "<p><label>Your username: {{ form.username }}</label></p>" + "{{ form.password1.errors.as_ul }}" + "<p><label>Password: {{ form.password1 }}</label></p>" + "{{ form.password2.errors.as_ul }}" + "<p><label>Password (again): {{ form.password2 }}</label></p>" '<input type="submit" required>' - '</form>' + "</form>" ) f = UserRegistration( - {'username': 'django', 'password1': 'foo', 'password2': 'bar'}, + {"username": "django", "password1": "foo", "password2": "bar"}, auto_id=False, ) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' - '<p><label>Your username: ' + t.render(Context({"form": f})), + "<form>" + "<p><label>Your username: " '<input type="text" name="username" value="django" maxlength="10" required>' - '</label></p>' - '<p><label>Password: ' + "</label></p>" + "<p><label>Password: " '<input type="password" name="password1" required></label></p>' - '<p><label>Password (again): ' + "<p><label>Password (again): " '<input type="password" name="password2" required></label></p>' '<input type="submit" required>' - '</form>', + "</form>", ) t = Template( - '<form>' - '{{ form.non_field_errors }}' - '{{ form.username.errors.as_ul }}' - '<p><label>Your username: {{ form.username }}</label></p>' - '{{ form.password1.errors.as_ul }}' - '<p><label>Password: {{ form.password1 }}</label></p>' - '{{ form.password2.errors.as_ul }}' - '<p><label>Password (again): {{ form.password2 }}</label></p>' + "<form>" + "{{ form.non_field_errors }}" + "{{ form.username.errors.as_ul }}" + "<p><label>Your username: {{ form.username }}</label></p>" + "{{ form.password1.errors.as_ul }}" + "<p><label>Password: {{ form.password1 }}</label></p>" + "{{ form.password2.errors.as_ul }}" + "<p><label>Password (again): {{ form.password2 }}</label></p>" '<input type="submit" required>' - '</form>' + "</form>" ) self.assertHTMLEqual( - t.render(Context({'form': f})), - '<form>' + t.render(Context({"form": f})), + "<form>" '<ul class="errorlist nonfield">' - '<li>Please make sure your passwords match.</li></ul>' - '<p><label>Your username: ' + "<li>Please make sure your passwords match.</li></ul>" + "<p><label>Your username: " '<input type="text" name="username" value="django" maxlength="10" required>' - '</label></p>' - '<p><label>Password: ' + "</label></p>" + "<p><label>Password: " '<input type="password" name="password1" required></label></p>' - '<p><label>Password (again): ' + "<p><label>Password (again): " '<input type="password" name="password2" required></label></p>' '<input type="submit" required>' - '</form>', + "</form>", ) def test_basic_processing_in_view(self): @@ -4033,77 +4491,83 @@ class TemplateTests(SimpleTestCase): def clean(self): if ( - self.cleaned_data.get('password1') and - self.cleaned_data.get('password2') and - self.cleaned_data['password1'] != self.cleaned_data['password2'] + self.cleaned_data.get("password1") + and self.cleaned_data.get("password2") + and self.cleaned_data["password1"] != self.cleaned_data["password2"] ): - raise ValidationError('Please make sure your passwords match.') + raise ValidationError("Please make sure your passwords match.") return self.cleaned_data def my_function(method, post_data): - if method == 'POST': + if method == "POST": form = UserRegistration(post_data, auto_id=False) else: form = UserRegistration(auto_id=False) if form.is_valid(): - return 'VALID: %r' % sorted(form.cleaned_data.items()) + return "VALID: %r" % sorted(form.cleaned_data.items()) t = Template( '<form method="post">' - '<table>' - '{{ form }}' - '</table>' + "<table>" + "{{ form }}" + "</table>" '<input type="submit" required>' - '</form>' + "</form>" ) - return t.render(Context({'form': form})) + return t.render(Context({"form": form})) # GET with an empty form and no errors. self.assertHTMLEqual( - my_function('GET', {}), + my_function("GET", {}), '<form method="post">' - '<table>' - '<tr><th>Username:</th><td>' + "<table>" + "<tr><th>Username:</th><td>" '<input type="text" name="username" maxlength="10" required></td></tr>' - '<tr><th>Password1:</th><td>' + "<tr><th>Password1:</th><td>" '<input type="password" name="password1" required></td></tr>' - '<tr><th>Password2:</th><td>' + "<tr><th>Password2:</th><td>" '<input type="password" name="password2" required></td></tr>' - '</table>' + "</table>" '<input type="submit" required>' - '</form>', + "</form>", ) # POST with erroneous data, a redisplayed form, with errors. self.assertHTMLEqual( - my_function('POST', { - 'username': 'this-is-a-long-username', - 'password1': 'foo', - 'password2': 'bar', - }), + my_function( + "POST", + { + "username": "this-is-a-long-username", + "password1": "foo", + "password2": "bar", + }, + ), '<form method="post">' - '<table>' + "<table>" '<tr><td colspan="2"><ul class="errorlist nonfield">' - '<li>Please make sure your passwords match.</li></ul></td></tr>' + "<li>Please make sure your passwords match.</li></ul></td></tr>" '<tr><th>Username:</th><td><ul class="errorlist">' - '<li>Ensure this value has at most 10 characters (it has 23).</li></ul>' + "<li>Ensure this value has at most 10 characters (it has 23).</li></ul>" '<input type="text" name="username" ' 'value="this-is-a-long-username" maxlength="10" required></td></tr>' - '<tr><th>Password1:</th><td>' + "<tr><th>Password1:</th><td>" '<input type="password" name="password1" required></td></tr>' - '<tr><th>Password2:</th><td>' + "<tr><th>Password2:</th><td>" '<input type="password" name="password2" required></td></tr>' - '</table>' + "</table>" '<input type="submit" required>' - '</form>', + "</form>", ) # POST with valid data (the success message). self.assertEqual( - my_function('POST', { - 'username': 'adrian', - 'password1': 'secret', - 'password2': 'secret', - }), + my_function( + "POST", + { + "username": "adrian", + "password1": "secret", + "password2": "secret", + }, + ), "VALID: [('password1', 'secret'), ('password2', 'secret'), " "('username', 'adrian')]", ) @@ -4113,10 +4577,10 @@ class OverrideTests(SimpleTestCase): def test_use_custom_template(self): class Person(Form): first_name = CharField() - template_name = 'forms_tests/form_snippet.html' + template_name = "forms_tests/form_snippet.html" - t = Template('{{ form }}') - html = t.render(Context({'form': Person()})) + t = Template("{{ form }}") + html = t.render(Context({"form": Person()})) expected = """ <div class="fieldWrapper"><label for="id_first_name">First name:</label> <input type="text" name="first_name" required id="id_first_name"></div> @@ -4125,14 +4589,14 @@ class OverrideTests(SimpleTestCase): def test_errorlist_override(self): class CustomErrorList(ErrorList): - template_name = 'forms_tests/error.html' + template_name = "forms_tests/error.html" class CommentForm(Form): name = CharField(max_length=50, required=False) email = EmailField() comment = CharField() - data = {'email': 'invalid'} + data = {"email": "invalid"} f = CommentForm(data, auto_id=False, error_class=CustomErrorList) self.assertHTMLEqual( f.as_p(), @@ -4148,18 +4612,18 @@ class OverrideTests(SimpleTestCase): def test_cyclic_context_boundfield_render(self): class FirstNameForm(Form): first_name = CharField() - template_name_label = 'forms_tests/cyclic_context_boundfield_render.html' + template_name_label = "forms_tests/cyclic_context_boundfield_render.html" f = FirstNameForm() try: - self.assertInHTML('<th>1</th>', f.render()) + self.assertInHTML("<th>1</th>", f.render()) except RecursionError: - self.fail('Cyclic reference in BoundField.render().') + self.fail("Cyclic reference in BoundField.render().") def test_legend_tag(self): class CustomFrameworkForm(FrameworkForm): - template_name = 'forms_tests/legend_test.html' - required_css_class = 'required' + template_name = "forms_tests/legend_test.html" + required_css_class = "required" f = CustomFrameworkForm() self.assertHTMLEqual( diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py index c5a4f259e0..9846cb5874 100644 --- a/tests/forms_tests/tests/test_formsets.py +++ b/tests/forms_tests/tests/test_formsets.py @@ -4,12 +4,24 @@ from unittest import mock from django.core.exceptions import ValidationError from django.forms import ( - BaseForm, CharField, DateField, FileField, Form, IntegerField, - SplitDateTimeField, formsets, + BaseForm, + CharField, + DateField, + FileField, + Form, + IntegerField, + SplitDateTimeField, + formsets, ) from django.forms.formsets import ( - INITIAL_FORM_COUNT, MAX_NUM_FORM_COUNT, MIN_NUM_FORM_COUNT, - TOTAL_FORM_COUNT, BaseFormSet, ManagementForm, all_valid, formset_factory, + INITIAL_FORM_COUNT, + MAX_NUM_FORM_COUNT, + MIN_NUM_FORM_COUNT, + TOTAL_FORM_COUNT, + BaseFormSet, + ManagementForm, + all_valid, + formset_factory, ) from django.forms.utils import ErrorList from django.forms.widgets import HiddenInput @@ -29,7 +41,7 @@ ChoiceFormSet = formset_factory(Choice) class ChoiceFormsetWithNonFormError(ChoiceFormSet): def clean(self): super().clean() - raise ValidationError('non-form error') + raise ValidationError("non-form error") class FavoriteDrinkForm(Form): @@ -41,15 +53,17 @@ class BaseFavoriteDrinksFormSet(BaseFormSet): seen_drinks = [] for drink in self.cleaned_data: - if drink['name'] in seen_drinks: - raise ValidationError('You may only specify a drink once.') + if drink["name"] in seen_drinks: + raise ValidationError("You may only specify a drink once.") - seen_drinks.append(drink['name']) + seen_drinks.append(drink["name"]) # A FormSet that takes a list of favorite drinks and raises an error if # there are any duplicates. -FavoriteDrinksFormSet = formset_factory(FavoriteDrinkForm, formset=BaseFavoriteDrinksFormSet, extra=3) +FavoriteDrinksFormSet = formset_factory( + FavoriteDrinkForm, formset=BaseFavoriteDrinksFormSet, extra=3 +) class CustomKwargForm(Form): @@ -59,16 +73,22 @@ class CustomKwargForm(Form): class FormsFormsetTestCase(SimpleTestCase): - def make_choiceformset( - self, formset_data=None, formset_class=ChoiceFormSet, - total_forms=None, initial_forms=0, max_num_forms=0, min_num_forms=0, **kwargs): + self, + formset_data=None, + formset_class=ChoiceFormSet, + total_forms=None, + initial_forms=0, + max_num_forms=0, + min_num_forms=0, + **kwargs, + ): """ Make a ChoiceFormset from the given formset_data. The data should be given as a list of (choice, votes) tuples. """ - kwargs.setdefault('prefix', 'choices') - kwargs.setdefault('auto_id', False) + kwargs.setdefault("prefix", "choices") + kwargs.setdefault("auto_id", False) if formset_data is None: return formset_class(**kwargs) @@ -77,18 +97,18 @@ class FormsFormsetTestCase(SimpleTestCase): total_forms = len(formset_data) def prefixed(*args): - args = (kwargs['prefix'],) + args - return '-'.join(args) + args = (kwargs["prefix"],) + args + return "-".join(args) data = { - prefixed('TOTAL_FORMS'): str(total_forms), - prefixed('INITIAL_FORMS'): str(initial_forms), - prefixed('MAX_NUM_FORMS'): str(max_num_forms), - prefixed('MIN_NUM_FORMS'): str(min_num_forms), + prefixed("TOTAL_FORMS"): str(total_forms), + prefixed("INITIAL_FORMS"): str(initial_forms), + prefixed("MAX_NUM_FORMS"): str(max_num_forms), + prefixed("MIN_NUM_FORMS"): str(min_num_forms), } for i, (choice, votes) in enumerate(formset_data): - data[prefixed(str(i), 'choice')] = choice - data[prefixed(str(i), 'votes')] = votes + data[prefixed(str(i), "choice")] = choice + data[prefixed(str(i), "votes")] = votes return formset_class(data, **kwargs) @@ -105,15 +125,18 @@ class FormsFormsetTestCase(SimpleTestCase): <input type="hidden" name="choices-MIN_NUM_FORMS" value="0"> <input type="hidden" name="choices-MAX_NUM_FORMS" value="1000"> <tr><th>Choice:</th><td><input type="text" name="choices-0-choice"></td></tr> -<tr><th>Votes:</th><td><input type="number" name="choices-0-votes"></td></tr>""" +<tr><th>Votes:</th><td><input type="number" name="choices-0-votes"></td></tr>""", ) # FormSet are treated similarly to Forms. FormSet has an is_valid() # method, and a cleaned_data or errors attribute depending on whether # all the forms passed validation. However, unlike a Form, cleaned_data # and errors will be a list of dicts rather than a single dict. - formset = self.make_choiceformset([('Calexico', '100')]) + formset = self.make_choiceformset([("Calexico", "100")]) self.assertTrue(formset.is_valid()) - self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}]) + self.assertEqual( + [form.cleaned_data for form in formset.forms], + [{"votes": 100, "choice": "Calexico"}], + ) # If a FormSet wasn't passed any data, is_valid() and has_changed() # return False. @@ -127,41 +150,45 @@ class FormsFormsetTestCase(SimpleTestCase): underlying forms. """ FormSet = formset_factory(CustomKwargForm, extra=2) - formset = FormSet(form_kwargs={'custom_kwarg': 1}) + formset = FormSet(form_kwargs={"custom_kwarg": 1}) for form in formset: - self.assertTrue(hasattr(form, 'custom_kwarg')) + self.assertTrue(hasattr(form, "custom_kwarg")) self.assertEqual(form.custom_kwarg, 1) def test_form_kwargs_formset_dynamic(self): """Form kwargs can be passed dynamically in a formset.""" + class DynamicBaseFormSet(BaseFormSet): def get_form_kwargs(self, index): - return {'custom_kwarg': index} + return {"custom_kwarg": index} - DynamicFormSet = formset_factory(CustomKwargForm, formset=DynamicBaseFormSet, extra=2) - formset = DynamicFormSet(form_kwargs={'custom_kwarg': 'ignored'}) + DynamicFormSet = formset_factory( + CustomKwargForm, formset=DynamicBaseFormSet, extra=2 + ) + formset = DynamicFormSet(form_kwargs={"custom_kwarg": "ignored"}) for i, form in enumerate(formset): - self.assertTrue(hasattr(form, 'custom_kwarg')) + self.assertTrue(hasattr(form, "custom_kwarg")) self.assertEqual(form.custom_kwarg, i) def test_form_kwargs_empty_form(self): FormSet = formset_factory(CustomKwargForm) - formset = FormSet(form_kwargs={'custom_kwarg': 1}) - self.assertTrue(hasattr(formset.empty_form, 'custom_kwarg')) + formset = FormSet(form_kwargs={"custom_kwarg": 1}) + self.assertTrue(hasattr(formset.empty_form, "custom_kwarg")) self.assertEqual(formset.empty_form.custom_kwarg, 1) def test_formset_validation(self): # FormSet instances can also have an error attribute if validation failed for # any of the forms. - formset = self.make_choiceformset([('Calexico', '')]) + formset = self.make_choiceformset([("Calexico", "")]) self.assertFalse(formset.is_valid()) - self.assertEqual(formset.errors, [{'votes': ['This field is required.']}]) + self.assertEqual(formset.errors, [{"votes": ["This field is required."]}]) def test_formset_validation_count(self): """ A formset's ManagementForm is validated once per FormSet.is_valid() call and each form of the formset is cleaned once. """ + def make_method_counter(func): """Add a counter to func for the number of times it's called.""" counter = Counter() @@ -173,12 +200,17 @@ class FormsFormsetTestCase(SimpleTestCase): return mocked_func, counter - mocked_is_valid, is_valid_counter = make_method_counter(formsets.ManagementForm.is_valid) + mocked_is_valid, is_valid_counter = make_method_counter( + formsets.ManagementForm.is_valid + ) mocked_full_clean, full_clean_counter = make_method_counter(BaseForm.full_clean) - formset = self.make_choiceformset([('Calexico', '100'), ('Any1', '42'), ('Any2', '101')]) + formset = self.make_choiceformset( + [("Calexico", "100"), ("Any1", "42"), ("Any2", "101")] + ) - with mock.patch('django.forms.formsets.ManagementForm.is_valid', mocked_is_valid), \ - mock.patch('django.forms.forms.BaseForm.full_clean', mocked_full_clean): + with mock.patch( + "django.forms.formsets.ManagementForm.is_valid", mocked_is_valid + ), mock.patch("django.forms.forms.BaseForm.full_clean", mocked_full_clean): self.assertTrue(formset.is_valid()) self.assertEqual(is_valid_counter.call_count, 1) self.assertEqual(full_clean_counter.call_count, 4) @@ -188,14 +220,14 @@ class FormsFormsetTestCase(SimpleTestCase): FormSet.has_changed() is True if any data is passed to its forms, even if the formset didn't validate. """ - blank_formset = self.make_choiceformset([('', '')]) + blank_formset = self.make_choiceformset([("", "")]) self.assertFalse(blank_formset.has_changed()) # invalid formset - invalid_formset = self.make_choiceformset([('Calexico', '')]) + invalid_formset = self.make_choiceformset([("Calexico", "")]) self.assertFalse(invalid_formset.is_valid()) self.assertTrue(invalid_formset.has_changed()) # valid formset - valid_formset = self.make_choiceformset([('Calexico', '100')]) + valid_formset = self.make_choiceformset([("Calexico", "100")]) self.assertTrue(valid_formset.is_valid()) self.assertTrue(valid_formset.has_changed()) @@ -205,40 +237,55 @@ class FormsFormsetTestCase(SimpleTestCase): dicts to the `initial` argument. By default, an extra blank form is included. """ - formset = self.make_choiceformset(initial=[{'choice': 'Calexico', 'votes': 100}]) + formset = self.make_choiceformset( + initial=[{"choice": "Calexico", "votes": 100}] + ) self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li> <li>Votes: <input type="number" name="choices-0-votes" value="100"></li> <li>Choice: <input type="text" name="choices-1-choice"></li> -<li>Votes: <input type="number" name="choices-1-votes"></li>""" +<li>Votes: <input type="number" name="choices-1-votes"></li>""", ) def test_blank_form_unfilled(self): """A form that's displayed as blank may be submitted as blank.""" - formset = self.make_choiceformset([('Calexico', '100'), ('', '')], initial_forms=1) + formset = self.make_choiceformset( + [("Calexico", "100"), ("", "")], initial_forms=1 + ) self.assertTrue(formset.is_valid()) - self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}, {}]) + self.assertEqual( + [form.cleaned_data for form in formset.forms], + [{"votes": 100, "choice": "Calexico"}, {}], + ) def test_second_form_partially_filled(self): """ If at least one field is filled out on a blank form, it will be validated. """ - formset = self.make_choiceformset([('Calexico', '100'), ('The Decemberists', '')], initial_forms=1) + formset = self.make_choiceformset( + [("Calexico", "100"), ("The Decemberists", "")], initial_forms=1 + ) self.assertFalse(formset.is_valid()) - self.assertEqual(formset.errors, [{}, {'votes': ['This field is required.']}]) + self.assertEqual(formset.errors, [{}, {"votes": ["This field is required."]}]) def test_delete_prefilled_data(self): """ Deleting prefilled data is an error. Removing data from form fields isn't the proper way to delete it. """ - formset = self.make_choiceformset([('', ''), ('', '')], initial_forms=1) + formset = self.make_choiceformset([("", ""), ("", "")], initial_forms=1) self.assertFalse(formset.is_valid()) self.assertEqual( formset.errors, - [{'votes': ['This field is required.'], 'choice': ['This field is required.']}, {}] + [ + { + "votes": ["This field is required."], + "choice": ["This field is required."], + }, + {}, + ], ) def test_displaying_more_than_one_blank_form(self): @@ -247,32 +294,32 @@ class FormsFormsetTestCase(SimpleTestCase): `extra` argument. """ ChoiceFormSet = formset_factory(Choice, extra=3) - formset = ChoiceFormSet(auto_id=False, prefix='choices') + formset = ChoiceFormSet(auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice"></li> <li>Votes: <input type="number" name="choices-0-votes"></li> <li>Choice: <input type="text" name="choices-1-choice"></li> <li>Votes: <input type="number" name="choices-1-votes"></li> <li>Choice: <input type="text" name="choices-2-choice"></li> -<li>Votes: <input type="number" name="choices-2-votes"></li>""" +<li>Votes: <input type="number" name="choices-2-votes"></li>""", ) # Since every form was displayed as blank, they are also accepted as # blank. This may seem a little strange, but min_num is used to require # a minimum number of forms to be completed. data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': '', - 'choices-0-votes': '', - 'choices-1-choice': '', - 'choices-1-votes': '', - 'choices-2-choice': '', - 'choices-2-votes': '', + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "", + "choices-0-votes": "", + "choices-1-choice": "", + "choices-1-votes": "", + "choices-2-choice": "", + "choices-2-votes": "", } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual([form.cleaned_data for form in formset.forms], [{}, {}, {}]) @@ -282,50 +329,53 @@ class FormsFormsetTestCase(SimpleTestCase): min_num argument. It will (essentially) increment the extra argument. """ ChoiceFormSet = formset_factory(Choice, extra=1, min_num=1) - formset = ChoiceFormSet(auto_id=False, prefix='choices') + formset = ChoiceFormSet(auto_id=False, prefix="choices") # Min_num forms are required; extra forms can be empty. self.assertFalse(formset.forms[0].empty_permitted) self.assertTrue(formset.forms[1].empty_permitted) self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice"></li> <li>Votes: <input type="number" name="choices-0-votes"></li> <li>Choice: <input type="text" name="choices-1-choice"></li> -<li>Votes: <input type="number" name="choices-1-votes"></li>""" +<li>Votes: <input type="number" name="choices-1-votes"></li>""", ) def test_min_num_displaying_more_than_one_blank_form_with_zero_extra(self): """More than 1 empty form can be displayed using min_num.""" ChoiceFormSet = formset_factory(Choice, extra=0, min_num=3) - formset = ChoiceFormSet(auto_id=False, prefix='choices') + formset = ChoiceFormSet(auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice"></li> <li>Votes: <input type="number" name="choices-0-votes"></li> <li>Choice: <input type="text" name="choices-1-choice"></li> <li>Votes: <input type="number" name="choices-1-votes"></li> <li>Choice: <input type="text" name="choices-2-choice"></li> -<li>Votes: <input type="number" name="choices-2-votes"></li>""" +<li>Votes: <input type="number" name="choices-2-votes"></li>""", ) def test_single_form_completed(self): """Just one form may be completed.""" data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-1-choice': '', - 'choices-1-votes': '', - 'choices-2-choice': '', - 'choices-2-votes': '', + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-1-choice": "", + "choices-1-votes": "", + "choices-2-choice": "", + "choices-2-votes": "", } ChoiceFormSet = formset_factory(Choice, extra=3) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) - self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}, {}, {}]) + self.assertEqual( + [form.cleaned_data for form in formset.forms], + [{"votes": 100, "choice": "Calexico"}, {}, {}], + ) def test_formset_validate_max_flag(self): """ @@ -335,19 +385,19 @@ class FormsFormsetTestCase(SimpleTestCase): in the returned data is not checked). """ data = { - 'choices-TOTAL_FORMS': '2', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '2', # max number of forms - should be ignored - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', + "choices-TOTAL_FORMS": "2", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "2", # max number of forms - should be ignored + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", } ChoiceFormSet = formset_factory(Choice, extra=1, max_num=1, validate_max=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertFalse(formset.is_valid()) - self.assertEqual(formset.non_form_errors(), ['Please submit at most 1 form.']) + self.assertEqual(formset.non_form_errors(), ["Please submit at most 1 form."]) self.assertEqual( str(formset.non_form_errors()), '<ul class="errorlist nonform"><li>Please submit at most 1 form.</li></ul>', @@ -361,23 +411,23 @@ class FormsFormsetTestCase(SimpleTestCase): in the returned data is not checked). """ data = { - 'choices-TOTAL_FORMS': '2', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - should be ignored - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', + "choices-TOTAL_FORMS": "2", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms - should be ignored + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", } ChoiceFormSet = formset_factory(Choice, extra=1, min_num=3, validate_min=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertFalse(formset.is_valid()) - self.assertEqual(formset.non_form_errors(), ['Please submit at least 3 forms.']) + self.assertEqual(formset.non_form_errors(), ["Please submit at least 3 forms."]) self.assertEqual( str(formset.non_form_errors()), '<ul class="errorlist nonform"><li>' - 'Please submit at least 3 forms.</li></ul>', + "Please submit at least 3 forms.</li></ul>", ) def test_formset_validate_min_unchanged_forms(self): @@ -386,65 +436,69 @@ class FormsFormsetTestCase(SimpleTestCase): as "empty". """ initial = [ - {'choice': 'Zero', 'votes': 0}, - {'choice': 'One', 'votes': 0}, + {"choice": "Zero", "votes": 0}, + {"choice": "One", "votes": 0}, ] data = { - 'choices-TOTAL_FORMS': '2', - 'choices-INITIAL_FORMS': '2', - 'choices-MIN_NUM_FORMS': '0', - 'choices-MAX_NUM_FORMS': '2', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', # changed from initial + "choices-TOTAL_FORMS": "2", + "choices-INITIAL_FORMS": "2", + "choices-MIN_NUM_FORMS": "0", + "choices-MAX_NUM_FORMS": "2", + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", # changed from initial } ChoiceFormSet = formset_factory(Choice, min_num=2, validate_min=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices', initial=initial) + formset = ChoiceFormSet(data, auto_id=False, prefix="choices", initial=initial) self.assertFalse(formset.forms[0].has_changed()) self.assertTrue(formset.forms[1].has_changed()) self.assertTrue(formset.is_valid()) def test_formset_validate_min_excludes_empty_forms(self): data = { - 'choices-TOTAL_FORMS': '2', - 'choices-INITIAL_FORMS': '0', + "choices-TOTAL_FORMS": "2", + "choices-INITIAL_FORMS": "0", } - ChoiceFormSet = formset_factory(Choice, extra=2, min_num=1, validate_min=True, can_delete=True) - formset = ChoiceFormSet(data, prefix='choices') + ChoiceFormSet = formset_factory( + Choice, extra=2, min_num=1, validate_min=True, can_delete=True + ) + formset = ChoiceFormSet(data, prefix="choices") self.assertFalse(formset.has_changed()) self.assertFalse(formset.is_valid()) - self.assertEqual(formset.non_form_errors(), ['Please submit at least 1 form.']) + self.assertEqual(formset.non_form_errors(), ["Please submit at least 1 form."]) def test_second_form_partially_filled_2(self): """A partially completed form is invalid.""" data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-1-choice': 'The Decemberists', - 'choices-1-votes': '', # missing value - 'choices-2-choice': '', - 'choices-2-votes': '', + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-1-choice": "The Decemberists", + "choices-1-votes": "", # missing value + "choices-2-choice": "", + "choices-2-votes": "", } ChoiceFormSet = formset_factory(Choice, extra=3) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertFalse(formset.is_valid()) - self.assertEqual(formset.errors, [{}, {'votes': ['This field is required.']}, {}]) + self.assertEqual( + formset.errors, [{}, {"votes": ["This field is required."]}, {}] + ) def test_more_initial_data(self): """ The extra argument works when the formset is pre-filled with initial data. """ - initial = [{'choice': 'Calexico', 'votes': 100}] + initial = [{"choice": "Calexico", "votes": 100}] ChoiceFormSet = formset_factory(Choice, extra=3) - formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') + formset = ChoiceFormSet(initial=initial, auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li> <li>Votes: <input type="number" name="choices-0-votes" value="100"></li> <li>Choice: <input type="text" name="choices-1-choice"></li> @@ -452,14 +506,14 @@ class FormsFormsetTestCase(SimpleTestCase): <li>Choice: <input type="text" name="choices-2-choice"></li> <li>Votes: <input type="number" name="choices-2-votes"></li> <li>Choice: <input type="text" name="choices-3-choice"></li> -<li>Votes: <input type="number" name="choices-3-votes"></li>""" +<li>Votes: <input type="number" name="choices-3-votes"></li>""", ) # Retrieving an empty form works. Tt shows up in the form list. self.assertTrue(formset.empty_form.empty_permitted) self.assertHTMLEqual( formset.empty_form.as_ul(), """<li>Choice: <input type="text" name="choices-__prefix__-choice"></li> -<li>Votes: <input type="number" name="choices-__prefix__-votes"></li>""" +<li>Votes: <input type="number" name="choices-__prefix__-votes"></li>""", ) def test_formset_with_deletion(self): @@ -469,10 +523,13 @@ class FormsFormsetTestCase(SimpleTestCase): formset.deleted_forms. """ ChoiceFormSet = formset_factory(Choice, can_delete=True) - initial = [{'choice': 'Calexico', 'votes': 100}, {'choice': 'Fergie', 'votes': 900}] - formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') + initial = [ + {"choice": "Calexico", "votes": 100}, + {"choice": "Fergie", "votes": 900}, + ] + formset = ChoiceFormSet(initial=initial, auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li> <li>Votes: <input type="number" name="choices-0-votes" value="100"></li> <li>Delete: <input type="checkbox" name="choices-0-DELETE"></li> @@ -481,38 +538,38 @@ class FormsFormsetTestCase(SimpleTestCase): <li>Delete: <input type="checkbox" name="choices-1-DELETE"></li> <li>Choice: <input type="text" name="choices-2-choice"></li> <li>Votes: <input type="number" name="choices-2-votes"></li> -<li>Delete: <input type="checkbox" name="choices-2-DELETE"></li>""" +<li>Delete: <input type="checkbox" name="choices-2-DELETE"></li>""", ) # To delete something, set that form's special delete field to 'on'. # Let's go ahead and delete Fergie. data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '2', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-0-DELETE': '', - 'choices-1-choice': 'Fergie', - 'choices-1-votes': '900', - 'choices-1-DELETE': 'on', - 'choices-2-choice': '', - 'choices-2-votes': '', - 'choices-2-DELETE': '', + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "2", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-0-DELETE": "", + "choices-1-choice": "Fergie", + "choices-1-votes": "900", + "choices-1-DELETE": "on", + "choices-2-choice": "", + "choices-2-votes": "", + "choices-2-DELETE": "", } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual( [form.cleaned_data for form in formset.forms], [ - {'votes': 100, 'DELETE': False, 'choice': 'Calexico'}, - {'votes': 900, 'DELETE': True, 'choice': 'Fergie'}, + {"votes": 100, "DELETE": False, "choice": "Calexico"}, + {"votes": 900, "DELETE": True, "choice": "Fergie"}, {}, - ] + ], ) self.assertEqual( [form.cleaned_data for form in formset.deleted_forms], - [{'votes': 900, 'DELETE': True, 'choice': 'Fergie'}] + [{"votes": 900, "DELETE": True, "choice": "Fergie"}], ) def test_formset_with_deletion_remove_deletion_flag(self): @@ -521,27 +578,28 @@ class FormsFormsetTestCase(SimpleTestCase): form's errors shouldn't make the entire formset invalid since it's going to be deleted. """ + class CheckForm(Form): field = IntegerField(min_value=100) data = { - 'check-TOTAL_FORMS': '3', # the number of forms rendered - 'check-INITIAL_FORMS': '2', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'check-MAX_NUM_FORMS': '0', # max number of forms - 'check-0-field': '200', - 'check-0-DELETE': '', - 'check-1-field': '50', - 'check-1-DELETE': 'on', - 'check-2-field': '', - 'check-2-DELETE': '', + "check-TOTAL_FORMS": "3", # the number of forms rendered + "check-INITIAL_FORMS": "2", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "check-MAX_NUM_FORMS": "0", # max number of forms + "check-0-field": "200", + "check-0-DELETE": "", + "check-1-field": "50", + "check-1-DELETE": "on", + "check-2-field": "", + "check-2-DELETE": "", } CheckFormSet = formset_factory(CheckForm, can_delete=True) - formset = CheckFormSet(data, prefix='check') + formset = CheckFormSet(data, prefix="check") self.assertTrue(formset.is_valid()) # If the deletion flag is removed, validation is enabled. - data['check-1-DELETE'] = '' - formset = CheckFormSet(data, prefix='check') + data["check-1-DELETE"] = "" + formset = CheckFormSet(data, prefix="check") self.assertFalse(formset.is_valid()) def test_formset_with_deletion_invalid_deleted_form(self): @@ -550,14 +608,16 @@ class FormsFormsetTestCase(SimpleTestCase): have been invalid. """ FavoriteDrinkFormset = formset_factory(form=FavoriteDrinkForm, can_delete=True) - formset = FavoriteDrinkFormset({ - 'form-0-name': '', - 'form-0-DELETE': 'on', # no name! - 'form-TOTAL_FORMS': 1, - 'form-INITIAL_FORMS': 1, - 'form-MIN_NUM_FORMS': 0, - 'form-MAX_NUM_FORMS': 1, - }) + formset = FavoriteDrinkFormset( + { + "form-0-name": "", + "form-0-DELETE": "on", # no name! + "form-TOTAL_FORMS": 1, + "form-INITIAL_FORMS": 1, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1, + } + ) self.assertTrue(formset.is_valid()) self.assertEqual(formset._errors, []) self.assertEqual(len(formset.deleted_forms), 1) @@ -568,7 +628,7 @@ class FormsFormsetTestCase(SimpleTestCase): class DeletionMethodFormSet(BaseFormSet): def get_deletion_widget(self): - return HiddenInput(attrs={'class': 'deletion'}) + return HiddenInput(attrs={"class": "deletion"}) tests = [ (DeletionAttributeFormSet, '<input type="hidden" name="form-0-DELETE">'), @@ -586,11 +646,11 @@ class FormsFormsetTestCase(SimpleTestCase): ) formset = ArticleFormSet(auto_id=False) self.assertHTMLEqual( - '\n'.join([form.as_ul() for form in formset.forms]), + "\n".join([form.as_ul() for form in formset.forms]), ( f'<li>Title: <input type="text" name="form-0-title"></li>' f'<li>Pub date: <input type="text" name="form-0-pub_date">' - f'{delete_html}</li>' + f"{delete_html}</li>" ), ) @@ -605,10 +665,13 @@ class FormsFormsetTestCase(SimpleTestCase): front of the list, you'd need to set its order to 0. """ ChoiceFormSet = formset_factory(Choice, can_order=True) - initial = [{'choice': 'Calexico', 'votes': 100}, {'choice': 'Fergie', 'votes': 900}] - formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') + initial = [ + {"choice": "Calexico", "votes": 100}, + {"choice": "Fergie", "votes": 900}, + ] + formset = ChoiceFormSet(initial=initial, auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li> <li>Votes: <input type="number" name="choices-0-votes" value="100"></li> <li>Order: <input type="number" name="choices-0-ORDER" value="1"></li> @@ -617,31 +680,31 @@ class FormsFormsetTestCase(SimpleTestCase): <li>Order: <input type="number" name="choices-1-ORDER" value="2"></li> <li>Choice: <input type="text" name="choices-2-choice"></li> <li>Votes: <input type="number" name="choices-2-votes"></li> -<li>Order: <input type="number" name="choices-2-ORDER"></li>""" +<li>Order: <input type="number" name="choices-2-ORDER"></li>""", ) data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '2', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-0-ORDER': '1', - 'choices-1-choice': 'Fergie', - 'choices-1-votes': '900', - 'choices-1-ORDER': '2', - 'choices-2-choice': 'The Decemberists', - 'choices-2-votes': '500', - 'choices-2-ORDER': '0', + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "2", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-0-ORDER": "1", + "choices-1-choice": "Fergie", + "choices-1-votes": "900", + "choices-1-ORDER": "2", + "choices-2-choice": "The Decemberists", + "choices-2-votes": "500", + "choices-2-ORDER": "0", } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual( [form.cleaned_data for form in formset.ordered_forms], [ - {'votes': 500, 'ORDER': 0, 'choice': 'The Decemberists'}, - {'votes': 100, 'ORDER': 1, 'choice': 'Calexico'}, - {'votes': 900, 'ORDER': 2, 'choice': 'Fergie'}, + {"votes": 500, "ORDER": 0, "choice": "The Decemberists"}, + {"votes": 100, "ORDER": 1, "choice": "Calexico"}, + {"votes": 900, "ORDER": 2, "choice": "Fergie"}, ], ) @@ -651,22 +714,27 @@ class FormsFormsetTestCase(SimpleTestCase): class OrderingMethodFormSet(BaseFormSet): def get_ordering_widget(self): - return HiddenInput(attrs={'class': 'ordering'}) + return HiddenInput(attrs={"class": "ordering"}) tests = ( (OrderingAttributeFormSet, '<input type="hidden" name="form-0-ORDER">'), - (OrderingMethodFormSet, '<input class="ordering" type="hidden" name="form-0-ORDER">'), + ( + OrderingMethodFormSet, + '<input class="ordering" type="hidden" name="form-0-ORDER">', + ), ) for formset_class, order_html in tests: with self.subTest(formset_class=formset_class.__name__): - ArticleFormSet = formset_factory(ArticleForm, formset=formset_class, can_order=True) + ArticleFormSet = formset_factory( + ArticleForm, formset=formset_class, can_order=True + ) formset = ArticleFormSet(auto_id=False) self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), ( '<li>Title: <input type="text" name="form-0-title"></li>' '<li>Pub date: <input type="text" name="form-0-pub_date">' - '%s</li>' % order_html + "%s</li>" % order_html ), ) @@ -676,46 +744,46 @@ class FormsFormsetTestCase(SimpleTestCase): they'll be sorted below everything else. """ data = { - 'choices-TOTAL_FORMS': '4', # the number of forms rendered - 'choices-INITIAL_FORMS': '3', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-0-ORDER': '1', - 'choices-1-choice': 'Fergie', - 'choices-1-votes': '900', - 'choices-1-ORDER': '2', - 'choices-2-choice': 'The Decemberists', - 'choices-2-votes': '500', - 'choices-2-ORDER': '', - 'choices-3-choice': 'Basia Bulat', - 'choices-3-votes': '50', - 'choices-3-ORDER': '', + "choices-TOTAL_FORMS": "4", # the number of forms rendered + "choices-INITIAL_FORMS": "3", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-0-ORDER": "1", + "choices-1-choice": "Fergie", + "choices-1-votes": "900", + "choices-1-ORDER": "2", + "choices-2-choice": "The Decemberists", + "choices-2-votes": "500", + "choices-2-ORDER": "", + "choices-3-choice": "Basia Bulat", + "choices-3-votes": "50", + "choices-3-ORDER": "", } ChoiceFormSet = formset_factory(Choice, can_order=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual( [form.cleaned_data for form in formset.ordered_forms], [ - {'votes': 100, 'ORDER': 1, 'choice': 'Calexico'}, - {'votes': 900, 'ORDER': 2, 'choice': 'Fergie'}, - {'votes': 500, 'ORDER': None, 'choice': 'The Decemberists'}, - {'votes': 50, 'ORDER': None, 'choice': 'Basia Bulat'}, + {"votes": 100, "ORDER": 1, "choice": "Calexico"}, + {"votes": 900, "ORDER": 2, "choice": "Fergie"}, + {"votes": 500, "ORDER": None, "choice": "The Decemberists"}, + {"votes": 50, "ORDER": None, "choice": "Basia Bulat"}, ], ) def test_ordering_blank_fieldsets(self): """Ordering works with blank fieldsets.""" data = { - 'choices-TOTAL_FORMS': '3', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms + "choices-TOTAL_FORMS": "3", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms } ChoiceFormSet = formset_factory(Choice, can_order=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual(formset.ordered_forms, []) @@ -723,13 +791,13 @@ class FormsFormsetTestCase(SimpleTestCase): """FormSets with ordering + deletion.""" ChoiceFormSet = formset_factory(Choice, can_order=True, can_delete=True) initial = [ - {'choice': 'Calexico', 'votes': 100}, - {'choice': 'Fergie', 'votes': 900}, - {'choice': 'The Decemberists', 'votes': 500}, + {"choice": "Calexico", "votes": 100}, + {"choice": "Fergie", "votes": 900}, + {"choice": "The Decemberists", "votes": 500}, ] - formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') + formset = ChoiceFormSet(initial=initial, auto_id=False, prefix="choices") self.assertHTMLEqual( - '\n'.join(form.as_ul() for form in formset.forms), + "\n".join(form.as_ul() for form in formset.forms), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li> <li>Votes: <input type="number" name="choices-0-votes" value="100"></li> <li>Order: <input type="number" name="choices-0-ORDER" value="1"></li> @@ -745,43 +813,48 @@ class FormsFormsetTestCase(SimpleTestCase): <li>Choice: <input type="text" name="choices-3-choice"></li> <li>Votes: <input type="number" name="choices-3-votes"></li> <li>Order: <input type="number" name="choices-3-ORDER"></li> -<li>Delete: <input type="checkbox" name="choices-3-DELETE"></li>""" +<li>Delete: <input type="checkbox" name="choices-3-DELETE"></li>""", ) # Let's delete Fergie, and put The Decemberists ahead of Calexico. data = { - 'choices-TOTAL_FORMS': '4', # the number of forms rendered - 'choices-INITIAL_FORMS': '3', # the number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', - 'choices-0-ORDER': '1', - 'choices-0-DELETE': '', - 'choices-1-choice': 'Fergie', - 'choices-1-votes': '900', - 'choices-1-ORDER': '2', - 'choices-1-DELETE': 'on', - 'choices-2-choice': 'The Decemberists', - 'choices-2-votes': '500', - 'choices-2-ORDER': '0', - 'choices-2-DELETE': '', - 'choices-3-choice': '', - 'choices-3-votes': '', - 'choices-3-ORDER': '', - 'choices-3-DELETE': '', + "choices-TOTAL_FORMS": "4", # the number of forms rendered + "choices-INITIAL_FORMS": "3", # the number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", + "choices-0-ORDER": "1", + "choices-0-DELETE": "", + "choices-1-choice": "Fergie", + "choices-1-votes": "900", + "choices-1-ORDER": "2", + "choices-1-DELETE": "on", + "choices-2-choice": "The Decemberists", + "choices-2-votes": "500", + "choices-2-ORDER": "0", + "choices-2-DELETE": "", + "choices-3-choice": "", + "choices-3-votes": "", + "choices-3-ORDER": "", + "choices-3-DELETE": "", } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertEqual( [form.cleaned_data for form in formset.ordered_forms], [ - {'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': 'The Decemberists'}, - {'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': 'Calexico'}, + { + "votes": 500, + "DELETE": False, + "ORDER": 0, + "choice": "The Decemberists", + }, + {"votes": 100, "DELETE": False, "ORDER": 1, "choice": "Calexico"}, ], ) self.assertEqual( [form.cleaned_data for form in formset.deleted_forms], - [{'votes': 900, 'DELETE': True, 'ORDER': 2, 'choice': 'Fergie'}] + [{"votes": 900, "DELETE": True, "ORDER": 2, "choice": "Fergie"}], ) def test_invalid_deleted_form_with_ordering(self): @@ -789,15 +862,19 @@ class FormsFormsetTestCase(SimpleTestCase): Can get ordered_forms from a valid formset even if a deleted form would have been invalid. """ - FavoriteDrinkFormset = formset_factory(form=FavoriteDrinkForm, can_delete=True, can_order=True) - formset = FavoriteDrinkFormset({ - 'form-0-name': '', - 'form-0-DELETE': 'on', # no name! - 'form-TOTAL_FORMS': 1, - 'form-INITIAL_FORMS': 1, - 'form-MIN_NUM_FORMS': 0, - 'form-MAX_NUM_FORMS': 1 - }) + FavoriteDrinkFormset = formset_factory( + form=FavoriteDrinkForm, can_delete=True, can_order=True + ) + formset = FavoriteDrinkFormset( + { + "form-0-name": "", + "form-0-DELETE": "on", # no name! + "form-TOTAL_FORMS": 1, + "form-INITIAL_FORMS": 1, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1, + } + ) self.assertTrue(formset.is_valid()) self.assertEqual(formset.ordered_forms, []) @@ -808,22 +885,22 @@ class FormsFormsetTestCase(SimpleTestCase): """ # Start out with a some duplicate data. data = { - 'drinks-TOTAL_FORMS': '2', # the number of forms rendered - 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data - 'drinks-MIN_NUM_FORMS': '0', # min number of forms - 'drinks-MAX_NUM_FORMS': '0', # max number of forms - 'drinks-0-name': 'Gin and Tonic', - 'drinks-1-name': 'Gin and Tonic', + "drinks-TOTAL_FORMS": "2", # the number of forms rendered + "drinks-INITIAL_FORMS": "0", # the number of forms with initial data + "drinks-MIN_NUM_FORMS": "0", # min number of forms + "drinks-MAX_NUM_FORMS": "0", # max number of forms + "drinks-0-name": "Gin and Tonic", + "drinks-1-name": "Gin and Tonic", } - formset = FavoriteDrinksFormSet(data, prefix='drinks') + formset = FavoriteDrinksFormSet(data, prefix="drinks") self.assertFalse(formset.is_valid()) # Any errors raised by formset.clean() are available via the # formset.non_form_errors() method. for error in formset.non_form_errors(): - self.assertEqual(str(error), 'You may only specify a drink once.') + self.assertEqual(str(error), "You may only specify a drink once.") # The valid case still works. - data['drinks-1-name'] = 'Bloody Mary' - formset = FavoriteDrinksFormSet(data, prefix='drinks') + data["drinks-1-name"] = "Bloody Mary" + formset = FavoriteDrinksFormSet(data, prefix="drinks") self.assertTrue(formset.is_valid()) self.assertEqual(formset.non_form_errors(), []) @@ -834,38 +911,44 @@ class FormsFormsetTestCase(SimpleTestCase): LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3) formset = LimitedFavoriteDrinkFormSet() self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> <td><input type="text" name="form-0-name" id="id_form-0-name"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> <td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr> <tr><th><label for="id_form-2-name">Name:</label></th> -<td><input type="text" name="form-2-name" id="id_form-2-name"></td></tr>""" +<td><input type="text" name="form-2-name" id="id_form-2-name"></td></tr>""", ) # If max_num is 0 then no form is rendered at all. - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=3, max_num=0 + ) formset = LimitedFavoriteDrinkFormSet() self.assertEqual(formset.forms, []) def test_limited_max_forms_two(self): - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=5, max_num=2) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=5, max_num=2 + ) formset = LimitedFavoriteDrinkFormSet() self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td> <input type="text" name="form-0-name" id="id_form-0-name"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> -<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""" +<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""", ) def test_limiting_extra_lest_than_max_num(self): """max_num has no effect when extra is less than max_num.""" - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=1, max_num=2 + ) formset = LimitedFavoriteDrinkFormSet() self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> -<td><input type="text" name="form-0-name" id="id_form-0-name"></td></tr>""" +<td><input type="text" name="form-0-name" id="id_form-0-name"></td></tr>""", ) def test_max_num_with_initial_data(self): @@ -873,13 +956,13 @@ class FormsFormsetTestCase(SimpleTestCase): # number of forms only controlled by the value of the initial and extra # parameters. LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1) - formset = LimitedFavoriteDrinkFormSet(initial=[{'name': 'Fernet and Coke'}]) + formset = LimitedFavoriteDrinkFormSet(initial=[{"name": "Fernet and Coke"}]) self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> <td><input type="text" name="form-0-name" value="Fernet and Coke" id="id_form-0-name"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> -<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""" +<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""", ) def test_max_num_zero(self): @@ -887,24 +970,28 @@ class FormsFormsetTestCase(SimpleTestCase): If max_num is 0 then no form is rendered at all, regardless of extra, unless initial data is present. """ - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=0) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=1, max_num=0 + ) formset = LimitedFavoriteDrinkFormSet() self.assertEqual(formset.forms, []) def test_max_num_zero_with_initial(self): # initial trumps max_num initial = [ - {'name': 'Fernet and Coke'}, - {'name': 'Bloody Mary'}, + {"name": "Fernet and Coke"}, + {"name": "Bloody Mary"}, ] - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=0) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=1, max_num=0 + ) formset = LimitedFavoriteDrinkFormSet(initial=initial) self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> <td><input id="id_form-0-name" name="form-0-name" type="text" value="Fernet and Coke"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> -<td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary"></td></tr>""" +<td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary"></td></tr>""", ) def test_more_initial_than_max_num(self): @@ -913,42 +1000,44 @@ class FormsFormsetTestCase(SimpleTestCase): displayed (but no extra forms). """ initial = [ - {'name': 'Gin Tonic'}, - {'name': 'Bloody Mary'}, - {'name': 'Jack and Coke'}, + {"name": "Gin Tonic"}, + {"name": "Bloody Mary"}, + {"name": "Jack and Coke"}, ] - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=1, max_num=2 + ) formset = LimitedFavoriteDrinkFormSet(initial=initial) self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> <td><input id="id_form-0-name" name="form-0-name" type="text" value="Gin Tonic"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> <td><input id="id_form-1-name" name="form-1-name" type="text" value="Bloody Mary"></td></tr> <tr><th><label for="id_form-2-name">Name:</label></th> -<td><input id="id_form-2-name" name="form-2-name" type="text" value="Jack and Coke"></td></tr>""" +<td><input id="id_form-2-name" name="form-2-name" type="text" value="Jack and Coke"></td></tr>""", ) def test_default_absolute_max(self): # absolute_max defaults to 2 * DEFAULT_MAX_NUM if max_num is None. data = { - 'form-TOTAL_FORMS': 2001, - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '0', + "form-TOTAL_FORMS": 2001, + "form-INITIAL_FORMS": "0", + "form-MAX_NUM_FORMS": "0", } formset = FavoriteDrinksFormSet(data=data) self.assertIs(formset.is_valid(), False) self.assertEqual( formset.non_form_errors(), - ['Please submit at most 1000 forms.'], + ["Please submit at most 1000 forms."], ) self.assertEqual(formset.absolute_max, 2000) def test_absolute_max(self): data = { - 'form-TOTAL_FORMS': '2001', - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '0', + "form-TOTAL_FORMS": "2001", + "form-INITIAL_FORMS": "0", + "form-MAX_NUM_FORMS": "0", } AbsoluteMaxFavoriteDrinksFormSet = formset_factory( FavoriteDrinkForm, @@ -958,20 +1047,20 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertIs(formset.is_valid(), True) self.assertEqual(len(formset.forms), 2001) # absolute_max provides a hard limit. - data['form-TOTAL_FORMS'] = '3001' + data["form-TOTAL_FORMS"] = "3001" formset = AbsoluteMaxFavoriteDrinksFormSet(data=data) self.assertIs(formset.is_valid(), False) self.assertEqual(len(formset.forms), 3000) self.assertEqual( formset.non_form_errors(), - ['Please submit at most 1000 forms.'], + ["Please submit at most 1000 forms."], ) def test_absolute_max_with_max_num(self): data = { - 'form-TOTAL_FORMS': '1001', - 'form-INITIAL_FORMS': '0', - 'form-MAX_NUM_FORMS': '0', + "form-TOTAL_FORMS": "1001", + "form-INITIAL_FORMS": "0", + "form-MAX_NUM_FORMS": "0", } LimitedFavoriteDrinksFormSet = formset_factory( FavoriteDrinkForm, @@ -983,7 +1072,7 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(len(formset.forms), 1000) self.assertEqual( formset.non_form_errors(), - ['Please submit at most 30 forms.'], + ["Please submit at most 30 forms."], ) def test_absolute_max_invalid(self): @@ -998,14 +1087,16 @@ class FormsFormsetTestCase(SimpleTestCase): One form from initial and extra=3 with max_num=2 results in the one initial form and one extra. """ - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=2) - formset = LimitedFavoriteDrinkFormSet(initial=[{'name': 'Gin Tonic'}]) + LimitedFavoriteDrinkFormSet = formset_factory( + FavoriteDrinkForm, extra=3, max_num=2 + ) + formset = LimitedFavoriteDrinkFormSet(initial=[{"name": "Gin Tonic"}]) self.assertHTMLEqual( - '\n'.join(str(form) for form in formset.forms), + "\n".join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th> <td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name"></td></tr> <tr><th><label for="id_form-1-name">Name:</label></th> -<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""" +<td><input type="text" name="form-1-name" id="id_form-1-name"></td></tr>""", ) def test_management_form_field_names(self): @@ -1023,34 +1114,36 @@ class FormsFormsetTestCase(SimpleTestCase): def test_management_form_prefix(self): """The management form has the correct prefix.""" formset = FavoriteDrinksFormSet() - self.assertEqual(formset.management_form.prefix, 'form') + self.assertEqual(formset.management_form.prefix, "form") data = { - 'form-TOTAL_FORMS': '2', - 'form-INITIAL_FORMS': '0', - 'form-MIN_NUM_FORMS': '0', - 'form-MAX_NUM_FORMS': '0', + "form-TOTAL_FORMS": "2", + "form-INITIAL_FORMS": "0", + "form-MIN_NUM_FORMS": "0", + "form-MAX_NUM_FORMS": "0", } formset = FavoriteDrinksFormSet(data=data) - self.assertEqual(formset.management_form.prefix, 'form') + self.assertEqual(formset.management_form.prefix, "form") formset = FavoriteDrinksFormSet(initial={}) - self.assertEqual(formset.management_form.prefix, 'form') + self.assertEqual(formset.management_form.prefix, "form") def test_non_form_errors(self): data = { - 'drinks-TOTAL_FORMS': '2', # the number of forms rendered - 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data - 'drinks-MIN_NUM_FORMS': '0', # min number of forms - 'drinks-MAX_NUM_FORMS': '0', # max number of forms - 'drinks-0-name': 'Gin and Tonic', - 'drinks-1-name': 'Gin and Tonic', + "drinks-TOTAL_FORMS": "2", # the number of forms rendered + "drinks-INITIAL_FORMS": "0", # the number of forms with initial data + "drinks-MIN_NUM_FORMS": "0", # min number of forms + "drinks-MAX_NUM_FORMS": "0", # max number of forms + "drinks-0-name": "Gin and Tonic", + "drinks-1-name": "Gin and Tonic", } - formset = FavoriteDrinksFormSet(data, prefix='drinks') + formset = FavoriteDrinksFormSet(data, prefix="drinks") self.assertFalse(formset.is_valid()) - self.assertEqual(formset.non_form_errors(), ['You may only specify a drink once.']) + self.assertEqual( + formset.non_form_errors(), ["You may only specify a drink once."] + ) self.assertEqual( str(formset.non_form_errors()), '<ul class="errorlist nonform"><li>' - 'You may only specify a drink once.</li></ul>', + "You may only specify a drink once.</li></ul>", ) def test_formset_iteration(self): @@ -1093,21 +1186,23 @@ class FormsFormsetTestCase(SimpleTestCase): """ Formset works with SplitDateTimeField(initial=datetime.datetime.now). """ + class SplitDateTimeForm(Form): when = SplitDateTimeField(initial=datetime.datetime.now) SplitDateTimeFormSet = formset_factory(SplitDateTimeForm) data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', - 'form-0-when_0': '1904-06-16', - 'form-0-when_1': '15:51:33', + "form-TOTAL_FORMS": "1", + "form-INITIAL_FORMS": "0", + "form-0-when_0": "1904-06-16", + "form-0-when_1": "15:51:33", } formset = SplitDateTimeFormSet(data) self.assertTrue(formset.is_valid()) def test_formset_error_class(self): """Formset's forms use the formset's error_class.""" + class CustomErrorList(ErrorList): pass @@ -1116,6 +1211,7 @@ class FormsFormsetTestCase(SimpleTestCase): def test_formset_calls_forms_is_valid(self): """Formsets call is_valid() on each form.""" + class AnotherChoice(Choice): def is_valid(self): self.is_valid_called = True @@ -1123,14 +1219,14 @@ class FormsFormsetTestCase(SimpleTestCase): AnotherChoiceFormSet = formset_factory(AnotherChoice) data = { - 'choices-TOTAL_FORMS': '1', # number of forms rendered - 'choices-INITIAL_FORMS': '0', # number of forms with initial data - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '0', # max number of forms - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', + "choices-TOTAL_FORMS": "1", # number of forms rendered + "choices-INITIAL_FORMS": "0", # number of forms with initial data + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "0", # max number of forms + "choices-0-choice": "Calexico", + "choices-0-votes": "100", } - formset = AnotherChoiceFormSet(data, auto_id=False, prefix='choices') + formset = AnotherChoiceFormSet(data, auto_id=False, prefix="choices") self.assertTrue(formset.is_valid()) self.assertTrue(all(form.is_valid_called for form in formset.forms)) @@ -1144,20 +1240,20 @@ class FormsFormsetTestCase(SimpleTestCase): # someone fiddles with the mgmt form data... formset = ChoiceFormSet( { - 'choices-TOTAL_FORMS': '4', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '4', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', - 'choices-2-choice': 'Two', - 'choices-2-votes': '2', - 'choices-3-choice': 'Three', - 'choices-3-votes': '3', + "choices-TOTAL_FORMS": "4", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "4", + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", + "choices-2-choice": "Two", + "choices-2-votes": "2", + "choices-3-choice": "Three", + "choices-3-votes": "3", }, - prefix='choices', + prefix="choices", ) # But we still only instantiate 3 forms self.assertEqual(len(formset.forms), 3) @@ -1176,20 +1272,20 @@ class FormsFormsetTestCase(SimpleTestCase): ChoiceFormSet = formset_factory(Choice, max_num=4) formset = ChoiceFormSet( { - 'choices-TOTAL_FORMS': '4', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', # min number of forms - 'choices-MAX_NUM_FORMS': '4', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', - 'choices-2-choice': 'Two', - 'choices-2-votes': '2', - 'choices-3-choice': 'Three', - 'choices-3-votes': '3', + "choices-TOTAL_FORMS": "4", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", # min number of forms + "choices-MAX_NUM_FORMS": "4", + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", + "choices-2-choice": "Two", + "choices-2-votes": "2", + "choices-3-choice": "Three", + "choices-3-votes": "3", }, - prefix='choices', + prefix="choices", ) # Four forms are instantiated and no exception is raised self.assertEqual(len(formset.forms), 4) @@ -1201,44 +1297,47 @@ class FormsFormsetTestCase(SimpleTestCase): If non_form_errors() is called without calling is_valid() first, it should ensure that full_clean() is called. """ + class BaseCustomFormSet(BaseFormSet): def clean(self): raise ValidationError("This is a non-form error") ChoiceFormSet = formset_factory(Choice, formset=BaseCustomFormSet) data = { - 'choices-TOTAL_FORMS': '1', - 'choices-INITIAL_FORMS': '0', + "choices-TOTAL_FORMS": "1", + "choices-INITIAL_FORMS": "0", } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertIsInstance(formset.non_form_errors(), ErrorList) - self.assertEqual(list(formset.non_form_errors()), ['This is a non-form error']) + self.assertEqual(list(formset.non_form_errors()), ["This is a non-form error"]) def test_validate_max_ignores_forms_marked_for_deletion(self): class CheckForm(Form): field = IntegerField() data = { - 'check-TOTAL_FORMS': '2', - 'check-INITIAL_FORMS': '0', - 'check-MAX_NUM_FORMS': '1', - 'check-0-field': '200', - 'check-0-DELETE': '', - 'check-1-field': '50', - 'check-1-DELETE': 'on', + "check-TOTAL_FORMS": "2", + "check-INITIAL_FORMS": "0", + "check-MAX_NUM_FORMS": "1", + "check-0-field": "200", + "check-0-DELETE": "", + "check-1-field": "50", + "check-1-DELETE": "on", } - CheckFormSet = formset_factory(CheckForm, max_num=1, validate_max=True, can_delete=True) - formset = CheckFormSet(data, prefix='check') + CheckFormSet = formset_factory( + CheckForm, max_num=1, validate_max=True, can_delete=True + ) + formset = CheckFormSet(data, prefix="check") self.assertTrue(formset.is_valid()) def test_formset_total_error_count(self): """A valid formset should have 0 total errors.""" data = [ # formset_data, expected error count - ([('Calexico', '100')], 0), - ([('Calexico', '')], 1), - ([('', 'invalid')], 2), - ([('Calexico', '100'), ('Calexico', '')], 1), - ([('Calexico', ''), ('Calexico', '')], 2), + ([("Calexico", "100")], 0), + ([("Calexico", "")], 1), + ([("", "invalid")], 2), + ([("Calexico", "100"), ("Calexico", "")], 1), + ([("Calexico", ""), ("Calexico", "")], 2), ] for formset_data, expected_error_count in data: formset = self.make_choiceformset(formset_data) @@ -1246,32 +1345,32 @@ class FormsFormsetTestCase(SimpleTestCase): def test_formset_total_error_count_with_non_form_errors(self): data = { - 'choices-TOTAL_FORMS': '2', # the number of forms rendered - 'choices-INITIAL_FORMS': '0', # the number of forms with initial data - 'choices-MAX_NUM_FORMS': '2', # max number of forms - should be ignored - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', + "choices-TOTAL_FORMS": "2", # the number of forms rendered + "choices-INITIAL_FORMS": "0", # the number of forms with initial data + "choices-MAX_NUM_FORMS": "2", # max number of forms - should be ignored + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", } ChoiceFormSet = formset_factory(Choice, extra=1, max_num=1, validate_max=True) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertEqual(formset.total_error_count(), 1) - data['choices-1-votes'] = '' - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + data["choices-1-votes"] = "" + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertEqual(formset.total_error_count(), 2) def test_html_safe(self): formset = self.make_choiceformset() - self.assertTrue(hasattr(formset, '__html__')) + self.assertTrue(hasattr(formset, "__html__")) self.assertEqual(str(formset), formset.__html__()) def test_can_delete_extra_formset_forms(self): ChoiceFormFormset = formset_factory(form=Choice, can_delete=True, extra=2) formset = ChoiceFormFormset() self.assertEqual(len(formset), 2) - self.assertIn('DELETE', formset.forms[0].fields) - self.assertIn('DELETE', formset.forms[1].fields) + self.assertIn("DELETE", formset.forms[0].fields) + self.assertIn("DELETE", formset.forms[1].fields) def test_disable_delete_extra_formset_forms(self): ChoiceFormFormset = formset_factory( @@ -1282,31 +1381,37 @@ class FormsFormsetTestCase(SimpleTestCase): ) formset = ChoiceFormFormset() self.assertEqual(len(formset), 2) - self.assertNotIn('DELETE', formset.forms[0].fields) - self.assertNotIn('DELETE', formset.forms[1].fields) + self.assertNotIn("DELETE", formset.forms[0].fields) + self.assertNotIn("DELETE", formset.forms[1].fields) - formset = ChoiceFormFormset(initial=[{'choice': 'Zero', 'votes': '1'}]) + formset = ChoiceFormFormset(initial=[{"choice": "Zero", "votes": "1"}]) self.assertEqual(len(formset), 3) - self.assertIn('DELETE', formset.forms[0].fields) - self.assertNotIn('DELETE', formset.forms[1].fields) - self.assertNotIn('DELETE', formset.forms[2].fields) + self.assertIn("DELETE", formset.forms[0].fields) + self.assertNotIn("DELETE", formset.forms[1].fields) + self.assertNotIn("DELETE", formset.forms[2].fields) - formset = ChoiceFormFormset(data={ - 'form-0-choice': 'Zero', - 'form-0-votes': '0', - 'form-0-DELETE': 'on', - 'form-1-choice': 'One', - 'form-1-votes': '1', - 'form-2-choice': '', - 'form-2-votes': '', - 'form-TOTAL_FORMS': '3', - 'form-INITIAL_FORMS': '1', - }, initial=[{'choice': 'Zero', 'votes': '1'}]) - self.assertEqual(formset.cleaned_data, [ - {'choice': 'Zero', 'votes': 0, 'DELETE': True}, - {'choice': 'One', 'votes': 1}, - {}, - ]) + formset = ChoiceFormFormset( + data={ + "form-0-choice": "Zero", + "form-0-votes": "0", + "form-0-DELETE": "on", + "form-1-choice": "One", + "form-1-votes": "1", + "form-2-choice": "", + "form-2-votes": "", + "form-TOTAL_FORMS": "3", + "form-INITIAL_FORMS": "1", + }, + initial=[{"choice": "Zero", "votes": "1"}], + ) + self.assertEqual( + formset.cleaned_data, + [ + {"choice": "Zero", "votes": 0, "DELETE": True}, + {"choice": "One", "votes": 1}, + {}, + ], + ) self.assertIs(formset._should_delete_form(formset.forms[0]), True) self.assertIs(formset._should_delete_form(formset.forms[1]), False) self.assertIs(formset._should_delete_form(formset.forms[2]), False) @@ -1317,18 +1422,19 @@ class FormsFormsetTestCase(SimpleTestCase): and ErrorList. """ from django.forms.renderers import Jinja2 + renderer = Jinja2() data = { - 'choices-TOTAL_FORMS': '2', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '', - 'choices-1-choice': 'One', - 'choices-1-votes': '', + "choices-TOTAL_FORMS": "2", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", + "choices-0-choice": "Zero", + "choices-0-votes": "", + "choices-1-choice": "One", + "choices-1-votes": "", } ChoiceFormSet = formset_factory(Choice, renderer=renderer) - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertEqual(formset.renderer, renderer) self.assertEqual(formset.forms[0].renderer, renderer) self.assertEqual(formset.management_form.renderer, renderer) @@ -1336,16 +1442,16 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(formset.empty_form.renderer, renderer) def test_repr(self): - valid_formset = self.make_choiceformset([('test', 1)]) + valid_formset = self.make_choiceformset([("test", 1)]) valid_formset.full_clean() - invalid_formset = self.make_choiceformset([('test', '')]) + invalid_formset = self.make_choiceformset([("test", "")]) invalid_formset.full_clean() partially_invalid_formset = self.make_choiceformset( - [('test', '1'), ('test', '')], + [("test", "1"), ("test", "")], ) partially_invalid_formset.full_clean() invalid_formset_non_form_errors_only = self.make_choiceformset( - [('test', '')], + [("test", "")], formset_class=ChoiceFormsetWithNonFormError, ) invalid_formset_non_form_errors_only.full_clean() @@ -1353,31 +1459,31 @@ class FormsFormsetTestCase(SimpleTestCase): cases = [ ( self.make_choiceformset(), - '<ChoiceFormSet: bound=False valid=Unknown total_forms=1>', + "<ChoiceFormSet: bound=False valid=Unknown total_forms=1>", ), ( self.make_choiceformset( formset_class=formset_factory(Choice, extra=10), ), - '<ChoiceFormSet: bound=False valid=Unknown total_forms=10>', + "<ChoiceFormSet: bound=False valid=Unknown total_forms=10>", ), ( self.make_choiceformset([]), - '<ChoiceFormSet: bound=True valid=Unknown total_forms=0>', + "<ChoiceFormSet: bound=True valid=Unknown total_forms=0>", ), ( - self.make_choiceformset([('test', 1)]), - '<ChoiceFormSet: bound=True valid=Unknown total_forms=1>', + self.make_choiceformset([("test", 1)]), + "<ChoiceFormSet: bound=True valid=Unknown total_forms=1>", ), - (valid_formset, '<ChoiceFormSet: bound=True valid=True total_forms=1>'), - (invalid_formset, '<ChoiceFormSet: bound=True valid=False total_forms=1>'), + (valid_formset, "<ChoiceFormSet: bound=True valid=True total_forms=1>"), + (invalid_formset, "<ChoiceFormSet: bound=True valid=False total_forms=1>"), ( partially_invalid_formset, - '<ChoiceFormSet: bound=True valid=False total_forms=2>', + "<ChoiceFormSet: bound=True valid=False total_forms=2>", ), ( invalid_formset_non_form_errors_only, - '<ChoiceFormsetWithNonFormError: bound=True valid=False total_forms=1>', + "<ChoiceFormsetWithNonFormError: bound=True valid=False total_forms=1>", ), ] for formset, expected_repr in cases: @@ -1385,8 +1491,8 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(repr(formset), expected_repr) def test_repr_do_not_trigger_validation(self): - formset = self.make_choiceformset([('test', 1)]) - with mock.patch.object(formset, 'full_clean') as mocked_full_clean: + formset = self.make_choiceformset([("test", 1)]) + with mock.patch.object(formset, "full_clean") as mocked_full_clean: repr(formset) mocked_full_clean.assert_not_called() formset.is_valid() @@ -1401,14 +1507,14 @@ class Jinja2FormsFormsetTestCase(FormsFormsetTestCase): class FormsetAsTagTests(SimpleTestCase): def setUp(self): data = { - 'choices-TOTAL_FORMS': '1', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', - 'choices-MAX_NUM_FORMS': '0', - 'choices-0-choice': 'Calexico', - 'choices-0-votes': '100', + "choices-TOTAL_FORMS": "1", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", + "choices-MAX_NUM_FORMS": "0", + "choices-0-choice": "Calexico", + "choices-0-votes": "100", } - self.formset = ChoiceFormSet(data, auto_id=False, prefix='choices') + self.formset = ChoiceFormSet(data, auto_id=False, prefix="choices") self.management_form_html = ( '<input type="hidden" name="choices-TOTAL_FORMS" value="1">' '<input type="hidden" name="choices-INITIAL_FORMS" value="0">' @@ -1419,30 +1525,33 @@ class FormsetAsTagTests(SimpleTestCase): def test_as_table(self): self.assertHTMLEqual( self.formset.as_table(), - self.management_form_html + ( - '<tr><th>Choice:</th><td>' + self.management_form_html + + ( + "<tr><th>Choice:</th><td>" '<input type="text" name="choices-0-choice" value="Calexico"></td></tr>' - '<tr><th>Votes:</th><td>' + "<tr><th>Votes:</th><td>" '<input type="number" name="choices-0-votes" value="100"></td></tr>' - ) + ), ) def test_as_p(self): self.assertHTMLEqual( self.formset.as_p(), - self.management_form_html + ( + self.management_form_html + + ( '<p>Choice: <input type="text" name="choices-0-choice" value="Calexico"></p>' '<p>Votes: <input type="number" name="choices-0-votes" value="100"></p>' - ) + ), ) def test_as_ul(self): self.assertHTMLEqual( self.formset.as_ul(), - self.management_form_html + ( + self.management_form_html + + ( '<li>Choice: <input type="text" name="choices-0-choice" value="Calexico"></li>' '<li>Votes: <input type="number" name="choices-0-votes" value="100"></li>' - ) + ), ) @@ -1466,9 +1575,9 @@ class TestIsBoundBehavior(SimpleTestCase): self.assertEqual( formset.non_form_errors(), [ - 'ManagementForm data is missing or has been tampered with. ' - 'Missing fields: form-TOTAL_FORMS, form-INITIAL_FORMS. ' - 'You may need to file a bug report if the issue persists.', + "ManagementForm data is missing or has been tampered with. " + "Missing fields: form-TOTAL_FORMS, form-INITIAL_FORMS. " + "You may need to file a bug report if the issue persists.", ], ) self.assertEqual(formset.errors, []) @@ -1477,29 +1586,29 @@ class TestIsBoundBehavior(SimpleTestCase): str(formset), '<tr><td colspan="2">' '<ul class="errorlist nonfield">' - '<li>(Hidden field TOTAL_FORMS) This field is required.</li>' - '<li>(Hidden field INITIAL_FORMS) This field is required.</li>' - '</ul>' + "<li>(Hidden field TOTAL_FORMS) This field is required.</li>" + "<li>(Hidden field INITIAL_FORMS) This field is required.</li>" + "</ul>" '<input type="hidden" name="form-TOTAL_FORMS" id="id_form-TOTAL_FORMS">' '<input type="hidden" name="form-INITIAL_FORMS" id="id_form-INITIAL_FORMS">' '<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">' '<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">' - '</td></tr>\n' + "</td></tr>\n", ) def test_management_form_invalid_data(self): data = { - 'form-TOTAL_FORMS': 'two', - 'form-INITIAL_FORMS': 'one', + "form-TOTAL_FORMS": "two", + "form-INITIAL_FORMS": "one", } formset = ArticleFormSet(data) self.assertIs(formset.is_valid(), False) self.assertEqual( formset.non_form_errors(), [ - 'ManagementForm data is missing or has been tampered with. ' - 'Missing fields: form-TOTAL_FORMS, form-INITIAL_FORMS. ' - 'You may need to file a bug report if the issue persists.', + "ManagementForm data is missing or has been tampered with. " + "Missing fields: form-TOTAL_FORMS, form-INITIAL_FORMS. " + "You may need to file a bug report if the issue persists.", ], ) self.assertEqual(formset.errors, []) @@ -1508,26 +1617,28 @@ class TestIsBoundBehavior(SimpleTestCase): str(formset), '<tr><td colspan="2">' '<ul class="errorlist nonfield">' - '<li>(Hidden field TOTAL_FORMS) Enter a whole number.</li>' - '<li>(Hidden field INITIAL_FORMS) Enter a whole number.</li>' - '</ul>' + "<li>(Hidden field TOTAL_FORMS) Enter a whole number.</li>" + "<li>(Hidden field INITIAL_FORMS) Enter a whole number.</li>" + "</ul>" '<input type="hidden" name="form-TOTAL_FORMS" value="two" id="id_form-TOTAL_FORMS">' '<input type="hidden" name="form-INITIAL_FORMS" value="one" id="id_form-INITIAL_FORMS">' '<input type="hidden" name="form-MIN_NUM_FORMS" id="id_form-MIN_NUM_FORMS">' '<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS">' - '</td></tr>\n', + "</td></tr>\n", ) def test_customize_management_form_error(self): - formset = ArticleFormSet({}, error_messages={'missing_management_form': 'customized'}) + formset = ArticleFormSet( + {}, error_messages={"missing_management_form": "customized"} + ) self.assertIs(formset.is_valid(), False) - self.assertEqual(formset.non_form_errors(), ['customized']) + self.assertEqual(formset.non_form_errors(), ["customized"]) self.assertEqual(formset.errors, []) def test_with_management_data_attrs_work_fine(self): data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', + "form-TOTAL_FORMS": "1", + "form-INITIAL_FORMS": "0", } formset = ArticleFormSet(data) self.assertEqual(0, formset.initial_form_count()) @@ -1540,30 +1651,29 @@ class TestIsBoundBehavior(SimpleTestCase): def test_form_errors_are_caught_by_formset(self): data = { - 'form-TOTAL_FORMS': '2', - 'form-INITIAL_FORMS': '0', - 'form-0-title': 'Test', - 'form-0-pub_date': '1904-06-16', - 'form-1-title': 'Test', - 'form-1-pub_date': '', # <-- this date is missing but required + "form-TOTAL_FORMS": "2", + "form-INITIAL_FORMS": "0", + "form-0-title": "Test", + "form-0-pub_date": "1904-06-16", + "form-1-title": "Test", + "form-1-pub_date": "", # <-- this date is missing but required } formset = ArticleFormSet(data) self.assertFalse(formset.is_valid()) - self.assertEqual([{}, {'pub_date': ['This field is required.']}], formset.errors) + self.assertEqual( + [{}, {"pub_date": ["This field is required."]}], formset.errors + ) def test_empty_forms_are_unbound(self): data = { - 'form-TOTAL_FORMS': '1', - 'form-INITIAL_FORMS': '0', - 'form-0-title': 'Test', - 'form-0-pub_date': '1904-06-16', + "form-TOTAL_FORMS": "1", + "form-INITIAL_FORMS": "0", + "form-0-title": "Test", + "form-0-pub_date": "1904-06-16", } unbound_formset = ArticleFormSet() bound_formset = ArticleFormSet(data) - empty_forms = [ - unbound_formset.empty_form, - bound_formset.empty_form - ] + empty_forms = [unbound_formset.empty_form, bound_formset.empty_form] # Empty forms should be unbound self.assertFalse(empty_forms[0].is_bound) self.assertFalse(empty_forms[1].is_bound) @@ -1579,17 +1689,24 @@ class TestIsBoundBehavior(TestIsBoundBehavior): class TestEmptyFormSet(SimpleTestCase): def test_empty_formset_is_valid(self): """An empty formset still calls clean()""" + class EmptyFsetWontValidate(BaseFormSet): def clean(self): - raise ValidationError('Clean method called') + raise ValidationError("Clean method called") - EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate) + EmptyFsetWontValidateFormset = formset_factory( + FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate + ) formset = EmptyFsetWontValidateFormset( - data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '0'}, + data={"form-INITIAL_FORMS": "0", "form-TOTAL_FORMS": "0"}, prefix="form", ) formset2 = EmptyFsetWontValidateFormset( - data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '1', 'form-0-name': 'bah'}, + data={ + "form-INITIAL_FORMS": "0", + "form-TOTAL_FORMS": "1", + "form-0-name": "bah", + }, prefix="form", ) self.assertFalse(formset.is_valid()) @@ -1597,33 +1714,36 @@ class TestEmptyFormSet(SimpleTestCase): def test_empty_formset_media(self): """Media is available on empty formset.""" + class MediaForm(Form): class Media: - js = ('some-file.js',) - self.assertIn('some-file.js', str(formset_factory(MediaForm, extra=0)().media)) + js = ("some-file.js",) + + self.assertIn("some-file.js", str(formset_factory(MediaForm, extra=0)().media)) def test_empty_formset_is_multipart(self): """is_multipart() works with an empty formset.""" + class FileForm(Form): file = FileField() + self.assertTrue(formset_factory(FileForm, extra=0)().is_multipart()) class AllValidTests(SimpleTestCase): - def test_valid(self): data = { - 'choices-TOTAL_FORMS': '2', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '0', - 'choices-1-choice': 'One', - 'choices-1-votes': '1', + "choices-TOTAL_FORMS": "2", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", + "choices-0-choice": "Zero", + "choices-0-votes": "0", + "choices-1-choice": "One", + "choices-1-votes": "1", } ChoiceFormSet = formset_factory(Choice) - formset1 = ChoiceFormSet(data, auto_id=False, prefix='choices') - formset2 = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset1 = ChoiceFormSet(data, auto_id=False, prefix="choices") + formset2 = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertIs(all_valid((formset1, formset2)), True) expected_errors = [{}, {}] self.assertEqual(formset1._errors, expected_errors) @@ -1632,18 +1752,21 @@ class AllValidTests(SimpleTestCase): def test_invalid(self): """all_valid() validates all forms, even when some are invalid.""" data = { - 'choices-TOTAL_FORMS': '2', - 'choices-INITIAL_FORMS': '0', - 'choices-MIN_NUM_FORMS': '0', - 'choices-0-choice': 'Zero', - 'choices-0-votes': '', - 'choices-1-choice': 'One', - 'choices-1-votes': '', + "choices-TOTAL_FORMS": "2", + "choices-INITIAL_FORMS": "0", + "choices-MIN_NUM_FORMS": "0", + "choices-0-choice": "Zero", + "choices-0-votes": "", + "choices-1-choice": "One", + "choices-1-votes": "", } ChoiceFormSet = formset_factory(Choice) - formset1 = ChoiceFormSet(data, auto_id=False, prefix='choices') - formset2 = ChoiceFormSet(data, auto_id=False, prefix='choices') + formset1 = ChoiceFormSet(data, auto_id=False, prefix="choices") + formset2 = ChoiceFormSet(data, auto_id=False, prefix="choices") self.assertIs(all_valid((formset1, formset2)), False) - expected_errors = [{'votes': ['This field is required.']}, {'votes': ['This field is required.']}] + expected_errors = [ + {"votes": ["This field is required."]}, + {"votes": ["This field is required."]}, + ] self.assertEqual(formset1._errors, expected_errors) self.assertEqual(formset2._errors, expected_errors) diff --git a/tests/forms_tests/tests/test_i18n.py b/tests/forms_tests/tests/test_i18n.py index 3590147933..777c84e4e4 100644 --- a/tests/forms_tests/tests/test_i18n.py +++ b/tests/forms_tests/tests/test_i18n.py @@ -1,5 +1,11 @@ from django.forms import ( - CharField, ChoiceField, Form, IntegerField, RadioSelect, Select, TextInput, + CharField, + ChoiceField, + Form, + IntegerField, + RadioSelect, + Select, + TextInput, ) from django.test import SimpleTestCase from django.utils import translation @@ -11,96 +17,100 @@ from . import jinja2_tests class FormsI18nTests(SimpleTestCase): def test_lazy_labels(self): class SomeForm(Form): - username = CharField(max_length=10, label=gettext_lazy('username')) + username = CharField(max_length=10, label=gettext_lazy("username")) f = SomeForm() self.assertHTMLEqual( f.as_p(), '<p><label for="id_username">username:</label>' - '<input id="id_username" type="text" name="username" maxlength="10" required></p>' + '<input id="id_username" type="text" name="username" maxlength="10" required></p>', ) # Translations are done at rendering time, so multi-lingual apps can define forms) - with translation.override('de'): + with translation.override("de"): self.assertHTMLEqual( f.as_p(), '<p><label for="id_username">Benutzername:</label>' - '<input id="id_username" type="text" name="username" maxlength="10" required></p>' + '<input id="id_username" type="text" name="username" maxlength="10" required></p>', ) - with translation.override('pl'): + with translation.override("pl"): self.assertHTMLEqual( f.as_p(), '<p><label for="id_username">nazwa u\u017cytkownika:</label>' - '<input id="id_username" type="text" name="username" maxlength="10" required></p>' + '<input id="id_username" type="text" name="username" maxlength="10" required></p>', ) def test_non_ascii_label(self): class SomeForm(Form): - field_1 = CharField(max_length=10, label=gettext_lazy('field_1')) + field_1 = CharField(max_length=10, label=gettext_lazy("field_1")) field_2 = CharField( max_length=10, - label=gettext_lazy('field_2'), - widget=TextInput(attrs={'id': 'field_2_id'}), + label=gettext_lazy("field_2"), + widget=TextInput(attrs={"id": "field_2_id"}), ) f = SomeForm() - self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>') self.assertHTMLEqual( - f['field_1'].legend_tag(), + f["field_1"].label_tag(), '<label for="id_field_1">field_1:</label>' + ) + self.assertHTMLEqual( + f["field_1"].legend_tag(), '<legend for="id_field_1">field_1:</legend>', ) - self.assertHTMLEqual(f['field_2'].label_tag(), '<label for="field_2_id">field_2:</label>') self.assertHTMLEqual( - f['field_2'].legend_tag(), + f["field_2"].label_tag(), '<label for="field_2_id">field_2:</label>' + ) + self.assertHTMLEqual( + f["field_2"].legend_tag(), '<legend for="field_2_id">field_2:</legend>', ) def test_non_ascii_choices(self): class SomeForm(Form): somechoice = ChoiceField( - choices=(('\xc5', 'En tied\xe4'), ('\xf8', 'Mies'), ('\xdf', 'Nainen')), + choices=(("\xc5", "En tied\xe4"), ("\xf8", "Mies"), ("\xdf", "Nainen")), widget=RadioSelect(), - label='\xc5\xf8\xdf', + label="\xc5\xf8\xdf", ) f = SomeForm() self.assertHTMLEqual( f.as_p(), - '<p><label>\xc5\xf8\xdf:</label>' + "<p><label>\xc5\xf8\xdf:</label>" '<div id="id_somechoice">\n' '<div><label for="id_somechoice_0">' '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required> ' - 'En tied\xe4</label></div>\n' + "En tied\xe4</label></div>\n" '<div><label for="id_somechoice_1">' '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required> ' 'Mies</label></div>\n<div><label for="id_somechoice_2">' '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required> ' - 'Nainen</label></div>\n</div></p>' + "Nainen</label></div>\n</div></p>", ) # Translated error messages - with translation.override('ru'): + with translation.override("ru"): f = SomeForm({}) self.assertHTMLEqual( f.as_p(), '<ul class="errorlist"><li>' - '\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c' - '\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n' - '<p><label>\xc5\xf8\xdf:</label>' + "\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c" + "\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n" + "<p><label>\xc5\xf8\xdf:</label>" ' <div id="id_somechoice">\n<div><label for="id_somechoice_0">' '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required> ' - 'En tied\xe4</label></div>\n' + "En tied\xe4</label></div>\n" '<div><label for="id_somechoice_1">' '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required> ' 'Mies</label></div>\n<div><label for="id_somechoice_2">' '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required> ' - 'Nainen</label></div>\n</div></p>' + "Nainen</label></div>\n</div></p>", ) def test_select_translated_text(self): # Deep copying translated text shouldn't raise an error. class CopyForm(Form): - degree = IntegerField(widget=Select(choices=((1, gettext_lazy('test')),))) + degree = IntegerField(widget=Select(choices=((1, gettext_lazy("test")),))) CopyForm() diff --git a/tests/forms_tests/tests/test_input_formats.py b/tests/forms_tests/tests/test_input_formats.py index 7b9da02a0c..3ac28b1b30 100644 --- a/tests/forms_tests/tests/test_input_formats.py +++ b/tests/forms_tests/tests/test_input_formats.py @@ -11,7 +11,7 @@ class LocalizedTimeTests(SimpleTestCase): def setUp(self): # nl/formats.py has customized TIME_INPUT_FORMATS: # ['%H:%M:%S', '%H.%M:%S', '%H.%M', '%H:%M'] - activate('nl') + activate("nl") def tearDown(self): deactivate() @@ -21,18 +21,18 @@ class LocalizedTimeTests(SimpleTestCase): f = forms.TimeField() # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30:05') + result = f.clean("13:30:05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '13:30:05') + self.assertEqual(text, "13:30:05") # Parse a time in a valid, but non-default format, get a parsed result - result = f.clean('13:30') + result = f.clean("13:30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -40,7 +40,7 @@ class LocalizedTimeTests(SimpleTestCase): self.assertEqual(text, "13:30:00") # ISO formats are accepted, even if not specified in formats.py - result = f.clean('13:30:05.000155') + result = f.clean("13:30:05.000155") self.assertEqual(result, time(13, 30, 5, 155)) def test_localized_timeField(self): @@ -48,18 +48,18 @@ class LocalizedTimeTests(SimpleTestCase): f = forms.TimeField(localize=True) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30:05') + result = f.clean("13:30:05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '13:30:05') + self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30') + result = f.clean("13:30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -71,12 +71,12 @@ class LocalizedTimeTests(SimpleTestCase): f = forms.TimeField(input_formats=["%H.%M.%S", "%H.%M"]) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30.05') + result = f.clean("13.30.05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -84,7 +84,7 @@ class LocalizedTimeTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30') + result = f.clean("13.30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -96,12 +96,12 @@ class LocalizedTimeTests(SimpleTestCase): f = forms.TimeField(input_formats=["%H.%M.%S", "%H.%M"], localize=True) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30.05') + result = f.clean("13.30.05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -109,7 +109,7 @@ class LocalizedTimeTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30') + result = f.clean("13.30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -125,18 +125,18 @@ class CustomTimeInputFormatsTests(SimpleTestCase): f = forms.TimeField() # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30:05 PM') + result = f.clean("1:30:05 PM") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '01:30:05 PM') + self.assertEqual(text, "01:30:05 PM") # Parse a time in a valid, but non-default format, get a parsed result - result = f.clean('1:30 PM') + result = f.clean("1:30 PM") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -148,18 +148,18 @@ class CustomTimeInputFormatsTests(SimpleTestCase): f = forms.TimeField(localize=True) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30:05 PM') + result = f.clean("1:30:05 PM") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '01:30:05 PM') + self.assertEqual(text, "01:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('01:30 PM') + result = f.clean("01:30 PM") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -171,12 +171,12 @@ class CustomTimeInputFormatsTests(SimpleTestCase): f = forms.TimeField(input_formats=["%H.%M.%S", "%H.%M"]) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30.05') + result = f.clean("13.30.05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -184,7 +184,7 @@ class CustomTimeInputFormatsTests(SimpleTestCase): self.assertEqual(text, "01:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30') + result = f.clean("13.30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -196,12 +196,12 @@ class CustomTimeInputFormatsTests(SimpleTestCase): f = forms.TimeField(input_formats=["%H.%M.%S", "%H.%M"], localize=True) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30.05') + result = f.clean("13.30.05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -209,7 +209,7 @@ class CustomTimeInputFormatsTests(SimpleTestCase): self.assertEqual(text, "01:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13.30') + result = f.clean("13.30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -223,10 +223,10 @@ class SimpleTimeFormatTests(SimpleTestCase): f = forms.TimeField() # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30:05') + result = f.clean("13:30:05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -234,7 +234,7 @@ class SimpleTimeFormatTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid, but non-default format, get a parsed result - result = f.clean('13:30') + result = f.clean("13:30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -246,10 +246,10 @@ class SimpleTimeFormatTests(SimpleTestCase): f = forms.TimeField() # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM') + f.clean("1:30:05 PM") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30:05') + result = f.clean("13:30:05") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -257,7 +257,7 @@ class SimpleTimeFormatTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('13:30') + result = f.clean("13:30") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -269,10 +269,10 @@ class SimpleTimeFormatTests(SimpleTestCase): f = forms.TimeField(input_formats=["%I:%M:%S %p", "%I:%M %p"]) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30:05 PM') + result = f.clean("1:30:05 PM") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -280,7 +280,7 @@ class SimpleTimeFormatTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30 PM') + result = f.clean("1:30 PM") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -292,10 +292,10 @@ class SimpleTimeFormatTests(SimpleTestCase): f = forms.TimeField(input_formats=["%I:%M:%S %p", "%I:%M %p"], localize=True) # Parse a time in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05') + f.clean("13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30:05 PM') + result = f.clean("1:30:05 PM") self.assertEqual(result, time(13, 30, 5)) # The parsed result does a round trip to the same format @@ -303,7 +303,7 @@ class SimpleTimeFormatTests(SimpleTestCase): self.assertEqual(text, "13:30:05") # Parse a time in a valid format, get a parsed result - result = f.clean('1:30 PM') + result = f.clean("1:30 PM") self.assertEqual(result, time(13, 30, 0)) # The parsed result does a round trip to default format @@ -313,7 +313,7 @@ class SimpleTimeFormatTests(SimpleTestCase): class LocalizedDateTests(SimpleTestCase): def setUp(self): - activate('de') + activate("de") def tearDown(self): deactivate() @@ -323,21 +323,21 @@ class LocalizedDateTests(SimpleTestCase): f = forms.DateField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21/12/2010') + f.clean("21/12/2010") # ISO formats are accepted, even if not specified in formats.py - self.assertEqual(f.clean('2010-12-21'), date(2010, 12, 21)) + self.assertEqual(f.clean("2010-12-21"), date(2010, 12, 21)) # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010') + self.assertEqual(text, "21.12.2010") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('21.12.10') + result = f.clean("21.12.10") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -349,18 +349,18 @@ class LocalizedDateTests(SimpleTestCase): f = forms.DateField(localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21/12/2010') + f.clean("21/12/2010") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010') + self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.10') + result = f.clean("21.12.10") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -372,14 +372,14 @@ class LocalizedDateTests(SimpleTestCase): f = forms.DateField(input_formats=["%m.%d.%Y", "%m-%d-%Y"]) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") with self.assertRaises(ValidationError): - f.clean('21/12/2010') + f.clean("21/12/2010") with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010') + result = f.clean("12.21.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -387,7 +387,7 @@ class LocalizedDateTests(SimpleTestCase): self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010') + result = f.clean("12-21-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -399,14 +399,14 @@ class LocalizedDateTests(SimpleTestCase): f = forms.DateField(input_formats=["%m.%d.%Y", "%m-%d-%Y"], localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") with self.assertRaises(ValidationError): - f.clean('21/12/2010') + f.clean("21/12/2010") with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010') + result = f.clean("12.21.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -414,7 +414,7 @@ class LocalizedDateTests(SimpleTestCase): self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010') + result = f.clean("12-21-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -430,18 +430,18 @@ class CustomDateInputFormatsTests(SimpleTestCase): f = forms.DateField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010') + self.assertEqual(text, "21.12.2010") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('21-12-2010') + result = f.clean("21-12-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -453,18 +453,18 @@ class CustomDateInputFormatsTests(SimpleTestCase): f = forms.DateField(localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010') + self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('21-12-2010') + result = f.clean("21-12-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -476,12 +476,12 @@ class CustomDateInputFormatsTests(SimpleTestCase): f = forms.DateField(input_formats=["%m.%d.%Y", "%m-%d-%Y"]) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010') + result = f.clean("12.21.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -489,7 +489,7 @@ class CustomDateInputFormatsTests(SimpleTestCase): self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010') + result = f.clean("12-21-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -501,12 +501,12 @@ class CustomDateInputFormatsTests(SimpleTestCase): f = forms.DateField(input_formats=["%m.%d.%Y", "%m-%d-%Y"], localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010') + result = f.clean("12.21.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -514,7 +514,7 @@ class CustomDateInputFormatsTests(SimpleTestCase): self.assertEqual(text, "21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010') + result = f.clean("12-21-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -528,10 +528,10 @@ class SimpleDateFormatTests(SimpleTestCase): f = forms.DateField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('2010-12-21') + result = f.clean("2010-12-21") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -539,7 +539,7 @@ class SimpleDateFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('12/21/2010') + result = f.clean("12/21/2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -551,10 +551,10 @@ class SimpleDateFormatTests(SimpleTestCase): f = forms.DateField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('21.12.2010') + f.clean("21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('2010-12-21') + result = f.clean("2010-12-21") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -562,7 +562,7 @@ class SimpleDateFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('12/21/2010') + result = f.clean("12/21/2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -574,10 +574,10 @@ class SimpleDateFormatTests(SimpleTestCase): f = forms.DateField(input_formats=["%d.%m.%Y", "%d-%m-%Y"]) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -585,7 +585,7 @@ class SimpleDateFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21-12-2010') + result = f.clean("21-12-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -597,10 +597,10 @@ class SimpleDateFormatTests(SimpleTestCase): f = forms.DateField(input_formats=["%d.%m.%Y", "%d-%m-%Y"], localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21') + f.clean("2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010') + result = f.clean("21.12.2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to the same format @@ -608,7 +608,7 @@ class SimpleDateFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21") # Parse a date in a valid format, get a parsed result - result = f.clean('21-12-2010') + result = f.clean("21-12-2010") self.assertEqual(result, date(2010, 12, 21)) # The parsed result does a round trip to default format @@ -618,7 +618,7 @@ class SimpleDateFormatTests(SimpleTestCase): class LocalizedDateTimeTests(SimpleTestCase): def setUp(self): - activate('de') + activate("de") def tearDown(self): deactivate() @@ -628,21 +628,23 @@ class LocalizedDateTimeTests(SimpleTestCase): f = forms.DateTimeField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM 21/12/2010') + f.clean("1:30:05 PM 21/12/2010") # ISO formats are accepted, even if not specified in formats.py - self.assertEqual(f.clean('2010-12-21 13:30:05'), datetime(2010, 12, 21, 13, 30, 5)) + self.assertEqual( + f.clean("2010-12-21 13:30:05"), datetime(2010, 12, 21, 13, 30, 5) + ) # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010 13:30:05') + result = f.clean("21.12.2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010 13:30:05') + self.assertEqual(text, "21.12.2010 13:30:05") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('21.12.2010 13:30') + result = f.clean("21.12.2010 13:30") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -654,18 +656,18 @@ class LocalizedDateTimeTests(SimpleTestCase): f = forms.DateTimeField(localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('1:30:05 PM 21/12/2010') + f.clean("1:30:05 PM 21/12/2010") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010 13:30:05') + result = f.clean("21.12.2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '21.12.2010 13:30:05') + self.assertEqual(text, "21.12.2010 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('21.12.2010 13:30') + result = f.clean("21.12.2010 13:30") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -677,14 +679,14 @@ class LocalizedDateTimeTests(SimpleTestCase): f = forms.DateTimeField(input_formats=["%H.%M.%S %m.%d.%Y", "%H.%M %m-%d-%Y"]) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010-12-21 13:30:05 13:30:05') + f.clean("2010-12-21 13:30:05 13:30:05") with self.assertRaises(ValidationError): - f.clean('1:30:05 PM 21/12/2010') + f.clean("1:30:05 PM 21/12/2010") with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('13.30.05 12.21.2010') + result = f.clean("13.30.05 12.21.2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -692,7 +694,7 @@ class LocalizedDateTimeTests(SimpleTestCase): self.assertEqual(text, "21.12.2010 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('13.30 12-21-2010') + result = f.clean("13.30 12-21-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -701,21 +703,23 @@ class LocalizedDateTimeTests(SimpleTestCase): def test_localized_dateTimeField_with_inputformat(self): "Localized DateTimeFields with manually specified input formats can accept those formats" - f = forms.DateTimeField(input_formats=["%H.%M.%S %m.%d.%Y", "%H.%M %m-%d-%Y"], localize=True) + f = forms.DateTimeField( + input_formats=["%H.%M.%S %m.%d.%Y", "%H.%M %m-%d-%Y"], localize=True + ) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") with self.assertRaises(ValidationError): - f.clean('1:30:05 PM 21/12/2010') + f.clean("1:30:05 PM 21/12/2010") with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('13.30.05 12.21.2010') + result = f.clean("13.30.05 12.21.2010") self.assertEqual(datetime(2010, 12, 21, 13, 30, 5), result) # ISO format is always valid. self.assertEqual( - f.clean('2010-12-21 13:30:05'), + f.clean("2010-12-21 13:30:05"), datetime(2010, 12, 21, 13, 30, 5), ) # The parsed result does a round trip to the same format @@ -723,7 +727,7 @@ class LocalizedDateTimeTests(SimpleTestCase): self.assertEqual(text, "21.12.2010 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('13.30 12-21-2010') + result = f.clean("13.30 12-21-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -739,18 +743,18 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): f = forms.DateTimeField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30:05 PM 21/12/2010') + result = f.clean("1:30:05 PM 21/12/2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip text = f.widget.format_value(result) - self.assertEqual(text, '01:30:05 PM 21/12/2010') + self.assertEqual(text, "01:30:05 PM 21/12/2010") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('1:30 PM 21-12-2010') + result = f.clean("1:30 PM 21-12-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -762,18 +766,18 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): f = forms.DateTimeField(localize=True) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30:05 PM 21/12/2010') + result = f.clean("1:30:05 PM 21/12/2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format text = f.widget.format_value(result) - self.assertEqual(text, '01:30:05 PM 21/12/2010') + self.assertEqual(text, "01:30:05 PM 21/12/2010") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30 PM 21-12-2010') + result = f.clean("1:30 PM 21-12-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -785,12 +789,12 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): f = forms.DateTimeField(input_formats=["%m.%d.%Y %H:%M:%S", "%m-%d-%Y %H:%M"]) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010 13:30:05') + result = f.clean("12.21.2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -798,7 +802,7 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): self.assertEqual(text, "01:30:05 PM 21/12/2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010 13:30') + result = f.clean("12-21-2010 13:30") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -807,15 +811,17 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): def test_localized_dateTimeField_with_inputformat(self): "Localized DateTimeFields with manually specified input formats can accept those formats" - f = forms.DateTimeField(input_formats=["%m.%d.%Y %H:%M:%S", "%m-%d-%Y %H:%M"], localize=True) + f = forms.DateTimeField( + input_formats=["%m.%d.%Y %H:%M:%S", "%m-%d-%Y %H:%M"], localize=True + ) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('12.21.2010 13:30:05') + result = f.clean("12.21.2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -823,7 +829,7 @@ class CustomDateTimeInputFormatsTests(SimpleTestCase): self.assertEqual(text, "01:30:05 PM 21/12/2010") # Parse a date in a valid format, get a parsed result - result = f.clean('12-21-2010 13:30') + result = f.clean("12-21-2010 13:30") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -837,10 +843,10 @@ class SimpleDateTimeFormatTests(SimpleTestCase): f = forms.DateTimeField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('2010-12-21 13:30:05') + result = f.clean("2010-12-21 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -848,7 +854,7 @@ class SimpleDateTimeFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21 13:30:05") # Parse a date in a valid, but non-default format, get a parsed result - result = f.clean('12/21/2010 13:30:05') + result = f.clean("12/21/2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to default format @@ -860,10 +866,10 @@ class SimpleDateTimeFormatTests(SimpleTestCase): f = forms.DateTimeField() # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('13:30:05 21.12.2010') + f.clean("13:30:05 21.12.2010") # Parse a date in a valid format, get a parsed result - result = f.clean('2010-12-21 13:30:05') + result = f.clean("2010-12-21 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -871,7 +877,7 @@ class SimpleDateTimeFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('12/21/2010 13:30:05') + result = f.clean("12/21/2010 13:30:05") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to default format @@ -880,13 +886,15 @@ class SimpleDateTimeFormatTests(SimpleTestCase): def test_dateTimeField_with_inputformat(self): "DateTimeFields with manually specified input formats can accept those formats" - f = forms.DateTimeField(input_formats=["%I:%M:%S %p %d.%m.%Y", "%I:%M %p %d-%m-%Y"]) + f = forms.DateTimeField( + input_formats=["%I:%M:%S %p %d.%m.%Y", "%I:%M %p %d-%m-%Y"] + ) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30:05 PM 21.12.2010') + result = f.clean("1:30:05 PM 21.12.2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -894,7 +902,7 @@ class SimpleDateTimeFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30 PM 21-12-2010') + result = f.clean("1:30 PM 21-12-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format @@ -903,13 +911,15 @@ class SimpleDateTimeFormatTests(SimpleTestCase): def test_localized_dateTimeField_with_inputformat(self): "Localized DateTimeFields with manually specified input formats can accept those formats" - f = forms.DateTimeField(input_formats=["%I:%M:%S %p %d.%m.%Y", "%I:%M %p %d-%m-%Y"], localize=True) + f = forms.DateTimeField( + input_formats=["%I:%M:%S %p %d.%m.%Y", "%I:%M %p %d-%m-%Y"], localize=True + ) # Parse a date in an unaccepted format; get an error with self.assertRaises(ValidationError): - f.clean('2010/12/21 13:30:05') + f.clean("2010/12/21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30:05 PM 21.12.2010') + result = f.clean("1:30:05 PM 21.12.2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30, 5)) # The parsed result does a round trip to the same format @@ -917,7 +927,7 @@ class SimpleDateTimeFormatTests(SimpleTestCase): self.assertEqual(text, "2010-12-21 13:30:05") # Parse a date in a valid format, get a parsed result - result = f.clean('1:30 PM 21-12-2010') + result = f.clean("1:30 PM 21-12-2010") self.assertEqual(result, datetime(2010, 12, 21, 13, 30)) # The parsed result does a round trip to default format diff --git a/tests/forms_tests/tests/test_media.py b/tests/forms_tests/tests/test_media.py index d145560d9b..59fd74f4c9 100644 --- a/tests/forms_tests/tests/test_media.py +++ b/tests/forms_tests/tests/test_media.py @@ -4,7 +4,7 @@ from django.test import SimpleTestCase, override_settings @override_settings( - STATIC_URL='http://media.example.com/static/', + STATIC_URL="http://media.example.com/static/", ) class FormsMediaTestCase(SimpleTestCase): """Tests for the media handling on widgets and forms""" @@ -12,8 +12,12 @@ class FormsMediaTestCase(SimpleTestCase): def test_construction(self): # Check construction of media objects m = Media( - css={'all': ('path/to/css1', '/path/to/css2')}, - js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'), + css={"all": ("path/to/css1", "/path/to/css2")}, + js=( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ), ) self.assertEqual( str(m), @@ -21,19 +25,21 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) self.assertEqual( repr(m), "Media(css={'all': ['path/to/css1', '/path/to/css2']}, " - "js=['/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'])" + "js=['/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'])", ) class Foo: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) m3 = Media(Foo) self.assertEqual( @@ -42,7 +48,7 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # A widget can exist without a media definition @@ -50,7 +56,7 @@ class FormsMediaTestCase(SimpleTestCase): pass w = MyWidget() - self.assertEqual(str(w.media), '') + self.assertEqual(str(w.media), "") def test_media_dsl(self): ############################################################### @@ -62,10 +68,12 @@ class FormsMediaTestCase(SimpleTestCase): # with the value of settings.MEDIA_URL class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) w1 = MyWidget1() self.assertEqual( @@ -74,21 +82,21 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # Media objects can be interrogated by media type self.assertEqual( - str(w1.media['css']), + str(w1.media["css"]), """<link href="http://media.example.com/static/path/to/css1" media="all" rel="stylesheet"> -<link href="/path/to/css2" media="all" rel="stylesheet">""" +<link href="/path/to/css2" media="all" rel="stylesheet">""", ) self.assertEqual( - str(w1.media['js']), + str(w1.media["js"]), """<script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) def test_combine_media(self): @@ -96,24 +104,22 @@ class FormsMediaTestCase(SimpleTestCase): # once. Duplicated media definitions are ignored. class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget2(TextInput): class Media: - css = { - 'all': ('/path/to/css2', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css2", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") class MyWidget3(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("path/to/css1", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") w1 = MyWidget1() w2 = MyWidget2() @@ -126,7 +132,7 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # media addition hasn't affected the original objects @@ -136,7 +142,7 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # Regression check for #12879: specifying the same CSS or JS file @@ -144,23 +150,29 @@ class FormsMediaTestCase(SimpleTestCase): # only being included once. class MyWidget4(TextInput): class Media: - css = {'all': ('/path/to/css1', '/path/to/css1')} - js = ('/path/to/js1', '/path/to/js1') + css = {"all": ("/path/to/css1", "/path/to/css1")} + js = ("/path/to/js1", "/path/to/js1") w4 = MyWidget4() - self.assertEqual(str(w4.media), """<link href="/path/to/css1" media="all" rel="stylesheet"> -<script src="/path/to/js1"></script>""") + self.assertEqual( + str(w4.media), + """<link href="/path/to/css1" media="all" rel="stylesheet"> +<script src="/path/to/js1"></script>""", + ) def test_media_deduplication(self): # A deduplication test applied directly to a Media object, to confirm # that the deduplication doesn't only happen at the point of merging # two or more media objects. media = Media( - css={'all': ('/path/to/css1', '/path/to/css1')}, - js=('/path/to/js1', '/path/to/js1'), + css={"all": ("/path/to/css1", "/path/to/css1")}, + js=("/path/to/js1", "/path/to/js1"), + ) + self.assertEqual( + str(media), + """<link href="/path/to/css1" media="all" rel="stylesheet"> +<script src="/path/to/js1"></script>""", ) - self.assertEqual(str(media), """<link href="/path/to/css1" media="all" rel="stylesheet"> -<script src="/path/to/js1"></script>""") def test_media_property(self): ############################################################### @@ -170,38 +182,53 @@ class FormsMediaTestCase(SimpleTestCase): # Widget media can be defined as a property class MyWidget4(TextInput): def _media(self): - return Media(css={'all': ('/some/path',)}, js=('/some/js',)) + return Media(css={"all": ("/some/path",)}, js=("/some/js",)) + media = property(_media) w4 = MyWidget4() - self.assertEqual(str(w4.media), """<link href="/some/path" media="all" rel="stylesheet"> -<script src="/some/js"></script>""") + self.assertEqual( + str(w4.media), + """<link href="/some/path" media="all" rel="stylesheet"> +<script src="/some/js"></script>""", + ) # Media properties can reference the media of their parents class MyWidget5(MyWidget4): def _media(self): - return super().media + Media(css={'all': ('/other/path',)}, js=('/other/js',)) + return super().media + Media( + css={"all": ("/other/path",)}, js=("/other/js",) + ) + media = property(_media) w5 = MyWidget5() - self.assertEqual(str(w5.media), """<link href="/some/path" media="all" rel="stylesheet"> + self.assertEqual( + str(w5.media), + """<link href="/some/path" media="all" rel="stylesheet"> <link href="/other/path" media="all" rel="stylesheet"> <script src="/some/js"></script> -<script src="/other/js"></script>""") +<script src="/other/js"></script>""", + ) def test_media_property_parent_references(self): # Media properties can reference the media of their parents, # even if the parent media was defined using a class class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget6(MyWidget1): def _media(self): - return super().media + Media(css={'all': ('/other/path',)}, js=('/other/js',)) + return super().media + Media( + css={"all": ("/other/path",)}, js=("/other/js",) + ) + media = property(_media) w6 = MyWidget6() @@ -213,7 +240,7 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="/other/js"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) def test_media_inheritance(self): @@ -224,10 +251,12 @@ class FormsMediaTestCase(SimpleTestCase): # If a widget extends another but provides no media definition, it inherits the parent widget's media class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget7(MyWidget1): pass @@ -239,16 +268,14 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # If a widget extends another but defines media, it extends the parent widget's media by default class MyWidget8(MyWidget1): class Media: - css = { - 'all': ('/path/to/css3', 'path/to/css1') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css3", "path/to/css1")} + js = ("/path/to/js1", "/path/to/js4") w8 = MyWidget8() self.assertEqual( @@ -259,7 +286,7 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) def test_media_inheritance_from_property(self): @@ -267,22 +294,23 @@ class FormsMediaTestCase(SimpleTestCase): # even if the parent defined media using a property. class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget4(TextInput): def _media(self): - return Media(css={'all': ('/some/path',)}, js=('/some/js',)) + return Media(css={"all": ("/some/path",)}, js=("/some/js",)) + media = property(_media) class MyWidget9(MyWidget4): class Media: - css = { - 'all': ('/other/path',) - } - js = ('/other/js',) + css = {"all": ("/other/path",)} + js = ("/other/js",) w9 = MyWidget9() self.assertEqual( @@ -290,40 +318,41 @@ class FormsMediaTestCase(SimpleTestCase): """<link href="/some/path" media="all" rel="stylesheet"> <link href="/other/path" media="all" rel="stylesheet"> <script src="/some/js"></script> -<script src="/other/js"></script>""" +<script src="/other/js"></script>""", ) # A widget can disable media inheritance by specifying 'extend=False' class MyWidget10(MyWidget1): class Media: extend = False - css = { - 'all': ('/path/to/css3', 'path/to/css1') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css3", "path/to/css1")} + js = ("/path/to/js1", "/path/to/js4") w10 = MyWidget10() - self.assertEqual(str(w10.media), """<link href="/path/to/css3" media="all" rel="stylesheet"> + self.assertEqual( + str(w10.media), + """<link href="/path/to/css3" media="all" rel="stylesheet"> <link href="http://media.example.com/static/path/to/css1" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> -<script src="/path/to/js4"></script>""") +<script src="/path/to/js4"></script>""", + ) def test_media_inheritance_extends(self): # A widget can explicitly enable full media inheritance by specifying 'extend=True' class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget11(MyWidget1): class Media: extend = True - css = { - 'all': ('/path/to/css3', 'path/to/css1') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css3", "path/to/css1")} + js = ("/path/to/js1", "/path/to/js4") w11 = MyWidget11() self.assertEqual( @@ -334,25 +363,25 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) def test_media_inheritance_single_type(self): # A widget can enable inheritance of one media type by specifying extend as a tuple class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget12(MyWidget1): class Media: - extend = ('css',) - css = { - 'all': ('/path/to/css3', 'path/to/css1') - } - js = ('/path/to/js1', '/path/to/js4') + extend = ("css",) + css = {"all": ("/path/to/css3", "path/to/css1")} + js = ("/path/to/js1", "/path/to/js4") w12 = MyWidget12() self.assertEqual( @@ -361,7 +390,7 @@ class FormsMediaTestCase(SimpleTestCase): <link href="http://media.example.com/static/path/to/css1" media="all" rel="stylesheet"> <link href="/path/to/css2" media="all" rel="stylesheet"> <script src="/path/to/js1"></script> -<script src="/path/to/js4"></script>""" +<script src="/path/to/js4"></script>""", ) def test_multi_media(self): @@ -373,11 +402,11 @@ class FormsMediaTestCase(SimpleTestCase): class MultimediaWidget(TextInput): class Media: css = { - 'screen, print': ('/file1', '/file2'), - 'screen': ('/file3',), - 'print': ('/file4',) + "screen, print": ("/file1", "/file2"), + "screen": ("/file3",), + "print": ("/file4",), } - js = ('/path/to/js1', '/path/to/js4') + js = ("/path/to/js1", "/path/to/js4") multimedia = MultimediaWidget() self.assertEqual( @@ -387,7 +416,7 @@ class FormsMediaTestCase(SimpleTestCase): <link href="/file1" media="screen, print" rel="stylesheet"> <link href="/file2" media="screen, print" rel="stylesheet"> <script src="/path/to/js1"></script> -<script src="/path/to/js4"></script>""" +<script src="/path/to/js4"></script>""", ) def test_multi_widget(self): @@ -397,24 +426,22 @@ class FormsMediaTestCase(SimpleTestCase): class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget2(TextInput): class Media: - css = { - 'all': ('/path/to/css2', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css2", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") class MyWidget3(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("path/to/css1", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") # MultiWidgets have a default media definition that gets all the # media from the component widgets @@ -432,7 +459,7 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) def test_form_media(self): @@ -442,29 +469,28 @@ class FormsMediaTestCase(SimpleTestCase): class MyWidget1(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css2') - } - js = ('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3') + css = {"all": ("path/to/css1", "/path/to/css2")} + js = ( + "/path/to/js1", + "http://media.other.com/path/to/js2", + "https://secure.other.com/path/to/js3", + ) class MyWidget2(TextInput): class Media: - css = { - 'all': ('/path/to/css2', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("/path/to/css2", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") class MyWidget3(TextInput): class Media: - css = { - 'all': ('path/to/css1', '/path/to/css3') - } - js = ('/path/to/js1', '/path/to/js4') + css = {"all": ("path/to/css1", "/path/to/css3")} + js = ("/path/to/js1", "/path/to/js4") # You can ask a form for the media required by its widgets. class MyForm(Form): field1 = CharField(max_length=20, widget=MyWidget1()) field2 = CharField(max_length=20, widget=MyWidget2()) + f1 = MyForm() self.assertEqual( str(f1.media), @@ -474,12 +500,13 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # Form media can be combined to produce a single media definition. class AnotherForm(Form): field3 = CharField(max_length=20, widget=MyWidget3()) + f2 = AnotherForm() self.assertEqual( str(f1.media + f2.media), @@ -489,7 +516,7 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/path/to/js1"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # Forms can also define media, following the same rules as widgets. @@ -498,10 +525,9 @@ class FormsMediaTestCase(SimpleTestCase): field2 = CharField(max_length=20, widget=MyWidget2()) class Media: - js = ('/some/form/javascript',) - css = { - 'all': ('/some/form/css',) - } + js = ("/some/form/javascript",) + css = {"all": ("/some/form/css",)} + f3 = FormWithMedia() self.assertEqual( str(f3.media), @@ -513,12 +539,14 @@ class FormsMediaTestCase(SimpleTestCase): <script src="/some/form/javascript"></script> <script src="http://media.other.com/path/to/js2"></script> <script src="/path/to/js4"></script> -<script src="https://secure.other.com/path/to/js3"></script>""" +<script src="https://secure.other.com/path/to/js3"></script>""", ) # Media works in templates self.assertEqual( - Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), + Template("{{ form.media.js }}{{ form.media.css }}").render( + Context({"form": f3}) + ), """<script src="/path/to/js1"></script> <script src="/some/form/javascript"></script> <script src="http://media.other.com/path/to/js2"></script> @@ -527,12 +555,12 @@ class FormsMediaTestCase(SimpleTestCase): """<link href="http://media.example.com/static/path/to/css1" media="all" rel="stylesheet"> <link href="/some/form/css" media="all" rel="stylesheet"> <link href="/path/to/css2" media="all" rel="stylesheet"> -<link href="/path/to/css3" media="all" rel="stylesheet">""" +<link href="/path/to/css3" media="all" rel="stylesheet">""", ) def test_html_safe(self): - media = Media(css={'all': ['/path/to/css']}, js=['/path/to/js']) - self.assertTrue(hasattr(Media, '__html__')) + media = Media(css={"all": ["/path/to/css"]}, js=["/path/to/js"]) + self.assertTrue(hasattr(Media, "__html__")) self.assertEqual(str(media), media.__html__()) def test_merge(self): @@ -544,7 +572,10 @@ class FormsMediaTestCase(SimpleTestCase): (([1, 2], [1, 3]), [1, 2, 3]), (([1, 2], [3, 2]), [1, 3, 2]), (([1, 2], [1, 2]), [1, 2]), - ([[1, 2], [1, 3], [2, 3], [5, 7], [5, 6], [6, 7, 9], [8, 9]], [1, 5, 8, 2, 6, 3, 7, 9]), + ( + [[1, 2], [1, 3], [2, 3], [5, 7], [5, 6], [6, 7, 9], [8, 9]], + [1, 5, 8, 2, 6, 3, 7, 9], + ), ((), []), (([1, 2],), [1, 2]), ) @@ -553,7 +584,7 @@ class FormsMediaTestCase(SimpleTestCase): self.assertEqual(Media.merge(*lists), expected) def test_merge_warning(self): - msg = 'Detected duplicate Media files in an opposite order: [1, 2], [2, 1]' + msg = "Detected duplicate Media files in an opposite order: [1, 2], [2, 1]" with self.assertWarnsMessage(RuntimeWarning, msg): self.assertEqual(Media.merge([1, 2], [2, 1]), [1, 2]) @@ -561,51 +592,60 @@ class FormsMediaTestCase(SimpleTestCase): """ The relative order of scripts is preserved in a three-way merge. """ - widget1 = Media(js=['color-picker.js']) - widget2 = Media(js=['text-editor.js']) - widget3 = Media(js=['text-editor.js', 'text-editor-extras.js', 'color-picker.js']) + widget1 = Media(js=["color-picker.js"]) + widget2 = Media(js=["text-editor.js"]) + widget3 = Media( + js=["text-editor.js", "text-editor-extras.js", "color-picker.js"] + ) merged = widget1 + widget2 + widget3 - self.assertEqual(merged._js, ['text-editor.js', 'text-editor-extras.js', 'color-picker.js']) + self.assertEqual( + merged._js, ["text-editor.js", "text-editor-extras.js", "color-picker.js"] + ) def test_merge_js_three_way2(self): # The merge prefers to place 'c' before 'b' and 'g' before 'h' to # preserve the original order. The preference 'c'->'b' is overridden by # widget3's media, but 'g'->'h' survives in the final ordering. - widget1 = Media(js=['a', 'c', 'f', 'g', 'k']) - widget2 = Media(js=['a', 'b', 'f', 'h', 'k']) - widget3 = Media(js=['b', 'c', 'f', 'k']) + widget1 = Media(js=["a", "c", "f", "g", "k"]) + widget2 = Media(js=["a", "b", "f", "h", "k"]) + widget3 = Media(js=["b", "c", "f", "k"]) merged = widget1 + widget2 + widget3 - self.assertEqual(merged._js, ['a', 'b', 'c', 'f', 'g', 'h', 'k']) + self.assertEqual(merged._js, ["a", "b", "c", "f", "g", "h", "k"]) def test_merge_css_three_way(self): - widget1 = Media(css={'screen': ['c.css'], 'all': ['d.css', 'e.css']}) - widget2 = Media(css={'screen': ['a.css']}) - widget3 = Media(css={'screen': ['a.css', 'b.css', 'c.css'], 'all': ['e.css']}) - widget4 = Media(css={'all': ['d.css', 'e.css'], 'screen': ['c.css']}) + widget1 = Media(css={"screen": ["c.css"], "all": ["d.css", "e.css"]}) + widget2 = Media(css={"screen": ["a.css"]}) + widget3 = Media(css={"screen": ["a.css", "b.css", "c.css"], "all": ["e.css"]}) + widget4 = Media(css={"all": ["d.css", "e.css"], "screen": ["c.css"]}) merged = widget1 + widget2 # c.css comes before a.css because widget1 + widget2 establishes this # order. - self.assertEqual(merged._css, {'screen': ['c.css', 'a.css'], 'all': ['d.css', 'e.css']}) + self.assertEqual( + merged._css, {"screen": ["c.css", "a.css"], "all": ["d.css", "e.css"]} + ) merged = merged + widget3 # widget3 contains an explicit ordering of c.css and a.css. - self.assertEqual(merged._css, {'screen': ['a.css', 'b.css', 'c.css'], 'all': ['d.css', 'e.css']}) + self.assertEqual( + merged._css, + {"screen": ["a.css", "b.css", "c.css"], "all": ["d.css", "e.css"]}, + ) # Media ordering does not matter. merged = widget1 + widget4 - self.assertEqual(merged._css, {'screen': ['c.css'], 'all': ['d.css', 'e.css']}) + self.assertEqual(merged._css, {"screen": ["c.css"], "all": ["d.css", "e.css"]}) def test_add_js_deduplication(self): - widget1 = Media(js=['a', 'b', 'c']) - widget2 = Media(js=['a', 'b']) - widget3 = Media(js=['a', 'c', 'b']) + widget1 = Media(js=["a", "b", "c"]) + widget2 = Media(js=["a", "b"]) + widget3 = Media(js=["a", "c", "b"]) merged = widget1 + widget1 - self.assertEqual(merged._js_lists, [['a', 'b', 'c']]) - self.assertEqual(merged._js, ['a', 'b', 'c']) + self.assertEqual(merged._js_lists, [["a", "b", "c"]]) + self.assertEqual(merged._js, ["a", "b", "c"]) merged = widget1 + widget2 - self.assertEqual(merged._js_lists, [['a', 'b', 'c'], ['a', 'b']]) - self.assertEqual(merged._js, ['a', 'b', 'c']) + self.assertEqual(merged._js_lists, [["a", "b", "c"], ["a", "b"]]) + self.assertEqual(merged._js, ["a", "b", "c"]) # Lists with items in a different order are preserved when added. merged = widget1 + widget3 - self.assertEqual(merged._js_lists, [['a', 'b', 'c'], ['a', 'c', 'b']]) + self.assertEqual(merged._js_lists, [["a", "b", "c"], ["a", "c", "b"]]) msg = ( "Detected duplicate Media files in an opposite order: " "['a', 'b', 'c'], ['a', 'c', 'b']" @@ -614,25 +654,31 @@ class FormsMediaTestCase(SimpleTestCase): merged._js def test_add_css_deduplication(self): - widget1 = Media(css={'screen': ['a.css'], 'all': ['b.css']}) - widget2 = Media(css={'screen': ['c.css']}) - widget3 = Media(css={'screen': ['a.css'], 'all': ['b.css', 'c.css']}) - widget4 = Media(css={'screen': ['a.css'], 'all': ['c.css', 'b.css']}) + widget1 = Media(css={"screen": ["a.css"], "all": ["b.css"]}) + widget2 = Media(css={"screen": ["c.css"]}) + widget3 = Media(css={"screen": ["a.css"], "all": ["b.css", "c.css"]}) + widget4 = Media(css={"screen": ["a.css"], "all": ["c.css", "b.css"]}) merged = widget1 + widget1 - self.assertEqual(merged._css_lists, [{'screen': ['a.css'], 'all': ['b.css']}]) - self.assertEqual(merged._css, {'screen': ['a.css'], 'all': ['b.css']}) + self.assertEqual(merged._css_lists, [{"screen": ["a.css"], "all": ["b.css"]}]) + self.assertEqual(merged._css, {"screen": ["a.css"], "all": ["b.css"]}) merged = widget1 + widget2 - self.assertEqual(merged._css_lists, [ - {'screen': ['a.css'], 'all': ['b.css']}, - {'screen': ['c.css']}, - ]) - self.assertEqual(merged._css, {'screen': ['a.css', 'c.css'], 'all': ['b.css']}) + self.assertEqual( + merged._css_lists, + [ + {"screen": ["a.css"], "all": ["b.css"]}, + {"screen": ["c.css"]}, + ], + ) + self.assertEqual(merged._css, {"screen": ["a.css", "c.css"], "all": ["b.css"]}) merged = widget3 + widget4 # Ordering within lists is preserved. - self.assertEqual(merged._css_lists, [ - {'screen': ['a.css'], 'all': ['b.css', 'c.css']}, - {'screen': ['a.css'], 'all': ['c.css', 'b.css']} - ]) + self.assertEqual( + merged._css_lists, + [ + {"screen": ["a.css"], "all": ["b.css", "c.css"]}, + {"screen": ["a.css"], "all": ["c.css", "b.css"]}, + ], + ) msg = ( "Detected duplicate Media files in an opposite order: " "['b.css', 'c.css'], ['c.css', 'b.css']" @@ -641,8 +687,8 @@ class FormsMediaTestCase(SimpleTestCase): merged._css def test_add_empty(self): - media = Media(css={'screen': ['a.css']}, js=['a']) + media = Media(css={"screen": ["a.css"]}, js=["a"]) empty_media = Media() merged = media + empty_media - self.assertEqual(merged._css_lists, [{'screen': ['a.css']}]) - self.assertEqual(merged._js_lists, [['a']]) + self.assertEqual(merged._css_lists, [{"screen": ["a.css"]}]) + self.assertEqual(merged._js_lists, [["a"]]) diff --git a/tests/forms_tests/tests/test_renderers.py b/tests/forms_tests/tests/test_renderers.py index 47452fa489..3e973ad8fc 100644 --- a/tests/forms_tests/tests/test_renderers.py +++ b/tests/forms_tests/tests/test_renderers.py @@ -2,7 +2,10 @@ import os import unittest from django.forms.renderers import ( - BaseRenderer, DjangoTemplates, Jinja2, TemplatesSetting, + BaseRenderer, + DjangoTemplates, + Jinja2, + TemplatesSetting, ) from django.test import SimpleTestCase @@ -13,38 +16,39 @@ except ImportError: class SharedTests: - expected_widget_dir = 'templates' + expected_widget_dir = "templates" def test_installed_apps_template_found(self): """Can find a custom template in INSTALLED_APPS.""" renderer = self.renderer() # Found because forms_tests is . - tpl = renderer.get_template('forms_tests/custom_widget.html') + tpl = renderer.get_template("forms_tests/custom_widget.html") expected_path = os.path.abspath( os.path.join( os.path.dirname(__file__), - '..', - self.expected_widget_dir + '/forms_tests/custom_widget.html', + "..", + self.expected_widget_dir + "/forms_tests/custom_widget.html", ) ) self.assertEqual(tpl.origin.name, expected_path) class BaseTemplateRendererTests(SimpleTestCase): - def test_get_renderer(self): - with self.assertRaisesMessage(NotImplementedError, 'subclasses must implement get_template()'): - BaseRenderer().get_template('') + with self.assertRaisesMessage( + NotImplementedError, "subclasses must implement get_template()" + ): + BaseRenderer().get_template("") class DjangoTemplatesTests(SharedTests, SimpleTestCase): renderer = DjangoTemplates -@unittest.skipIf(jinja2 is None, 'jinja2 required') +@unittest.skipIf(jinja2 is None, "jinja2 required") class Jinja2Tests(SharedTests, SimpleTestCase): renderer = Jinja2 - expected_widget_dir = 'jinja2' + expected_widget_dir = "jinja2" class TemplatesSettingTests(SharedTests, SimpleTestCase): diff --git a/tests/forms_tests/tests/test_utils.py b/tests/forms_tests/tests/test_utils.py index e0e9a0e22e..c4a2e5c651 100644 --- a/tests/forms_tests/tests/test_utils.py +++ b/tests/forms_tests/tests/test_utils.py @@ -16,28 +16,31 @@ class FormsUtilsTestCase(SimpleTestCase): # flatatt # ########### - self.assertEqual(flatatt({'id': "header"}), ' id="header"') - self.assertEqual(flatatt({'class': "news", 'title': "Read this"}), ' class="news" title="Read this"') + self.assertEqual(flatatt({"id": "header"}), ' id="header"') self.assertEqual( - flatatt({'class': "news", 'title': "Read this", 'required': "required"}), - ' class="news" required="required" title="Read this"' + flatatt({"class": "news", "title": "Read this"}), + ' class="news" title="Read this"', ) self.assertEqual( - flatatt({'class': "news", 'title': "Read this", 'required': True}), - ' class="news" title="Read this" required' + flatatt({"class": "news", "title": "Read this", "required": "required"}), + ' class="news" required="required" title="Read this"', ) self.assertEqual( - flatatt({'class': "news", 'title': "Read this", 'required': False}), - ' class="news" title="Read this"' + flatatt({"class": "news", "title": "Read this", "required": True}), + ' class="news" title="Read this" required', ) - self.assertEqual(flatatt({'class': None}), '') - self.assertEqual(flatatt({}), '') + self.assertEqual( + flatatt({"class": "news", "title": "Read this", "required": False}), + ' class="news" title="Read this"', + ) + self.assertEqual(flatatt({"class": None}), "") + self.assertEqual(flatatt({}), "") def test_flatatt_no_side_effects(self): """ flatatt() does not modify the dict passed in. """ - attrs = {'foo': 'bar', 'true': True, 'false': False} + attrs = {"foo": "bar", "true": True, "false": False} attrs_copy = copy.copy(attrs) self.assertEqual(attrs, attrs_copy) @@ -58,46 +61,62 @@ class FormsUtilsTestCase(SimpleTestCase): # Can take a string. self.assertHTMLEqual( str(ErrorList(ValidationError("There was an error.").messages)), - '<ul class="errorlist"><li>There was an error.</li></ul>' + '<ul class="errorlist"><li>There was an error.</li></ul>', ) # Can take a Unicode string. self.assertHTMLEqual( str(ErrorList(ValidationError("Not \u03C0.").messages)), - '<ul class="errorlist"><li>Not π.</li></ul>' + '<ul class="errorlist"><li>Not π.</li></ul>', ) # Can take a lazy string. self.assertHTMLEqual( str(ErrorList(ValidationError(gettext_lazy("Error.")).messages)), - '<ul class="errorlist"><li>Error.</li></ul>' + '<ul class="errorlist"><li>Error.</li></ul>', ) # Can take a list. self.assertHTMLEqual( str(ErrorList(ValidationError(["Error one.", "Error two."]).messages)), - '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>' + '<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>', ) # Can take a dict. self.assertHTMLEqual( - str(ErrorList(sorted(ValidationError({'error_1': "1. Error one.", 'error_2': "2. Error two."}).messages))), - '<ul class="errorlist"><li>1. Error one.</li><li>2. Error two.</li></ul>' + str( + ErrorList( + sorted( + ValidationError( + {"error_1": "1. Error one.", "error_2": "2. Error two."} + ).messages + ) + ) + ), + '<ul class="errorlist"><li>1. Error one.</li><li>2. Error two.</li></ul>', ) # Can take a mixture in a list. self.assertHTMLEqual( - str(ErrorList(sorted(ValidationError([ - "1. First error.", - "2. Not \u03C0.", - gettext_lazy("3. Error."), - { - 'error_1': "4. First dict error.", - 'error_2': "5. Second dict error.", - }, - ]).messages))), + str( + ErrorList( + sorted( + ValidationError( + [ + "1. First error.", + "2. Not \u03C0.", + gettext_lazy("3. Error."), + { + "error_1": "4. First dict error.", + "error_2": "5. Second dict error.", + }, + ] + ).messages + ) + ) + ), '<ul class="errorlist">' - '<li>1. First error.</li>' - '<li>2. Not π.</li>' - '<li>3. Error.</li>' - '<li>4. First dict error.</li>' - '<li>5. Second dict error.</li>' - '</ul>' + "<li>1. First error.</li>" + "<li>2. Not π.</li>" + "<li>3. Error.</li>" + "<li>4. First dict error.</li>" + "<li>5. Second dict error.</li>" + "</ul>", ) class VeryBadError: @@ -107,7 +126,7 @@ class FormsUtilsTestCase(SimpleTestCase): # Can take a non-string. self.assertHTMLEqual( str(ErrorList(ValidationError(VeryBadError()).messages)), - '<ul class="errorlist"><li>A very bad error.</li></ul>' + '<ul class="errorlist"><li>A very bad error.</li></ul>', ) # Escapes non-safe input but not input marked safe. @@ -115,36 +134,38 @@ class FormsUtilsTestCase(SimpleTestCase): self.assertHTMLEqual( str(ErrorList([example])), '<ul class="errorlist"><li>Example of link: ' - '<a href="http://www.example.com/">example</a></li></ul>' + "<a href="http://www.example.com/">example</a></li></ul>", ) self.assertHTMLEqual( str(ErrorList([mark_safe(example)])), '<ul class="errorlist"><li>Example of link: ' - '<a href="http://www.example.com/">example</a></li></ul>' + '<a href="http://www.example.com/">example</a></li></ul>', ) self.assertHTMLEqual( - str(ErrorDict({'name': example})), + str(ErrorDict({"name": example})), '<ul class="errorlist"><li>nameExample of link: ' - '<a href="http://www.example.com/">example</a></li></ul>' + "<a href="http://www.example.com/">example</a></li></ul>", ) self.assertHTMLEqual( - str(ErrorDict({'name': mark_safe(example)})), + str(ErrorDict({"name": mark_safe(example)})), '<ul class="errorlist"><li>nameExample of link: ' - '<a href="http://www.example.com/">example</a></li></ul>' + '<a href="http://www.example.com/">example</a></li></ul>', ) def test_error_dict_copy(self): e = ErrorDict() - e['__all__'] = ErrorList([ - ValidationError( - message='message %(i)s', - params={'i': 1}, - ), - ValidationError( - message='message %(i)s', - params={'i': 2}, - ), - ]) + e["__all__"] = ErrorList( + [ + ValidationError( + message="message %(i)s", + params={"i": 1}, + ), + ValidationError( + message="message %(i)s", + params={"i": 2}, + ), + ] + ) e_copy = copy.copy(e) self.assertEqual(e, e_copy) @@ -155,56 +176,70 @@ class FormsUtilsTestCase(SimpleTestCase): def test_error_dict_html_safe(self): e = ErrorDict() - e['username'] = 'Invalid username.' - self.assertTrue(hasattr(ErrorDict, '__html__')) + e["username"] = "Invalid username." + self.assertTrue(hasattr(ErrorDict, "__html__")) self.assertEqual(str(e), e.__html__()) def test_error_list_html_safe(self): - e = ErrorList(['Invalid username.']) - self.assertTrue(hasattr(ErrorList, '__html__')) + e = ErrorList(["Invalid username."]) + self.assertTrue(hasattr(ErrorList, "__html__")) self.assertEqual(str(e), e.__html__()) def test_error_dict_is_dict(self): self.assertIsInstance(ErrorDict(), dict) def test_error_dict_is_json_serializable(self): - init_errors = ErrorDict([ - ('__all__', ErrorList([ - ValidationError('Sorry this form only works on leap days.') - ])), - ('name', ErrorList([ValidationError('This field is required.')])), - ]) - min_value_error_list = ErrorList([ - ValidationError('Ensure this value is greater than or equal to 0.') - ]) + init_errors = ErrorDict( + [ + ( + "__all__", + ErrorList( + [ValidationError("Sorry this form only works on leap days.")] + ), + ), + ("name", ErrorList([ValidationError("This field is required.")])), + ] + ) + min_value_error_list = ErrorList( + [ValidationError("Ensure this value is greater than or equal to 0.")] + ) e = ErrorDict( init_errors, - date=ErrorList([ - ErrorDict({ - 'day': min_value_error_list, - 'month': min_value_error_list, - 'year': min_value_error_list, - }), - ]), - ) - e['renderer'] = ErrorList([ - ValidationError( - 'Select a valid choice. That choice is not one of the ' - 'available choices.' + date=ErrorList( + [ + ErrorDict( + { + "day": min_value_error_list, + "month": min_value_error_list, + "year": min_value_error_list, + } + ), + ] ), - ]) - self.assertJSONEqual(json.dumps(e), { - '__all__': ['Sorry this form only works on leap days.'], - 'name': ['This field is required.'], - 'date': [ - { - 'day': ['Ensure this value is greater than or equal to 0.'], - 'month': ['Ensure this value is greater than or equal to 0.'], - 'year': ['Ensure this value is greater than or equal to 0.'], - }, - ], - 'renderer': [ - 'Select a valid choice. That choice is not one of the ' - 'available choices.' - ], - }) + ) + e["renderer"] = ErrorList( + [ + ValidationError( + "Select a valid choice. That choice is not one of the " + "available choices." + ), + ] + ) + self.assertJSONEqual( + json.dumps(e), + { + "__all__": ["Sorry this form only works on leap days."], + "name": ["This field is required."], + "date": [ + { + "day": ["Ensure this value is greater than or equal to 0."], + "month": ["Ensure this value is greater than or equal to 0."], + "year": ["Ensure this value is greater than or equal to 0."], + }, + ], + "renderer": [ + "Select a valid choice. That choice is not one of the " + "available choices." + ], + }, + ) diff --git a/tests/forms_tests/tests/test_validators.py b/tests/forms_tests/tests/test_validators.py index 2f26bbfbb7..731e1c9817 100644 --- a/tests/forms_tests/tests/test_validators.py +++ b/tests/forms_tests/tests/test_validators.py @@ -16,40 +16,42 @@ class TestFieldWithValidators(TestCase): validators=[ validators.validate_integer, validators.validate_email, - ] + ], ) string = forms.CharField( max_length=50, validators=[ validators.RegexValidator( - regex='^[a-zA-Z]*$', + regex="^[a-zA-Z]*$", message="Letters only.", ) - ] + ], ) ignore_case_string = forms.CharField( max_length=50, validators=[ validators.RegexValidator( - regex='^[a-z]*$', + regex="^[a-z]*$", message="Letters only.", flags=re.IGNORECASE, ) - ] + ], ) - form = UserForm({ - 'full_name': 'not int nor mail', - 'string': '2 is not correct', - 'ignore_case_string': "IgnORE Case strIng", - }) + form = UserForm( + { + "full_name": "not int nor mail", + "string": "2 is not correct", + "ignore_case_string": "IgnORE Case strIng", + } + ) with self.assertRaises(ValidationError) as e: - form.fields['full_name'].clean('not int nor mail') + form.fields["full_name"].clean("not int nor mail") self.assertEqual(2, len(e.exception.messages)) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors['string'], ["Letters only."]) - self.assertEqual(form.errors['string'], ["Letters only."]) + self.assertEqual(form.errors["string"], ["Letters only."]) + self.assertEqual(form.errors["string"], ["Letters only."]) def test_field_validators_can_be_any_iterable(self): class UserForm(forms.Form): @@ -58,39 +60,42 @@ class TestFieldWithValidators(TestCase): validators=( validators.validate_integer, validators.validate_email, - ) + ), ) - form = UserForm({'full_name': 'not int nor mail'}) + form = UserForm({"full_name": "not int nor mail"}) self.assertFalse(form.is_valid()) - self.assertEqual(form.errors['full_name'], ['Enter a valid integer.', 'Enter a valid email address.']) + self.assertEqual( + form.errors["full_name"], + ["Enter a valid integer.", "Enter a valid email address."], + ) class ValidatorCustomMessageTests(TestCase): def test_value_placeholder_with_char_field(self): cases = [ - (validators.validate_integer, '-42.5', 'invalid'), - (validators.validate_email, 'a', 'invalid'), - (validators.validate_email, 'a@b\n.com', 'invalid'), - (validators.validate_email, 'a\n@b.com', 'invalid'), - (validators.validate_slug, '你 好', 'invalid'), - (validators.validate_unicode_slug, '你 好', 'invalid'), - (validators.validate_ipv4_address, '256.1.1.1', 'invalid'), - (validators.validate_ipv6_address, '1:2', 'invalid'), - (validators.validate_ipv46_address, '256.1.1.1', 'invalid'), - (validators.validate_comma_separated_integer_list, 'a,b,c', 'invalid'), - (validators.int_list_validator(), '-1,2,3', 'invalid'), - (validators.MaxLengthValidator(10), 11 * 'x', 'max_length'), - (validators.MinLengthValidator(10), 9 * 'x', 'min_length'), - (validators.URLValidator(), 'no_scheme', 'invalid'), - (validators.URLValidator(), 'http://test[.com', 'invalid'), - (validators.URLValidator(), 'http://[::1:2::3]/', 'invalid'), + (validators.validate_integer, "-42.5", "invalid"), + (validators.validate_email, "a", "invalid"), + (validators.validate_email, "a@b\n.com", "invalid"), + (validators.validate_email, "a\n@b.com", "invalid"), + (validators.validate_slug, "你 好", "invalid"), + (validators.validate_unicode_slug, "你 好", "invalid"), + (validators.validate_ipv4_address, "256.1.1.1", "invalid"), + (validators.validate_ipv6_address, "1:2", "invalid"), + (validators.validate_ipv46_address, "256.1.1.1", "invalid"), + (validators.validate_comma_separated_integer_list, "a,b,c", "invalid"), + (validators.int_list_validator(), "-1,2,3", "invalid"), + (validators.MaxLengthValidator(10), 11 * "x", "max_length"), + (validators.MinLengthValidator(10), 9 * "x", "min_length"), + (validators.URLValidator(), "no_scheme", "invalid"), + (validators.URLValidator(), "http://test[.com", "invalid"), + (validators.URLValidator(), "http://[::1:2::3]/", "invalid"), ( validators.URLValidator(), - 'http://' + '.'.join(['a' * 35 for _ in range(9)]), - 'invalid', + "http://" + ".".join(["a" * 35 for _ in range(9)]), + "invalid", ), - (validators.RegexValidator('[0-9]+'), 'xxxxxx', 'invalid'), + (validators.RegexValidator("[0-9]+"), "xxxxxx", "invalid"), ] for validator, value, code in cases: if isinstance(validator, types.FunctionType): @@ -98,71 +103,74 @@ class ValidatorCustomMessageTests(TestCase): else: name = type(validator).__name__ with self.subTest(name, value=value): + class MyForm(forms.Form): field = forms.CharField( validators=[validator], - error_messages={code: '%(value)s'}, + error_messages={code: "%(value)s"}, ) - form = MyForm({'field': value}) + form = MyForm({"field": value}) self.assertIs(form.is_valid(), False) - self.assertEqual(form.errors, {'field': [value]}) + self.assertEqual(form.errors, {"field": [value]}) def test_value_placeholder_with_null_character(self): class MyForm(forms.Form): field = forms.CharField( - error_messages={'null_characters_not_allowed': '%(value)s'}, + error_messages={"null_characters_not_allowed": "%(value)s"}, ) - form = MyForm({'field': 'a\0b'}) + form = MyForm({"field": "a\0b"}) self.assertIs(form.is_valid(), False) - self.assertEqual(form.errors, {'field': ['a\x00b']}) + self.assertEqual(form.errors, {"field": ["a\x00b"]}) def test_value_placeholder_with_integer_field(self): cases = [ - (validators.MaxValueValidator(0), 1, 'max_value'), - (validators.MinValueValidator(0), -1, 'min_value'), - (validators.URLValidator(), '1', 'invalid'), + (validators.MaxValueValidator(0), 1, "max_value"), + (validators.MinValueValidator(0), -1, "min_value"), + (validators.URLValidator(), "1", "invalid"), ] for validator, value, code in cases: with self.subTest(type(validator).__name__, value=value): + class MyForm(forms.Form): field = forms.IntegerField( validators=[validator], - error_messages={code: '%(value)s'}, + error_messages={code: "%(value)s"}, ) - form = MyForm({'field': value}) + form = MyForm({"field": value}) self.assertIs(form.is_valid(), False) - self.assertEqual(form.errors, {'field': [str(value)]}) + self.assertEqual(form.errors, {"field": [str(value)]}) def test_value_placeholder_with_decimal_field(self): cases = [ - ('NaN', 'invalid'), - ('123', 'max_digits'), - ('0.12', 'max_decimal_places'), - ('12', 'max_whole_digits'), + ("NaN", "invalid"), + ("123", "max_digits"), + ("0.12", "max_decimal_places"), + ("12", "max_whole_digits"), ] for value, code in cases: with self.subTest(value=value): + class MyForm(forms.Form): field = forms.DecimalField( max_digits=2, decimal_places=1, - error_messages={code: '%(value)s'}, + error_messages={code: "%(value)s"}, ) - form = MyForm({'field': value}) + form = MyForm({"field": value}) self.assertIs(form.is_valid(), False) - self.assertEqual(form.errors, {'field': [value]}) + self.assertEqual(form.errors, {"field": [value]}) def test_value_placeholder_with_file_field(self): class MyForm(forms.Form): field = forms.FileField( validators=[validators.validate_image_file_extension], - error_messages={'invalid_extension': '%(value)s'}, + error_messages={"invalid_extension": "%(value)s"}, ) - form = MyForm(files={'field': SimpleUploadedFile('myfile.txt', b'abc')}) + form = MyForm(files={"field": SimpleUploadedFile("myfile.txt", b"abc")}) self.assertIs(form.is_valid(), False) - self.assertEqual(form.errors, {'field': ['myfile.txt']}) + self.assertEqual(form.errors, {"field": ["myfile.txt"]}) diff --git a/tests/forms_tests/tests/test_widgets.py b/tests/forms_tests/tests/test_widgets.py index f429f92547..e28c1f2462 100644 --- a/tests/forms_tests/tests/test_widgets.py +++ b/tests/forms_tests/tests/test_widgets.py @@ -5,18 +5,21 @@ from django.urls import reverse from ..models import Article -@override_settings(ROOT_URLCONF='forms_tests.urls') +@override_settings(ROOT_URLCONF="forms_tests.urls") class LiveWidgetTests(AdminSeleniumTestCase): - available_apps = ['forms_tests'] + AdminSeleniumTestCase.available_apps + available_apps = ["forms_tests"] + AdminSeleniumTestCase.available_apps def test_textarea_trailing_newlines(self): """ A roundtrip on a ModelForm doesn't alter the TextField value """ from selenium.webdriver.common.by import By + article = Article.objects.create(content="\nTst\n") - self.selenium.get(self.live_server_url + reverse('article_form', args=[article.pk])) - self.selenium.find_element(By.ID, 'submit').click() + self.selenium.get( + self.live_server_url + reverse("article_form", args=[article.pk]) + ) + self.selenium.find_element(By.ID, "submit").click() article = Article.objects.get(pk=article.pk) self.assertEqual(article.content, "\r\nTst\r\n") diff --git a/tests/forms_tests/tests/tests.py b/tests/forms_tests/tests/tests.py index 24ae09a800..5a860037e5 100644 --- a/tests/forms_tests/tests/tests.py +++ b/tests/forms_tests/tests/tests.py @@ -7,8 +7,13 @@ from django.forms.models import ModelFormMetaclass from django.test import SimpleTestCase, TestCase from ..models import ( - BoundaryModel, ChoiceFieldModel, ChoiceModel, ChoiceOptionModel, Defaults, - FileModel, OptionalMultiChoiceModel, + BoundaryModel, + ChoiceFieldModel, + ChoiceModel, + ChoiceOptionModel, + Defaults, + FileModel, + OptionalMultiChoiceModel, ) from . import jinja2_tests @@ -16,39 +21,39 @@ from . import jinja2_tests class ChoiceFieldForm(ModelForm): class Meta: model = ChoiceFieldModel - fields = '__all__' + fields = "__all__" class OptionalMultiChoiceModelForm(ModelForm): class Meta: model = OptionalMultiChoiceModel - fields = '__all__' + fields = "__all__" class ChoiceFieldExclusionForm(ModelForm): multi_choice = CharField(max_length=50) class Meta: - exclude = ['multi_choice'] + exclude = ["multi_choice"] model = ChoiceFieldModel class EmptyCharLabelChoiceForm(ModelForm): class Meta: model = ChoiceModel - fields = ['name', 'choice'] + fields = ["name", "choice"] class EmptyIntegerLabelChoiceForm(ModelForm): class Meta: model = ChoiceModel - fields = ['name', 'choice_integer'] + fields = ["name", "choice_integer"] class EmptyCharLabelNoneChoiceForm(ModelForm): class Meta: model = ChoiceModel - fields = ['name', 'choice_string_w_none'] + fields = ["name", "choice_string_w_none"] class FileForm(Form): @@ -59,31 +64,36 @@ class TestTicket14567(TestCase): """ The return values of ModelMultipleChoiceFields are QuerySets """ + def test_empty_queryset_return(self): "If a model's ManyToManyField has blank=True and is saved with no data, a queryset is returned." - option = ChoiceOptionModel.objects.create(name='default') - form = OptionalMultiChoiceModelForm({'multi_choice_optional': '', 'multi_choice': [option.pk]}) + option = ChoiceOptionModel.objects.create(name="default") + form = OptionalMultiChoiceModelForm( + {"multi_choice_optional": "", "multi_choice": [option.pk]} + ) self.assertTrue(form.is_valid()) # The empty value is a QuerySet - self.assertIsInstance(form.cleaned_data['multi_choice_optional'], models.query.QuerySet) + self.assertIsInstance( + form.cleaned_data["multi_choice_optional"], models.query.QuerySet + ) # While we're at it, test whether a QuerySet is returned if there *is* a value. - self.assertIsInstance(form.cleaned_data['multi_choice'], models.query.QuerySet) + self.assertIsInstance(form.cleaned_data["multi_choice"], models.query.QuerySet) class ModelFormCallableModelDefault(TestCase): def test_no_empty_option(self): "If a model's ForeignKey has blank=False and a default, no empty option is created (Refs #10792)." - option = ChoiceOptionModel.objects.create(name='default') + option = ChoiceOptionModel.objects.create(name="default") - choices = list(ChoiceFieldForm().fields['choice'].choices) + choices = list(ChoiceFieldForm().fields["choice"].choices) self.assertEqual(len(choices), 1) self.assertEqual(choices[0], (option.pk, str(option))) def test_callable_initial_value(self): "The initial value for a callable default returning a queryset is the pk (refs #13769)" - ChoiceOptionModel.objects.create(id=1, name='default') - ChoiceOptionModel.objects.create(id=2, name='option 2') - ChoiceOptionModel.objects.create(id=3, name='option 3') + ChoiceOptionModel.objects.create(id=1, name="default") + ChoiceOptionModel.objects.create(id=2, name="option 2") + ChoiceOptionModel.objects.create(id=3, name="option 3") self.assertHTMLEqual( ChoiceFieldForm().as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice"> @@ -107,21 +117,25 @@ class ModelFormCallableModelDefault(TestCase): <option value="1" selected>ChoiceOption 1</option> <option value="2">ChoiceOption 2</option> <option value="3">ChoiceOption 3</option> -</select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0"></p>""" +</select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0"></p>""", ) def test_initial_instance_value(self): "Initial instances for model fields may also be instances (refs #7287)" - ChoiceOptionModel.objects.create(id=1, name='default') - obj2 = ChoiceOptionModel.objects.create(id=2, name='option 2') - obj3 = ChoiceOptionModel.objects.create(id=3, name='option 3') + ChoiceOptionModel.objects.create(id=1, name="default") + obj2 = ChoiceOptionModel.objects.create(id=2, name="option 2") + obj3 = ChoiceOptionModel.objects.create(id=3, name="option 3") self.assertHTMLEqual( - ChoiceFieldForm(initial={ - 'choice': obj2, - 'choice_int': obj2, - 'multi_choice': [obj2, obj3], - 'multi_choice_int': ChoiceOptionModel.objects.exclude(name="default"), - }).as_p(), + ChoiceFieldForm( + initial={ + "choice": obj2, + "choice_int": obj2, + "multi_choice": [obj2, obj3], + "multi_choice_int": ChoiceOptionModel.objects.exclude( + name="default" + ), + } + ).as_p(), """<p><label for="id_choice">Choice:</label> <select name="choice" id="id_choice"> <option value="1">ChoiceOption 1</option> <option value="2" selected>ChoiceOption 2</option> @@ -145,19 +159,24 @@ class ModelFormCallableModelDefault(TestCase): <option value="2" selected>ChoiceOption 2</option> <option value="3" selected>ChoiceOption 3</option> </select><input type="hidden" name="initial-multi_choice_int" value="2" id="initial-id_multi_choice_int_0"> -<input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1"></p>""" +<input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1"></p>""", ) class FormsModelTestCase(TestCase): def test_unicode_filename(self): # FileModel with Unicode filename and data ######################### - file1 = SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह'.encode()) - f = FileForm(data={}, files={'file1': file1}, auto_id=False) + file1 = SimpleUploadedFile( + "我隻氣墊船裝滿晒鱔.txt", "मेरी मँडराने वाली नाव सर्पमीनों से भरी ह".encode() + ) + f = FileForm(data={}, files={"file1": file1}, auto_id=False) self.assertTrue(f.is_valid()) - self.assertIn('file1', f.cleaned_data) - m = FileModel.objects.create(file=f.cleaned_data['file1']) - self.assertEqual(m.file.name, 'tests/\u6211\u96bb\u6c23\u588a\u8239\u88dd\u6eff\u6652\u9c54.txt') + self.assertIn("file1", f.cleaned_data) + m = FileModel.objects.create(file=f.cleaned_data["file1"]) + self.assertEqual( + m.file.name, + "tests/\u6211\u96bb\u6c23\u588a\u8239\u88dd\u6eff\u6652\u9c54.txt", + ) m.delete() def test_boundary_conditions(self): @@ -165,13 +184,13 @@ class FormsModelTestCase(TestCase): class BoundaryForm(ModelForm): class Meta: model = BoundaryModel - fields = '__all__' + fields = "__all__" - f = BoundaryForm({'positive_integer': 100}) + f = BoundaryForm({"positive_integer": 100}) self.assertTrue(f.is_valid()) - f = BoundaryForm({'positive_integer': 0}) + f = BoundaryForm({"positive_integer": 0}) self.assertTrue(f.is_valid()) - f = BoundaryForm({'positive_integer': -100}) + f = BoundaryForm({"positive_integer": -100}) self.assertFalse(f.is_valid()) def test_formfield_initial(self): @@ -181,22 +200,26 @@ class FormsModelTestCase(TestCase): class DefaultsForm(ModelForm): class Meta: model = Defaults - fields = '__all__' + fields = "__all__" - self.assertEqual(DefaultsForm().fields['name'].initial, 'class default value') - self.assertEqual(DefaultsForm().fields['def_date'].initial, datetime.date(1980, 1, 1)) - self.assertEqual(DefaultsForm().fields['value'].initial, 42) - r1 = DefaultsForm()['callable_default'].as_widget() - r2 = DefaultsForm()['callable_default'].as_widget() + self.assertEqual(DefaultsForm().fields["name"].initial, "class default value") + self.assertEqual( + DefaultsForm().fields["def_date"].initial, datetime.date(1980, 1, 1) + ) + self.assertEqual(DefaultsForm().fields["value"].initial, 42) + r1 = DefaultsForm()["callable_default"].as_widget() + r2 = DefaultsForm()["callable_default"].as_widget() self.assertNotEqual(r1, r2) # In a ModelForm that is passed an instance, the initial values come from the # instance's values, not the model's defaults. - foo_instance = Defaults(name='instance value', def_date=datetime.date(1969, 4, 4), value=12) + foo_instance = Defaults( + name="instance value", def_date=datetime.date(1969, 4, 4), value=12 + ) instance_form = DefaultsForm(instance=foo_instance) - self.assertEqual(instance_form.initial['name'], 'instance value') - self.assertEqual(instance_form.initial['def_date'], datetime.date(1969, 4, 4)) - self.assertEqual(instance_form.initial['value'], 12) + self.assertEqual(instance_form.initial["name"], "instance value") + self.assertEqual(instance_form.initial["def_date"], datetime.date(1969, 4, 4)) + self.assertEqual(instance_form.initial["value"], 12) from django.forms import CharField @@ -205,13 +228,15 @@ class FormsModelTestCase(TestCase): class Meta: model = Defaults - exclude = ['name', 'callable_default'] + exclude = ["name", "callable_default"] - f = ExcludingForm({'name': 'Hello', 'value': 99, 'def_date': datetime.date(1999, 3, 2)}) + f = ExcludingForm( + {"name": "Hello", "value": 99, "def_date": datetime.date(1999, 3, 2)} + ) self.assertTrue(f.is_valid()) - self.assertEqual(f.cleaned_data['name'], 'Hello') + self.assertEqual(f.cleaned_data["name"], "Hello") obj = f.save() - self.assertEqual(obj.name, 'class default value') + self.assertEqual(obj.name, "class default value") self.assertEqual(obj.value, 99) self.assertEqual(obj.def_date, datetime.date(1999, 3, 2)) @@ -221,19 +246,20 @@ class RelatedModelFormTests(SimpleTestCase): """ Test for issue 10405 """ + class A(models.Model): ref = models.ForeignKey("B", models.CASCADE) class Meta: model = A - fields = '__all__' + fields = "__all__" msg = ( "Cannot create form field for 'ref' yet, because " "its related model 'B' has not been loaded yet" ) with self.assertRaisesMessage(ValueError, msg): - ModelFormMetaclass('Form', (ModelForm,), {'Meta': Meta}) + ModelFormMetaclass("Form", (ModelForm,), {"Meta": Meta}) class B(models.Model): pass @@ -242,6 +268,7 @@ class RelatedModelFormTests(SimpleTestCase): """ Test for issue 10405 """ + class C(models.Model): ref = models.ForeignKey("D", models.CASCADE) @@ -250,38 +277,45 @@ class RelatedModelFormTests(SimpleTestCase): class Meta: model = C - fields = '__all__' + fields = "__all__" - self.assertTrue(issubclass(ModelFormMetaclass('Form', (ModelForm,), {'Meta': Meta}), ModelForm)) + self.assertTrue( + issubclass( + ModelFormMetaclass("Form", (ModelForm,), {"Meta": Meta}), ModelForm + ) + ) class ManyToManyExclusionTestCase(TestCase): def test_m2m_field_exclusion(self): # Issue 12337. save_instance should honor the passed-in exclude keyword. - opt1 = ChoiceOptionModel.objects.create(id=1, name='default') - opt2 = ChoiceOptionModel.objects.create(id=2, name='option 2') - opt3 = ChoiceOptionModel.objects.create(id=3, name='option 3') + opt1 = ChoiceOptionModel.objects.create(id=1, name="default") + opt2 = ChoiceOptionModel.objects.create(id=2, name="option 2") + opt3 = ChoiceOptionModel.objects.create(id=3, name="option 3") initial = { - 'choice': opt1, - 'choice_int': opt1, + "choice": opt1, + "choice_int": opt1, } data = { - 'choice': opt2.pk, - 'choice_int': opt2.pk, - 'multi_choice': 'string data!', - 'multi_choice_int': [opt1.pk], + "choice": opt2.pk, + "choice_int": opt2.pk, + "multi_choice": "string data!", + "multi_choice_int": [opt1.pk], } instance = ChoiceFieldModel.objects.create(**initial) instance.multi_choice.set([opt2, opt3]) instance.multi_choice_int.set([opt2, opt3]) form = ChoiceFieldExclusionForm(data=data, instance=instance) self.assertTrue(form.is_valid()) - self.assertEqual(form.cleaned_data['multi_choice'], data['multi_choice']) + self.assertEqual(form.cleaned_data["multi_choice"], data["multi_choice"]) form.save() - self.assertEqual(form.instance.choice.pk, data['choice']) - self.assertEqual(form.instance.choice_int.pk, data['choice_int']) + self.assertEqual(form.instance.choice.pk, data["choice"]) + self.assertEqual(form.instance.choice_int.pk, data["choice_int"]) self.assertEqual(list(form.instance.multi_choice.all()), [opt2, opt3]) - self.assertEqual([obj.pk for obj in form.instance.multi_choice_int.all()], data['multi_choice_int']) + self.assertEqual( + [obj.pk for obj in form.instance.multi_choice_int.all()], + data["multi_choice_int"], + ) class EmptyLabelTestCase(TestCase): @@ -294,7 +328,7 @@ class EmptyLabelTestCase(TestCase): <option value="" selected>No Preference</option> <option value="f">Foo</option> <option value="b">Bar</option> -</select></p>""" +</select></p>""", ) def test_empty_field_char_none(self): @@ -307,25 +341,27 @@ class EmptyLabelTestCase(TestCase): <option value="" selected>No Preference</option> <option value="f">Foo</option> <option value="b">Bar</option> -</select></p>""" +</select></p>""", ) def test_save_empty_label_forms(self): # Saving a form with a blank choice results in the expected # value being stored in the database. tests = [ - (EmptyCharLabelNoneChoiceForm, 'choice_string_w_none', None), - (EmptyIntegerLabelChoiceForm, 'choice_integer', None), - (EmptyCharLabelChoiceForm, 'choice', ''), + (EmptyCharLabelNoneChoiceForm, "choice_string_w_none", None), + (EmptyIntegerLabelChoiceForm, "choice_integer", None), + (EmptyCharLabelChoiceForm, "choice", ""), ] for form, key, expected in tests: with self.subTest(form=form): - f = form({'name': 'some-key', key: ''}) + f = form({"name": "some-key", key: ""}) self.assertTrue(f.is_valid()) m = f.save() self.assertEqual(expected, getattr(m, key)) - self.assertEqual('No Preference', getattr(m, 'get_{}_display'.format(key))()) + self.assertEqual( + "No Preference", getattr(m, "get_{}_display".format(key))() + ) def test_empty_field_integer(self): f = EmptyIntegerLabelChoiceForm() @@ -337,16 +373,16 @@ class EmptyLabelTestCase(TestCase): <option value="" selected>No Preference</option> <option value="1">Foo</option> <option value="2">Bar</option> -</select></p>""" +</select></p>""", ) def test_get_display_value_on_none(self): - m = ChoiceModel.objects.create(name='test', choice='', choice_integer=None) + m = ChoiceModel.objects.create(name="test", choice="", choice_integer=None) self.assertIsNone(m.choice_integer) - self.assertEqual('No Preference', m.get_choice_integer_display()) + self.assertEqual("No Preference", m.get_choice_integer_display()) def test_html_rendering_of_prepopulated_models(self): - none_model = ChoiceModel(name='none-test', choice_integer=None) + none_model = ChoiceModel(name="none-test", choice_integer=None) f = EmptyIntegerLabelChoiceForm(instance=none_model) self.assertHTMLEqual( f.as_p(), @@ -357,10 +393,10 @@ class EmptyLabelTestCase(TestCase): <option value="" selected>No Preference</option> <option value="1">Foo</option> <option value="2">Bar</option> -</select></p>""" +</select></p>""", ) - foo_model = ChoiceModel(name='foo-test', choice_integer=1) + foo_model = ChoiceModel(name="foo-test", choice_integer=1) f = EmptyIntegerLabelChoiceForm(instance=foo_model) self.assertHTMLEqual( f.as_p(), @@ -371,7 +407,7 @@ class EmptyLabelTestCase(TestCase): <option value="">No Preference</option> <option value="1" selected>Foo</option> <option value="2">Bar</option> -</select></p>""" +</select></p>""", ) diff --git a/tests/forms_tests/urls.py b/tests/forms_tests/urls.py index 7e27927099..4063568a81 100644 --- a/tests/forms_tests/urls.py +++ b/tests/forms_tests/urls.py @@ -3,6 +3,6 @@ from django.urls import path from .views import ArticleFormView, form_view urlpatterns = [ - path('form_view/', form_view, name='form_view'), - path('model_form/<int:pk>/', ArticleFormView.as_view(), name='article_form'), + path("form_view/", form_view, name="form_view"), + path("model_form/<int:pk>/", ArticleFormView.as_view(), name="article_form"), ] diff --git a/tests/forms_tests/views.py b/tests/forms_tests/views.py index 20f1bf161d..b03472824d 100644 --- a/tests/forms_tests/views.py +++ b/tests/forms_tests/views.py @@ -11,12 +11,12 @@ class ArticleForm(forms.ModelForm): class Meta: model = Article - fields = '__all__' + fields = "__all__" class ArticleFormView(UpdateView): model = Article - success_url = '/' + success_url = "/" form_class = ArticleForm @@ -24,6 +24,6 @@ def form_view(request): class Form(forms.Form): number = forms.FloatField() - template = Template('<html>{{ form }}</html>') - context = Context({'form': Form()}) + template = Template("<html>{{ form }}</html>") + context = Context({"form": Form()}) return HttpResponse(template.render(context)) diff --git a/tests/forms_tests/widget_tests/base.py b/tests/forms_tests/widget_tests/base.py index 339d78bc71..c29099abf2 100644 --- a/tests/forms_tests/widget_tests/base.py +++ b/tests/forms_tests/widget_tests/base.py @@ -8,24 +8,32 @@ except ImportError: class WidgetTest(SimpleTestCase): - beatles = (('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')) + beatles = (("J", "John"), ("P", "Paul"), ("G", "George"), ("R", "Ringo")) @classmethod def setUpClass(cls): cls.django_renderer = DjangoTemplates() cls.jinja2_renderer = Jinja2() if jinja2 else None - cls.renderers = [cls.django_renderer] + ([cls.jinja2_renderer] if cls.jinja2_renderer else []) + cls.renderers = [cls.django_renderer] + ( + [cls.jinja2_renderer] if cls.jinja2_renderer else [] + ) super().setUpClass() - def check_html(self, widget, name, value, html='', attrs=None, strict=False, **kwargs): + def check_html( + self, widget, name, value, html="", attrs=None, strict=False, **kwargs + ): assertEqual = self.assertEqual if strict else self.assertHTMLEqual if self.jinja2_renderer: - output = widget.render(name, value, attrs=attrs, renderer=self.jinja2_renderer, **kwargs) + output = widget.render( + name, value, attrs=attrs, renderer=self.jinja2_renderer, **kwargs + ) # Django escapes quotes with '"' while Jinja2 uses '"'. - output = output.replace('"', '"') + output = output.replace(""", """) # Django escapes single quotes with ''' while Jinja2 uses '''. - output = output.replace(''', ''') + output = output.replace("'", "'") assertEqual(output, html) - output = widget.render(name, value, attrs=attrs, renderer=self.django_renderer, **kwargs) + output = widget.render( + name, value, attrs=attrs, renderer=self.django_renderer, **kwargs + ) assertEqual(output, html) diff --git a/tests/forms_tests/widget_tests/test_checkboxinput.py b/tests/forms_tests/widget_tests/test_checkboxinput.py index 8dba2178c9..0f65e876df 100644 --- a/tests/forms_tests/widget_tests/test_checkboxinput.py +++ b/tests/forms_tests/widget_tests/test_checkboxinput.py @@ -7,18 +7,26 @@ class CheckboxInputTest(WidgetTest): widget = CheckboxInput() def test_render_empty(self): - self.check_html(self.widget, 'is_cool', '', html='<input type="checkbox" name="is_cool">') + self.check_html( + self.widget, "is_cool", "", html='<input type="checkbox" name="is_cool">' + ) def test_render_none(self): - self.check_html(self.widget, 'is_cool', None, html='<input type="checkbox" name="is_cool">') + self.check_html( + self.widget, "is_cool", None, html='<input type="checkbox" name="is_cool">' + ) def test_render_false(self): - self.check_html(self.widget, 'is_cool', False, html='<input type="checkbox" name="is_cool">') + self.check_html( + self.widget, "is_cool", False, html='<input type="checkbox" name="is_cool">' + ) def test_render_true(self): self.check_html( - self.widget, 'is_cool', True, - html='<input checked type="checkbox" name="is_cool">' + self.widget, + "is_cool", + True, + html='<input checked type="checkbox" name="is_cool">', ) def test_render_value(self): @@ -27,7 +35,9 @@ class CheckboxInputTest(WidgetTest): checkbox and set the 'value' attribute. """ self.check_html( - self.widget, 'is_cool', 'foo', + self.widget, + "is_cool", + "foo", html='<input checked type="checkbox" name="is_cool" value="foo">', ) @@ -36,11 +46,15 @@ class CheckboxInputTest(WidgetTest): Integers are handled by value, not as booleans (#17114). """ self.check_html( - self.widget, 'is_cool', 0, + self.widget, + "is_cool", + 0, html='<input checked type="checkbox" name="is_cool" value="0">', ) self.check_html( - self.widget, 'is_cool', 1, + self.widget, + "is_cool", + 1, html='<input checked type="checkbox" name="is_cool" value="1">', ) @@ -49,30 +63,43 @@ class CheckboxInputTest(WidgetTest): You can pass 'check_test' to the constructor. This is a callable that takes the value and returns True if the box should be checked. """ - widget = CheckboxInput(check_test=lambda value: value.startswith('hello')) - self.check_html(widget, 'greeting', '', html=( - '<input type="checkbox" name="greeting">' - )) - self.check_html(widget, 'greeting', 'hello', html=( - '<input checked type="checkbox" name="greeting" value="hello">' - )) - self.check_html(widget, 'greeting', 'hello there', html=( - '<input checked type="checkbox" name="greeting" value="hello there">' - )) - self.check_html(widget, 'greeting', 'hello & goodbye', html=( - '<input checked type="checkbox" name="greeting" value="hello & goodbye">' - )) + widget = CheckboxInput(check_test=lambda value: value.startswith("hello")) + self.check_html( + widget, "greeting", "", html=('<input type="checkbox" name="greeting">') + ) + self.check_html( + widget, + "greeting", + "hello", + html=('<input checked type="checkbox" name="greeting" value="hello">'), + ) + self.check_html( + widget, + "greeting", + "hello there", + html=( + '<input checked type="checkbox" name="greeting" value="hello there">' + ), + ) + self.check_html( + widget, + "greeting", + "hello & goodbye", + html=( + '<input checked type="checkbox" name="greeting" value="hello & goodbye">' + ), + ) def test_render_check_exception(self): """ Calling check_test() shouldn't swallow exceptions (#17888). """ widget = CheckboxInput( - check_test=lambda value: value.startswith('hello'), + check_test=lambda value: value.startswith("hello"), ) with self.assertRaises(AttributeError): - widget.render('greeting', True) + widget.render("greeting", True) def test_value_from_datadict(self): """ @@ -80,17 +107,19 @@ class CheckboxInputTest(WidgetTest): the data dictionary (because HTML form submission doesn't send any result for unchecked checkboxes). """ - self.assertFalse(self.widget.value_from_datadict({}, {}, 'testing')) + self.assertFalse(self.widget.value_from_datadict({}, {}, "testing")) def test_value_from_datadict_string_int(self): - value = self.widget.value_from_datadict({'testing': '0'}, {}, 'testing') + value = self.widget.value_from_datadict({"testing": "0"}, {}, "testing") self.assertIs(value, True) def test_value_omitted_from_data(self): - self.assertIs(self.widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False) - self.assertIs(self.widget.value_omitted_from_data({}, {}, 'field'), False) + self.assertIs( + self.widget.value_omitted_from_data({"field": "value"}, {}, "field"), False + ) + self.assertIs(self.widget.value_omitted_from_data({}, {}, "field"), False) def test_get_context_does_not_mutate_attrs(self): - attrs = {'checked': False} - self.widget.get_context('name', True, attrs) - self.assertIs(attrs['checked'], False) + attrs = {"checked": False} + self.widget.get_context("name", True, attrs) + self.assertIs(attrs["checked"], False) diff --git a/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py b/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py index 65025ed748..35db8192ef 100644 --- a/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py +++ b/tests/forms_tests/widget_tests/test_checkboxselectmultiple.py @@ -11,31 +11,45 @@ class CheckboxSelectMultipleTest(WidgetTest): widget = CheckboxSelectMultiple def test_render_value(self): - self.check_html(self.widget(choices=self.beatles), 'beatles', ['J'], html=""" + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["J"], + html=""" <div> <div><label><input checked type="checkbox" name="beatles" value="J"> John</label></div> <div><label><input type="checkbox" name="beatles" value="P"> Paul</label></div> <div><label><input type="checkbox" name="beatles" value="G"> George</label></div> <div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div> </div> - """) + """, + ) def test_render_value_multiple(self): - self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'P'], html=""" + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["J", "P"], + html=""" <div> <div><label><input checked type="checkbox" name="beatles" value="J"> John</label></div> <div><label><input checked type="checkbox" name="beatles" value="P"> Paul</label></div> <div><label><input type="checkbox" name="beatles" value="G"> George</label></div> <div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div> </div> - """) + """, + ) def test_render_none(self): """ If the value is None, none of the options are selected, even if the choices have an empty option. """ - self.check_html(self.widget(choices=(('', 'Unknown'),) + self.beatles), 'beatles', None, html=""" + self.check_html( + self.widget(choices=(("", "Unknown"),) + self.beatles), + "beatles", + None, + html=""" <div> <div><label><input type="checkbox" name="beatles" value=""> Unknown</label></div> <div><label><input type="checkbox" name="beatles" value="J"> John</label></div> @@ -43,13 +57,14 @@ class CheckboxSelectMultipleTest(WidgetTest): <div><label><input type="checkbox" name="beatles" value="G"> George</label></div> <div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div> </div> - """) + """, + ) def test_nested_choices(self): nested_choices = ( - ('unknown', 'Unknown'), - ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), - ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), + ("unknown", "Unknown"), + ("Audio", (("vinyl", "Vinyl"), ("cd", "CD"))), + ("Video", (("vhs", "VHS"), ("dvd", "DVD"))), ) html = """ <div id="media"> @@ -71,15 +86,18 @@ class CheckboxSelectMultipleTest(WidgetTest): </div> """ self.check_html( - self.widget(choices=nested_choices), 'nestchoice', ('vinyl', 'dvd'), - attrs={'id': 'media'}, html=html, + self.widget(choices=nested_choices), + "nestchoice", + ("vinyl", "dvd"), + attrs={"id": "media"}, + html=html, ) def test_nested_choices_without_id(self): nested_choices = ( - ('unknown', 'Unknown'), - ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), - ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), + ("unknown", "Unknown"), + ("Audio", (("vinyl", "Vinyl"), ("cd", "CD"))), + ("Video", (("vhs", "VHS"), ("dvd", "DVD"))), ) html = """ <div> @@ -95,13 +113,18 @@ class CheckboxSelectMultipleTest(WidgetTest): </div> </div> """ - self.check_html(self.widget(choices=nested_choices), 'nestchoice', ('vinyl', 'dvd'), html=html) + self.check_html( + self.widget(choices=nested_choices), + "nestchoice", + ("vinyl", "dvd"), + html=html, + ) def test_separate_ids(self): """ Each input gets a separate ID. """ - choices = [('a', 'A'), ('b', 'B'), ('c', 'C')] + choices = [("a", "A"), ("b", "B"), ("c", "C")] html = """ <div id="abc"> <div> @@ -113,13 +136,21 @@ class CheckboxSelectMultipleTest(WidgetTest): </div> </div> """ - self.check_html(self.widget(choices=choices), 'letters', ['a', 'c'], attrs={'id': 'abc'}, html=html) + self.check_html( + self.widget(choices=choices), + "letters", + ["a", "c"], + attrs={"id": "abc"}, + html=html, + ) def test_separate_ids_constructor(self): """ Each input gets a separate ID when the ID is passed to the constructor. """ - widget = CheckboxSelectMultiple(attrs={'id': 'abc'}, choices=[('a', 'A'), ('b', 'B'), ('c', 'C')]) + widget = CheckboxSelectMultiple( + attrs={"id": "abc"}, choices=[("a", "A"), ("b", "B"), ("c", "C")] + ) html = """ <div id="abc"> <div> @@ -131,14 +162,14 @@ class CheckboxSelectMultipleTest(WidgetTest): </div> </div> """ - self.check_html(widget, 'letters', ['a', 'c'], html=html) + self.check_html(widget, "letters", ["a", "c"], html=html) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_doesnt_localize_input_value(self): choices = [ - (1, 'One'), - (1000, 'One thousand'), - (1000000, 'One million'), + (1, "One"), + (1000, "One thousand"), + (1000000, "One million"), ] html = """ <div> @@ -147,11 +178,11 @@ class CheckboxSelectMultipleTest(WidgetTest): <div><label><input type="checkbox" name="numbers" value="1000000"> One million</label></div> </div> """ - self.check_html(self.widget(choices=choices), 'numbers', None, html=html) + self.check_html(self.widget(choices=choices), "numbers", None, html=html) choices = [ - (datetime.time(0, 0), 'midnight'), - (datetime.time(12, 0), 'noon'), + (datetime.time(0, 0), "midnight"), + (datetime.time(12, 0), "noon"), ] html = """ <div> @@ -159,7 +190,7 @@ class CheckboxSelectMultipleTest(WidgetTest): <div><label><input type="checkbox" name="times" value="12:00:00"> noon</label></div> </div> """ - self.check_html(self.widget(choices=choices), 'times', None, html=html) + self.check_html(self.widget(choices=choices), "times", None, html=html) def test_use_required_attribute(self): widget = self.widget(choices=self.beatles) @@ -167,22 +198,25 @@ class CheckboxSelectMultipleTest(WidgetTest): # to be checked instead of at least one. self.assertIs(widget.use_required_attribute(None), False) self.assertIs(widget.use_required_attribute([]), False) - self.assertIs(widget.use_required_attribute(['J', 'P']), False) + self.assertIs(widget.use_required_attribute(["J", "P"]), False) def test_value_omitted_from_data(self): widget = self.widget(choices=self.beatles) - self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), False) - self.assertIs(widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False) + self.assertIs(widget.value_omitted_from_data({}, {}, "field"), False) + self.assertIs( + widget.value_omitted_from_data({"field": "value"}, {}, "field"), False + ) def test_label(self): """ CheckboxSelectMultiple doesn't contain 'for="field_0"' in the <label> because clicking that would toggle the first checkbox. """ + class TestForm(forms.Form): f = forms.MultipleChoiceField(widget=CheckboxSelectMultiple) - bound_field = TestForm()['f'] - self.assertEqual(bound_field.field.widget.id_for_label('id'), '') - self.assertEqual(bound_field.label_tag(), '<label>F:</label>') - self.assertEqual(bound_field.legend_tag(), '<legend>F:</legend>') + bound_field = TestForm()["f"] + self.assertEqual(bound_field.field.widget.id_for_label("id"), "") + self.assertEqual(bound_field.label_tag(), "<label>F:</label>") + self.assertEqual(bound_field.legend_tag(), "<legend>F:</legend>") diff --git a/tests/forms_tests/widget_tests/test_clearablefileinput.py b/tests/forms_tests/widget_tests/test_clearablefileinput.py index dee44c4239..03fe34306b 100644 --- a/tests/forms_tests/widget_tests/test_clearablefileinput.py +++ b/tests/forms_tests/widget_tests/test_clearablefileinput.py @@ -9,7 +9,8 @@ class FakeFieldFile: Quacks like a FieldFile (has a .url and string representation), but doesn't require us to care about storages etc. """ - url = 'something' + + url = "something" def __str__(self): return self.url @@ -23,35 +24,46 @@ class ClearableFileInputTest(WidgetTest): A ClearableFileInput with is_required False and rendered with an initial value that is a file renders a clear checkbox. """ - self.check_html(self.widget, 'myfile', FakeFieldFile(), html=( - """ + self.check_html( + self.widget, + "myfile", + FakeFieldFile(), + html=( + """ Currently: <a href="something">something</a> <input type="checkbox" name="myfile-clear" id="myfile-clear_id"> <label for="myfile-clear_id">Clear</label><br> Change: <input type="file" name="myfile"> """ - )) + ), + ) def test_html_escaped(self): """ A ClearableFileInput should escape name, filename, and URL when rendering HTML (#15182). """ + class StrangeFieldFile: url = "something?chapter=1§=2©=3&lang=en" def __str__(self): - return '''something<div onclick="alert('oops')">.jpg''' + return """something<div onclick="alert('oops')">.jpg""" - self.check_html(ClearableFileInput(), 'my<div>file', StrangeFieldFile(), html=( - """ + self.check_html( + ClearableFileInput(), + "my<div>file", + StrangeFieldFile(), + html=( + """ Currently: <a href="something?chapter=1&sect=2&copy=3&lang=en"> something<div onclick="alert('oops')">.jpg</a> <input type="checkbox" name="my<div>file-clear" id="my<div>file-clear_id"> <label for="my<div>file-clear_id">Clear</label><br> Change: <input type="file" name="my<div>file"> """ - )) + ), + ) def test_clear_input_renders_only_if_not_required(self): """ @@ -60,26 +72,33 @@ class ClearableFileInputTest(WidgetTest): """ widget = ClearableFileInput() widget.is_required = True - self.check_html(widget, 'myfile', FakeFieldFile(), html=( - """ + self.check_html( + widget, + "myfile", + FakeFieldFile(), + html=( + """ Currently: <a href="something">something</a> <br> Change: <input type="file" name="myfile"> """ - )) + ), + ) def test_clear_input_renders_only_if_initial(self): """ A ClearableFileInput instantiated with no initial value does not render a clear checkbox. """ - self.check_html(self.widget, 'myfile', None, html='<input type="file" name="myfile">') + self.check_html( + self.widget, "myfile", None, html='<input type="file" name="myfile">' + ) def test_render_disabled(self): self.check_html( self.widget, - 'myfile', + "myfile", FakeFieldFile(), - attrs={'disabled': True}, + attrs={"disabled": True}, html=( 'Currently: <a href="something">something</a>' '<input type="checkbox" name="myfile-clear" ' @@ -92,14 +111,19 @@ class ClearableFileInputTest(WidgetTest): def test_render_as_subwidget(self): """A ClearableFileInput as a subwidget of MultiWidget.""" widget = MultiWidget(widgets=(self.widget,)) - self.check_html(widget, 'myfile', [FakeFieldFile()], html=( - """ + self.check_html( + widget, + "myfile", + [FakeFieldFile()], + html=( + """ Currently: <a href="something">something</a> <input type="checkbox" name="myfile_0-clear" id="myfile_0-clear_id"> <label for="myfile_0-clear_id">Clear</label><br> Change: <input type="file" name="myfile_0"> """ - )) + ), + ) def test_clear_input_checked_returns_false(self): """ @@ -107,9 +131,9 @@ class ClearableFileInputTest(WidgetTest): checkbox is checked, if not required. """ value = self.widget.value_from_datadict( - data={'myfile-clear': True}, + data={"myfile-clear": True}, files={}, - name='myfile', + name="myfile", ) self.assertIs(value, False) @@ -120,12 +144,12 @@ class ClearableFileInputTest(WidgetTest): """ widget = ClearableFileInput() widget.is_required = True - field = SimpleUploadedFile('something.txt', b'content') + field = SimpleUploadedFile("something.txt", b"content") value = widget.value_from_datadict( - data={'myfile-clear': True}, - files={'myfile': field}, - name='myfile', + data={"myfile-clear": True}, + files={"myfile": field}, + name="myfile", ) self.assertEqual(value, field) @@ -134,45 +158,50 @@ class ClearableFileInputTest(WidgetTest): A ClearableFileInput should not mask exceptions produced while checking that it has a value. """ + class FailingURLFieldFile: @property def url(self): - raise ValueError('Canary') + raise ValueError("Canary") def __str__(self): - return 'value' + return "value" - with self.assertRaisesMessage(ValueError, 'Canary'): - self.widget.render('myfile', FailingURLFieldFile()) + with self.assertRaisesMessage(ValueError, "Canary"): + self.widget.render("myfile", FailingURLFieldFile()) def test_url_as_property(self): class URLFieldFile: @property def url(self): - return 'https://www.python.org/' + return "https://www.python.org/" def __str__(self): - return 'value' + return "value" - html = self.widget.render('myfile', URLFieldFile()) + html = self.widget.render("myfile", URLFieldFile()) self.assertInHTML('<a href="https://www.python.org/">value</a>', html) def test_return_false_if_url_does_not_exists(self): class NoURLFieldFile: def __str__(self): - return 'value' + return "value" - html = self.widget.render('myfile', NoURLFieldFile()) + html = self.widget.render("myfile", NoURLFieldFile()) self.assertHTMLEqual(html, '<input name="myfile" type="file">') def test_use_required_attribute(self): # False when initial data exists. The file input is left blank by the # user to keep the existing, initial value. self.assertIs(self.widget.use_required_attribute(None), True) - self.assertIs(self.widget.use_required_attribute('resume.txt'), False) + self.assertIs(self.widget.use_required_attribute("resume.txt"), False) def test_value_omitted_from_data(self): widget = ClearableFileInput() - self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), True) - self.assertIs(widget.value_omitted_from_data({}, {'field': 'x'}, 'field'), False) - self.assertIs(widget.value_omitted_from_data({'field-clear': 'y'}, {}, 'field'), False) + self.assertIs(widget.value_omitted_from_data({}, {}, "field"), True) + self.assertIs( + widget.value_omitted_from_data({}, {"field": "x"}, "field"), False + ) + self.assertIs( + widget.value_omitted_from_data({"field-clear": "y"}, {}, "field"), False + ) diff --git a/tests/forms_tests/widget_tests/test_dateinput.py b/tests/forms_tests/widget_tests/test_dateinput.py index fa08b345c1..07446480f6 100644 --- a/tests/forms_tests/widget_tests/test_dateinput.py +++ b/tests/forms_tests/widget_tests/test_dateinput.py @@ -10,36 +10,53 @@ class DateInputTest(WidgetTest): widget = DateInput() def test_render_none(self): - self.check_html(self.widget, 'date', None, html='<input type="text" name="date">') + self.check_html( + self.widget, "date", None, html='<input type="text" name="date">' + ) def test_render_value(self): d = date(2007, 9, 17) - self.assertEqual(str(d), '2007-09-17') + self.assertEqual(str(d), "2007-09-17") - self.check_html(self.widget, 'date', d, html='<input type="text" name="date" value="2007-09-17">') - self.check_html(self.widget, 'date', date(2007, 9, 17), html=( - '<input type="text" name="date" value="2007-09-17">' - )) + self.check_html( + self.widget, + "date", + d, + html='<input type="text" name="date" value="2007-09-17">', + ) + self.check_html( + self.widget, + "date", + date(2007, 9, 17), + html=('<input type="text" name="date" value="2007-09-17">'), + ) def test_string(self): """ Should be able to initialize from a string value. """ - self.check_html(self.widget, 'date', '2007-09-17', html=( - '<input type="text" name="date" value="2007-09-17">' - )) + self.check_html( + self.widget, + "date", + "2007-09-17", + html=('<input type="text" name="date" value="2007-09-17">'), + ) def test_format(self): """ Use 'format' to change the way a value is displayed. """ d = date(2007, 9, 17) - widget = DateInput(format='%d/%m/%Y', attrs={'type': 'date'}) - self.check_html(widget, 'date', d, html='<input type="date" name="date" value="17/09/2007">') + widget = DateInput(format="%d/%m/%Y", attrs={"type": "date"}) + self.check_html( + widget, "date", d, html='<input type="date" name="date" value="17/09/2007">' + ) - @translation.override('de-at') + @translation.override("de-at") def test_l10n(self): self.check_html( - self.widget, 'date', date(2007, 9, 17), + self.widget, + "date", + date(2007, 9, 17), html='<input type="text" name="date" value="17.09.2007">', ) diff --git a/tests/forms_tests/widget_tests/test_datetimeinput.py b/tests/forms_tests/widget_tests/test_datetimeinput.py index 0a2571f5b7..5795660f30 100644 --- a/tests/forms_tests/widget_tests/test_datetimeinput.py +++ b/tests/forms_tests/widget_tests/test_datetimeinput.py @@ -12,42 +12,60 @@ class DateTimeInputTest(WidgetTest): widget = DateTimeInput() def test_render_none(self): - self.check_html(self.widget, 'date', None, '<input type="text" name="date">') + self.check_html(self.widget, "date", None, '<input type="text" name="date">') def test_render_value(self): """ The microseconds are trimmed on display, by default. """ d = datetime(2007, 9, 17, 12, 51, 34, 482548) - self.assertEqual(str(d), '2007-09-17 12:51:34.482548') - self.check_html(self.widget, 'date', d, html=( - '<input type="text" name="date" value="2007-09-17 12:51:34">' - )) - self.check_html(self.widget, 'date', datetime(2007, 9, 17, 12, 51, 34), html=( - '<input type="text" name="date" value="2007-09-17 12:51:34">' - )) - self.check_html(self.widget, 'date', datetime(2007, 9, 17, 12, 51), html=( - '<input type="text" name="date" value="2007-09-17 12:51:00">' - )) + self.assertEqual(str(d), "2007-09-17 12:51:34.482548") + self.check_html( + self.widget, + "date", + d, + html=('<input type="text" name="date" value="2007-09-17 12:51:34">'), + ) + self.check_html( + self.widget, + "date", + datetime(2007, 9, 17, 12, 51, 34), + html=('<input type="text" name="date" value="2007-09-17 12:51:34">'), + ) + self.check_html( + self.widget, + "date", + datetime(2007, 9, 17, 12, 51), + html=('<input type="text" name="date" value="2007-09-17 12:51:00">'), + ) def test_render_formatted(self): """ Use 'format' to change the way a value is displayed. """ widget = DateTimeInput( - format='%d/%m/%Y %H:%M', attrs={'type': 'datetime'}, + format="%d/%m/%Y %H:%M", + attrs={"type": "datetime"}, ) d = datetime(2007, 9, 17, 12, 51, 34, 482548) - self.check_html(widget, 'date', d, html='<input type="datetime" name="date" value="17/09/2007 12:51">') + self.check_html( + widget, + "date", + d, + html='<input type="datetime" name="date" value="17/09/2007 12:51">', + ) - @translation.override('de-at') + @translation.override("de-at") def test_l10n(self): d = datetime(2007, 9, 17, 12, 51, 34, 482548) - self.check_html(self.widget, 'date', d, html=( - '<input type="text" name="date" value="17.09.2007 12:51:34">' - )) + self.check_html( + self.widget, + "date", + d, + html=('<input type="text" name="date" value="17.09.2007 12:51:34">'), + ) - @translation.override('de-at') + @translation.override("de-at") def test_locale_aware(self): d = datetime(2007, 9, 17, 12, 51, 34, 482548) # RemovedInDjango50Warning: When the deprecation ends, remove @@ -56,15 +74,23 @@ class DateTimeInputTest(WidgetTest): # locale-dictated formats. with ignore_warnings(category=RemovedInDjango50Warning): with self.settings(USE_L10N=False): - with self.settings(DATETIME_INPUT_FORMATS=[ - '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', - ]): + with self.settings( + DATETIME_INPUT_FORMATS=[ + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%d %H:%M:%S.%f", + "%Y-%m-%d %H:%M", + ] + ): self.check_html( - self.widget, 'date', d, + self.widget, + "date", + d, html='<input type="text" name="date" value="2007-09-17 12:51:34">', ) - with translation.override('es'): + with translation.override("es"): self.check_html( - self.widget, 'date', d, + self.widget, + "date", + d, html='<input type="text" name="date" value="17/09/2007 12:51:34">', ) diff --git a/tests/forms_tests/widget_tests/test_fileinput.py b/tests/forms_tests/widget_tests/test_fileinput.py index 8eec26253a..ea11c639e4 100644 --- a/tests/forms_tests/widget_tests/test_fileinput.py +++ b/tests/forms_tests/widget_tests/test_fileinput.py @@ -11,16 +11,27 @@ class FileInputTest(WidgetTest): FileInput widgets never render the value attribute. The old value isn't useful if a form is updated or an error occurred. """ - self.check_html(self.widget, 'email', 'test@example.com', html='<input type="file" name="email">') - self.check_html(self.widget, 'email', '', html='<input type="file" name="email">') - self.check_html(self.widget, 'email', None, html='<input type="file" name="email">') + self.check_html( + self.widget, + "email", + "test@example.com", + html='<input type="file" name="email">', + ) + self.check_html( + self.widget, "email", "", html='<input type="file" name="email">' + ) + self.check_html( + self.widget, "email", None, html='<input type="file" name="email">' + ) def test_value_omitted_from_data(self): - self.assertIs(self.widget.value_omitted_from_data({}, {}, 'field'), True) - self.assertIs(self.widget.value_omitted_from_data({}, {'field': 'value'}, 'field'), False) + self.assertIs(self.widget.value_omitted_from_data({}, {}, "field"), True) + self.assertIs( + self.widget.value_omitted_from_data({}, {"field": "value"}, "field"), False + ) def test_use_required_attribute(self): # False when initial data exists. The file input is left blank by the # user to keep the existing, initial value. self.assertIs(self.widget.use_required_attribute(None), True) - self.assertIs(self.widget.use_required_attribute('resume.txt'), False) + self.assertIs(self.widget.use_required_attribute("resume.txt"), False) diff --git a/tests/forms_tests/widget_tests/test_hiddeninput.py b/tests/forms_tests/widget_tests/test_hiddeninput.py index a7d036410c..ba5e796501 100644 --- a/tests/forms_tests/widget_tests/test_hiddeninput.py +++ b/tests/forms_tests/widget_tests/test_hiddeninput.py @@ -7,11 +7,13 @@ class HiddenInputTest(WidgetTest): widget = HiddenInput() def test_render(self): - self.check_html(self.widget, 'email', '', html='<input type="hidden" name="email">') + self.check_html( + self.widget, "email", "", html='<input type="hidden" name="email">' + ) def test_use_required_attribute(self): # Always False to avoid browser validation on inputs hidden from the # user. self.assertIs(self.widget.use_required_attribute(None), False) - self.assertIs(self.widget.use_required_attribute(''), False) - self.assertIs(self.widget.use_required_attribute('foo'), False) + self.assertIs(self.widget.use_required_attribute(""), False) + self.assertIs(self.widget.use_required_attribute("foo"), False) diff --git a/tests/forms_tests/widget_tests/test_input.py b/tests/forms_tests/widget_tests/test_input.py index 8be971826e..72c2c217c0 100644 --- a/tests/forms_tests/widget_tests/test_input.py +++ b/tests/forms_tests/widget_tests/test_input.py @@ -4,12 +4,20 @@ from .base import WidgetTest class InputTests(WidgetTest): - def test_attrs_with_type(self): - attrs = {'type': 'date'} + attrs = {"type": "date"} widget = Input(attrs) - self.check_html(widget, 'name', 'value', '<input type="date" name="name" value="value">') + self.check_html( + widget, "name", "value", '<input type="date" name="name" value="value">' + ) # reuse the same attrs for another widget - self.check_html(Input(attrs), 'name', 'value', '<input type="date" name="name" value="value">') - attrs['type'] = 'number' # shouldn't change the widget type - self.check_html(widget, 'name', 'value', '<input type="date" name="name" value="value">') + self.check_html( + Input(attrs), + "name", + "value", + '<input type="date" name="name" value="value">', + ) + attrs["type"] = "number" # shouldn't change the widget type + self.check_html( + widget, "name", "value", '<input type="date" name="name" value="value">' + ) diff --git a/tests/forms_tests/widget_tests/test_multiplehiddeninput.py b/tests/forms_tests/widget_tests/test_multiplehiddeninput.py index 37d54174ee..d0ad188929 100644 --- a/tests/forms_tests/widget_tests/test_multiplehiddeninput.py +++ b/tests/forms_tests/widget_tests/test_multiplehiddeninput.py @@ -8,13 +8,17 @@ class MultipleHiddenInputTest(WidgetTest): def test_render_single(self): self.check_html( - self.widget, 'email', ['test@example.com'], + self.widget, + "email", + ["test@example.com"], html='<input type="hidden" name="email" value="test@example.com">', ) def test_render_multiple(self): self.check_html( - self.widget, 'email', ['test@example.com', 'foo@example.com'], + self.widget, + "email", + ["test@example.com", "foo@example.com"], html=( '<input type="hidden" name="email" value="test@example.com">\n' '<input type="hidden" name="email" value="foo@example.com">' @@ -23,13 +27,19 @@ class MultipleHiddenInputTest(WidgetTest): def test_render_attrs(self): self.check_html( - self.widget, 'email', ['test@example.com'], attrs={'class': 'fun'}, + self.widget, + "email", + ["test@example.com"], + attrs={"class": "fun"}, html='<input type="hidden" name="email" value="test@example.com" class="fun">', ) def test_render_attrs_multiple(self): self.check_html( - self.widget, 'email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}, + self.widget, + "email", + ["test@example.com", "foo@example.com"], + attrs={"class": "fun"}, html=( '<input type="hidden" name="email" value="test@example.com" class="fun">\n' '<input type="hidden" name="email" value="foo@example.com" class="fun">' @@ -37,36 +47,46 @@ class MultipleHiddenInputTest(WidgetTest): ) def test_render_attrs_constructor(self): - widget = MultipleHiddenInput(attrs={'class': 'fun'}) - self.check_html(widget, 'email', [], '') + widget = MultipleHiddenInput(attrs={"class": "fun"}) + self.check_html(widget, "email", [], "") self.check_html( - widget, 'email', ['foo@example.com'], + widget, + "email", + ["foo@example.com"], html='<input type="hidden" class="fun" value="foo@example.com" name="email">', ) self.check_html( - widget, 'email', ['foo@example.com', 'test@example.com'], + widget, + "email", + ["foo@example.com", "test@example.com"], html=( '<input type="hidden" class="fun" value="foo@example.com" name="email">\n' '<input type="hidden" class="fun" value="test@example.com" name="email">' ), ) self.check_html( - widget, 'email', ['foo@example.com'], attrs={'class': 'special'}, + widget, + "email", + ["foo@example.com"], + attrs={"class": "special"}, html='<input type="hidden" class="special" value="foo@example.com" name="email">', ) def test_render_empty(self): - self.check_html(self.widget, 'email', [], '') + self.check_html(self.widget, "email", [], "") def test_render_none(self): - self.check_html(self.widget, 'email', None, '') + self.check_html(self.widget, "email", None, "") def test_render_increment_id(self): """ Each input should get a separate ID. """ self.check_html( - self.widget, 'letters', ['a', 'b', 'c'], attrs={'id': 'hideme'}, + self.widget, + "letters", + ["a", "b", "c"], + attrs={"id": "hideme"}, html=( '<input type="hidden" name="letters" value="a" id="hideme_0">\n' '<input type="hidden" name="letters" value="b" id="hideme_1">\n' diff --git a/tests/forms_tests/widget_tests/test_multiwidget.py b/tests/forms_tests/widget_tests/test_multiwidget.py index cb1e9d31c5..c3f676e3f7 100644 --- a/tests/forms_tests/widget_tests/test_multiwidget.py +++ b/tests/forms_tests/widget_tests/test_multiwidget.py @@ -2,8 +2,15 @@ import copy from datetime import datetime from django.forms import ( - CharField, FileInput, MultipleChoiceField, MultiValueField, MultiWidget, - RadioSelect, SelectMultiple, SplitDateTimeField, SplitDateTimeWidget, + CharField, + FileInput, + MultipleChoiceField, + MultiValueField, + MultiWidget, + RadioSelect, + SelectMultiple, + SplitDateTimeField, + SplitDateTimeWidget, TextInput, ) @@ -13,8 +20,8 @@ from .base import WidgetTest class MyMultiWidget(MultiWidget): def decompress(self, value): if value: - return value.split('__') - return ['', ''] + return value.split("__") + return ["", ""] class ComplexMultiWidget(MultiWidget): @@ -28,9 +35,11 @@ class ComplexMultiWidget(MultiWidget): def decompress(self, value): if value: - data = value.split(',') + data = value.split(",") return [ - data[0], list(data[1]), datetime.strptime(data[2], "%Y-%m-%d %H:%M:%S") + data[0], + list(data[1]), + datetime.strptime(data[2], "%Y-%m-%d %H:%M:%S"), ] return [None, None, None] @@ -46,8 +55,10 @@ class ComplexField(MultiValueField): def compress(self, data_list): if data_list: - return '%s,%s,%s' % ( - data_list[0], ''.join(data_list[1]), data_list[2], + return "%s,%s,%s" % ( + data_list[0], + "".join(data_list[1]), + data_list[2], ) return None @@ -56,6 +67,7 @@ class DeepCopyWidget(MultiWidget): """ Used to test MultiWidget.__deepcopy__(). """ + def __init__(self, choices=[]): widgets = [ RadioSelect(choices=choices), @@ -75,6 +87,7 @@ class DeepCopyWidget(MultiWidget): The choices for this widget are the Select widget's choices. """ return self.widgets[0].choices + choices = property(_get_choices, _set_choices) @@ -82,97 +95,144 @@ class MultiWidgetTest(WidgetTest): def test_subwidgets_name(self): widget = MultiWidget( widgets={ - '': TextInput(), - 'big': TextInput(attrs={'class': 'big'}), - 'small': TextInput(attrs={'class': 'small'}), + "": TextInput(), + "big": TextInput(attrs={"class": "big"}), + "small": TextInput(attrs={"class": "small"}), }, ) - self.check_html(widget, 'name', ['John', 'George', 'Paul'], html=( - '<input type="text" name="name" value="John">' - '<input type="text" name="name_big" value="George" class="big">' - '<input type="text" name="name_small" value="Paul" class="small">' - )) + self.check_html( + widget, + "name", + ["John", "George", "Paul"], + html=( + '<input type="text" name="name" value="John">' + '<input type="text" name="name_big" value="George" class="big">' + '<input type="text" name="name_small" value="Paul" class="small">' + ), + ) def test_text_inputs(self): widget = MyMultiWidget( widgets=( - TextInput(attrs={'class': 'big'}), - TextInput(attrs={'class': 'small'}), + TextInput(attrs={"class": "big"}), + TextInput(attrs={"class": "small"}), ) ) - self.check_html(widget, 'name', ['john', 'lennon'], html=( - '<input type="text" class="big" value="john" name="name_0">' - '<input type="text" class="small" value="lennon" name="name_1">' - )) - self.check_html(widget, 'name', 'john__lennon', html=( - '<input type="text" class="big" value="john" name="name_0">' - '<input type="text" class="small" value="lennon" name="name_1">' - )) - self.check_html(widget, 'name', 'john__lennon', attrs={'id': 'foo'}, html=( - '<input id="foo_0" type="text" class="big" value="john" name="name_0">' - '<input id="foo_1" type="text" class="small" value="lennon" name="name_1">' - )) + self.check_html( + widget, + "name", + ["john", "lennon"], + html=( + '<input type="text" class="big" value="john" name="name_0">' + '<input type="text" class="small" value="lennon" name="name_1">' + ), + ) + self.check_html( + widget, + "name", + "john__lennon", + html=( + '<input type="text" class="big" value="john" name="name_0">' + '<input type="text" class="small" value="lennon" name="name_1">' + ), + ) + self.check_html( + widget, + "name", + "john__lennon", + attrs={"id": "foo"}, + html=( + '<input id="foo_0" type="text" class="big" value="john" name="name_0">' + '<input id="foo_1" type="text" class="small" value="lennon" name="name_1">' + ), + ) def test_constructor_attrs(self): widget = MyMultiWidget( widgets=( - TextInput(attrs={'class': 'big'}), - TextInput(attrs={'class': 'small'}), + TextInput(attrs={"class": "big"}), + TextInput(attrs={"class": "small"}), + ), + attrs={"id": "bar"}, + ) + self.check_html( + widget, + "name", + ["john", "lennon"], + html=( + '<input id="bar_0" type="text" class="big" value="john" name="name_0">' + '<input id="bar_1" type="text" class="small" value="lennon" name="name_1">' ), - attrs={'id': 'bar'}, ) - self.check_html(widget, 'name', ['john', 'lennon'], html=( - '<input id="bar_0" type="text" class="big" value="john" name="name_0">' - '<input id="bar_1" type="text" class="small" value="lennon" name="name_1">' - )) def test_constructor_attrs_with_type(self): - attrs = {'type': 'number'} + attrs = {"type": "number"} widget = MyMultiWidget(widgets=(TextInput, TextInput()), attrs=attrs) - self.check_html(widget, 'code', ['1', '2'], html=( - '<input type="number" value="1" name="code_0">' - '<input type="number" value="2" name="code_1">' - )) - widget = MyMultiWidget(widgets=(TextInput(attrs), TextInput(attrs)), attrs={'class': 'bar'}) - self.check_html(widget, 'code', ['1', '2'], html=( - '<input type="number" value="1" name="code_0" class="bar">' - '<input type="number" value="2" name="code_1" class="bar">' - )) + self.check_html( + widget, + "code", + ["1", "2"], + html=( + '<input type="number" value="1" name="code_0">' + '<input type="number" value="2" name="code_1">' + ), + ) + widget = MyMultiWidget( + widgets=(TextInput(attrs), TextInput(attrs)), attrs={"class": "bar"} + ) + self.check_html( + widget, + "code", + ["1", "2"], + html=( + '<input type="number" value="1" name="code_0" class="bar">' + '<input type="number" value="2" name="code_1" class="bar">' + ), + ) def test_value_omitted_from_data(self): widget = MyMultiWidget(widgets=(TextInput(), TextInput())) - self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), True) - self.assertIs(widget.value_omitted_from_data({'field_0': 'x'}, {}, 'field'), False) - self.assertIs(widget.value_omitted_from_data({'field_1': 'y'}, {}, 'field'), False) - self.assertIs(widget.value_omitted_from_data({'field_0': 'x', 'field_1': 'y'}, {}, 'field'), False) + self.assertIs(widget.value_omitted_from_data({}, {}, "field"), True) + self.assertIs( + widget.value_omitted_from_data({"field_0": "x"}, {}, "field"), False + ) + self.assertIs( + widget.value_omitted_from_data({"field_1": "y"}, {}, "field"), False + ) + self.assertIs( + widget.value_omitted_from_data( + {"field_0": "x", "field_1": "y"}, {}, "field" + ), + False, + ) def test_value_from_datadict_subwidgets_name(self): - widget = MultiWidget(widgets={'x': TextInput(), '': TextInput()}) + widget = MultiWidget(widgets={"x": TextInput(), "": TextInput()}) tests = [ ({}, [None, None]), - ({'field': 'x'}, [None, 'x']), - ({'field_x': 'y'}, ['y', None]), - ({'field': 'x', 'field_x': 'y'}, ['y', 'x']), + ({"field": "x"}, [None, "x"]), + ({"field_x": "y"}, ["y", None]), + ({"field": "x", "field_x": "y"}, ["y", "x"]), ] for data, expected in tests: with self.subTest(data): self.assertEqual( - widget.value_from_datadict(data, {}, 'field'), + widget.value_from_datadict(data, {}, "field"), expected, ) def test_value_omitted_from_data_subwidgets_name(self): - widget = MultiWidget(widgets={'x': TextInput(), '': TextInput()}) + widget = MultiWidget(widgets={"x": TextInput(), "": TextInput()}) tests = [ ({}, True), - ({'field': 'x'}, False), - ({'field_x': 'y'}, False), - ({'field': 'x', 'field_x': 'y'}, False), + ({"field": "x"}, False), + ({"field_x": "y"}, False), + ({"field": "x", "field_x": "y"}, False), ] for data, expected in tests: with self.subTest(data): self.assertIs( - widget.value_omitted_from_data(data, {}, 'field'), + widget.value_omitted_from_data(data, {}, "field"), expected, ) @@ -195,8 +255,12 @@ class MultiWidgetTest(WidgetTest): MultiWidgets can be composed of other MultiWidgets. """ widget = ComplexMultiWidget() - self.check_html(widget, 'name', 'some text,JP,2007-04-25 06:24:00', html=( - """ + self.check_html( + widget, + "name", + "some text,JP,2007-04-25 06:24:00", + html=( + """ <input type="text" name="name_0" value="some text"> <select multiple name="name_1"> <option value="J" selected>John</option> @@ -207,13 +271,18 @@ class MultiWidgetTest(WidgetTest): <input type="text" name="name_2_0" value="2007-04-25"> <input type="text" name="name_2_1" value="06:24:00"> """ - )) + ), + ) def test_no_whitespace_between_widgets(self): widget = MyMultiWidget(widgets=(TextInput, TextInput())) - self.check_html(widget, 'code', None, html=( - '<input type="text" name="code_0"><input type="text" name="code_1">' - ), strict=True) + self.check_html( + widget, + "code", + None, + html=('<input type="text" name="code_0"><input type="text" name="code_1">'), + strict=True, + ) def test_deepcopy(self): """ diff --git a/tests/forms_tests/widget_tests/test_nullbooleanselect.py b/tests/forms_tests/widget_tests/test_nullbooleanselect.py index 4e34020cdd..927abdba01 100644 --- a/tests/forms_tests/widget_tests/test_nullbooleanselect.py +++ b/tests/forms_tests/widget_tests/test_nullbooleanselect.py @@ -8,85 +8,130 @@ class NullBooleanSelectTest(WidgetTest): widget = NullBooleanSelect() def test_render_true(self): - self.check_html(self.widget, 'is_cool', True, html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + True, + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_false(self): - self.check_html(self.widget, 'is_cool', False, html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + False, + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> </select>""" - )) + ), + ) def test_render_none(self): - self.check_html(self.widget, 'is_cool', None, html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + None, + html=( + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_value_unknown(self): - self.check_html(self.widget, 'is_cool', 'unknown', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "unknown", + html=( + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_value_true(self): - self.check_html(self.widget, 'is_cool', 'true', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "true", + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_value_false(self): - self.check_html(self.widget, 'is_cool', 'false', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "false", + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> </select>""" - )) + ), + ) def test_render_value_1(self): - self.check_html(self.widget, 'is_cool', '1', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "1", + html=( + """<select name="is_cool"> <option value="unknown" selected>Unknown</option> <option value="true">Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_value_2(self): - self.check_html(self.widget, 'is_cool', '2', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "2", + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true" selected>Yes</option> <option value="false">No</option> </select>""" - )) + ), + ) def test_render_value_3(self): - self.check_html(self.widget, 'is_cool', '3', html=( - """<select name="is_cool"> + self.check_html( + self.widget, + "is_cool", + "3", + html=( + """<select name="is_cool"> <option value="unknown">Unknown</option> <option value="true">Yes</option> <option value="false" selected>No</option> </select>""" - )) + ), + ) def test_l10n(self): """ @@ -94,13 +139,18 @@ class NullBooleanSelectTest(WidgetTest): """ widget = NullBooleanSelect() - with translation.override('de-at'): - self.check_html(widget, 'id_bool', True, html=( - """ + with translation.override("de-at"): + self.check_html( + widget, + "id_bool", + True, + html=( + """ <select name="id_bool"> <option value="unknown">Unbekannt</option> <option value="true" selected>Ja</option> <option value="false">Nein</option> </select> """ - )) + ), + ) diff --git a/tests/forms_tests/widget_tests/test_numberinput.py b/tests/forms_tests/widget_tests/test_numberinput.py index 9fda30e156..a6427e6e37 100644 --- a/tests/forms_tests/widget_tests/test_numberinput.py +++ b/tests/forms_tests/widget_tests/test_numberinput.py @@ -5,11 +5,12 @@ from .base import WidgetTest class NumberInputTests(WidgetTest): - @override_settings(USE_THOUSAND_SEPARATOR=True) def test_attrs_not_localized(self): - widget = NumberInput(attrs={'max': 12345, 'min': 1234, 'step': 9999}) + widget = NumberInput(attrs={"max": 12345, "min": 1234, "step": 9999}) self.check_html( - widget, 'name', 'value', - '<input type="number" name="name" value="value" max="12345" min="1234" step="9999">' + widget, + "name", + "value", + '<input type="number" name="name" value="value" max="12345" min="1234" step="9999">', ) diff --git a/tests/forms_tests/widget_tests/test_passwordinput.py b/tests/forms_tests/widget_tests/test_passwordinput.py index ecbe274d69..1adf0cc3cb 100644 --- a/tests/forms_tests/widget_tests/test_passwordinput.py +++ b/tests/forms_tests/widget_tests/test_passwordinput.py @@ -7,10 +7,17 @@ class PasswordInputTest(WidgetTest): widget = PasswordInput() def test_render(self): - self.check_html(self.widget, 'password', '', html='<input type="password" name="password">') + self.check_html( + self.widget, "password", "", html='<input type="password" name="password">' + ) def test_render_ignore_value(self): - self.check_html(self.widget, 'password', 'secret', html='<input type="password" name="password">') + self.check_html( + self.widget, + "password", + "secret", + html='<input type="password" name="password">', + ) def test_render_value_true(self): """ @@ -18,9 +25,15 @@ class PasswordInputTest(WidgetTest): render its value. For security reasons, this is off by default. """ widget = PasswordInput(render_value=True) - self.check_html(widget, 'password', '', html='<input type="password" name="password">') - self.check_html(widget, 'password', None, html='<input type="password" name="password">') self.check_html( - widget, 'password', 'test@example.com', + widget, "password", "", html='<input type="password" name="password">' + ) + self.check_html( + widget, "password", None, html='<input type="password" name="password">' + ) + self.check_html( + widget, + "password", + "test@example.com", html='<input type="password" name="password" value="test@example.com">', ) diff --git a/tests/forms_tests/widget_tests/test_radioselect.py b/tests/forms_tests/widget_tests/test_radioselect.py index 9622517144..89e4022f1c 100644 --- a/tests/forms_tests/widget_tests/test_radioselect.py +++ b/tests/forms_tests/widget_tests/test_radioselect.py @@ -10,8 +10,12 @@ class RadioSelectTest(WidgetTest): widget = RadioSelect def test_render(self): - choices = (('', '------'),) + self.beatles - self.check_html(self.widget(choices=choices), 'beatle', 'J', html=""" + choices = (("", "------"),) + self.beatles + self.check_html( + self.widget(choices=choices), + "beatle", + "J", + html=""" <div> <div><label><input type="radio" name="beatle" value=""> ------</label></div> <div><label><input checked type="radio" name="beatle" value="J"> John</label></div> @@ -19,13 +23,14 @@ class RadioSelectTest(WidgetTest): <div><label><input type="radio" name="beatle" value="G"> George</label></div> <div><label><input type="radio" name="beatle" value="R"> Ringo</label></div> </div> - """) + """, + ) def test_nested_choices(self): nested_choices = ( - ('unknown', 'Unknown'), - ('Audio', (('vinyl', 'Vinyl'), ('cd', 'CD'))), - ('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))), + ("unknown", "Unknown"), + ("Audio", (("vinyl", "Vinyl"), ("cd", "CD"))), + ("Video", (("vhs", "VHS"), ("dvd", "DVD"))), ) html = """ <div id="media"> @@ -47,8 +52,11 @@ class RadioSelectTest(WidgetTest): </div> """ self.check_html( - self.widget(choices=nested_choices), 'nestchoice', 'dvd', - attrs={'id': 'media'}, html=html, + self.widget(choices=nested_choices), + "nestchoice", + "dvd", + attrs={"id": "media"}, + html=html, ) def test_constructor_attrs(self): @@ -56,7 +64,7 @@ class RadioSelectTest(WidgetTest): Attributes provided at instantiation are passed to the constituent inputs. """ - widget = RadioSelect(attrs={'id': 'foo'}, choices=self.beatles) + widget = RadioSelect(attrs={"id": "foo"}, choices=self.beatles) html = """ <div id="foo"> <div> @@ -67,7 +75,7 @@ class RadioSelectTest(WidgetTest): <div><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle"> Ringo</label></div> </div> """ - self.check_html(widget, 'beatle', 'J', html=html) + self.check_html(widget, "beatle", "J", html=html) def test_render_attrs(self): """ @@ -84,7 +92,13 @@ class RadioSelectTest(WidgetTest): <div><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle"> Ringo</label></div> </div> """ - self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', attrs={'id': 'bar'}, html=html) + self.check_html( + self.widget(choices=self.beatles), + "beatle", + "J", + attrs={"id": "bar"}, + html=html, + ) def test_class_attrs(self): """ @@ -99,14 +113,20 @@ class RadioSelectTest(WidgetTest): <div><label><input type="radio" class="bar" value="R" name="beatle"> Ringo</label></div> </div> """ - self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', attrs={'class': 'bar'}, html=html) + self.check_html( + self.widget(choices=self.beatles), + "beatle", + "J", + attrs={"class": "bar"}, + html=html, + ) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_doesnt_localize_input_value(self): choices = [ - (1, 'One'), - (1000, 'One thousand'), - (1000000, 'One million'), + (1, "One"), + (1000, "One thousand"), + (1000000, "One million"), ] html = """ <div> @@ -115,11 +135,11 @@ class RadioSelectTest(WidgetTest): <div><label><input type="radio" name="number" value="1000000"> One million</label></div> </div> """ - self.check_html(self.widget(choices=choices), 'number', None, html=html) + self.check_html(self.widget(choices=choices), "number", None, html=html) choices = [ - (datetime.time(0, 0), 'midnight'), - (datetime.time(12, 0), 'noon'), + (datetime.time(0, 0), "midnight"), + (datetime.time(12, 0), "noon"), ] html = """ <div> @@ -127,12 +147,16 @@ class RadioSelectTest(WidgetTest): <div><label><input type="radio" name="time" value="12:00:00"> noon</label></div> </div> """ - self.check_html(self.widget(choices=choices), 'time', None, html=html) + self.check_html(self.widget(choices=choices), "time", None, html=html) def test_render_as_subwidget(self): """A RadioSelect as a subwidget of MultiWidget.""" - choices = (('', '------'),) + self.beatles - self.check_html(MultiWidget([self.widget(choices=choices)]), 'beatle', ['J'], html=""" + choices = (("", "------"),) + self.beatles + self.check_html( + MultiWidget([self.widget(choices=choices)]), + "beatle", + ["J"], + html=""" <div> <div><label><input type="radio" name="beatle_0" value=""> ------</label></div> <div><label><input checked type="radio" name="beatle_0" value="J"> John</label></div> @@ -140,4 +164,5 @@ class RadioSelectTest(WidgetTest): <div><label><input type="radio" name="beatle_0" value="G"> George</label></div> <div><label><input type="radio" name="beatle_0" value="R"> Ringo</label></div> </div> - """) + """, + ) diff --git a/tests/forms_tests/widget_tests/test_select.py b/tests/forms_tests/widget_tests/test_select.py index dc2030e3ae..e78feeb110 100644 --- a/tests/forms_tests/widget_tests/test_select.py +++ b/tests/forms_tests/widget_tests/test_select.py @@ -10,87 +10,115 @@ from .base import WidgetTest class SelectTest(WidgetTest): widget = Select - nested_widget = Select(choices=( - ('outer1', 'Outer 1'), - ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))), - )) + nested_widget = Select( + choices=( + ("outer1", "Outer 1"), + ('Group "1"', (("inner1", "Inner 1"), ("inner2", "Inner 2"))), + ) + ) def test_render(self): - self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', html=( - """<select name="beatle"> + self.check_html( + self.widget(choices=self.beatles), + "beatle", + "J", + html=( + """<select name="beatle"> <option value="J" selected>John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_none(self): """ If the value is None, none of the options are selected. """ - self.check_html(self.widget(choices=self.beatles), 'beatle', None, html=( - """<select name="beatle"> + self.check_html( + self.widget(choices=self.beatles), + "beatle", + None, + html=( + """<select name="beatle"> <option value="J">John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_label_value(self): """ If the value corresponds to a label (but not to an option value), none of the options are selected. """ - self.check_html(self.widget(choices=self.beatles), 'beatle', 'John', html=( - """<select name="beatle"> + self.check_html( + self.widget(choices=self.beatles), + "beatle", + "John", + html=( + """<select name="beatle"> <option value="J">John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_selected(self): """ Only one option can be selected (#8103). """ - choices = [('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra')] + choices = [("0", "0"), ("1", "1"), ("2", "2"), ("3", "3"), ("0", "extra")] - self.check_html(self.widget(choices=choices), 'choices', '0', html=( - """<select name="choices"> + self.check_html( + self.widget(choices=choices), + "choices", + "0", + html=( + """<select name="choices"> <option value="0" selected>0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="0">extra</option> </select>""" - )) + ), + ) def test_constructor_attrs(self): """ Select options shouldn't inherit the parent widget attrs. """ widget = Select( - attrs={'class': 'super', 'id': 'super'}, + attrs={"class": "super", "id": "super"}, choices=[(1, 1), (2, 2), (3, 3)], ) - self.check_html(widget, 'num', 2, html=( - """<select name="num" class="super" id="super"> + self.check_html( + widget, + "num", + 2, + html=( + """<select name="num" class="super" id="super"> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> </select>""" - )) + ), + ) def test_compare_to_str(self): """ The value is compared to its str(). """ self.check_html( - self.widget(choices=[('1', '1'), ('2', '2'), ('3', '3')]), - 'num', 2, + self.widget(choices=[("1", "1"), ("2", "2"), ("3", "3")]), + "num", + 2, html=( """<select name="num"> <option value="1">1</option> @@ -101,7 +129,8 @@ class SelectTest(WidgetTest): ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), - 'num', '2', + "num", + "2", html=( """<select name="num"> <option value="1">1</option> @@ -112,7 +141,8 @@ class SelectTest(WidgetTest): ) self.check_html( self.widget(choices=[(1, 1), (2, 2), (3, 3)]), - 'num', 2, + "num", + 2, html=( """<select name="num"> <option value="1">1</option> @@ -124,56 +154,78 @@ class SelectTest(WidgetTest): def test_choices_constructor(self): widget = Select(choices=[(1, 1), (2, 2), (3, 3)]) - self.check_html(widget, 'num', 2, html=( - """<select name="num"> + self.check_html( + widget, + "num", + 2, + html=( + """<select name="num"> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> </select>""" - )) + ), + ) def test_choices_constructor_generator(self): """ If choices is passed to the constructor and is a generator, it can be iterated over multiple times without getting consumed. """ + def get_choices(): for i in range(5): yield (i, i) widget = Select(choices=get_choices()) - self.check_html(widget, 'num', 2, html=( - """<select name="num"> + self.check_html( + widget, + "num", + 2, + html=( + """<select name="num"> <option value="0">0</option> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> <option value="4">4</option> </select>""" - )) - self.check_html(widget, 'num', 3, html=( - """<select name="num"> + ), + ) + self.check_html( + widget, + "num", + 3, + html=( + """<select name="num"> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3" selected>3</option> <option value="4">4</option> </select>""" - )) + ), + ) def test_choices_escaping(self): - choices = (('bad', 'you & me'), ('good', mark_safe('you > me'))) - self.check_html(self.widget(choices=choices), 'escape', None, html=( - """<select name="escape"> + choices = (("bad", "you & me"), ("good", mark_safe("you > me"))) + self.check_html( + self.widget(choices=choices), + "escape", + None, + html=( + """<select name="escape"> <option value="bad">you & me</option> <option value="good">you > me</option> </select>""" - )) + ), + ) def test_choices_unicode(self): self.check_html( - self.widget(choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), - 'email', 'ŠĐĆŽćžšđ', + self.widget(choices=[("ŠĐĆŽćžšđ", "ŠĐabcĆŽćžšđ"), ("ćžšđ", "abcćžšđ")]), + "email", + "ŠĐĆŽćžšđ", html=( """<select name="email"> <option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected> @@ -188,44 +240,59 @@ class SelectTest(WidgetTest): """ Choices can be nested one level in order to create HTML optgroups. """ - self.check_html(self.nested_widget, 'nestchoice', None, html=( - """<select name="nestchoice"> + self.check_html( + self.nested_widget, + "nestchoice", + None, + html=( + """<select name="nestchoice"> <option value="outer1">Outer 1</option> <optgroup label="Group "1""> <option value="inner1">Inner 1</option> <option value="inner2">Inner 2</option> </optgroup> </select>""" - )) + ), + ) def test_choices_select_outer(self): - self.check_html(self.nested_widget, 'nestchoice', 'outer1', html=( - """<select name="nestchoice"> + self.check_html( + self.nested_widget, + "nestchoice", + "outer1", + html=( + """<select name="nestchoice"> <option value="outer1" selected>Outer 1</option> <optgroup label="Group "1""> <option value="inner1">Inner 1</option> <option value="inner2">Inner 2</option> </optgroup> </select>""" - )) + ), + ) def test_choices_select_inner(self): - self.check_html(self.nested_widget, 'nestchoice', 'inner1', html=( - """<select name="nestchoice"> + self.check_html( + self.nested_widget, + "nestchoice", + "inner1", + html=( + """<select name="nestchoice"> <option value="outer1">Outer 1</option> <optgroup label="Group "1""> <option value="inner1" selected>Inner 1</option> <option value="inner2">Inner 2</option> </optgroup> </select>""" - )) + ), + ) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_doesnt_localize_option_value(self): choices = [ - (1, 'One'), - (1000, 'One thousand'), - (1000000, 'One million'), + (1, "One"), + (1000, "One thousand"), + (1000000, "One million"), ] html = """ <select name="number"> @@ -234,11 +301,11 @@ class SelectTest(WidgetTest): <option value="1000000">One million</option> </select> """ - self.check_html(self.widget(choices=choices), 'number', None, html=html) + self.check_html(self.widget(choices=choices), "number", None, html=html) choices = [ - (datetime.time(0, 0), 'midnight'), - (datetime.time(12, 0), 'noon'), + (datetime.time(0, 0), "midnight"), + (datetime.time(12, 0), "noon"), ] html = """ <select name="time"> @@ -246,118 +313,142 @@ class SelectTest(WidgetTest): <option value="12:00:00">noon</option> </select> """ - self.check_html(self.widget(choices=choices), 'time', None, html=html) + self.check_html(self.widget(choices=choices), "time", None, html=html) def test_options(self): - options = list(self.widget(choices=self.beatles).options( - 'name', ['J'], attrs={'class': 'super'}, - )) + options = list( + self.widget(choices=self.beatles).options( + "name", + ["J"], + attrs={"class": "super"}, + ) + ) self.assertEqual(len(options), 4) - self.assertEqual(options[0]['name'], 'name') - self.assertEqual(options[0]['value'], 'J') - self.assertEqual(options[0]['label'], 'John') - self.assertEqual(options[0]['index'], '0') - self.assertIs(options[0]['selected'], True) + self.assertEqual(options[0]["name"], "name") + self.assertEqual(options[0]["value"], "J") + self.assertEqual(options[0]["label"], "John") + self.assertEqual(options[0]["index"], "0") + self.assertIs(options[0]["selected"], True) # Template-related attributes - self.assertEqual(options[1]['name'], 'name') - self.assertEqual(options[1]['value'], 'P') - self.assertEqual(options[1]['label'], 'Paul') - self.assertEqual(options[1]['index'], '1') - self.assertIs(options[1]['selected'], False) + self.assertEqual(options[1]["name"], "name") + self.assertEqual(options[1]["value"], "P") + self.assertEqual(options[1]["label"], "Paul") + self.assertEqual(options[1]["index"], "1") + self.assertIs(options[1]["selected"], False) def test_optgroups(self): choices = [ - ('Audio', [ - ('vinyl', 'Vinyl'), - ('cd', 'CD'), - ]), - ('Video', [ - ('vhs', 'VHS Tape'), - ('dvd', 'DVD'), - ]), - ('unknown', 'Unknown'), + ( + "Audio", + [ + ("vinyl", "Vinyl"), + ("cd", "CD"), + ], + ), + ( + "Video", + [ + ("vhs", "VHS Tape"), + ("dvd", "DVD"), + ], + ), + ("unknown", "Unknown"), ] - groups = list(self.widget(choices=choices).optgroups( - 'name', ['vhs'], attrs={'class': 'super'}, - )) + groups = list( + self.widget(choices=choices).optgroups( + "name", + ["vhs"], + attrs={"class": "super"}, + ) + ) audio, video, unknown = groups label, options, index = audio - self.assertEqual(label, 'Audio') + self.assertEqual(label, "Audio") self.assertEqual( options, - [{ - 'value': 'vinyl', - 'type': 'select', - 'attrs': {}, - 'index': '0_0', - 'label': 'Vinyl', - 'template_name': 'django/forms/widgets/select_option.html', - 'name': 'name', - 'selected': False, - 'wrap_label': True, - }, { - 'value': 'cd', - 'type': 'select', - 'attrs': {}, - 'index': '0_1', - 'label': 'CD', - 'template_name': 'django/forms/widgets/select_option.html', - 'name': 'name', - 'selected': False, - 'wrap_label': True, - }] + [ + { + "value": "vinyl", + "type": "select", + "attrs": {}, + "index": "0_0", + "label": "Vinyl", + "template_name": "django/forms/widgets/select_option.html", + "name": "name", + "selected": False, + "wrap_label": True, + }, + { + "value": "cd", + "type": "select", + "attrs": {}, + "index": "0_1", + "label": "CD", + "template_name": "django/forms/widgets/select_option.html", + "name": "name", + "selected": False, + "wrap_label": True, + }, + ], ) self.assertEqual(index, 0) label, options, index = video - self.assertEqual(label, 'Video') + self.assertEqual(label, "Video") self.assertEqual( options, - [{ - 'value': 'vhs', - 'template_name': 'django/forms/widgets/select_option.html', - 'label': 'VHS Tape', - 'attrs': {'selected': True}, - 'index': '1_0', - 'name': 'name', - 'selected': True, - 'type': 'select', - 'wrap_label': True, - }, { - 'value': 'dvd', - 'template_name': 'django/forms/widgets/select_option.html', - 'label': 'DVD', - 'attrs': {}, - 'index': '1_1', - 'name': 'name', - 'selected': False, - 'type': 'select', - 'wrap_label': True, - }] + [ + { + "value": "vhs", + "template_name": "django/forms/widgets/select_option.html", + "label": "VHS Tape", + "attrs": {"selected": True}, + "index": "1_0", + "name": "name", + "selected": True, + "type": "select", + "wrap_label": True, + }, + { + "value": "dvd", + "template_name": "django/forms/widgets/select_option.html", + "label": "DVD", + "attrs": {}, + "index": "1_1", + "name": "name", + "selected": False, + "type": "select", + "wrap_label": True, + }, + ], ) self.assertEqual(index, 1) label, options, index = unknown self.assertIsNone(label) self.assertEqual( options, - [{ - 'value': 'unknown', - 'selected': False, - 'template_name': 'django/forms/widgets/select_option.html', - 'label': 'Unknown', - 'attrs': {}, - 'index': '2', - 'name': 'name', - 'type': 'select', - 'wrap_label': True, - }] + [ + { + "value": "unknown", + "selected": False, + "template_name": "django/forms/widgets/select_option.html", + "label": "Unknown", + "attrs": {}, + "index": "2", + "name": "name", + "type": "select", + "wrap_label": True, + } + ], ) self.assertEqual(index, 2) def test_optgroups_integer_choices(self): """The option 'value' is the same type as what's in `choices`.""" - groups = list(self.widget(choices=[[0, 'choice text']]).optgroups('name', ['vhs'])) + groups = list( + self.widget(choices=[[0, "choice text"]]).optgroups("name", ["vhs"]) + ) label, options, index = groups[0] - self.assertEqual(options[0]['value'], 0) + self.assertEqual(options[0]["value"], 0) def test_deepcopy(self): """ @@ -372,19 +463,19 @@ class SelectTest(WidgetTest): self.assertIsNot(widget.attrs, obj.attrs) def test_doesnt_render_required_when_impossible_to_select_empty_field(self): - widget = self.widget(choices=[('J', 'John'), ('P', 'Paul')]) + widget = self.widget(choices=[("J", "John"), ("P", "Paul")]) self.assertIs(widget.use_required_attribute(initial=None), False) def test_renders_required_when_possible_to_select_empty_field_str(self): - widget = self.widget(choices=[('', 'select please'), ('P', 'Paul')]) + widget = self.widget(choices=[("", "select please"), ("P", "Paul")]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_renders_required_when_possible_to_select_empty_field_list(self): - widget = self.widget(choices=[['', 'select please'], ['P', 'Paul']]) + widget = self.widget(choices=[["", "select please"], ["P", "Paul"]]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_renders_required_when_possible_to_select_empty_field_none(self): - widget = self.widget(choices=[(None, 'select please'), ('P', 'Paul')]) + widget = self.widget(choices=[(None, "select please"), ("P", "Paul")]) self.assertIs(widget.use_required_attribute(initial=None), True) def test_doesnt_render_required_when_no_choices_are_available(self): diff --git a/tests/forms_tests/widget_tests/test_selectdatewidget.py b/tests/forms_tests/widget_tests/test_selectdatewidget.py index 6a922e4e71..de0c35cd5b 100644 --- a/tests/forms_tests/widget_tests/test_selectdatewidget.py +++ b/tests/forms_tests/widget_tests/test_selectdatewidget.py @@ -12,12 +12,27 @@ from .base import WidgetTest class SelectDateWidgetTest(WidgetTest): maxDiff = None widget = SelectDateWidget( - years=('2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016'), + years=( + "2007", + "2008", + "2009", + "2010", + "2011", + "2012", + "2013", + "2014", + "2015", + "2016", + ), ) def test_render_empty(self): - self.check_html(self.widget, 'mydate', '', html=( - """ + self.check_html( + self.widget, + "mydate", + "", + html=( + """ <select name="mydate_month" id="id_mydate_month"> <option selected value="">---</option> <option value="1">January</option> @@ -83,20 +98,25 @@ class SelectDateWidgetTest(WidgetTest): <option value="2016">2016</option> </select> """ - )) + ), + ) def test_render_none(self): """ Rendering the None or '' values should yield the same output. """ self.assertHTMLEqual( - self.widget.render('mydate', None), - self.widget.render('mydate', ''), + self.widget.render("mydate", None), + self.widget.render("mydate", ""), ) def test_render_string(self): - self.check_html(self.widget, 'mydate', '2010-04-15', html=( - """ + self.check_html( + self.widget, + "mydate", + "2010-04-15", + html=( + """ <select name="mydate_month" id="id_mydate_month"> <option value="">---</option> <option value="1">January</option> @@ -162,20 +182,25 @@ class SelectDateWidgetTest(WidgetTest): <option value="2016">2016</option> </select> """ - )) + ), + ) def test_render_datetime(self): self.assertHTMLEqual( - self.widget.render('mydate', date(2010, 4, 15)), - self.widget.render('mydate', '2010-04-15'), + self.widget.render("mydate", date(2010, 4, 15)), + self.widget.render("mydate", "2010-04-15"), ) def test_render_invalid_date(self): """ Invalid dates should still render the failed date. """ - self.check_html(self.widget, 'mydate', '2010-02-31', html=( - """ + self.check_html( + self.widget, + "mydate", + "2010-02-31", + html=( + """ <select name="mydate_month" id="id_mydate_month"> <option value="">---</option> <option value="1">January</option> @@ -241,12 +266,17 @@ class SelectDateWidgetTest(WidgetTest): <option value="2016">2016</option> </select> """ - )) + ), + ) def test_custom_months(self): - widget = SelectDateWidget(months=MONTHS_AP, years=('2013',)) - self.check_html(widget, 'mydate', '', html=( - """ + widget = SelectDateWidget(months=MONTHS_AP, years=("2013",)) + self.check_html( + widget, + "mydate", + "", + html=( + """ <select name="mydate_month" id="id_mydate_month"> <option selected value="">---</option> <option value="1">Jan.</option> @@ -303,7 +333,8 @@ class SelectDateWidgetTest(WidgetTest): <option value="2013">2013</option> </select> """ - )) + ), + ) def test_selectdate_required(self): class GetNotRequiredDate(Form): @@ -312,20 +343,26 @@ class SelectDateWidgetTest(WidgetTest): class GetRequiredDate(Form): mydate = DateField(widget=SelectDateWidget, required=True) - self.assertFalse(GetNotRequiredDate().fields['mydate'].widget.is_required) - self.assertTrue(GetRequiredDate().fields['mydate'].widget.is_required) + self.assertFalse(GetNotRequiredDate().fields["mydate"].widget.is_required) + self.assertTrue(GetRequiredDate().fields["mydate"].widget.is_required) def test_selectdate_empty_label(self): - w = SelectDateWidget(years=('2014',), empty_label='empty_label') + w = SelectDateWidget(years=("2014",), empty_label="empty_label") # Rendering the default state with empty_label set as string. - self.assertInHTML('<option selected value="">empty_label</option>', w.render('mydate', ''), count=3) + self.assertInHTML( + '<option selected value="">empty_label</option>', + w.render("mydate", ""), + count=3, + ) - w = SelectDateWidget(years=('2014',), empty_label=('empty_year', 'empty_month', 'empty_day')) + w = SelectDateWidget( + years=("2014",), empty_label=("empty_year", "empty_month", "empty_day") + ) # Rendering the default state with empty_label tuple. self.assertHTMLEqual( - w.render('mydate', ''), + w.render("mydate", ""), """ <select name="mydate_month" id="id_mydate_month"> <option selected value="">empty_month</option> @@ -385,21 +422,36 @@ class SelectDateWidgetTest(WidgetTest): """, ) - with self.assertRaisesMessage(ValueError, 'empty_label list/tuple must have 3 elements.'): - SelectDateWidget(years=('2014',), empty_label=('not enough', 'values')) + with self.assertRaisesMessage( + ValueError, "empty_label list/tuple must have 3 elements." + ): + SelectDateWidget(years=("2014",), empty_label=("not enough", "values")) - @translation.override('nl') + @translation.override("nl") def test_l10n(self): w = SelectDateWidget( - years=('2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016') + years=( + "2007", + "2008", + "2009", + "2010", + "2011", + "2012", + "2013", + "2014", + "2015", + "2016", + ) ) self.assertEqual( - w.value_from_datadict({'date_year': '2010', 'date_month': '8', 'date_day': '13'}, {}, 'date'), - '13-08-2010', + w.value_from_datadict( + {"date_year": "2010", "date_month": "8", "date_day": "13"}, {}, "date" + ), + "13-08-2010", ) self.assertHTMLEqual( - w.render('date', '13-08-2010'), + w.render("date", "13-08-2010"), """ <select name="date_day" id="id_date_day"> <option value="">---</option> @@ -469,20 +521,24 @@ class SelectDateWidgetTest(WidgetTest): ) # Even with an invalid date, the widget should reflect the entered value (#17401). - self.assertEqual(w.render('mydate', '2010-02-30').count('selected'), 3) + self.assertEqual(w.render("mydate", "2010-02-30").count("selected"), 3) # Years before 1900 should work. - w = SelectDateWidget(years=('1899',)) + w = SelectDateWidget(years=("1899",)) self.assertEqual( - w.value_from_datadict({'date_year': '1899', 'date_month': '8', 'date_day': '13'}, {}, 'date'), - '13-08-1899', + w.value_from_datadict( + {"date_year": "1899", "date_month": "8", "date_day": "13"}, {}, "date" + ), + "13-08-1899", ) # And years before 1000 (demonstrating the need for # sanitize_strftime_format). - w = SelectDateWidget(years=('0001',)) + w = SelectDateWidget(years=("0001",)) self.assertEqual( - w.value_from_datadict({'date_year': '0001', 'date_month': '8', 'date_day': '13'}, {}, 'date'), - '13-08-0001', + w.value_from_datadict( + {"date_year": "0001", "date_month": "8", "date_day": "13"}, {}, "date" + ), + "13-08-0001", ) # RemovedInDjango50Warning: When the deprecation ends, remove @@ -490,77 +546,110 @@ class SelectDateWidgetTest(WidgetTest): # format-related settings will take precedence over locale-dictated # formats. @ignore_warnings(category=RemovedInDjango50Warning) - @override_settings(USE_L10N=False, DATE_INPUT_FORMATS=['%d.%m.%Y']) + @override_settings(USE_L10N=False, DATE_INPUT_FORMATS=["%d.%m.%Y"]) def test_custom_input_format(self): - w = SelectDateWidget(years=('0001', '1899', '2009', '2010')) + w = SelectDateWidget(years=("0001", "1899", "2009", "2010")) for values, expected_value in ( - (('0001', '8', '13'), '13.08.0001'), - (('1899', '7', '11'), '11.07.1899'), - (('2009', '3', '7'), '07.03.2009'), + (("0001", "8", "13"), "13.08.0001"), + (("1899", "7", "11"), "11.07.1899"), + (("2009", "3", "7"), "07.03.2009"), ): with self.subTest(values=values): data = { - 'field_%s' % field: value - for field, value in zip(('year', 'month', 'day'), values) + "field_%s" % field: value + for field, value in zip(("year", "month", "day"), values) } - self.assertEqual(w.value_from_datadict(data, {}, 'field'), expected_value) + self.assertEqual( + w.value_from_datadict(data, {}, "field"), expected_value + ) expected_dict = { field: int(value) - for field, value in zip(('year', 'month', 'day'), values) + for field, value in zip(("year", "month", "day"), values) } self.assertEqual(w.format_value(expected_value), expected_dict) def test_format_value(self): valid_formats = [ - '2000-1-1', '2000-10-15', '2000-01-01', - '2000-01-0', '2000-0-01', '2000-0-0', - '0-01-01', '0-01-0', '0-0-01', '0-0-0', + "2000-1-1", + "2000-10-15", + "2000-01-01", + "2000-01-0", + "2000-0-01", + "2000-0-0", + "0-01-01", + "0-01-0", + "0-0-01", + "0-0-0", ] for value in valid_formats: - year, month, day = (int(x) or '' for x in value.split('-')) + year, month, day = (int(x) or "" for x in value.split("-")) with self.subTest(value=value): - self.assertEqual(self.widget.format_value(value), {'day': day, 'month': month, 'year': year}) + self.assertEqual( + self.widget.format_value(value), + {"day": day, "month": month, "year": year}, + ) invalid_formats = [ - '2000-01-001', '2000-001-01', '2-01-01', '20-01-01', '200-01-01', - '20000-01-01', + "2000-01-001", + "2000-001-01", + "2-01-01", + "20-01-01", + "200-01-01", + "20000-01-01", ] for value in invalid_formats: with self.subTest(value=value): - self.assertEqual(self.widget.format_value(value), {'day': None, 'month': None, 'year': None}) + self.assertEqual( + self.widget.format_value(value), + {"day": None, "month": None, "year": None}, + ) def test_value_from_datadict(self): tests = [ - (('2000', '12', '1'), '2000-12-01'), - (('', '12', '1'), '0-12-1'), - (('2000', '', '1'), '2000-0-1'), - (('2000', '12', ''), '2000-12-0'), - (('', '', '', ''), None), - ((None, '12', '1'), None), - (('2000', None, '1'), None), - (('2000', '12', None), None), + (("2000", "12", "1"), "2000-12-01"), + (("", "12", "1"), "0-12-1"), + (("2000", "", "1"), "2000-0-1"), + (("2000", "12", ""), "2000-12-0"), + (("", "", "", ""), None), + ((None, "12", "1"), None), + (("2000", None, "1"), None), + (("2000", "12", None), None), ] for values, expected in tests: with self.subTest(values=values): data = {} - for field_name, value in zip(('year', 'month', 'day'), values): + for field_name, value in zip(("year", "month", "day"), values): if value is not None: - data['field_%s' % field_name] = value - self.assertEqual(self.widget.value_from_datadict(data, {}, 'field'), expected) + data["field_%s" % field_name] = value + self.assertEqual( + self.widget.value_from_datadict(data, {}, "field"), expected + ) def test_value_omitted_from_data(self): - self.assertIs(self.widget.value_omitted_from_data({}, {}, 'field'), True) - self.assertIs(self.widget.value_omitted_from_data({'field_month': '12'}, {}, 'field'), False) - self.assertIs(self.widget.value_omitted_from_data({'field_year': '2000'}, {}, 'field'), False) - self.assertIs(self.widget.value_omitted_from_data({'field_day': '1'}, {}, 'field'), False) - data = {'field_day': '1', 'field_month': '12', 'field_year': '2000'} - self.assertIs(self.widget.value_omitted_from_data(data, {}, 'field'), False) + self.assertIs(self.widget.value_omitted_from_data({}, {}, "field"), True) + self.assertIs( + self.widget.value_omitted_from_data({"field_month": "12"}, {}, "field"), + False, + ) + self.assertIs( + self.widget.value_omitted_from_data({"field_year": "2000"}, {}, "field"), + False, + ) + self.assertIs( + self.widget.value_omitted_from_data({"field_day": "1"}, {}, "field"), False + ) + data = {"field_day": "1", "field_month": "12", "field_year": "2000"} + self.assertIs(self.widget.value_omitted_from_data(data, {}, "field"), False) @override_settings(USE_THOUSAND_SEPARATOR=True) def test_years_rendered_without_separator(self): widget = SelectDateWidget(years=(2007,)) - self.check_html(widget, 'mydate', '', html=( - """ + self.check_html( + widget, + "mydate", + "", + html=( + """ <select name="mydate_month" id="id_mydate_month"> <option selected value="">---</option> <option value="1">January</option> @@ -615,4 +704,5 @@ class SelectDateWidgetTest(WidgetTest): <option value="2007">2007</option> </select> """ - )) + ), + ) diff --git a/tests/forms_tests/widget_tests/test_selectmultiple.py b/tests/forms_tests/widget_tests/test_selectmultiple.py index eb144ba4b3..99b53521e7 100644 --- a/tests/forms_tests/widget_tests/test_selectmultiple.py +++ b/tests/forms_tests/widget_tests/test_selectmultiple.py @@ -5,134 +5,188 @@ from .base import WidgetTest class SelectMultipleTest(WidgetTest): widget = SelectMultiple - numeric_choices = (('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra')) + numeric_choices = (("0", "0"), ("1", "1"), ("2", "2"), ("3", "3"), ("0", "extra")) def test_format_value(self): widget = self.widget(choices=self.numeric_choices) self.assertEqual(widget.format_value(None), []) - self.assertEqual(widget.format_value(''), ['']) - self.assertEqual(widget.format_value([3, 0, 1]), ['3', '0', '1']) + self.assertEqual(widget.format_value(""), [""]) + self.assertEqual(widget.format_value([3, 0, 1]), ["3", "0", "1"]) def test_render_selected(self): - self.check_html(self.widget(choices=self.beatles), 'beatles', ['J'], html=( - """<select multiple name="beatles"> + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["J"], + html=( + """<select multiple name="beatles"> <option value="J" selected>John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_multiple_selected(self): - self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'P'], html=( - """<select multiple name="beatles"> + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["J", "P"], + html=( + """<select multiple name="beatles"> <option value="J" selected>John</option> <option value="P" selected>Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_none(self): """ If the value is None, none of the options are selected, even if the choices have an empty option. """ - self.check_html(self.widget(choices=(('', 'Unknown'),) + self.beatles), 'beatles', None, html=( - """<select multiple name="beatles"> + self.check_html( + self.widget(choices=(("", "Unknown"),) + self.beatles), + "beatles", + None, + html=( + """<select multiple name="beatles"> <option value="">Unknown</option> <option value="J">John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_render_value_label(self): """ If the value corresponds to a label (but not to an option value), none of the options are selected. """ - self.check_html(self.widget(choices=self.beatles), 'beatles', ['John'], html=( - """<select multiple name="beatles"> + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["John"], + html=( + """<select multiple name="beatles"> <option value="J">John</option> <option value="P">Paul</option> <option value="G">George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_multiple_options_same_value(self): """ Multiple options with the same value can be selected (#8103). """ - self.check_html(self.widget(choices=self.numeric_choices), 'choices', ['0'], html=( - """<select multiple name="choices"> + self.check_html( + self.widget(choices=self.numeric_choices), + "choices", + ["0"], + html=( + """<select multiple name="choices"> <option value="0" selected>0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="0" selected>extra</option> </select>""" - )) + ), + ) def test_multiple_values_invalid(self): """ If multiple values are given, but some of them are not valid, the valid ones are selected. """ - self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'G', 'foo'], html=( - """<select multiple name="beatles"> + self.check_html( + self.widget(choices=self.beatles), + "beatles", + ["J", "G", "foo"], + html=( + """<select multiple name="beatles"> <option value="J" selected>John</option> <option value="P">Paul</option> <option value="G" selected>George</option> <option value="R">Ringo</option> </select>""" - )) + ), + ) def test_compare_string(self): - choices = [('1', '1'), ('2', '2'), ('3', '3')] + choices = [("1", "1"), ("2", "2"), ("3", "3")] - self.check_html(self.widget(choices=choices), 'nums', [2], html=( - """<select multiple name="nums"> + self.check_html( + self.widget(choices=choices), + "nums", + [2], + html=( + """<select multiple name="nums"> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> </select>""" - )) + ), + ) - self.check_html(self.widget(choices=choices), 'nums', ['2'], html=( - """<select multiple name="nums"> + self.check_html( + self.widget(choices=choices), + "nums", + ["2"], + html=( + """<select multiple name="nums"> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> </select>""" - )) + ), + ) - self.check_html(self.widget(choices=choices), 'nums', [2], html=( - """<select multiple name="nums"> + self.check_html( + self.widget(choices=choices), + "nums", + [2], + html=( + """<select multiple name="nums"> <option value="1">1</option> <option value="2" selected>2</option> <option value="3">3</option> </select>""" - )) + ), + ) def test_optgroup_select_multiple(self): - widget = SelectMultiple(choices=( - ('outer1', 'Outer 1'), - ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))), - )) - self.check_html(widget, 'nestchoice', ['outer1', 'inner2'], html=( - """<select multiple name="nestchoice"> + widget = SelectMultiple( + choices=( + ("outer1", "Outer 1"), + ('Group "1"', (("inner1", "Inner 1"), ("inner2", "Inner 2"))), + ) + ) + self.check_html( + widget, + "nestchoice", + ["outer1", "inner2"], + html=( + """<select multiple name="nestchoice"> <option value="outer1" selected>Outer 1</option> <optgroup label="Group "1""> <option value="inner1">Inner 1</option> <option value="inner2" selected>Inner 2</option> </optgroup> </select>""" - )) + ), + ) def test_value_omitted_from_data(self): widget = self.widget(choices=self.beatles) - self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), False) - self.assertIs(widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False) + self.assertIs(widget.value_omitted_from_data({}, {}, "field"), False) + self.assertIs( + widget.value_omitted_from_data({"field": "value"}, {}, "field"), False + ) diff --git a/tests/forms_tests/widget_tests/test_splitdatetimewidget.py b/tests/forms_tests/widget_tests/test_splitdatetimewidget.py index ebb30da148..ca48505b85 100644 --- a/tests/forms_tests/widget_tests/test_splitdatetimewidget.py +++ b/tests/forms_tests/widget_tests/test_splitdatetimewidget.py @@ -9,45 +9,72 @@ class SplitDateTimeWidgetTest(WidgetTest): widget = SplitDateTimeWidget() def test_render_empty(self): - self.check_html(self.widget, 'date', '', html=( - '<input type="text" name="date_0"><input type="text" name="date_1">' - )) + self.check_html( + self.widget, + "date", + "", + html=('<input type="text" name="date_0"><input type="text" name="date_1">'), + ) def test_render_none(self): - self.check_html(self.widget, 'date', None, html=( - '<input type="text" name="date_0"><input type="text" name="date_1">' - )) + self.check_html( + self.widget, + "date", + None, + html=('<input type="text" name="date_0"><input type="text" name="date_1">'), + ) def test_render_datetime(self): - self.check_html(self.widget, 'date', datetime(2006, 1, 10, 7, 30), html=( - '<input type="text" name="date_0" value="2006-01-10">' - '<input type="text" name="date_1" value="07:30:00">' - )) + self.check_html( + self.widget, + "date", + datetime(2006, 1, 10, 7, 30), + html=( + '<input type="text" name="date_0" value="2006-01-10">' + '<input type="text" name="date_1" value="07:30:00">' + ), + ) def test_render_date_and_time(self): - self.check_html(self.widget, 'date', [date(2006, 1, 10), time(7, 30)], html=( - '<input type="text" name="date_0" value="2006-01-10">' - '<input type="text" name="date_1" value="07:30:00">' - )) + self.check_html( + self.widget, + "date", + [date(2006, 1, 10), time(7, 30)], + html=( + '<input type="text" name="date_0" value="2006-01-10">' + '<input type="text" name="date_1" value="07:30:00">' + ), + ) def test_constructor_attrs(self): - widget = SplitDateTimeWidget(attrs={'class': 'pretty'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=( - '<input type="text" class="pretty" value="2006-01-10" name="date_0">' - '<input type="text" class="pretty" value="07:30:00" name="date_1">' - )) + widget = SplitDateTimeWidget(attrs={"class": "pretty"}) + self.check_html( + widget, + "date", + datetime(2006, 1, 10, 7, 30), + html=( + '<input type="text" class="pretty" value="2006-01-10" name="date_0">' + '<input type="text" class="pretty" value="07:30:00" name="date_1">' + ), + ) def test_constructor_different_attrs(self): html = ( '<input type="text" class="foo" value="2006-01-10" name="date_0">' '<input type="text" class="bar" value="07:30:00" name="date_1">' ) - widget = SplitDateTimeWidget(date_attrs={'class': 'foo'}, time_attrs={'class': 'bar'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) - widget = SplitDateTimeWidget(date_attrs={'class': 'foo'}, attrs={'class': 'bar'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) - widget = SplitDateTimeWidget(time_attrs={'class': 'bar'}, attrs={'class': 'foo'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitDateTimeWidget( + date_attrs={"class": "foo"}, time_attrs={"class": "bar"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitDateTimeWidget( + date_attrs={"class": "foo"}, attrs={"class": "bar"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitDateTimeWidget( + time_attrs={"class": "bar"}, attrs={"class": "foo"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) def test_formatting(self): """ @@ -55,9 +82,15 @@ class SplitDateTimeWidgetTest(WidgetTest): displayed. """ widget = SplitDateTimeWidget( - date_format='%d/%m/%Y', time_format='%H:%M', + date_format="%d/%m/%Y", + time_format="%H:%M", + ) + self.check_html( + widget, + "date", + datetime(2006, 1, 10, 7, 30), + html=( + '<input type="text" name="date_0" value="10/01/2006">' + '<input type="text" name="date_1" value="07:30">' + ), ) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=( - '<input type="text" name="date_0" value="10/01/2006">' - '<input type="text" name="date_1" value="07:30">' - )) diff --git a/tests/forms_tests/widget_tests/test_splithiddendatetimewidget.py b/tests/forms_tests/widget_tests/test_splithiddendatetimewidget.py index c574eb6f7b..549f8c7754 100644 --- a/tests/forms_tests/widget_tests/test_splithiddendatetimewidget.py +++ b/tests/forms_tests/widget_tests/test_splithiddendatetimewidget.py @@ -10,43 +10,74 @@ class SplitHiddenDateTimeWidgetTest(WidgetTest): widget = SplitHiddenDateTimeWidget() def test_render_empty(self): - self.check_html(self.widget, 'date', '', html=( - '<input type="hidden" name="date_0"><input type="hidden" name="date_1">' - )) + self.check_html( + self.widget, + "date", + "", + html=( + '<input type="hidden" name="date_0"><input type="hidden" name="date_1">' + ), + ) def test_render_value(self): d = datetime(2007, 9, 17, 12, 51, 34, 482548) - self.check_html(self.widget, 'date', d, html=( - '<input type="hidden" name="date_0" value="2007-09-17">' - '<input type="hidden" name="date_1" value="12:51:34">' - )) - self.check_html(self.widget, 'date', datetime(2007, 9, 17, 12, 51, 34), html=( - '<input type="hidden" name="date_0" value="2007-09-17">' - '<input type="hidden" name="date_1" value="12:51:34">' - )) - self.check_html(self.widget, 'date', datetime(2007, 9, 17, 12, 51), html=( - '<input type="hidden" name="date_0" value="2007-09-17">' - '<input type="hidden" name="date_1" value="12:51:00">' - )) + self.check_html( + self.widget, + "date", + d, + html=( + '<input type="hidden" name="date_0" value="2007-09-17">' + '<input type="hidden" name="date_1" value="12:51:34">' + ), + ) + self.check_html( + self.widget, + "date", + datetime(2007, 9, 17, 12, 51, 34), + html=( + '<input type="hidden" name="date_0" value="2007-09-17">' + '<input type="hidden" name="date_1" value="12:51:34">' + ), + ) + self.check_html( + self.widget, + "date", + datetime(2007, 9, 17, 12, 51), + html=( + '<input type="hidden" name="date_0" value="2007-09-17">' + '<input type="hidden" name="date_1" value="12:51:00">' + ), + ) - @translation.override('de-at') + @translation.override("de-at") def test_l10n(self): d = datetime(2007, 9, 17, 12, 51) - self.check_html(self.widget, 'date', d, html=( - """ + self.check_html( + self.widget, + "date", + d, + html=( + """ <input type="hidden" name="date_0" value="17.09.2007"> <input type="hidden" name="date_1" value="12:51:00"> """ - )) + ), + ) def test_constructor_different_attrs(self): html = ( '<input type="hidden" class="foo" value="2006-01-10" name="date_0">' '<input type="hidden" class="bar" value="07:30:00" name="date_1">' ) - widget = SplitHiddenDateTimeWidget(date_attrs={'class': 'foo'}, time_attrs={'class': 'bar'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) - widget = SplitHiddenDateTimeWidget(date_attrs={'class': 'foo'}, attrs={'class': 'bar'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) - widget = SplitHiddenDateTimeWidget(time_attrs={'class': 'bar'}, attrs={'class': 'foo'}) - self.check_html(widget, 'date', datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitHiddenDateTimeWidget( + date_attrs={"class": "foo"}, time_attrs={"class": "bar"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitHiddenDateTimeWidget( + date_attrs={"class": "foo"}, attrs={"class": "bar"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) + widget = SplitHiddenDateTimeWidget( + time_attrs={"class": "bar"}, attrs={"class": "foo"} + ) + self.check_html(widget, "date", datetime(2006, 1, 10, 7, 30), html=html) diff --git a/tests/forms_tests/widget_tests/test_textarea.py b/tests/forms_tests/widget_tests/test_textarea.py index 490848fab3..e92dfc51f4 100644 --- a/tests/forms_tests/widget_tests/test_textarea.py +++ b/tests/forms_tests/widget_tests/test_textarea.py @@ -8,27 +8,55 @@ class TextareaTest(WidgetTest): widget = Textarea() def test_render(self): - self.check_html(self.widget, 'msg', 'value', html=( - '<textarea rows="10" cols="40" name="msg">value</textarea>' - )) + self.check_html( + self.widget, + "msg", + "value", + html=('<textarea rows="10" cols="40" name="msg">value</textarea>'), + ) def test_render_required(self): widget = Textarea() widget.is_required = True - self.check_html(widget, 'msg', 'value', html='<textarea rows="10" cols="40" name="msg">value</textarea>') + self.check_html( + widget, + "msg", + "value", + html='<textarea rows="10" cols="40" name="msg">value</textarea>', + ) def test_render_empty(self): - self.check_html(self.widget, 'msg', '', html='<textarea rows="10" cols="40" name="msg"></textarea>') + self.check_html( + self.widget, + "msg", + "", + html='<textarea rows="10" cols="40" name="msg"></textarea>', + ) def test_render_none(self): - self.check_html(self.widget, 'msg', None, html='<textarea rows="10" cols="40" name="msg"></textarea>') + self.check_html( + self.widget, + "msg", + None, + html='<textarea rows="10" cols="40" name="msg"></textarea>', + ) def test_escaping(self): - self.check_html(self.widget, 'msg', 'some "quoted" & ampersanded value', html=( - '<textarea rows="10" cols="40" name="msg">some "quoted" & ampersanded value</textarea>' - )) + self.check_html( + self.widget, + "msg", + 'some "quoted" & ampersanded value', + html=( + '<textarea rows="10" cols="40" name="msg">some "quoted" & ampersanded value</textarea>' + ), + ) def test_mark_safe(self): - self.check_html(self.widget, 'msg', mark_safe('pre "quoted" value'), html=( - '<textarea rows="10" cols="40" name="msg">pre "quoted" value</textarea>' - )) + self.check_html( + self.widget, + "msg", + mark_safe("pre "quoted" value"), + html=( + '<textarea rows="10" cols="40" name="msg">pre "quoted" value</textarea>' + ), + ) diff --git a/tests/forms_tests/widget_tests/test_textinput.py b/tests/forms_tests/widget_tests/test_textinput.py index 260e86f740..52ffabec65 100644 --- a/tests/forms_tests/widget_tests/test_textinput.py +++ b/tests/forms_tests/widget_tests/test_textinput.py @@ -8,43 +8,64 @@ class TextInputTest(WidgetTest): widget = TextInput() def test_render(self): - self.check_html(self.widget, 'email', '', html='<input type="text" name="email">') + self.check_html( + self.widget, "email", "", html='<input type="text" name="email">' + ) def test_render_none(self): - self.check_html(self.widget, 'email', None, html='<input type="text" name="email">') + self.check_html( + self.widget, "email", None, html='<input type="text" name="email">' + ) def test_render_value(self): - self.check_html(self.widget, 'email', 'test@example.com', html=( - '<input type="text" name="email" value="test@example.com">' - )) + self.check_html( + self.widget, + "email", + "test@example.com", + html=('<input type="text" name="email" value="test@example.com">'), + ) def test_render_boolean(self): """ Boolean values are rendered to their string forms ("True" and "False"). """ - self.check_html(self.widget, 'get_spam', False, html=( - '<input type="text" name="get_spam" value="False">' - )) - self.check_html(self.widget, 'get_spam', True, html=( - '<input type="text" name="get_spam" value="True">' - )) + self.check_html( + self.widget, + "get_spam", + False, + html=('<input type="text" name="get_spam" value="False">'), + ) + self.check_html( + self.widget, + "get_spam", + True, + html=('<input type="text" name="get_spam" value="True">'), + ) def test_render_quoted(self): self.check_html( - self.widget, 'email', 'some "quoted" & ampersanded value', + self.widget, + "email", + 'some "quoted" & ampersanded value', html='<input type="text" name="email" value="some "quoted" & ampersanded value">', ) def test_render_custom_attrs(self): self.check_html( - self.widget, 'email', 'test@example.com', attrs={'class': 'fun'}, + self.widget, + "email", + "test@example.com", + attrs={"class": "fun"}, html='<input type="text" name="email" value="test@example.com" class="fun">', ) def test_render_unicode(self): self.check_html( - self.widget, 'email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}, + self.widget, + "email", + "ŠĐĆŽćžšđ", + attrs={"class": "fun"}, html=( '<input type="text" name="email" ' 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" class="fun">' @@ -52,10 +73,14 @@ class TextInputTest(WidgetTest): ) def test_constructor_attrs(self): - widget = TextInput(attrs={'class': 'fun', 'type': 'email'}) - self.check_html(widget, 'email', '', html='<input type="email" class="fun" name="email">') + widget = TextInput(attrs={"class": "fun", "type": "email"}) self.check_html( - widget, 'email', 'foo@example.com', + widget, "email", "", html='<input type="email" class="fun" name="email">' + ) + self.check_html( + widget, + "email", + "foo@example.com", html='<input type="email" class="fun" value="foo@example.com" name="email">', ) @@ -64,18 +89,26 @@ class TextInputTest(WidgetTest): `attrs` passed to render() get precedence over those passed to the constructor """ - widget = TextInput(attrs={'class': 'pretty'}) + widget = TextInput(attrs={"class": "pretty"}) self.check_html( - widget, 'email', '', attrs={'class': 'special'}, + widget, + "email", + "", + attrs={"class": "special"}, html='<input type="text" class="special" name="email">', ) def test_attrs_safestring(self): - widget = TextInput(attrs={'onBlur': mark_safe("function('foo')")}) - self.check_html(widget, 'email', '', html='<input onBlur="function(\'foo\')" type="text" name="email">') + widget = TextInput(attrs={"onBlur": mark_safe("function('foo')")}) + self.check_html( + widget, + "email", + "", + html='<input onBlur="function(\'foo\')" type="text" name="email">', + ) def test_use_required_attribute(self): # Text inputs can safely trigger the browser validation. self.assertIs(self.widget.use_required_attribute(None), True) - self.assertIs(self.widget.use_required_attribute(''), True) - self.assertIs(self.widget.use_required_attribute('resume.txt'), True) + self.assertIs(self.widget.use_required_attribute(""), True) + self.assertIs(self.widget.use_required_attribute("resume.txt"), True) diff --git a/tests/forms_tests/widget_tests/test_timeinput.py b/tests/forms_tests/widget_tests/test_timeinput.py index 6060168eb3..6f56a07f5e 100644 --- a/tests/forms_tests/widget_tests/test_timeinput.py +++ b/tests/forms_tests/widget_tests/test_timeinput.py @@ -10,37 +10,60 @@ class TimeInputTest(WidgetTest): widget = TimeInput() def test_render_none(self): - self.check_html(self.widget, 'time', None, html='<input type="text" name="time">') + self.check_html( + self.widget, "time", None, html='<input type="text" name="time">' + ) def test_render_value(self): """ The microseconds are trimmed on display, by default. """ t = time(12, 51, 34, 482548) - self.assertEqual(str(t), '12:51:34.482548') - self.check_html(self.widget, 'time', t, html='<input type="text" name="time" value="12:51:34">') - self.check_html(self.widget, 'time', time(12, 51, 34), html=( - '<input type="text" name="time" value="12:51:34">' - )) - self.check_html(self.widget, 'time', time(12, 51), html=( - '<input type="text" name="time" value="12:51:00">' - )) + self.assertEqual(str(t), "12:51:34.482548") + self.check_html( + self.widget, + "time", + t, + html='<input type="text" name="time" value="12:51:34">', + ) + self.check_html( + self.widget, + "time", + time(12, 51, 34), + html=('<input type="text" name="time" value="12:51:34">'), + ) + self.check_html( + self.widget, + "time", + time(12, 51), + html=('<input type="text" name="time" value="12:51:00">'), + ) def test_string(self): """Initializing from a string value.""" - self.check_html(self.widget, 'time', '13:12:11', html=( - '<input type="text" name="time" value="13:12:11">' - )) + self.check_html( + self.widget, + "time", + "13:12:11", + html=('<input type="text" name="time" value="13:12:11">'), + ) def test_format(self): """ Use 'format' to change the way a value is displayed. """ t = time(12, 51, 34, 482548) - widget = TimeInput(format='%H:%M', attrs={'type': 'time'}) - self.check_html(widget, 'time', t, html='<input type="time" name="time" value="12:51">') + widget = TimeInput(format="%H:%M", attrs={"type": "time"}) + self.check_html( + widget, "time", t, html='<input type="time" name="time" value="12:51">' + ) - @translation.override('de-at') + @translation.override("de-at") def test_l10n(self): t = time(12, 51, 34, 482548) - self.check_html(self.widget, 'time', t, html='<input type="text" name="time" value="12:51:34">') + self.check_html( + self.widget, + "time", + t, + html='<input type="text" name="time" value="12:51:34">', + ) diff --git a/tests/forms_tests/widget_tests/test_widget.py b/tests/forms_tests/widget_tests/test_widget.py index 8cde388b8f..9e243570d7 100644 --- a/tests/forms_tests/widget_tests/test_widget.py +++ b/tests/forms_tests/widget_tests/test_widget.py @@ -5,22 +5,29 @@ from .base import WidgetTest class WidgetTests(WidgetTest): - def test_format_value(self): widget = Widget() self.assertIsNone(widget.format_value(None)) - self.assertIsNone(widget.format_value('')) - self.assertEqual(widget.format_value('español'), 'español') - self.assertEqual(widget.format_value(42.5), '42.5') + self.assertIsNone(widget.format_value("")) + self.assertEqual(widget.format_value("español"), "español") + self.assertEqual(widget.format_value(42.5), "42.5") def test_value_omitted_from_data(self): widget = Widget() - self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), True) - self.assertIs(widget.value_omitted_from_data({'field': 'value'}, {}, 'field'), False) + self.assertIs(widget.value_omitted_from_data({}, {}, "field"), True) + self.assertIs( + widget.value_omitted_from_data({"field": "value"}, {}, "field"), False + ) def test_no_trailing_newline_in_attrs(self): - self.check_html(Input(), 'name', 'value', strict=True, html='<input type="None" name="name" value="value">') + self.check_html( + Input(), + "name", + "value", + strict=True, + html='<input type="None" name="name" value="value">', + ) def test_attr_false_not_rendered(self): html = '<input type="None" name="name" value="value">' - self.check_html(Input(), 'name', 'value', html=html, attrs={'readonly': False}) + self.check_html(Input(), "name", "value", html=html, attrs={"readonly": False}) |
