From 05cbec9dd7f9f0b6a9b59b29ac6c9272b6ae50d8 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 17 Oct 2014 13:23:14 +0100 Subject: [PATCH] Use serializers.ValidationError --- docs/topics/3.0-announcement.md | 14 ++- rest_framework/authtoken/serializers.py | 6 +- rest_framework/exceptions.py | 9 +- rest_framework/fields.py | 12 +-- rest_framework/serializers.py | 32 +++--- tests/test_fields.py | 134 ++++++++++++------------ tests/test_relations.py | 10 +- tests/test_validation.py | 10 +- 8 files changed, 120 insertions(+), 107 deletions(-) diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md index f868b344a..658b50d31 100644 --- a/docs/topics/3.0-announcement.md +++ b/docs/topics/3.0-announcement.md @@ -144,11 +144,15 @@ The corresponding code would now look like this: logging.info('Creating ticket "%s"' % name) serializer.save(user=request.user) # Include the user when saving. -#### Use `rest_framework.exceptions.ValidationFailed`. +#### Using `serializers.ValidationError`. -Django's `ValidationError` class is intended for use with HTML forms and it's API makes its use slightly awkward with nested validation errors as can occur in serializers. +Previously `serializers.ValidationError` error was simply a synonym for `django.core.exceptions.ValidationError`. This has now been altered so that it inherits from the standard `APIException` base class. -We now include a simpler `ValidationFailed` exception class in REST framework that you should use when raising validation failures. +The reason behind this is that Django's `ValidationError` class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers. + +For most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you are always using the `serializers.ValidationError` exception class, and not Django's built-in exception. + +We strongly recommend that you use the namespaced import style of `import serializers` and not `from serializers import ValidationError` in order to avoid any potential confusion. #### Change to `validate_`. @@ -156,14 +160,14 @@ The `validate_` method hooks that can be attached to serializer clas def validate_score(self, attrs, source): if attrs[score] % 10 != 0: - raise ValidationError('This field should be a multiple of ten.') + raise serializers.ValidationError('This field should be a multiple of ten.') return attrs This is now simplified slightly, and the method hooks simply take the value to be validated, and return it's validated value. def validate_score(self, value): if value % 10 != 0: - raise ValidationError('This field should be a multiple of ten.') + raise serializers.ValidationError('This field should be a multiple of ten.') return value Any ad-hoc validation that applies to more than one field should go in the `.validate(self, attrs)` method as usual. diff --git a/rest_framework/authtoken/serializers.py b/rest_framework/authtoken/serializers.py index a808d0a32..f31dded17 100644 --- a/rest_framework/authtoken/serializers.py +++ b/rest_framework/authtoken/serializers.py @@ -18,13 +18,13 @@ class AuthTokenSerializer(serializers.Serializer): if user: if not user.is_active: msg = _('User account is disabled.') - raise exceptions.ValidationFailed(msg) + raise exceptions.ValidationError(msg) else: msg = _('Unable to log in with provided credentials.') - raise exceptions.ValidationFailed(msg) + raise exceptions.ValidationError(msg) else: msg = _('Must include "username" and "password"') - raise exceptions.ValidationFailed(msg) + raise exceptions.ValidationError(msg) attrs['user'] = user return attrs diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index b7c2d16d6..388d3dee9 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -24,7 +24,14 @@ class APIException(Exception): return self.detail -class ValidationFailed(APIException): +# The recommended style for using `ValidationError` is to keep it namespaced +# under `serializers`, in order to minimize potential confusion with Django's +# built in `ValidationError`. For example: +# +# from rest_framework import serializers +# raise serializers.ValidationError('Value was invalid') + +class ValidationError(APIException): status_code = status.HTTP_400_BAD_REQUEST def __init__(self, detail): diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 597d5e122..2da4aa8b2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -13,7 +13,7 @@ from rest_framework.compat import ( smart_text, EmailValidator, MinValueValidator, MaxValueValidator, MinLengthValidator, MaxLengthValidator, URLValidator ) -from rest_framework.exceptions import ValidationFailed +from rest_framework.exceptions import ValidationError from rest_framework.settings import api_settings from rest_framework.utils import html, representation, humanize_datetime import copy @@ -102,7 +102,7 @@ NOT_READ_ONLY_DEFAULT = 'May not set both `read_only` and `default`' NOT_REQUIRED_DEFAULT = 'May not set both `required` and `default`' USE_READONLYFIELD = 'Field(read_only=True) should be ReadOnlyField' MISSING_ERROR_MESSAGE = ( - 'ValidationFailed raised by `{class_name}`, but error key `{key}` does ' + 'ValidationError raised by `{class_name}`, but error key `{key}` does ' 'not exist in the `error_messages` dictionary.' ) @@ -264,7 +264,7 @@ class Field(object): def run_validators(self, value): """ Test the given value against all the validators on the field, - and either raise a `ValidationFailed` or simply return. + and either raise a `ValidationError` or simply return. """ errors = [] for validator in self.validators: @@ -272,12 +272,12 @@ class Field(object): validator.serializer_field = self try: validator(value) - except ValidationFailed as exc: + except ValidationError as exc: errors.extend(exc.detail) except DjangoValidationError as exc: errors.extend(exc.messages) if errors: - raise ValidationFailed(errors) + raise ValidationError(errors) def validate(self, value): pass @@ -305,7 +305,7 @@ class Field(object): msg = MISSING_ERROR_MESSAGE.format(class_name=class_name, key=key) raise AssertionError(msg) message_string = msg.format(**kwargs) - raise ValidationFailed(message_string) + raise ValidationError(message_string) @property def root(self): diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 30e6bfeb1..d29dc684a 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -14,7 +14,7 @@ from django.core.exceptions import ImproperlyConfigured from django.db import models from django.utils import six from django.utils.datastructures import SortedDict -from rest_framework.exceptions import ValidationFailed +from rest_framework.exceptions import ValidationError from rest_framework.fields import empty, set_value, Field, SkipField from rest_framework.settings import api_settings from rest_framework.utils import html, model_meta, representation @@ -77,13 +77,6 @@ class BaseSerializer(Field): raise NotImplementedError('`create()` must be implemented.') def save(self, **kwargs): - assert not hasattr(self, 'restore_object'), ( - 'Serializer %s has old-style version 2 `.restore_object()` ' - 'that is no longer compatible with REST framework 3. ' - 'Use the new-style `.create()` and `.update()` methods instead.' % - self.__class__.__name__ - ) - validated_data = self.validated_data if kwargs: validated_data = dict( @@ -105,17 +98,24 @@ class BaseSerializer(Field): return self.instance def is_valid(self, raise_exception=False): + assert not hasattr(self, 'restore_object'), ( + 'Serializer %s has old-style version 2 `.restore_object()` ' + 'that is no longer compatible with REST framework 3. ' + 'Use the new-style `.create()` and `.update()` methods instead.' % + self.__class__.__name__ + ) + if not hasattr(self, '_validated_data'): try: self._validated_data = self.run_validation(self._initial_data) - except ValidationFailed as exc: + except ValidationError as exc: self._validated_data = {} self._errors = exc.detail else: self._errors = {} if self._errors and raise_exception: - raise ValidationFailed(self._errors) + raise ValidationError(self._errors) return not bool(self._errors) @@ -124,6 +124,8 @@ class BaseSerializer(Field): if not hasattr(self, '_data'): if self.instance is not None and not getattr(self, '_errors', None): self._data = self.to_representation(self.instance) + elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None): + self._data = self.to_representation(self.validated_data) else: self._data = self.get_initial() return self._data @@ -329,7 +331,7 @@ class Serializer(BaseSerializer): return None if not isinstance(data, dict): - raise ValidationFailed({ + raise ValidationError({ api_settings.NON_FIELD_ERRORS_KEY: ['Invalid data'] }) @@ -338,8 +340,8 @@ class Serializer(BaseSerializer): self.run_validators(value) value = self.validate(value) assert value is not None, '.validate() should return the validated data' - except ValidationFailed as exc: - raise ValidationFailed({ + except ValidationError as exc: + raise ValidationError({ api_settings.NON_FIELD_ERRORS_KEY: exc.detail }) return value @@ -359,7 +361,7 @@ class Serializer(BaseSerializer): validated_value = field.run_validation(primitive_value) if validate_method is not None: validated_value = validate_method(validated_value) - except ValidationFailed as exc: + except ValidationError as exc: errors[field.field_name] = exc.detail except SkipField: pass @@ -367,7 +369,7 @@ class Serializer(BaseSerializer): set_value(ret, field.source_attrs, validated_value) if errors: - raise ValidationFailed(errors) + raise ValidationError(errors) return ret diff --git a/tests/test_fields.py b/tests/test_fields.py index 5e8c67c54..6dc5f87d2 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -1,6 +1,6 @@ from decimal import Decimal from django.utils import timezone -from rest_framework import exceptions, fields, serializers +from rest_framework import serializers import datetime import django import pytest @@ -17,8 +17,8 @@ class TestEmpty: """ By default a field must be included in the input. """ - field = fields.IntegerField() - with pytest.raises(exceptions.ValidationFailed) as exc_info: + field = serializers.IntegerField() + with pytest.raises(serializers.ValidationError) as exc_info: field.run_validation() assert exc_info.value.detail == ['This field is required.'] @@ -26,16 +26,16 @@ class TestEmpty: """ If `required=False` then a field may be omitted from the input. """ - field = fields.IntegerField(required=False) - with pytest.raises(fields.SkipField): + field = serializers.IntegerField(required=False) + with pytest.raises(serializers.SkipField): field.run_validation() def test_disallow_null(self): """ By default `None` is not a valid input. """ - field = fields.IntegerField() - with pytest.raises(exceptions.ValidationFailed) as exc_info: + field = serializers.IntegerField() + with pytest.raises(serializers.ValidationError) as exc_info: field.run_validation(None) assert exc_info.value.detail == ['This field may not be null.'] @@ -43,7 +43,7 @@ class TestEmpty: """ If `allow_null=True` then `None` is a valid input. """ - field = fields.IntegerField(allow_null=True) + field = serializers.IntegerField(allow_null=True) output = field.run_validation(None) assert output is None @@ -51,8 +51,8 @@ class TestEmpty: """ By default '' is not a valid input. """ - field = fields.CharField() - with pytest.raises(exceptions.ValidationFailed) as exc_info: + field = serializers.CharField() + with pytest.raises(serializers.ValidationError) as exc_info: field.run_validation('') assert exc_info.value.detail == ['This field may not be blank.'] @@ -60,7 +60,7 @@ class TestEmpty: """ If `allow_blank=True` then '' is a valid input. """ - field = fields.CharField(allow_blank=True) + field = serializers.CharField(allow_blank=True) output = field.run_validation('') assert output is '' @@ -68,7 +68,7 @@ class TestEmpty: """ If `default` is set, then omitted values get the default input. """ - field = fields.IntegerField(default=123) + field = serializers.IntegerField(default=123) output = field.run_validation() assert output is 123 @@ -96,13 +96,13 @@ class TestSource: class TestReadOnly: def setup(self): class TestSerializer(serializers.Serializer): - read_only = fields.ReadOnlyField() - writable = fields.IntegerField() + read_only = serializers.ReadOnlyField() + writable = serializers.IntegerField() self.Serializer = TestSerializer def test_validate_read_only(self): """ - Read-only fields should not be included in validation. + Read-only serializers.should not be included in validation. """ data = {'read_only': 123, 'writable': 456} serializer = self.Serializer(data=data) @@ -111,7 +111,7 @@ class TestReadOnly: def test_serialize_read_only(self): """ - Read-only fields should be serialized. + Read-only serializers.should be serialized. """ instance = {'read_only': 123, 'writable': 456} serializer = self.Serializer(instance) @@ -121,13 +121,13 @@ class TestReadOnly: class TestWriteOnly: def setup(self): class TestSerializer(serializers.Serializer): - write_only = fields.IntegerField(write_only=True) - readable = fields.IntegerField() + write_only = serializers.IntegerField(write_only=True) + readable = serializers.IntegerField() self.Serializer = TestSerializer def test_validate_write_only(self): """ - Write-only fields should be included in validation. + Write-only serializers.should be included in validation. """ data = {'write_only': 123, 'readable': 456} serializer = self.Serializer(data=data) @@ -136,7 +136,7 @@ class TestWriteOnly: def test_serialize_write_only(self): """ - Write-only fields should not be serialized. + Write-only serializers.should not be serialized. """ instance = {'write_only': 123, 'readable': 456} serializer = self.Serializer(instance) @@ -146,8 +146,8 @@ class TestWriteOnly: class TestInitial: def setup(self): class TestSerializer(serializers.Serializer): - initial_field = fields.IntegerField(initial=123) - blank_field = fields.IntegerField() + initial_field = serializers.IntegerField(initial=123) + blank_field = serializers.IntegerField() self.serializer = TestSerializer() def test_initial(self): @@ -163,7 +163,7 @@ class TestInitial: class TestLabel: def setup(self): class TestSerializer(serializers.Serializer): - labeled = fields.IntegerField(label='My label') + labeled = serializers.IntegerField(label='My label') self.serializer = TestSerializer() def test_label(self): @@ -189,7 +189,7 @@ class TestInvalidErrorKey: with pytest.raises(AssertionError) as exc_info: self.field.to_native(123) expected = ( - 'ValidationFailed raised by `ExampleField`, but error key ' + 'ValidationError raised by `ExampleField`, but error key ' '`incorrect` does not exist in the `error_messages` dictionary.' ) assert str(exc_info.value) == expected @@ -198,7 +198,7 @@ class TestInvalidErrorKey: class TestBooleanHTMLInput: def setup(self): class TestSerializer(serializers.Serializer): - archived = fields.BooleanField() + archived = serializers.BooleanField() self.Serializer = TestSerializer def test_empty_html_checkbox(self): @@ -243,7 +243,7 @@ class FieldValues: Ensure that invalid values raise the expected validation error. """ for input_value, expected_failure in get_items(self.invalid_inputs): - with pytest.raises(exceptions.ValidationFailed) as exc_info: + with pytest.raises(serializers.ValidationError) as exc_info: self.field.run_validation(input_value) assert exc_info.value.detail == expected_failure @@ -283,7 +283,7 @@ class TestBooleanField(FieldValues): False: False, 'other': True } - field = fields.BooleanField() + field = serializers.BooleanField() class TestNullBooleanField(FieldValues): @@ -310,7 +310,7 @@ class TestNullBooleanField(FieldValues): None: None, 'other': True } - field = fields.NullBooleanField() + field = serializers.NullBooleanField() # String types... @@ -330,7 +330,7 @@ class TestCharField(FieldValues): 1: '1', 'abc': 'abc' } - field = fields.CharField() + field = serializers.CharField() class TestEmailField(FieldValues): @@ -345,7 +345,7 @@ class TestEmailField(FieldValues): 'examplecom': ['Enter a valid email address.'] } outputs = {} - field = fields.EmailField() + field = serializers.EmailField() class TestRegexField(FieldValues): @@ -359,7 +359,7 @@ class TestRegexField(FieldValues): 'A9': ["This value does not match the required pattern."] } outputs = {} - field = fields.RegexField(regex='[a-z][0-9]') + field = serializers.RegexField(regex='[a-z][0-9]') class TestSlugField(FieldValues): @@ -373,7 +373,7 @@ class TestSlugField(FieldValues): 'slug 99': ["Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."] } outputs = {} - field = fields.SlugField() + field = serializers.SlugField() class TestURLField(FieldValues): @@ -387,7 +387,7 @@ class TestURLField(FieldValues): 'example.com': ['Enter a valid URL.'] } outputs = {} - field = fields.URLField() + field = serializers.URLField() # Number types... @@ -415,7 +415,7 @@ class TestIntegerField(FieldValues): 1.0: 1, 0.0: 0 } - field = fields.IntegerField() + field = serializers.IntegerField() class TestMinMaxIntegerField(FieldValues): @@ -435,7 +435,7 @@ class TestMinMaxIntegerField(FieldValues): '4': ['Ensure this value is less than or equal to 3.'], } outputs = {} - field = fields.IntegerField(min_value=1, max_value=3) + field = serializers.IntegerField(min_value=1, max_value=3) class TestFloatField(FieldValues): @@ -461,7 +461,7 @@ class TestFloatField(FieldValues): 1.0: 1.0, 0.0: 0.0, } - field = fields.FloatField() + field = serializers.FloatField() class TestMinMaxFloatField(FieldValues): @@ -483,7 +483,7 @@ class TestMinMaxFloatField(FieldValues): '3.1': ['Ensure this value is less than or equal to 3.'], } outputs = {} - field = fields.FloatField(min_value=1, max_value=3) + field = serializers.FloatField(min_value=1, max_value=3) class TestDecimalField(FieldValues): @@ -518,7 +518,7 @@ class TestDecimalField(FieldValues): Decimal('1.09'): '1.1', Decimal('0.04'): '0.0' } - field = fields.DecimalField(max_digits=3, decimal_places=1) + field = serializers.DecimalField(max_digits=3, decimal_places=1) class TestMinMaxDecimalField(FieldValues): @@ -534,7 +534,7 @@ class TestMinMaxDecimalField(FieldValues): '20.1': ['Ensure this value is less than or equal to 20.'], } outputs = {} - field = fields.DecimalField( + field = serializers.DecimalField( max_digits=3, decimal_places=1, min_value=10, max_value=20 ) @@ -554,13 +554,13 @@ class TestNoStringCoercionDecimalField(FieldValues): Decimal('1.09'): Decimal('1.1'), Decimal('0.04'): Decimal('0.0'), } - field = fields.DecimalField( + field = serializers.DecimalField( max_digits=3, decimal_places=1, coerce_to_string=False ) -# Date & time fields... +# Date & time serializers... class TestDateField(FieldValues): """ @@ -578,7 +578,7 @@ class TestDateField(FieldValues): outputs = { datetime.date(2001, 1, 1): '2001-01-01' } - field = fields.DateField() + field = serializers.DateField() class TestCustomInputFormatDateField(FieldValues): @@ -592,7 +592,7 @@ class TestCustomInputFormatDateField(FieldValues): '2001-01-01': ['Date has wrong format. Use one of these formats instead: DD [Jan-Dec] YYYY'] } outputs = {} - field = fields.DateField(input_formats=['%d %b %Y']) + field = serializers.DateField(input_formats=['%d %b %Y']) class TestCustomOutputFormatDateField(FieldValues): @@ -604,7 +604,7 @@ class TestCustomOutputFormatDateField(FieldValues): outputs = { datetime.date(2001, 1, 1): '01 Jan 2001' } - field = fields.DateField(format='%d %b %Y') + field = serializers.DateField(format='%d %b %Y') class TestNoOutputFormatDateField(FieldValues): @@ -616,7 +616,7 @@ class TestNoOutputFormatDateField(FieldValues): outputs = { datetime.date(2001, 1, 1): datetime.date(2001, 1, 1) } - field = fields.DateField(format=None) + field = serializers.DateField(format=None) class TestDateTimeField(FieldValues): @@ -641,7 +641,7 @@ class TestDateTimeField(FieldValues): datetime.datetime(2001, 1, 1, 13, 00): '2001-01-01T13:00:00', datetime.datetime(2001, 1, 1, 13, 00, tzinfo=timezone.UTC()): '2001-01-01T13:00:00Z' } - field = fields.DateTimeField(default_timezone=timezone.UTC()) + field = serializers.DateTimeField(default_timezone=timezone.UTC()) class TestCustomInputFormatDateTimeField(FieldValues): @@ -655,7 +655,7 @@ class TestCustomInputFormatDateTimeField(FieldValues): '2001-01-01T20:50': ['Datetime has wrong format. Use one of these formats instead: hh:mm[AM|PM], DD [Jan-Dec] YYYY'] } outputs = {} - field = fields.DateTimeField(default_timezone=timezone.UTC(), input_formats=['%I:%M%p, %d %b %Y']) + field = serializers.DateTimeField(default_timezone=timezone.UTC(), input_formats=['%I:%M%p, %d %b %Y']) class TestCustomOutputFormatDateTimeField(FieldValues): @@ -667,7 +667,7 @@ class TestCustomOutputFormatDateTimeField(FieldValues): outputs = { datetime.datetime(2001, 1, 1, 13, 00): '01:00PM, 01 Jan 2001', } - field = fields.DateTimeField(format='%I:%M%p, %d %b %Y') + field = serializers.DateTimeField(format='%I:%M%p, %d %b %Y') class TestNoOutputFormatDateTimeField(FieldValues): @@ -679,7 +679,7 @@ class TestNoOutputFormatDateTimeField(FieldValues): outputs = { datetime.datetime(2001, 1, 1, 13, 00): datetime.datetime(2001, 1, 1, 13, 00), } - field = fields.DateTimeField(format=None) + field = serializers.DateTimeField(format=None) class TestNaiveDateTimeField(FieldValues): @@ -692,7 +692,7 @@ class TestNaiveDateTimeField(FieldValues): } invalid_inputs = {} outputs = {} - field = fields.DateTimeField(default_timezone=None) + field = serializers.DateTimeField(default_timezone=None) class TestTimeField(FieldValues): @@ -710,7 +710,7 @@ class TestTimeField(FieldValues): outputs = { datetime.time(13, 00): '13:00:00' } - field = fields.TimeField() + field = serializers.TimeField() class TestCustomInputFormatTimeField(FieldValues): @@ -724,7 +724,7 @@ class TestCustomInputFormatTimeField(FieldValues): '13:00': ['Time has wrong format. Use one of these formats instead: hh:mm[AM|PM]'], } outputs = {} - field = fields.TimeField(input_formats=['%I:%M%p']) + field = serializers.TimeField(input_formats=['%I:%M%p']) class TestCustomOutputFormatTimeField(FieldValues): @@ -736,7 +736,7 @@ class TestCustomOutputFormatTimeField(FieldValues): outputs = { datetime.time(13, 00): '01:00PM' } - field = fields.TimeField(format='%I:%M%p') + field = serializers.TimeField(format='%I:%M%p') class TestNoOutputFormatTimeField(FieldValues): @@ -748,7 +748,7 @@ class TestNoOutputFormatTimeField(FieldValues): outputs = { datetime.time(13, 00): datetime.time(13, 00) } - field = fields.TimeField(format=None) + field = serializers.TimeField(format=None) # Choice types... @@ -768,7 +768,7 @@ class TestChoiceField(FieldValues): outputs = { 'good': 'good' } - field = fields.ChoiceField( + field = serializers.ChoiceField( choices=[ ('poor', 'Poor quality'), ('medium', 'Medium quality'), @@ -794,7 +794,7 @@ class TestChoiceFieldWithType(FieldValues): '1': 1, 1: 1 } - field = fields.ChoiceField( + field = serializers.ChoiceField( choices=[ (1, 'Poor quality'), (2, 'Medium quality'), @@ -819,7 +819,7 @@ class TestChoiceFieldWithListChoices(FieldValues): outputs = { 'good': 'good' } - field = fields.ChoiceField(choices=('poor', 'medium', 'good')) + field = serializers.ChoiceField(choices=('poor', 'medium', 'good')) class TestMultipleChoiceField(FieldValues): @@ -838,7 +838,7 @@ class TestMultipleChoiceField(FieldValues): outputs = [ (['aircon', 'manual'], set(['aircon', 'manual'])) ] - field = fields.MultipleChoiceField( + field = serializers.MultipleChoiceField( choices=[ ('aircon', 'AirCon'), ('manual', 'Manual drive'), @@ -847,7 +847,7 @@ class TestMultipleChoiceField(FieldValues): ) -# File fields... +# File serializers... class MockFile: def __init__(self, name='', size=0, url=''): @@ -881,7 +881,7 @@ class TestFileField(FieldValues): (MockFile(name='example.txt', url='/example.txt'), '/example.txt'), ('', None) ] - field = fields.FileField(max_length=10) + field = serializers.FileField(max_length=10) class TestFieldFieldWithName(FieldValues): @@ -893,14 +893,14 @@ class TestFieldFieldWithName(FieldValues): outputs = [ (MockFile(name='example.txt', url='/example.txt'), 'example.txt') ] - field = fields.FileField(use_url=False) + field = serializers.FileField(use_url=False) # Stub out mock Django `forms.ImageField` class so we don't *actually* # call into it's regular validation, or require PIL for testing. class FailImageValidation(object): def to_python(self, value): - raise exceptions.ValidationFailed(self.error_messages['invalid_image']) + raise serializers.ValidationError(self.error_messages['invalid_image']) class PassImageValidation(object): @@ -917,7 +917,7 @@ class TestInvalidImageField(FieldValues): (MockFile(name='example.txt', size=10), ['Upload a valid image. The file you uploaded was either not an image or a corrupted image.']) ] outputs = {} - field = fields.ImageField(_DjangoImageField=FailImageValidation) + field = serializers.ImageField(_DjangoImageField=FailImageValidation) class TestValidImageField(FieldValues): @@ -929,10 +929,10 @@ class TestValidImageField(FieldValues): ] invalid_inputs = {} outputs = {} - field = fields.ImageField(_DjangoImageField=PassImageValidation) + field = serializers.ImageField(_DjangoImageField=PassImageValidation) -# Composite fields... +# Composite serializers... class TestListField(FieldValues): """ @@ -950,7 +950,7 @@ class TestListField(FieldValues): ([1, 2, 3], [1, 2, 3]), (['1', '2', '3'], [1, 2, 3]) ] - field = fields.ListField(child=fields.IntegerField()) + field = serializers.ListField(child=serializers.IntegerField()) # Tests for FieldField. @@ -963,7 +963,7 @@ class MockRequest: class TestFileFieldContext: def test_fully_qualified_when_request_in_context(self): - field = fields.FileField(max_length=10) + field = serializers.FileField(max_length=10) field._context = {'request': MockRequest()} obj = MockFile(name='example.txt', url='/example.txt') value = field.to_representation(obj) diff --git a/tests/test_relations.py b/tests/test_relations.py index 53c1b25c7..16ead1f2f 100644 --- a/tests/test_relations.py +++ b/tests/test_relations.py @@ -1,6 +1,6 @@ from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset from django.core.exceptions import ImproperlyConfigured -from rest_framework import exceptions, serializers +from rest_framework import serializers from rest_framework.test import APISimpleTestCase import pytest @@ -30,13 +30,13 @@ class TestPrimaryKeyRelatedField(APISimpleTestCase): assert instance is self.instance def test_pk_related_lookup_does_not_exist(self): - with pytest.raises(exceptions.ValidationFailed) as excinfo: + with pytest.raises(serializers.ValidationError) as excinfo: self.field.to_internal_value(4) msg = excinfo.value.detail[0] assert msg == "Invalid pk '4' - object does not exist." def test_pk_related_lookup_invalid_type(self): - with pytest.raises(exceptions.ValidationFailed) as excinfo: + with pytest.raises(serializers.ValidationError) as excinfo: self.field.to_internal_value(BadType()) msg = excinfo.value.detail[0] assert msg == 'Incorrect type. Expected pk value, received BadType.' @@ -120,13 +120,13 @@ class TestSlugRelatedField(APISimpleTestCase): assert instance is self.instance def test_slug_related_lookup_does_not_exist(self): - with pytest.raises(exceptions.ValidationFailed) as excinfo: + with pytest.raises(serializers.ValidationError) as excinfo: self.field.to_internal_value('doesnotexist') msg = excinfo.value.detail[0] assert msg == 'Object with name=doesnotexist does not exist.' def test_slug_related_lookup_invalid_type(self): - with pytest.raises(exceptions.ValidationFailed) as excinfo: + with pytest.raises(serializers.ValidationError) as excinfo: self.field.to_internal_value(BadType()) msg = excinfo.value.detail[0] assert msg == 'Invalid value.' diff --git a/tests/test_validation.py b/tests/test_validation.py index 849c7e9d5..4d64e6e11 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.core.validators import MaxValueValidator from django.db import models from django.test import TestCase -from rest_framework import exceptions, generics, serializers, status +from rest_framework import generics, serializers, status from rest_framework.test import APIRequestFactory factory = APIRequestFactory() @@ -37,7 +37,7 @@ class ShouldValidateModelSerializer(serializers.ModelSerializer): def validate_renamed(self, value): if len(value) < 3: - raise exceptions.ValidationFailed('Minimum 3 characters.') + raise serializers.ValidationError('Minimum 3 characters.') return value class Meta: @@ -73,10 +73,10 @@ class ValidationSerializer(serializers.Serializer): foo = serializers.CharField() def validate_foo(self, attrs, source): - raise exceptions.ValidationFailed("foo invalid") + raise serializers.ValidationError("foo invalid") def validate(self, attrs): - raise exceptions.ValidationFailed("serializer invalid") + raise serializers.ValidationError("serializer invalid") class TestAvoidValidation(TestCase): @@ -158,7 +158,7 @@ class TestChoiceFieldChoicesValidate(TestCase): value = self.CHOICES[0][0] try: f.to_internal_value(value) - except exceptions.ValidationFailed: + except serializers.ValidationError: self.fail("Value %s does not validate" % str(value)) # def test_nested_choices(self):