From d92b24a0b74f681a538f6faff59bb00c6cd447e2 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 1 Nov 2016 06:27:11 -0400 Subject: [PATCH] Make serializer fields import explicit (#4628) --- rest_framework/serializers.py | 29 +++++++++++++++++++--- tests/test_serializer.py | 45 ++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 39987cd07..1bdcd12c3 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -12,18 +12,27 @@ response content is handled by parsers and renderers. """ from __future__ import unicode_literals +import copy +import inspect import traceback +from collections import OrderedDict +from django.core.exceptions import ValidationError as DjangoValidationError +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.db.models import DurationField as ModelDurationField from django.db.models.fields import Field as DjangoModelField from django.db.models.fields import FieldDoesNotExist +from django.utils import six, timezone from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from rest_framework.compat import JSONField as ModelJSONField from rest_framework.compat import postgres_fields, set_many, unicode_to_repr -from rest_framework.utils import model_meta +from rest_framework.exceptions import ErrorDetail, ValidationError +from rest_framework.fields import get_error_detail, set_value +from rest_framework.settings import api_settings +from rest_framework.utils import html, model_meta, representation from rest_framework.utils.field_mapping import ( ClassLookupDict, get_field_kwargs, get_nested_relation_kwargs, get_relation_kwargs, get_url_kwargs @@ -42,9 +51,23 @@ from rest_framework.validators import ( # # This helps keep the separation between model fields, form fields, and # serializer fields more explicit. +from rest_framework.fields import ( # NOQA # isort:skip + BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField, + DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField, + HiddenField, IPAddressField, ImageField, IntegerField, JSONField, ListField, + ModelField, MultipleChoiceField, NullBooleanField, ReadOnlyField, RegexField, + SerializerMethodField, SlugField, TimeField, URLField, UUIDField, +) +from rest_framework.relations import ( # NOQA # isort:skip + HyperlinkedIdentityField, HyperlinkedRelatedField, ManyRelatedField, + PrimaryKeyRelatedField, RelatedField, SlugRelatedField, StringRelatedField, +) -from rest_framework.fields import * # NOQA # isort:skip -from rest_framework.relations import * # NOQA # isort:skip +# Non-field imports, but public API +from rest_framework.fields import ( # NOQA # isort:skip + CreateOnlyDefault, CurrentUserDefault, SkipField, empty +) +from rest_framework.relations import Hyperlink, PKOnlyObject # NOQA # isort:skip # We assume that 'validators' are intended for the child serializer, # rather than the parent serializer. diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 32be39faa..8c8b5b163 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -1,17 +1,60 @@ # coding: utf-8 from __future__ import unicode_literals +import inspect import pickle import re import pytest -from rest_framework import serializers +from rest_framework import fields, relations, serializers from rest_framework.compat import unicode_repr +from rest_framework.fields import Field from .utils import MockObject +# Test serializer fields imports. +# ------------------------------- + +class TestFieldImports: + def is_field(self, name, value): + return ( + isinstance(value, type) and + issubclass(value, Field) and + not name.startswith('_') + ) + + def test_fields(self): + msg = "Expected `fields.%s` to be imported in `serializers`" + field_classes = [ + key for key, value + in inspect.getmembers(fields) + if self.is_field(key, value) + ] + + # sanity check + assert 'Field' in field_classes + assert 'BooleanField' in field_classes + + for field in field_classes: + assert hasattr(serializers, field), msg % field + + def test_relations(self): + msg = "Expected `relations.%s` to be imported in `serializers`" + field_classes = [ + key for key, value + in inspect.getmembers(relations) + if self.is_field(key, value) + ] + + # sanity check + assert 'RelatedField' in field_classes + + for field in field_classes: + assert hasattr(serializers, field), msg % field + + # Tests for core functionality. # -----------------------------