diff --git a/rest_framework/fields.py b/rest_framework/fields.py index bedc02b94..5cafed555 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -320,7 +320,7 @@ class Field: default_empty_html = empty initial = None - def __init__(self, read_only=False, write_only=False, + def __init__(self, *, read_only=False, write_only=False, required=None, default=empty, initial=empty, source=None, label=None, help_text=None, style=None, error_messages=None, validators=None, allow_null=False): @@ -1163,14 +1163,14 @@ class DateTimeField(Field): } datetime_parser = datetime.datetime.strptime - def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs): + def __init__(self, format=empty, input_formats=None, default_timezone=None, **kwargs): if format is not empty: self.format = format if input_formats is not None: self.input_formats = input_formats if default_timezone is not None: self.timezone = default_timezone - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def enforce_timezone(self, value): """ @@ -1249,12 +1249,12 @@ class DateField(Field): } datetime_parser = datetime.datetime.strptime - def __init__(self, format=empty, input_formats=None, *args, **kwargs): + def __init__(self, format=empty, input_formats=None, **kwargs): if format is not empty: self.format = format if input_formats is not None: self.input_formats = input_formats - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def to_internal_value(self, value): input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) @@ -1315,12 +1315,12 @@ class TimeField(Field): } datetime_parser = datetime.datetime.strptime - def __init__(self, format=empty, input_formats=None, *args, **kwargs): + def __init__(self, format=empty, input_formats=None, **kwargs): if format is not empty: self.format = format if input_formats is not None: self.input_formats = input_formats - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def to_internal_value(self, value): input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS) @@ -1470,9 +1470,9 @@ class MultipleChoiceField(ChoiceField): } default_empty_html = [] - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self.allow_empty = kwargs.pop('allow_empty', True) - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def get_value(self, dictionary): if self.field_name not in dictionary: @@ -1529,12 +1529,12 @@ class FileField(Field): 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), } - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self.max_length = kwargs.pop('max_length', None) self.allow_empty_file = kwargs.pop('allow_empty_file', False) if 'use_url' in kwargs: self.use_url = kwargs.pop('use_url') - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): try: @@ -1578,9 +1578,9 @@ class ImageField(FileField): ), } - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField) - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): # Image validation is a bit grungy, so we'll just outright @@ -1595,8 +1595,8 @@ class ImageField(FileField): # Composite field types... class _UnvalidatedField(Field): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, **kwargs): + super().__init__(**kwargs) self.allow_blank = True self.allow_null = True @@ -1617,7 +1617,7 @@ class ListField(Field): 'max_length': _('Ensure this field has no more than {max_length} elements.') } - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self.child = kwargs.pop('child', copy.deepcopy(self.child)) self.allow_empty = kwargs.pop('allow_empty', True) self.max_length = kwargs.pop('max_length', None) @@ -1629,7 +1629,7 @@ class ListField(Field): "Remove `source=` from the field declaration." ) - super().__init__(*args, **kwargs) + super().__init__(**kwargs) self.child.bind(field_name='', parent=self) if self.max_length is not None: message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) @@ -1694,7 +1694,7 @@ class DictField(Field): 'empty': _('This dictionary may not be empty.'), } - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self.child = kwargs.pop('child', copy.deepcopy(self.child)) self.allow_empty = kwargs.pop('allow_empty', True) @@ -1704,7 +1704,7 @@ class DictField(Field): "Remove `source=` from the field declaration." ) - super().__init__(*args, **kwargs) + super().__init__(**kwargs) self.child.bind(field_name='', parent=self) def get_value(self, dictionary): @@ -1753,8 +1753,8 @@ class DictField(Field): class HStoreField(DictField): child = CharField(allow_blank=True, allow_null=True) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, **kwargs): + super().__init__(**kwargs) assert isinstance(self.child, CharField), ( "The `child` argument must be an instance of `CharField`, " "as the hstore extension stores values as strings." @@ -1769,11 +1769,11 @@ class JSONField(Field): # Workaround for isinstance calls when importing the field isn't possible _is_jsonfield = True - def __init__(self, *args, **kwargs): + def __init__(self, **kwargs): self.binary = kwargs.pop('binary', False) self.encoder = kwargs.pop('encoder', None) self.decoder = kwargs.pop('decoder', None) - super().__init__(*args, **kwargs) + super().__init__(**kwargs) def get_value(self, dictionary): if html.is_html_input(dictionary) and self.field_name in dictionary: diff --git a/tests/test_fields.py b/tests/test_fields.py index d99ca9c40..2d4cc44ae 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -2010,6 +2010,11 @@ class TestListField(FieldValues): field.to_internal_value(input_value) assert exc_info.value.detail == ['Expected a list of items but got type "dict".'] + def test_constructor_misuse_raises(self): + # Test that `ListField` can only be instantiated with keyword arguments + with pytest.raises(TypeError): + serializers.ListField(serializers.CharField()) + class TestNestedListField(FieldValues): """