Skip to content

Commit a094f59

Browse files
committed
Make Field constructors keyword-only
1 parent 010c8d4 commit a094f59

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

rest_framework/fields.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ class Field:
320320
default_empty_html = empty
321321
initial = None
322322

323-
def __init__(self, read_only=False, write_only=False,
323+
def __init__(self, *, read_only=False, write_only=False,
324324
required=None, default=empty, initial=empty, source=None,
325325
label=None, help_text=None, style=None,
326326
error_messages=None, validators=None, allow_null=False):
@@ -1161,14 +1161,14 @@ class DateTimeField(Field):
11611161
}
11621162
datetime_parser = datetime.datetime.strptime
11631163

1164-
def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs):
1164+
def __init__(self, format=empty, input_formats=None, default_timezone=None, **kwargs):
11651165
if format is not empty:
11661166
self.format = format
11671167
if input_formats is not None:
11681168
self.input_formats = input_formats
11691169
if default_timezone is not None:
11701170
self.timezone = default_timezone
1171-
super().__init__(*args, **kwargs)
1171+
super().__init__(**kwargs)
11721172

11731173
def enforce_timezone(self, value):
11741174
"""
@@ -1247,12 +1247,12 @@ class DateField(Field):
12471247
}
12481248
datetime_parser = datetime.datetime.strptime
12491249

1250-
def __init__(self, format=empty, input_formats=None, *args, **kwargs):
1250+
def __init__(self, format=empty, input_formats=None, **kwargs):
12511251
if format is not empty:
12521252
self.format = format
12531253
if input_formats is not None:
12541254
self.input_formats = input_formats
1255-
super().__init__(*args, **kwargs)
1255+
super().__init__(**kwargs)
12561256

12571257
def to_internal_value(self, value):
12581258
input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS)
@@ -1313,12 +1313,12 @@ class TimeField(Field):
13131313
}
13141314
datetime_parser = datetime.datetime.strptime
13151315

1316-
def __init__(self, format=empty, input_formats=None, *args, **kwargs):
1316+
def __init__(self, format=empty, input_formats=None, **kwargs):
13171317
if format is not empty:
13181318
self.format = format
13191319
if input_formats is not None:
13201320
self.input_formats = input_formats
1321-
super().__init__(*args, **kwargs)
1321+
super().__init__(**kwargs)
13221322

13231323
def to_internal_value(self, value):
13241324
input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS)
@@ -1468,9 +1468,9 @@ class MultipleChoiceField(ChoiceField):
14681468
}
14691469
default_empty_html = []
14701470

1471-
def __init__(self, *args, **kwargs):
1471+
def __init__(self, **kwargs):
14721472
self.allow_empty = kwargs.pop('allow_empty', True)
1473-
super().__init__(*args, **kwargs)
1473+
super().__init__(**kwargs)
14741474

14751475
def get_value(self, dictionary):
14761476
if self.field_name not in dictionary:
@@ -1527,12 +1527,12 @@ class FileField(Field):
15271527
'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'),
15281528
}
15291529

1530-
def __init__(self, *args, **kwargs):
1530+
def __init__(self, **kwargs):
15311531
self.max_length = kwargs.pop('max_length', None)
15321532
self.allow_empty_file = kwargs.pop('allow_empty_file', False)
15331533
if 'use_url' in kwargs:
15341534
self.use_url = kwargs.pop('use_url')
1535-
super().__init__(*args, **kwargs)
1535+
super().__init__(**kwargs)
15361536

15371537
def to_internal_value(self, data):
15381538
try:
@@ -1576,9 +1576,9 @@ class ImageField(FileField):
15761576
),
15771577
}
15781578

1579-
def __init__(self, *args, **kwargs):
1579+
def __init__(self, **kwargs):
15801580
self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField)
1581-
super().__init__(*args, **kwargs)
1581+
super().__init__(**kwargs)
15821582

15831583
def to_internal_value(self, data):
15841584
# Image validation is a bit grungy, so we'll just outright
@@ -1593,8 +1593,8 @@ def to_internal_value(self, data):
15931593
# Composite field types...
15941594

15951595
class _UnvalidatedField(Field):
1596-
def __init__(self, *args, **kwargs):
1597-
super().__init__(*args, **kwargs)
1596+
def __init__(self, **kwargs):
1597+
super().__init__(**kwargs)
15981598
self.allow_blank = True
15991599
self.allow_null = True
16001600

@@ -1615,7 +1615,7 @@ class ListField(Field):
16151615
'max_length': _('Ensure this field has no more than {max_length} elements.')
16161616
}
16171617

1618-
def __init__(self, *args, **kwargs):
1618+
def __init__(self, **kwargs):
16191619
self.child = kwargs.pop('child', copy.deepcopy(self.child))
16201620
self.allow_empty = kwargs.pop('allow_empty', True)
16211621
self.max_length = kwargs.pop('max_length', None)
@@ -1627,7 +1627,7 @@ def __init__(self, *args, **kwargs):
16271627
"Remove `source=` from the field declaration."
16281628
)
16291629

1630-
super().__init__(*args, **kwargs)
1630+
super().__init__(**kwargs)
16311631
self.child.bind(field_name='', parent=self)
16321632
if self.max_length is not None:
16331633
message = lazy_format(self.error_messages['max_length'], max_length=self.max_length)
@@ -1692,7 +1692,7 @@ class DictField(Field):
16921692
'empty': _('This dictionary may not be empty.'),
16931693
}
16941694

1695-
def __init__(self, *args, **kwargs):
1695+
def __init__(self, **kwargs):
16961696
self.child = kwargs.pop('child', copy.deepcopy(self.child))
16971697
self.allow_empty = kwargs.pop('allow_empty', True)
16981698

@@ -1702,7 +1702,7 @@ def __init__(self, *args, **kwargs):
17021702
"Remove `source=` from the field declaration."
17031703
)
17041704

1705-
super().__init__(*args, **kwargs)
1705+
super().__init__(**kwargs)
17061706
self.child.bind(field_name='', parent=self)
17071707

17081708
def get_value(self, dictionary):
@@ -1751,8 +1751,8 @@ def run_child_validation(self, data):
17511751
class HStoreField(DictField):
17521752
child = CharField(allow_blank=True, allow_null=True)
17531753

1754-
def __init__(self, *args, **kwargs):
1755-
super().__init__(*args, **kwargs)
1754+
def __init__(self, **kwargs):
1755+
super().__init__(**kwargs)
17561756
assert isinstance(self.child, CharField), (
17571757
"The `child` argument must be an instance of `CharField`, "
17581758
"as the hstore extension stores values as strings."
@@ -1767,11 +1767,11 @@ class JSONField(Field):
17671767
# Workaround for isinstance calls when importing the field isn't possible
17681768
_is_jsonfield = True
17691769

1770-
def __init__(self, *args, **kwargs):
1770+
def __init__(self, **kwargs):
17711771
self.binary = kwargs.pop('binary', False)
17721772
self.encoder = kwargs.pop('encoder', None)
17731773
self.decoder = kwargs.pop('decoder', None)
1774-
super().__init__(*args, **kwargs)
1774+
super().__init__(**kwargs)
17751775

17761776
def get_value(self, dictionary):
17771777
if html.is_html_input(dictionary) and self.field_name in dictionary:

tests/test_fields.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,11 @@ def test_collection_types_are_invalid_input(self):
19861986
field.to_internal_value(input_value)
19871987
assert exc_info.value.detail == ['Expected a list of items but got type "dict".']
19881988

1989+
def test_constructor_misuse_raises(self):
1990+
# Test that `ListField` can only be instantiated with keyword arguments
1991+
with pytest.raises(TypeError):
1992+
serializers.ListField(serializers.CharField())
1993+
19891994

19901995
class TestNestedListField(FieldValues):
19911996
"""

0 commit comments

Comments
 (0)