diff --git a/.travis.yml b/.travis.yml index 9543cb4525..d77943dbf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ dist: xenial matrix: fast_finish: true include: - - { python: "2.7", env: DJANGO=1.11 } - { python: "3.4", env: DJANGO=1.11 } - { python: "3.4", env: DJANGO=2.0 } @@ -25,9 +24,10 @@ matrix: - { python: "3.7", env: DJANGO=2.2 } - { python: "3.7", env: DJANGO=master } - - { python: "3.7", env: TOXENV=base } - - { python: "2.7", env: TOXENV=lint } - - { python: "2.7", env: TOXENV=docs } + - { python: "3.6", env: TOXENV=base } + - { python: "3.6", env: TOXENV=lint } + - { python: "3.6", env: TOXENV=docs } + - python: "3.7" env: TOXENV=dist diff --git a/README.md b/README.md index 66079edf07..921f50c8a7 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,10 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements -* Python (2.7, 3.4, 3.5, 3.6, 3.7) +* Python (3.4, 3.5, 3.6, 3.7) * Django (1.11, 2.0, 2.1, 2.2) + We **highly recommend** and only officially support the latest patch release of each Python and Django series. diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index 25150d5255..ae009b7403 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -1,7 +1,6 @@ """ Provides various authentication policies. """ -from __future__ import unicode_literals import base64 import binascii @@ -33,7 +32,7 @@ def _reject(self, request, reason): return reason -class BaseAuthentication(object): +class BaseAuthentication: """ All authentication classes should extend BaseAuthentication. """ diff --git a/rest_framework/authtoken/migrations/0001_initial.py b/rest_framework/authtoken/migrations/0001_initial.py index 75780fedf2..6a46ccfffe 100644 --- a/rest_framework/authtoken/migrations/0001_initial.py +++ b/rest_framework/authtoken/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.conf import settings from django.db import migrations, models diff --git a/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py b/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py index 9f7e58e226..43119099a3 100644 --- a/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py +++ b/rest_framework/authtoken/migrations/0002_auto_20160226_1747.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.conf import settings from django.db import migrations, models diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py index 7e96eff93b..0ed02c4154 100644 --- a/rest_framework/authtoken/models.py +++ b/rest_framework/authtoken/models.py @@ -3,11 +3,9 @@ from django.conf import settings from django.db import models -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ -@python_2_unicode_compatible class Token(models.Model): """ The default authorization token model. @@ -32,7 +30,7 @@ class Meta: def save(self, *args, **kwargs): if not self.key: self.key = self.generate_key() - return super(Token, self).save(*args, **kwargs) + return super().save(*args, **kwargs) def generate_key(self): return binascii.hexlify(os.urandom(20)).decode() diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 9422e6ad56..9c78c288e8 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -3,22 +3,13 @@ versions of Django/Python, and compatibility wrappers around optional packages. """ -from __future__ import unicode_literals - import sys +from collections.abc import Mapping, MutableMapping # noqa from django.conf import settings from django.core import validators -from django.utils import six from django.views.generic import View -try: - # Python 3 - from collections.abc import Mapping, MutableMapping # noqa -except ImportError: - # Python 2.7 - from collections import Mapping, MutableMapping # noqa - try: from django.urls import ( # noqa URLPattern, @@ -92,8 +83,7 @@ def make_url_resolver(regex, urlpatterns): def unicode_repr(instance): # Get the repr of an instance, but ensure it is a unicode string # on both python 3 (already the case) and 2 (not the case). - if six.PY2: - return repr(instance).decode('utf-8') + return repr(instance) @@ -101,8 +91,7 @@ def unicode_to_repr(value): # Coerce a unicode string to the correct repr return type, depending on # the Python version. We wrap all our `__repr__` implementations with # this and then use unicode throughout internally. - if six.PY2: - return value.encode('utf-8') + return value @@ -168,10 +157,7 @@ def is_guardian_installed(): """ django-guardian is optional and only imported if in INSTALLED_APPS. """ - if six.PY2: - # Guardian 1.5.0, for Django 2.2 is NOT compatible with Python 2.7. - # Remove when dropping PY2. - return False + return 'guardian' in settings.INSTALLED_APPS @@ -284,17 +270,13 @@ def md_filter_add_syntax_highlight(md): # `separators` argument to `json.dumps()` differs between 2.x and 3.x # See: https://bugs.python.org/issue22767 -if six.PY3: - SHORT_SEPARATORS = (',', ':') - LONG_SEPARATORS = (', ', ': ') - INDENT_SEPARATORS = (',', ': ') -else: - SHORT_SEPARATORS = (b',', b':') - LONG_SEPARATORS = (b', ', b': ') - INDENT_SEPARATORS = (b',', b': ') + +SHORT_SEPARATORS = (',', ':') +LONG_SEPARATORS = (', ', ': ') +INDENT_SEPARATORS = (',', ': ') -class CustomValidatorMessage(object): +class CustomValidatorMessage: """ We need to avoid evaluation of `lazy` translated `message` in `django.core.validators.BaseValidator.__init__`. https://github.com/django/django/blob/75ed5900321d170debef4ac452b8b3cf8a1c2384/django/core/validators.py#L297 @@ -304,7 +286,7 @@ class CustomValidatorMessage(object): def __init__(self, *args, **kwargs): self.message = kwargs.pop('message', self.message) - super(CustomValidatorMessage, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class MinValueValidator(CustomValidatorMessage, validators.MinValueValidator): diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 30bfcc4e53..537c995b2d 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -6,7 +6,6 @@ based views, as well as the `@detail_route` and `@list_route` decorators, which are used to annotate methods on viewsets that should be included by routers. """ -from __future__ import unicode_literals import types import warnings diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index f79b161294..b67e20fccf 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -4,7 +4,6 @@ In addition Django's built in 403 and 404 exceptions are handled. (`django.http.Http404` and `django.core.exceptions.PermissionDenied`) """ -from __future__ import unicode_literals import math @@ -76,7 +75,7 @@ def __new__(cls, string, code=None): return self def __eq__(self, other): - r = super(ErrorDetail, self).__eq__(other) + r = super().__eq__(other) try: return r and self.code == other.code except AttributeError: @@ -196,7 +195,7 @@ class MethodNotAllowed(APIException): def __init__(self, method, detail=None, code=None): if detail is None: detail = force_text(self.default_detail).format(method=method) - super(MethodNotAllowed, self).__init__(detail, code) + super().__init__(detail, code) class NotAcceptable(APIException): @@ -206,7 +205,7 @@ class NotAcceptable(APIException): def __init__(self, detail=None, code=None, available_renderers=None): self.available_renderers = available_renderers - super(NotAcceptable, self).__init__(detail, code) + super().__init__(detail, code) class UnsupportedMediaType(APIException): @@ -217,7 +216,7 @@ class UnsupportedMediaType(APIException): def __init__(self, media_type, detail=None, code=None): if detail is None: detail = force_text(self.default_detail).format(media_type=media_type) - super(UnsupportedMediaType, self).__init__(detail, code) + super().__init__(detail, code) class Throttled(APIException): @@ -238,7 +237,7 @@ def __init__(self, wait=None, detail=None, code=None): self.extra_detail_plural.format(wait=wait), wait)))) self.wait = wait - super(Throttled, self).__init__(detail, code) + super().__init__(detail, code) def server_error(request, *args, **kwargs): diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c8f65db0e5..c14a5a223b 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import copy import datetime import decimal @@ -185,18 +183,18 @@ def iter_options(grouped_choices, cutoff=None, cutoff_text=None): """ Helper function for options and option groups in templates. """ - class StartOptionGroup(object): + class StartOptionGroup: start_option_group = True end_option_group = False def __init__(self, label): self.label = label - class EndOptionGroup(object): + class EndOptionGroup: start_option_group = False end_option_group = True - class Option(object): + class Option: start_option_group = False end_option_group = False @@ -251,7 +249,7 @@ def get_error_detail(exc_info): } -class CreateOnlyDefault(object): +class CreateOnlyDefault: """ This class may be used to provide default values that are only used for create operations, but that do not return any value for update @@ -278,7 +276,7 @@ def __repr__(self): ) -class CurrentUserDefault(object): +class CurrentUserDefault: def set_context(self, serializer_field): self.user = serializer_field.context['request'].user @@ -305,7 +303,7 @@ class SkipField(Exception): ) -class Field(object): +class Field: _creation_counter = 0 default_error_messages = { @@ -724,7 +722,7 @@ class NullBooleanField(Field): def __init__(self, **kwargs): assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.' kwargs['allow_null'] = True - super(NullBooleanField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): try: @@ -764,7 +762,7 @@ def __init__(self, **kwargs): self.trim_whitespace = kwargs.pop('trim_whitespace', True) self.max_length = kwargs.pop('max_length', None) self.min_length = kwargs.pop('min_length', None) - super(CharField, self).__init__(**kwargs) + super().__init__(**kwargs) if self.max_length is not None: message = lazy( self.error_messages['max_length'].format, @@ -790,7 +788,7 @@ def run_validation(self, data=empty): if not self.allow_blank: self.fail('blank') return '' - return super(CharField, self).run_validation(data) + return super().run_validation(data) def to_internal_value(self, data): # We're lenient with allowing basic numerics to be coerced into strings, @@ -811,7 +809,7 @@ class EmailField(CharField): } def __init__(self, **kwargs): - super(EmailField, self).__init__(**kwargs) + super().__init__(**kwargs) validator = EmailValidator(message=self.error_messages['invalid']) self.validators.append(validator) @@ -822,7 +820,7 @@ class RegexField(CharField): } def __init__(self, regex, **kwargs): - super(RegexField, self).__init__(**kwargs) + super().__init__(**kwargs) validator = RegexValidator(regex, message=self.error_messages['invalid']) self.validators.append(validator) @@ -834,7 +832,7 @@ class SlugField(CharField): } def __init__(self, allow_unicode=False, **kwargs): - super(SlugField, self).__init__(**kwargs) + super().__init__(**kwargs) self.allow_unicode = allow_unicode if self.allow_unicode: validator = RegexValidator(re.compile(r'^[-\w]+\Z', re.UNICODE), message=self.error_messages['invalid_unicode']) @@ -849,7 +847,7 @@ class URLField(CharField): } def __init__(self, **kwargs): - super(URLField, self).__init__(**kwargs) + super().__init__(**kwargs) validator = URLValidator(message=self.error_messages['invalid']) self.validators.append(validator) @@ -868,7 +866,7 @@ def __init__(self, **kwargs): 'Invalid format for uuid representation. ' 'Must be one of "{0}"'.format('", "'.join(self.valid_formats)) ) - super(UUIDField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): if not isinstance(data, uuid.UUID): @@ -900,7 +898,7 @@ class IPAddressField(CharField): def __init__(self, protocol='both', **kwargs): self.protocol = protocol.lower() self.unpack_ipv4 = (self.protocol == 'both') - super(IPAddressField, self).__init__(**kwargs) + super().__init__(**kwargs) validators, error_message = ip_address_validators(protocol, self.unpack_ipv4) self.validators.extend(validators) @@ -915,7 +913,7 @@ def to_internal_value(self, data): except DjangoValidationError: self.fail('invalid', value=data) - return super(IPAddressField, self).to_internal_value(data) + return super().to_internal_value(data) # Number types... @@ -933,7 +931,7 @@ class IntegerField(Field): def __init__(self, **kwargs): self.max_value = kwargs.pop('max_value', None) self.min_value = kwargs.pop('min_value', None) - super(IntegerField, self).__init__(**kwargs) + super().__init__(**kwargs) if self.max_value is not None: message = lazy( self.error_messages['max_value'].format, @@ -973,7 +971,7 @@ class FloatField(Field): def __init__(self, **kwargs): self.max_value = kwargs.pop('max_value', None) self.min_value = kwargs.pop('min_value', None) - super(FloatField, self).__init__(**kwargs) + super().__init__(**kwargs) if self.max_value is not None: message = lazy( self.error_messages['max_value'].format, @@ -1031,7 +1029,7 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value= else: self.max_whole_digits = None - super(DecimalField, self).__init__(**kwargs) + super().__init__(**kwargs) if self.max_value is not None: message = lazy( @@ -1167,7 +1165,7 @@ def __init__(self, format=empty, input_formats=None, default_timezone=None, *arg self.input_formats = input_formats if default_timezone is not None: self.timezone = default_timezone - super(DateTimeField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def enforce_timezone(self, value): """ @@ -1251,7 +1249,7 @@ def __init__(self, format=empty, input_formats=None, *args, **kwargs): self.format = format if input_formats is not None: self.input_formats = input_formats - super(DateField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def to_internal_value(self, value): input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) @@ -1317,7 +1315,7 @@ def __init__(self, format=empty, input_formats=None, *args, **kwargs): self.format = format if input_formats is not None: self.input_formats = input_formats - super(TimeField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def to_internal_value(self, value): input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS) @@ -1378,7 +1376,7 @@ class DurationField(Field): def __init__(self, **kwargs): self.max_value = kwargs.pop('max_value', None) self.min_value = kwargs.pop('min_value', None) - super(DurationField, self).__init__(**kwargs) + super().__init__(**kwargs) if self.max_value is not None: message = lazy( self.error_messages['max_value'].format, @@ -1420,7 +1418,7 @@ def __init__(self, choices, **kwargs): self.allow_blank = kwargs.pop('allow_blank', False) - super(ChoiceField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): if data == '' and self.allow_blank: @@ -1473,7 +1471,7 @@ class MultipleChoiceField(ChoiceField): def __init__(self, *args, **kwargs): self.allow_empty = kwargs.pop('allow_empty', True) - super(MultipleChoiceField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def get_value(self, dictionary): if self.field_name not in dictionary: @@ -1516,7 +1514,7 @@ def __init__(self, path, match=None, recursive=False, allow_files=True, allow_folders=allow_folders, required=required ) kwargs['choices'] = field.choices - super(FilePathField, self).__init__(**kwargs) + super().__init__(**kwargs) # File types... @@ -1535,7 +1533,7 @@ def __init__(self, *args, **kwargs): self.allow_empty_file = kwargs.pop('allow_empty_file', False) if 'use_url' in kwargs: self.use_url = kwargs.pop('use_url') - super(FileField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def to_internal_value(self, data): try: @@ -1581,13 +1579,13 @@ class ImageField(FileField): def __init__(self, *args, **kwargs): self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField) - super(ImageField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def to_internal_value(self, data): # Image validation is a bit grungy, so we'll just outright # defer to Django's implementation so we don't need to # consider it, or treat PIL as a test dependency. - file_object = super(ImageField, self).to_internal_value(data) + file_object = super().to_internal_value(data) django_field = self._DjangoImageField() django_field.error_messages = self.error_messages return django_field.clean(file_object) @@ -1597,7 +1595,7 @@ def to_internal_value(self, data): class _UnvalidatedField(Field): def __init__(self, *args, **kwargs): - super(_UnvalidatedField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.allow_blank = True self.allow_null = True @@ -1630,7 +1628,7 @@ def __init__(self, *args, **kwargs): "Remove `source=` from the field declaration." ) - super(ListField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) if self.max_length is not None: message = self.error_messages['max_length'].format(max_length=self.max_length) @@ -1703,7 +1701,7 @@ def __init__(self, *args, **kwargs): "Remove `source=` from the field declaration." ) - super(DictField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) def get_value(self, dictionary): @@ -1750,7 +1748,7 @@ class HStoreField(DictField): child = CharField(allow_blank=True, allow_null=True) def __init__(self, *args, **kwargs): - super(HStoreField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) assert isinstance(self.child, CharField), ( "The `child` argument must be an instance of `CharField`, " "as the hstore extension stores values as strings." @@ -1764,7 +1762,7 @@ class JSONField(Field): def __init__(self, *args, **kwargs): self.binary = kwargs.pop('binary', False) - super(JSONField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def get_value(self, dictionary): if html.is_html_input(dictionary) and self.field_name in dictionary: @@ -1817,7 +1815,7 @@ class ExampleSerializer(Serializer): def __init__(self, **kwargs): kwargs['read_only'] = True - super(ReadOnlyField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_representation(self, value): return value @@ -1834,7 +1832,7 @@ class HiddenField(Field): def __init__(self, **kwargs): assert 'default' in kwargs, 'default is a required argument.' kwargs['write_only'] = True - super(HiddenField, self).__init__(**kwargs) + super().__init__(**kwargs) def get_value(self, dictionary): # We always use the default value for `HiddenField`. @@ -1864,7 +1862,7 @@ def __init__(self, method_name=None, **kwargs): self.method_name = method_name kwargs['source'] = '*' kwargs['read_only'] = True - super(SerializerMethodField, self).__init__(**kwargs) + super().__init__(**kwargs) def bind(self, field_name, parent): # In order to enforce a consistent style, we error if a redundant @@ -1882,7 +1880,7 @@ def bind(self, field_name, parent): if self.method_name is None: self.method_name = default_method_name - super(SerializerMethodField, self).bind(field_name, parent) + super().bind(field_name, parent) def to_representation(self, value): method = getattr(self.parent, self.method_name) @@ -1905,7 +1903,7 @@ def __init__(self, model_field, **kwargs): # The `max_length` option is supported by Django's base `Field` class, # so we'd better support it here. max_length = kwargs.pop('max_length', None) - super(ModelField, self).__init__(**kwargs) + super().__init__(**kwargs) if max_length is not None: message = lazy( self.error_messages['max_length'].format, diff --git a/rest_framework/filters.py b/rest_framework/filters.py index bb1b86586c..5b1f389ac1 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -2,7 +2,6 @@ Provides generic filtering backends that can be used to filter the results returned by list views. """ -from __future__ import unicode_literals import operator import warnings @@ -24,7 +23,7 @@ from rest_framework.settings import api_settings -class BaseFilterBackend(object): +class BaseFilterBackend: """ A base class from which all filter backend classes should inherit. """ diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 8d0bf284a9..2034827c1b 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -1,7 +1,6 @@ """ Generic views that provide commonly needed behaviour. """ -from __future__ import unicode_literals from django.core.exceptions import ValidationError from django.db.models.query import QuerySet diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py index 9f93244693..a68ac7ef25 100644 --- a/rest_framework/metadata.py +++ b/rest_framework/metadata.py @@ -6,7 +6,6 @@ Future implementations might use JSON schema or other definitions in order to return this information in a more standardized way. """ -from __future__ import unicode_literals from collections import OrderedDict @@ -19,7 +18,7 @@ from rest_framework.utils.field_mapping import ClassLookupDict -class BaseMetadata(object): +class BaseMetadata: def determine_metadata(self, request, view): """ Return a dictionary of metadata about the view. diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index de10d69308..ff21d790fc 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -4,14 +4,13 @@ We don't bind behaviour to http method handlers yet, which allows mixin classes to be composed in interesting ways. """ -from __future__ import unicode_literals from rest_framework import status from rest_framework.response import Response from rest_framework.settings import api_settings -class CreateModelMixin(object): +class CreateModelMixin: """ Create a model instance. """ @@ -32,7 +31,7 @@ def get_success_headers(self, data): return {} -class ListModelMixin(object): +class ListModelMixin: """ List a queryset. """ @@ -48,7 +47,7 @@ def list(self, request, *args, **kwargs): return Response(serializer.data) -class RetrieveModelMixin(object): +class RetrieveModelMixin: """ Retrieve a model instance. """ @@ -58,7 +57,7 @@ def retrieve(self, request, *args, **kwargs): return Response(serializer.data) -class UpdateModelMixin(object): +class UpdateModelMixin: """ Update a model instance. """ @@ -84,7 +83,7 @@ def partial_update(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) -class DestroyModelMixin(object): +class DestroyModelMixin: """ Destroy a model instance. """ diff --git a/rest_framework/negotiation.py b/rest_framework/negotiation.py index ca1b59f12e..7d80ba12d8 100644 --- a/rest_framework/negotiation.py +++ b/rest_framework/negotiation.py @@ -2,7 +2,6 @@ Content negotiation deals with selecting an appropriate renderer given the incoming request. Typically this will be based on the request's Accept header. """ -from __future__ import unicode_literals from django.http import Http404 @@ -13,7 +12,7 @@ ) -class BaseContentNegotiation(object): +class BaseContentNegotiation: def select_parser(self, request, parsers): raise NotImplementedError('.select_parser() must be implemented') diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index b11d7cdf3a..d593944333 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -3,7 +3,6 @@ Pagination serializers determine the structure of the output that should be used for paginated responses. """ -from __future__ import unicode_literals from base64 import b64decode, b64encode from collections import OrderedDict, namedtuple @@ -133,7 +132,7 @@ def invert(x): PAGE_BREAK = PageLink(url=None, number=None, is_active=False, is_break=True) -class BasePagination(object): +class BasePagination: display_page_controls = False def paginate_queryset(self, queryset, request, view=None): # pragma: no cover diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 35d0d1aa70..d20c6071bd 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -4,7 +4,6 @@ They give us a generic way of being able to handle various media types on the request, such as form content or json encoded data. """ -from __future__ import unicode_literals import codecs @@ -25,13 +24,13 @@ from rest_framework.utils import json -class DataAndFiles(object): +class DataAndFiles: def __init__(self, data, files): self.data = data self.files = files -class BaseParser(object): +class BaseParser: """ All parsers should extend `BaseParser`, specifying a `media_type` attribute, and overriding the `.parse()` method. diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 5d75f54bad..7f374d561f 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -1,7 +1,6 @@ """ Provides a set of pluggable permission policies. """ -from __future__ import unicode_literals from django.http import Http404 from django.utils import six diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 31c1e75618..27e29676d2 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - import sys from collections import OrderedDict @@ -9,9 +6,7 @@ from django.db.models.query import QuerySet from django.urls import NoReverseMatch, Resolver404, get_script_prefix, resolve from django.utils import six -from django.utils.encoding import ( - python_2_unicode_compatible, smart_text, uri_to_iri -) +from django.utils.encoding import smart_text, uri_to_iri from django.utils.six.moves.urllib import parse as urlparse from django.utils.translation import ugettext_lazy as _ @@ -70,8 +65,7 @@ def name(self): is_hyperlink = True -@python_2_unicode_compatible -class PKOnlyObject(object): +class PKOnlyObject: """ This is a mock object, used for when we only need the pk of the object instance, but still want to return an object with a .pk attribute, @@ -121,7 +115,7 @@ def __init__(self, **kwargs): ) kwargs.pop('many', None) kwargs.pop('allow_empty', None) - super(RelatedField, self).__init__(**kwargs) + super().__init__(**kwargs) def __new__(cls, *args, **kwargs): # We override this method in order to automagically create @@ -157,7 +151,7 @@ def run_validation(self, data=empty): # We force empty strings to None values for relational fields. if data == '': data = None - return super(RelatedField, self).run_validation(data) + return super().run_validation(data) def get_queryset(self): queryset = self.queryset @@ -189,7 +183,7 @@ def get_attribute(self, instance): pass # Standard case, return the object instance. - return super(RelatedField, self).get_attribute(instance) + return super().get_attribute(instance) def get_choices(self, cutoff=None): queryset = self.get_queryset() @@ -236,7 +230,7 @@ class StringRelatedField(RelatedField): def __init__(self, **kwargs): kwargs['read_only'] = True - super(StringRelatedField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_representation(self, value): return six.text_type(value) @@ -251,7 +245,7 @@ class PrimaryKeyRelatedField(RelatedField): def __init__(self, **kwargs): self.pk_field = kwargs.pop('pk_field', None) - super(PrimaryKeyRelatedField, self).__init__(**kwargs) + super().__init__(**kwargs) def use_pk_only_optimization(self): return True @@ -297,7 +291,7 @@ def __init__(self, view_name=None, **kwargs): # implicit `self` argument to be passed. self.reverse = reverse - super(HyperlinkedRelatedField, self).__init__(**kwargs) + super().__init__(**kwargs) def use_pk_only_optimization(self): return self.lookup_field == 'pk' @@ -432,7 +426,7 @@ def __init__(self, view_name=None, **kwargs): assert view_name is not None, 'The `view_name` argument is required.' kwargs['read_only'] = True kwargs['source'] = '*' - super(HyperlinkedIdentityField, self).__init__(view_name, **kwargs) + super().__init__(view_name, **kwargs) def use_pk_only_optimization(self): # We have the complete object instance already. We don't need @@ -453,7 +447,7 @@ class SlugRelatedField(RelatedField): def __init__(self, slug_field=None, **kwargs): assert slug_field is not None, 'The `slug_field` argument is required.' self.slug_field = slug_field - super(SlugRelatedField, self).__init__(**kwargs) + super().__init__(**kwargs) def to_internal_value(self, data): try: @@ -502,7 +496,7 @@ def __init__(self, child_relation=None, *args, **kwargs): self.html_cutoff_text or _(api_settings.HTML_SELECT_CUTOFF_TEXT) ) assert child_relation is not None, '`child_relation` is a required argument.' - super(ManyRelatedField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.child_relation.bind(field_name='', parent=self) def get_value(self, dictionary): diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index f043e63278..15b4c6d009 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -6,7 +6,6 @@ REST framework also provides an HTML renderer that renders the browsable API. """ -from __future__ import unicode_literals import base64 from collections import OrderedDict @@ -40,7 +39,7 @@ def zero_as_none(value): return None if value == 0 else value -class BaseRenderer(object): +class BaseRenderer: """ All renderers should extend this class, setting the `media_type` and `format` attributes, and override the `.render()` method. @@ -791,7 +790,7 @@ def get_context(self, data, accepted_media_type, renderer_context): """ Render the HTML for the browsable API representation. """ - context = super(AdminRenderer, self).get_context( + context = super().get_context( data, accepted_media_type, renderer_context ) diff --git a/rest_framework/request.py b/rest_framework/request.py index a6d92e2bdc..e167058307 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -8,7 +8,6 @@ - full support of PUT method, including support for file uploads - form overloading of HTTP method, content type and content """ -from __future__ import unicode_literals import io import sys @@ -34,7 +33,7 @@ def is_form_media_type(media_type): base_media_type == 'multipart/form-data') -class override_method(object): +class override_method: """ A context manager that temporarily overrides the method on a request, additionally setting the `view.request` attribute. @@ -81,7 +80,7 @@ def wrap_attributeerrors(): six.reraise(type(exc), exc, info[2]) -class Empty(object): +class Empty: """ Placeholder for unset attributes. Cannot use `None`, as that may be a valid value. @@ -126,7 +125,7 @@ def clone_request(request, method): return ret -class ForcedAuthentication(object): +class ForcedAuthentication: """ This authentication class is used if the test client or request factory forcibly authenticated the request. @@ -140,7 +139,7 @@ def authenticate(self, request): return (self.force_user, self.force_token) -class Request(object): +class Request: """ Wrapper allowing to enhance a standard `HttpRequest` instance. diff --git a/rest_framework/response.py b/rest_framework/response.py index bf06632557..1285738c5b 100644 --- a/rest_framework/response.py +++ b/rest_framework/response.py @@ -4,7 +4,6 @@ The appropriate renderer is called during Django's template response rendering. """ -from __future__ import unicode_literals from django.template.response import SimpleTemplateResponse from django.utils import six @@ -29,7 +28,7 @@ def __init__(self, data=None, status=None, Setting 'renderer' and 'media_type' will typically be deferred, For example being set automatically by the `APIView`. """ - super(Response, self).__init__(None, status=status) + super().__init__(None, status=status) if isinstance(data, Serializer): msg = ( @@ -94,7 +93,7 @@ def __getstate__(self): """ Remove attributes from the response that shouldn't be cached. """ - state = super(Response, self).__getstate__() + state = super().__getstate__() for key in ( 'accepted_renderer', 'renderer_context', 'resolver_match', 'client', 'request', 'json', 'wsgi_request' diff --git a/rest_framework/reverse.py b/rest_framework/reverse.py index e9cf737f19..1e0d8b43d3 100644 --- a/rest_framework/reverse.py +++ b/rest_framework/reverse.py @@ -1,7 +1,6 @@ """ Provide urlresolver functions that return fully qualified URLs or view names """ -from __future__ import unicode_literals from django.urls import NoReverseMatch from django.urls import reverse as django_reverse diff --git a/rest_framework/routers.py b/rest_framework/routers.py index 1cacea1812..50918f9416 100644 --- a/rest_framework/routers.py +++ b/rest_framework/routers.py @@ -13,7 +13,6 @@ urlpatterns = router.urls """ -from __future__ import unicode_literals import itertools import warnings @@ -39,7 +38,7 @@ DynamicRoute = namedtuple('DynamicRoute', ['url', 'name', 'detail', 'initkwargs']) -class DynamicDetailRoute(object): +class DynamicDetailRoute: def __new__(cls, url, name, initkwargs): warnings.warn( "`DynamicDetailRoute` is deprecated and will be removed in 3.10 " @@ -50,7 +49,7 @@ def __new__(cls, url, name, initkwargs): return DynamicRoute(url, name, True, initkwargs) -class DynamicListRoute(object): +class DynamicListRoute: def __new__(cls, url, name, initkwargs): warnings.warn( "`DynamicListRoute` is deprecated and will be removed in 3.10 in " @@ -173,7 +172,7 @@ class SimpleRouter(BaseRouter): def __init__(self, trailing_slash=True): self.trailing_slash = '/' if trailing_slash else '' - super(SimpleRouter, self).__init__() + super().__init__() def get_default_basename(self, viewset): """ @@ -365,7 +364,7 @@ def __init__(self, *args, **kwargs): self.root_renderers = kwargs.pop('root_renderers') else: self.root_renderers = list(api_settings.DEFAULT_RENDERER_CLASSES) - super(DefaultRouter, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def get_api_root_view(self, api_urls=None): """ @@ -383,7 +382,7 @@ def get_urls(self): Generate the list of URL patterns, including a default root view for the API, and appending `.json` style format suffixes. """ - urls = super(DefaultRouter, self).get_urls() + urls = super().get_urls() if self.include_root_view: view = self.get_api_root_view(api_urls=urls) diff --git a/rest_framework/schemas/generators.py b/rest_framework/schemas/generators.py index db226a6c16..5073daf040 100644 --- a/rest_framework/schemas/generators.py +++ b/rest_framework/schemas/generators.py @@ -68,7 +68,7 @@ class LinkNode(OrderedDict): def __init__(self): self.links = [] self.methods_counter = Counter() - super(LinkNode, self).__init__() + super().__init__() def get_available_key(self, preferred_key): if preferred_key not in self: @@ -140,7 +140,7 @@ def endpoint_ordering(endpoint): ) -class EndpointEnumerator(object): +class EndpointEnumerator: """ A class to determine the available API endpoints that a project exposes. """ @@ -232,7 +232,7 @@ def get_allowed_methods(self, callback): return [method for method in methods if method not in ('OPTIONS', 'HEAD')] -class SchemaGenerator(object): +class SchemaGenerator: # Map HTTP methods onto actions. default_mapping = { 'get': 'retrieve', diff --git a/rest_framework/schemas/inspectors.py b/rest_framework/schemas/inspectors.py index 85142edce4..56b04d8df7 100644 --- a/rest_framework/schemas/inspectors.py +++ b/rest_framework/schemas/inspectors.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ inspectors.py # Per-endpoint view introspection @@ -125,7 +124,7 @@ def get_pk_description(model, model_field): ) -class ViewInspector(object): +class ViewInspector: """ Descriptor class on APIView. @@ -207,7 +206,7 @@ def __init__(self, manual_fields=None): * `manual_fields`: list of `coreapi.Field` instances that will be added to auto-generated fields, overwriting on `Field.name` """ - super(AutoSchema, self).__init__() + super().__init__() if manual_fields is None: manual_fields = [] self._manual_fields = manual_fields @@ -475,7 +474,7 @@ def __init__(self, fields, description='', encoding=None): * `fields`: list of `coreapi.Field` instances. * `description`: String description for view. Optional. """ - super(ManualSchema, self).__init__() + super().__init__() assert all(isinstance(f, coreapi.Field) for f in fields), "`fields` must be a list of coreapi.Field instances" self._fields = fields self._description = description @@ -498,7 +497,7 @@ def get_link(self, path, method, base_url): class DefaultSchema(ViewInspector): """Allows overriding AutoSchema using DEFAULT_SCHEMA_CLASS setting""" def __get__(self, instance, owner): - result = super(DefaultSchema, self).__get__(instance, owner) + result = super().__get__(instance, owner) if not isinstance(result, DefaultSchema): return result diff --git a/rest_framework/schemas/views.py b/rest_framework/schemas/views.py index f5e327a941..73b4a80718 100644 --- a/rest_framework/schemas/views.py +++ b/rest_framework/schemas/views.py @@ -17,7 +17,7 @@ class SchemaView(APIView): public = False def __init__(self, *args, **kwargs): - super(SchemaView, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.renderer_classes is None: self.renderer_classes = [ renderers.OpenAPIRenderer, diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 9830edb3f0..a50c91eb0f 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -10,7 +10,6 @@ 2. The process of marshalling between python primitives and request and response content is handled by parsers and renderers. """ -from __future__ import unicode_literals import copy import inspect diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 8db9c81eda..d31cf70224 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -18,7 +18,6 @@ REST framework settings, checking for user settings first, then falling back to the defaults. """ -from __future__ import unicode_literals from importlib import import_module @@ -187,7 +186,7 @@ def import_from_string(val, setting_name): raise ImportError(msg) -class APISettings(object): +class APISettings: """ A settings object, that allows API settings to be accessed as properties. For example: diff --git a/rest_framework/status.py b/rest_framework/status.py index 4b4561cfcd..1489b440cf 100644 --- a/rest_framework/status.py +++ b/rest_framework/status.py @@ -5,7 +5,6 @@ And RFC 6585 - https://tools.ietf.org/html/rfc6585 And RFC 4918 - https://tools.ietf.org/html/rfc4918 """ -from __future__ import unicode_literals def is_informational(code): diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index f48675d5eb..15a37fcdc2 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, unicode_literals - import re from collections import OrderedDict diff --git a/rest_framework/test.py b/rest_framework/test.py index edacf0066d..d7e9ffd1f0 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -1,8 +1,6 @@ -# -- coding: utf-8 -- - # Note that we import as `DjangoRequestFactory` and `DjangoClient` in order # to make it harder for the user to import the wrong thing without realizing. -from __future__ import unicode_literals + import io from importlib import import_module @@ -32,7 +30,7 @@ class HeaderDict(requests.packages.urllib3._collections.HTTPHeaderDict): def get_all(self, key, default): return self.getheaders(key) - class MockOriginalResponse(object): + class MockOriginalResponse: def __init__(self, headers): self.msg = HeaderDict(headers) self.closed = False diff --git a/rest_framework/throttling.py b/rest_framework/throttling.py index 834ced148e..6c497edc5b 100644 --- a/rest_framework/throttling.py +++ b/rest_framework/throttling.py @@ -1,7 +1,6 @@ """ Provides various throttling policies. """ -from __future__ import unicode_literals import time @@ -11,7 +10,7 @@ from rest_framework.settings import api_settings -class BaseThrottle(object): +class BaseThrottle: """ Rate throttling of requests. """ diff --git a/rest_framework/urlpatterns.py b/rest_framework/urlpatterns.py index ab3a74978f..831d344ddc 100644 --- a/rest_framework/urlpatterns.py +++ b/rest_framework/urlpatterns.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.conf.urls import include, url from rest_framework.compat import ( diff --git a/rest_framework/urls.py b/rest_framework/urls.py index 0e4c2661bd..521a3db759 100644 --- a/rest_framework/urls.py +++ b/rest_framework/urls.py @@ -11,7 +11,6 @@ You should make sure your authentication settings include `SessionAuthentication`. """ -from __future__ import unicode_literals from django.conf.urls import url from django.contrib.auth import views diff --git a/rest_framework/utils/breadcrumbs.py b/rest_framework/utils/breadcrumbs.py index e0374ffd00..54990e9f6c 100644 --- a/rest_framework/utils/breadcrumbs.py +++ b/rest_framework/utils/breadcrumbs.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.urls import get_script_prefix, resolve diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index d8f4aeb4eb..9f74409896 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -1,8 +1,6 @@ """ Helper classes for parsers. """ -from __future__ import absolute_import, unicode_literals - import datetime import decimal import json # noqa @@ -65,4 +63,4 @@ def default(self, obj): pass elif hasattr(obj, '__iter__'): return tuple(item for item in obj) - return super(JSONEncoder, self).default(obj) + return super().default(obj) diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 927d08ff25..1281ee1672 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -16,7 +16,7 @@ ) -class ClassLookupDict(object): +class ClassLookupDict: """ Takes a dictionary with classes as keys. Lookups against this object will traverses the object's inheritance diff --git a/rest_framework/utils/formatting.py b/rest_framework/utils/formatting.py index aa805f14e3..0c58665a8e 100644 --- a/rest_framework/utils/formatting.py +++ b/rest_framework/utils/formatting.py @@ -1,7 +1,6 @@ """ Utility functions to return a formatted name and description for a given view. """ -from __future__ import unicode_literals import re diff --git a/rest_framework/utils/json.py b/rest_framework/utils/json.py index cb55723801..82b306ddab 100644 --- a/rest_framework/utils/json.py +++ b/rest_framework/utils/json.py @@ -6,8 +6,6 @@ handled by users at the renderer and parser layer. """ -from __future__ import absolute_import - import functools import json # noqa diff --git a/rest_framework/utils/mediatypes.py b/rest_framework/utils/mediatypes.py index f4acf4807e..e808dfa362 100644 --- a/rest_framework/utils/mediatypes.py +++ b/rest_framework/utils/mediatypes.py @@ -3,10 +3,8 @@ See https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 """ -from __future__ import unicode_literals from django.http.multipartparser import parse_header -from django.utils.encoding import python_2_unicode_compatible from rest_framework import HTTP_HEADER_ENCODING @@ -46,8 +44,7 @@ def order_by_precedence(media_type_lst): return [media_types for media_types in ret if media_types] -@python_2_unicode_compatible -class _MediaType(object): +class _MediaType: def __init__(self, media_type_str): self.orig = '' if (media_type_str is None) else media_type_str self.full_type, self.params = parse_header(self.orig.encode(HTTP_HEADER_ENCODING)) diff --git a/rest_framework/utils/representation.py b/rest_framework/utils/representation.py index deeaf1f63f..6290065e3c 100644 --- a/rest_framework/utils/representation.py +++ b/rest_framework/utils/representation.py @@ -2,7 +2,6 @@ Helper functions for creating user-friendly representations of serializer classes and serializer fields. """ -from __future__ import unicode_literals import re diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index c24e51d091..8e27a925bb 100644 --- a/rest_framework/utils/serializer_helpers.py +++ b/rest_framework/utils/serializer_helpers.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from collections import OrderedDict from django.utils.encoding import force_text @@ -17,7 +15,7 @@ class ReturnDict(OrderedDict): def __init__(self, *args, **kwargs): self.serializer = kwargs.pop('serializer') - super(ReturnDict, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def copy(self): return ReturnDict(self, serializer=self.serializer) @@ -40,7 +38,7 @@ class ReturnList(list): def __init__(self, *args, **kwargs): self.serializer = kwargs.pop('serializer') - super(ReturnList, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def __repr__(self): return list.__repr__(self) @@ -51,7 +49,7 @@ def __reduce__(self): return (list, (list(self),)) -class BoundField(object): +class BoundField: """ A field object that also includes `.value` and `.error` properties. Returned when iterating over a serializer instance, @@ -105,7 +103,7 @@ class NestedBoundField(BoundField): def __init__(self, field, value, errors, prefix=''): if value is None or value is '': value = {} - super(NestedBoundField, self).__init__(field, value, errors, prefix) + super().__init__(field, value, errors, prefix) def __iter__(self): for field in self.fields.values(): diff --git a/rest_framework/validators.py b/rest_framework/validators.py index 2ea3e5ac15..1976f0bc59 100644 --- a/rest_framework/validators.py +++ b/rest_framework/validators.py @@ -6,7 +6,6 @@ object creation, and makes it possible to switch between using the implicit `ModelSerializer` class and an equivalent explicit `Serializer` class. """ -from __future__ import unicode_literals from django.db import DataError from django.utils.translation import ugettext_lazy as _ @@ -33,7 +32,7 @@ def qs_filter(queryset, **kwargs): return queryset.none() -class UniqueValidator(object): +class UniqueValidator: """ Validator that corresponds to `unique=True` on a model field. @@ -88,7 +87,7 @@ def __repr__(self): )) -class UniqueTogetherValidator(object): +class UniqueTogetherValidator: """ Validator that corresponds to `unique_together = (...)` on a model class. @@ -177,7 +176,7 @@ def __repr__(self): )) -class BaseUniqueForValidator(object): +class BaseUniqueForValidator: message = None missing_message = _('This field is required.') diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 206ff6c2ec..d776df8ce9 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - import re from django.utils.translation import ugettext_lazy as _ @@ -13,7 +10,7 @@ from rest_framework.utils.mediatypes import _MediaType -class BaseVersioning(object): +class BaseVersioning: default_version = api_settings.DEFAULT_VERSION allowed_versions = api_settings.ALLOWED_VERSIONS version_param = api_settings.VERSION_PARAM diff --git a/rest_framework/views.py b/rest_framework/views.py index 9d5d959e9d..98e6517765 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -1,7 +1,6 @@ """ Provides an APIView class that is the base of all views in REST framework. """ -from __future__ import unicode_literals from django.conf import settings from django.core.exceptions import PermissionDenied diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py index 7146828d2f..68d6611391 100644 --- a/rest_framework/viewsets.py +++ b/rest_framework/viewsets.py @@ -16,7 +16,6 @@ router.register(r'users', UserViewSet, 'user') urlpatterns = router.urls """ -from __future__ import unicode_literals from collections import OrderedDict from functools import update_wrapper @@ -34,7 +33,7 @@ def _is_extra_action(attr): return hasattr(attr, 'mapping') -class ViewSetMixin(object): +class ViewSetMixin: """ This is the magic. diff --git a/tests/authentication/migrations/0001_initial.py b/tests/authentication/migrations/0001_initial.py index cfc8872400..548b3576bb 100644 --- a/tests/authentication/migrations/0001_initial.py +++ b/tests/authentication/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.conf import settings from django.db import migrations, models diff --git a/tests/authentication/models.py b/tests/authentication/models.py index b8d1fd5a6b..1a721de4d3 100644 --- a/tests/authentication/models.py +++ b/tests/authentication/models.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - from django.conf import settings from django.db import models diff --git a/tests/authentication/test_authentication.py b/tests/authentication/test_authentication.py index 7937735424..8e7ccb9927 100644 --- a/tests/authentication/test_authentication.py +++ b/tests/authentication/test_authentication.py @@ -1,7 +1,3 @@ -# coding: utf-8 - -from __future__ import unicode_literals - import base64 import pytest @@ -253,7 +249,7 @@ def test_post_form_session_auth_failing(self): assert response.status_code == status.HTTP_403_FORBIDDEN -class BaseTokenAuthTests(object): +class BaseTokenAuthTests: """Token authentication""" model = None path = None diff --git a/tests/browsable_api/auth_urls.py b/tests/browsable_api/auth_urls.py index 0e93797172..7530c5e408 100644 --- a/tests/browsable_api/auth_urls.py +++ b/tests/browsable_api/auth_urls.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.conf.urls import include, url from .views import MockView diff --git a/tests/browsable_api/no_auth_urls.py b/tests/browsable_api/no_auth_urls.py index 5fc95c7276..348bfe1c0c 100644 --- a/tests/browsable_api/no_auth_urls.py +++ b/tests/browsable_api/no_auth_urls.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.conf.urls import url from .views import MockView diff --git a/tests/browsable_api/test_browsable_api.py b/tests/browsable_api/test_browsable_api.py index 684d7ae143..81090e2235 100644 --- a/tests/browsable_api/test_browsable_api.py +++ b/tests/browsable_api/test_browsable_api.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.contrib.auth.models import User from django.test import TestCase, override_settings diff --git a/tests/browsable_api/test_browsable_nested_api.py b/tests/browsable_api/test_browsable_nested_api.py index 8f38b3c4e5..3fef74023d 100644 --- a/tests/browsable_api/test_browsable_nested_api.py +++ b/tests/browsable_api/test_browsable_nested_api.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.conf.urls import url from django.test import TestCase from django.test.utils import override_settings diff --git a/tests/browsable_api/test_form_rendering.py b/tests/browsable_api/test_form_rendering.py index d8378a2cab..ff2d0e05a9 100644 --- a/tests/browsable_api/test_form_rendering.py +++ b/tests/browsable_api/test_form_rendering.py @@ -1,9 +1,9 @@ from django.test import TestCase +from tests.models import BasicModel from rest_framework import generics, renderers, serializers, status from rest_framework.response import Response from rest_framework.test import APIRequestFactory -from tests.models import BasicModel factory = APIRequestFactory() diff --git a/tests/browsable_api/views.py b/tests/browsable_api/views.py index 03758f10b3..e1cf13a1ec 100644 --- a/tests/browsable_api/views.py +++ b/tests/browsable_api/views.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from rest_framework import authentication, renderers from rest_framework.response import Response from rest_framework.views import APIView diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py index 55bc243cbd..d0e2e9b559 100644 --- a/tests/generic_relations/models.py +++ b/tests/generic_relations/models.py @@ -5,10 +5,8 @@ ) from django.contrib.contenttypes.models import ContentType from django.db import models -from django.utils.encoding import python_2_unicode_compatible -@python_2_unicode_compatible class Tag(models.Model): """ Tags have a descriptive slug, and are attached to an arbitrary object. @@ -22,7 +20,6 @@ def __str__(self): return self.tag -@python_2_unicode_compatible class Bookmark(models.Model): """ A URL bookmark that may have multiple tags attached. @@ -34,7 +31,6 @@ def __str__(self): return 'Bookmark: %s' % self.url -@python_2_unicode_compatible class Note(models.Model): """ A textual note that may have multiple tags attached. diff --git a/tests/generic_relations/test_generic_relations.py b/tests/generic_relations/test_generic_relations.py index c8de332e1d..c6f2b0de4d 100644 --- a/tests/generic_relations/test_generic_relations.py +++ b/tests/generic_relations/test_generic_relations.py @@ -1,10 +1,46 @@ -from __future__ import unicode_literals - +from django.contrib.contenttypes.fields import ( + GenericForeignKey, GenericRelation +) +from django.contrib.contenttypes.models import ContentType +from django.db import models from django.test import TestCase from rest_framework import serializers -from .models import Bookmark, Note, Tag + +class Tag(models.Model): + """ + Tags have a descriptive slug, and are attached to an arbitrary object. + """ + tag = models.SlugField() + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField() + tagged_item = GenericForeignKey('content_type', 'object_id') + + def __str__(self): + return self.tag + + +class Bookmark(models.Model): + """ + A URL bookmark that may have multiple tags attached. + """ + url = models.URLField() + tags = GenericRelation(Tag) + + def __str__(self): + return 'Bookmark: %s' % self.url + + +class Note(models.Model): + """ + A textual note that may have multiple tags attached. + """ + text = models.TextField() + tags = GenericRelation(Tag) + + def __str__(self): + return 'Note: %s' % self.text class TestGenericRelations(TestCase): diff --git a/tests/importable/test_installed.py b/tests/importable/test_installed.py index 072d3b2e43..fff51fd8f9 100644 --- a/tests/importable/test_installed.py +++ b/tests/importable/test_installed.py @@ -1,5 +1,4 @@ from django.conf import settings - from tests import importable diff --git a/tests/models.py b/tests/models.py index 17bf23cda4..f389a51a92 100644 --- a/tests/models.py +++ b/tests/models.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import uuid from django.db import models diff --git a/tests/test_api_client.py b/tests/test_api_client.py index e4354ec603..74a3579e2f 100644 --- a/tests/test_api_client.py +++ b/tests/test_api_client.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import os import tempfile import unittest diff --git a/tests/test_atomic_requests.py b/tests/test_atomic_requests.py index bddd480a5a..aba54bf70a 100644 --- a/tests/test_atomic_requests.py +++ b/tests/test_atomic_requests.py @@ -1,18 +1,16 @@ -from __future__ import unicode_literals - import unittest from django.conf.urls import url from django.db import connection, connections, transaction from django.http import Http404 from django.test import TestCase, TransactionTestCase, override_settings +from tests.models import BasicModel from rest_framework import status from rest_framework.exceptions import APIException from rest_framework.response import Response from rest_framework.test import APIRequestFactory from rest_framework.views import APIView -from tests.models import BasicModel factory = APIRequestFactory() diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 13dd41ff3a..3f24e7ef03 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import pytest from django.test import TestCase diff --git a/tests/test_description.py b/tests/test_description.py index 702e56332f..ae00fe4a97 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -1,9 +1,4 @@ -# -- coding: utf-8 -- - -from __future__ import unicode_literals - from django.test import TestCase -from django.utils.encoding import python_2_unicode_compatible from rest_framework.compat import apply_markdown from rest_framework.utils.formatting import dedent @@ -157,8 +152,8 @@ class that can be converted to a string. """ # use a mock object instead of gettext_lazy to ensure that we can't end # up with a test case string in our l10n catalog - @python_2_unicode_compatible - class MockLazyStr(object): + + class MockLazyStr: def __init__(self, string): self.s = string diff --git a/tests/test_encoders.py b/tests/test_encoders.py index 12eca8105d..c66954b807 100644 --- a/tests/test_encoders.py +++ b/tests/test_encoders.py @@ -10,7 +10,7 @@ from rest_framework.utils.encoders import JSONEncoder -class MockList(object): +class MockList: def tolist(self): return [1, 2, 3] diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index ce0ed8514f..a21334d84e 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.test import RequestFactory, TestCase from django.utils import six, translation from django.utils.translation import ugettext_lazy as _ diff --git a/tests/test_fields.py b/tests/test_fields.py index 12c936b229..1e04883deb 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -192,7 +192,7 @@ def test_callable_source(self): class ExampleSerializer(serializers.Serializer): example_field = serializers.CharField(source='example_callable') - class ExampleInstance(object): + class ExampleInstance: def example_callable(self): return 'example callable value' @@ -203,7 +203,7 @@ def test_callable_source_raises(self): class ExampleSerializer(serializers.Serializer): example_field = serializers.CharField(source='example_callable', read_only=True) - class ExampleInstance(object): + class ExampleInstance: def example_callable(self): raise AttributeError('method call failed') diff --git a/tests/test_filters.py b/tests/test_filters.py index 088d25436d..0f619a310d 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import datetime import pytest diff --git a/tests/test_generateschema.py b/tests/test_generateschema.py index 915c6ea059..d09b668ec9 100644 --- a/tests/test_generateschema.py +++ b/tests/test_generateschema.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import pytest from django.conf.urls import url from django.core.management import call_command diff --git a/tests/test_generics.py b/tests/test_generics.py index c0ff1c5c4e..74e760307a 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -1,20 +1,18 @@ -from __future__ import unicode_literals - import pytest from django.db import models from django.http import Http404 from django.shortcuts import get_object_or_404 from django.test import TestCase from django.utils import six - -from rest_framework import generics, renderers, serializers, status -from rest_framework.response import Response -from rest_framework.test import APIRequestFactory from tests.models import ( BasicModel, ForeignKeySource, ForeignKeyTarget, RESTFrameworkModel, UUIDForeignKeyTarget ) +from rest_framework import generics, renderers, serializers, status +from rest_framework.response import Response +from rest_framework.test import APIRequestFactory + factory = APIRequestFactory() diff --git a/tests/test_htmlrenderer.py b/tests/test_htmlrenderer.py index decd25a3fe..9ae3d0b8f8 100644 --- a/tests/test_htmlrenderer.py +++ b/tests/test_htmlrenderer.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import django.template.loader import pytest from django.conf.urls import url @@ -47,7 +45,7 @@ def not_found(request): @override_settings(ROOT_URLCONF='tests.test_htmlrenderer') class TemplateHTMLRendererTests(TestCase): def setUp(self): - class MockResponse(object): + class MockResponse: template_name = None self.mock_response = MockResponse() self._monkey_patch_get_template() @@ -105,14 +103,14 @@ def test_get_template_names_returns_own_template_name(self): def test_get_template_names_returns_view_template_name(self): renderer = TemplateHTMLRenderer() - class MockResponse(object): + class MockResponse: template_name = None - class MockView(object): + class MockView: def get_template_names(self): return ['template from get_template_names method'] - class MockView2(object): + class MockView2: template_name = 'template from template_name attribute' template_name = renderer.get_template_names(self.mock_response, diff --git a/tests/test_metadata.py b/tests/test_metadata.py index fe4ea4b428..e1a1fd3528 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import pytest from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 9df7d8e3e6..28a5e558a1 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -22,7 +22,7 @@ def post(self, request): ] -class RequestUserMiddleware(object): +class RequestUserMiddleware: def __init__(self, get_response): self.get_response = get_response @@ -34,7 +34,7 @@ def __call__(self, request): return response -class RequestPOSTMiddleware(object): +class RequestPOSTMiddleware: def __init__(self, get_response): self.get_response = get_response diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 898c859a4f..a89f916af7 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -5,8 +5,6 @@ These tests deal with ensuring that we correctly map the model fields onto an appropriate set of serializer fields for each case. """ -from __future__ import unicode_literals - import datetime import decimal import sys diff --git a/tests/test_multitable_inheritance.py b/tests/test_multitable_inheritance.py index 2ddd37ebba..772bc69d63 100644 --- a/tests/test_multitable_inheritance.py +++ b/tests/test_multitable_inheritance.py @@ -1,10 +1,8 @@ -from __future__ import unicode_literals - from django.db import models from django.test import TestCase +from tests.models import RESTFrameworkModel from rest_framework import serializers -from tests.models import RESTFrameworkModel # Models diff --git a/tests/test_negotiation.py b/tests/test_negotiation.py index 7ce3f92a9b..089a86c624 100644 --- a/tests/test_negotiation.py +++ b/tests/test_negotiation.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import pytest from django.http import Http404 from django.test import TestCase @@ -80,7 +78,7 @@ def test_mediatype_string_representation(self): assert str(mediatype) == 'test/*; foo=bar' def test_raise_error_if_no_suitable_renderers_found(self): - class MockRenderer(object): + class MockRenderer: format = 'xml' renderers = [MockRenderer()] with pytest.raises(Http404): diff --git a/tests/test_one_to_one_with_inheritance.py b/tests/test_one_to_one_with_inheritance.py index 789c7fcb97..35758544c1 100644 --- a/tests/test_one_to_one_with_inheritance.py +++ b/tests/test_one_to_one_with_inheritance.py @@ -1,13 +1,11 @@ -from __future__ import unicode_literals - from django.db import models from django.test import TestCase - -from rest_framework import serializers from tests.models import RESTFrameworkModel # Models from tests.test_multitable_inheritance import ChildModel +from rest_framework import serializers + # Regression test for #4290 class ChildAssociatedModel(RESTFrameworkModel): diff --git a/tests/test_pagination.py b/tests/test_pagination.py index 6d940fe2b0..26510fe984 100644 --- a/tests/test_pagination.py +++ b/tests/test_pagination.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - import pytest from django.core.paginator import Paginator as DjangoPaginator from django.db import models @@ -799,11 +796,11 @@ class TestCursorPagination(CursorPaginationTestsMixin): """ def setup(self): - class MockObject(object): + class MockObject: def __init__(self, idx): self.created = idx - class MockQuerySet(object): + class MockQuerySet: def __init__(self, items): self.items = items diff --git a/tests/test_parsers.py b/tests/test_parsers.py index e793948e37..e77950be93 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import io import math @@ -42,7 +39,7 @@ def test_parse(self): class TestFileUploadParser(TestCase): def setUp(self): - class MockRequest(object): + class MockRequest: pass self.stream = io.BytesIO( "Test text file".encode('utf-8') diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 2fabdfa05c..04fb3700f8 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import base64 import unittest import warnings @@ -19,6 +17,7 @@ from rest_framework.filters import DjangoObjectPermissionsFilter from rest_framework.routers import DefaultRouter from rest_framework.test import APIRequestFactory + from tests.models import BasicModel factory = APIRequestFactory() diff --git a/tests/test_relations_hyperlink.py b/tests/test_relations_hyperlink.py index 887a6f423a..2cc0e45e28 100644 --- a/tests/test_relations_hyperlink.py +++ b/tests/test_relations_hyperlink.py @@ -1,15 +1,13 @@ -from __future__ import unicode_literals - from django.conf.urls import url from django.test import TestCase, override_settings - -from rest_framework import serializers -from rest_framework.test import APIRequestFactory from tests.models import ( ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget, NullableForeignKeySource, NullableOneToOneSource, OneToOneTarget ) +from rest_framework import serializers +from rest_framework.test import APIRequestFactory + factory = APIRequestFactory() request = factory.get('/') # Just to ensure we have a request in the serializer context diff --git a/tests/test_relations_pk.py b/tests/test_relations_pk.py index 2cffb62e6b..c5e5629b7a 100644 --- a/tests/test_relations_pk.py +++ b/tests/test_relations_pk.py @@ -1,9 +1,5 @@ -from __future__ import unicode_literals - from django.test import TestCase from django.utils import six - -from rest_framework import serializers from tests.models import ( ForeignKeySource, ForeignKeySourceWithLimitedChoices, ForeignKeySourceWithQLimitedChoices, ForeignKeyTarget, ManyToManySource, @@ -12,6 +8,8 @@ UUIDForeignKeyTarget ) +from rest_framework import serializers + # ManyToMany class ManyToManyTargetSerializer(serializers.ModelSerializer): diff --git a/tests/test_relations_slug.py b/tests/test_relations_slug.py index 0b9ca79d3d..d79eb86278 100644 --- a/tests/test_relations_slug.py +++ b/tests/test_relations_slug.py @@ -1,10 +1,10 @@ from django.test import TestCase - -from rest_framework import serializers from tests.models import ( ForeignKeySource, ForeignKeyTarget, NullableForeignKeySource ) +from rest_framework import serializers + class ForeignKeyTargetSerializer(serializers.ModelSerializer): sources = serializers.SlugRelatedField( diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 60a0c0307d..17afa09fbe 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import re from collections import OrderedDict @@ -348,7 +345,7 @@ def keys(self): self.assertEqual(data, {'key': 'string value', '2': 3}) def test_render_obj_with_getitem(self): - class DictLike(object): + class DictLike: def __init__(self): self._dict = {} @@ -647,7 +644,7 @@ def test_get_description_returns_empty_string_for_401_and_403_statuses(self): assert self.renderer.get_description({}, status_code=403) == '' def test_get_filter_form_returns_none_if_data_is_not_list_instance(self): - class DummyView(object): + class DummyView: get_queryset = None filter_backends = None diff --git a/tests/test_request.py b/tests/test_request.py index 83d295a128..488193cc0e 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -1,8 +1,6 @@ """ Tests for content parsing, and form-overloaded content parsing. """ -from __future__ import unicode_literals - import os.path import tempfile diff --git a/tests/test_requests_client.py b/tests/test_requests_client.py index 161429f73e..59b388c5a6 100644 --- a/tests/test_requests_client.py +++ b/tests/test_requests_client.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest from django.conf.urls import url diff --git a/tests/test_response.py b/tests/test_response.py index e92bf54c16..66fce9aec8 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,8 +1,7 @@ -from __future__ import unicode_literals - from django.conf.urls import include, url from django.test import TestCase, override_settings from django.utils import six +from tests.models import BasicModel from rest_framework import generics, routers, serializers, status, viewsets from rest_framework.parsers import JSONParser @@ -11,7 +10,6 @@ ) from rest_framework.response import Response from rest_framework.views import APIView -from tests.models import BasicModel # Serializer used to test BasicModel diff --git a/tests/test_reverse.py b/tests/test_reverse.py index 145b1a54f3..9ab1667c52 100644 --- a/tests/test_reverse.py +++ b/tests/test_reverse.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.conf.urls import url from django.test import TestCase, override_settings from django.urls import NoReverseMatch @@ -19,7 +17,7 @@ def null_view(request): ] -class MockVersioningScheme(object): +class MockVersioningScheme: def __init__(self, raise_error=False): self.raise_error = raise_error diff --git a/tests/test_routers.py b/tests/test_routers.py index cca2ea7122..adcec8bd62 100644 --- a/tests/test_routers.py +++ b/tests/test_routers.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import warnings from collections import namedtuple diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 3cb9e0cda8..fc7a8302d0 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -29,7 +29,7 @@ factory = APIRequestFactory() -class MockUser(object): +class MockUser: def is_authenticated(self): return True diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 0f1e81965a..8a1df04ec0 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - import inspect import pickle import re @@ -160,7 +157,7 @@ def test_custom_to_internal_value(self): to_internal_value() is expected to return a dict, but subclasses may return application specific type. """ - class Point(object): + class Point: def __init__(self, srid, x, y): self.srid = srid self.coords = (x, y) diff --git a/tests/test_serializer_bulk_update.py b/tests/test_serializer_bulk_update.py index d9e5d79782..82c14bf81e 100644 --- a/tests/test_serializer_bulk_update.py +++ b/tests/test_serializer_bulk_update.py @@ -1,8 +1,6 @@ """ Tests to cover bulk create and update using serializers. """ -from __future__ import unicode_literals - from django.test import TestCase from django.utils import six diff --git a/tests/test_settings.py b/tests/test_settings.py index 51e9751b25..b78125ff95 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.test import TestCase, override_settings from rest_framework.settings import APISettings, api_settings diff --git a/tests/test_status.py b/tests/test_status.py index 1cd6e229e9..07d893bee9 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from django.test import TestCase from rest_framework.status import ( diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index 45bfd4aeb7..796a7f6775 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -1,6 +1,3 @@ -# encoding: utf-8 -from __future__ import unicode_literals - import unittest from django.template import Context, Template diff --git a/tests/test_testing.py b/tests/test_testing.py index 7868f724c1..b7fc7e3081 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,6 +1,3 @@ -# encoding: utf-8 -from __future__ import unicode_literals - from io import BytesIO from django.conf.urls import url diff --git a/tests/test_throttling.py b/tests/test_throttling.py index b220a33a6f..b20b6a809c 100644 --- a/tests/test_throttling.py +++ b/tests/test_throttling.py @@ -1,7 +1,6 @@ """ Tests for the throttling implementations in the permissions module. """ -from __future__ import unicode_literals import pytest from django.contrib.auth.models import User @@ -296,7 +295,7 @@ def test_unscoped_view_not_throttled(self): assert response.status_code == 200 def test_get_cache_key_returns_correct_key_if_user_is_authenticated(self): - class DummyView(object): + class DummyView: throttle_scope = 'user' request = Request(HttpRequest()) diff --git a/tests/test_urlpatterns.py b/tests/test_urlpatterns.py index 59ba395d29..25cc0032ee 100644 --- a/tests/test_urlpatterns.py +++ b/tests/test_urlpatterns.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest from collections import namedtuple diff --git a/tests/test_utils.py b/tests/test_utils.py index 28b06b1735..996b3c8afc 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.conf.urls import url from django.test import TestCase, override_settings @@ -12,6 +9,7 @@ from rest_framework.utils.urls import remove_query_param, replace_query_param from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet + from tests.models import BasicModel diff --git a/tests/test_validation.py b/tests/test_validation.py index 4132a7b00f..b2d611e53f 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import re from django.core.validators import MaxValueValidator, RegexValidator diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 7e650e2752..526df8292c 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -321,7 +321,7 @@ class TestHyperlinkedRelatedField(URLPatternsTestCase, APITestCase): def setUp(self): super(TestHyperlinkedRelatedField, self).setUp() - class MockQueryset(object): + class MockQueryset: def get(self, pk): return 'object %s' % pk diff --git a/tests/test_views.py b/tests/test_views.py index f0919e8461..cca78e8433 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import copy import sys diff --git a/tests/utils.py b/tests/utils.py index 509e6a1027..06e5b9abe6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -2,7 +2,7 @@ from django.urls import NoReverseMatch -class MockObject(object): +class MockObject: def __init__(self, **kwargs): self._kwargs = kwargs for key, val in kwargs.items(): @@ -16,7 +16,7 @@ def __str__(self): return '<MockObject %s>' % kwargs_str -class MockQueryset(object): +class MockQueryset: def __init__(self, iterable): self.items = iterable @@ -33,7 +33,7 @@ def get(self, **lookup): raise ObjectDoesNotExist() -class BadType(object): +class BadType: """ When used as a lookup with a `MockQueryset`, these objects will raise a `TypeError`, as occurs in Django when making diff --git a/tox.ini b/tox.ini index 776af3b6e7..d478be846d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - {py27,py34,py35,py36}-django111, + {py34,py35,py36}-django111, {py34,py35,py36,py37}-django20, {py35,py36,py37}-django21 {py35,py36,py37}-django22 @@ -44,14 +44,14 @@ deps = -rrequirements/requirements-optionals.txt [testenv:lint] -basepython = python2.7 +basepython = python3.6 commands = ./runtests.py --lintonly deps = -rrequirements/requirements-codestyle.txt -rrequirements/requirements-testing.txt [testenv:docs] -basepython = python2.7 +basepython = python3.6 commands = mkdocs build deps = -rrequirements/requirements-testing.txt