Dropped Python 2 compatibility. (#6615)

Thanks to Jon Dufresne (@jdufresne) for review.

Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
Co-authored-by: Rizwan Mansuri <Rizwan@webbyfox.com>
This commit is contained in:
Carlton Gibson 2019-04-30 17:53:44 +02:00 committed by GitHub
parent 5c992baf32
commit 0407a0df8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 473 additions and 795 deletions

View File

@ -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 }
@ -26,8 +25,8 @@ matrix:
- { 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.7", env: TOXENV=lint }
- { python: "3.7", env: TOXENV=docs }
- python: "3.7"
env: TOXENV=dist

View File

@ -53,7 +53,7 @@ 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

View File

@ -629,7 +629,7 @@ Our `ColorField` class above currently does not perform any data validation.
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
def to_internal_value(self, data):
if not isinstance(data, six.text_type):
if not isinstance(data, str):
msg = 'Incorrect type. Expected a string, but got %s'
raise ValidationError(msg % type(data).__name__)
@ -653,7 +653,7 @@ The `.fail()` method is a shortcut for raising `ValidationError` that takes a me
}
def to_internal_value(self, data):
if not isinstance(data, six.text_type):
if not isinstance(data, str):
self.fail('incorrect_type', input_type=type(data).__name__)
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):

View File

@ -1,14 +1,11 @@
"""
Provides various authentication policies.
"""
from __future__ import unicode_literals
import base64
import binascii
from django.contrib.auth import authenticate, get_user_model
from django.middleware.csrf import CsrfViewMiddleware
from django.utils.six import text_type
from django.utils.translation import ugettext_lazy as _
from rest_framework import HTTP_HEADER_ENCODING, exceptions
@ -21,7 +18,7 @@ def get_authorization_header(request):
Hide some test client ickyness where the header can be unicode.
"""
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if isinstance(auth, text_type):
if isinstance(auth, str):
# Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING)
return auth
@ -33,7 +30,7 @@ class CSRFCheck(CsrfViewMiddleware):
return reason
class BaseAuthentication(object):
class BaseAuthentication:
"""
All authentication classes should extend BaseAuthentication.
"""

View File

@ -38,8 +38,8 @@ class Command(BaseCommand):
token = self.create_user_token(username, reset_token)
except UserModel.DoesNotExist:
raise CommandError(
'Cannot create the Token: user {0} does not exist'.format(
'Cannot create the Token: user {} does not exist'.format(
username)
)
self.stdout.write(
'Generated token {0} for user {1}'.format(token.key, username))
'Generated token {} for user {}'.format(token.key, username))

View File

@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models

View File

@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models

View File

@ -3,11 +3,9 @@ import os
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 Token(models.Model):
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()

View File

@ -2,23 +2,13 @@
The `compat` module provides support for backwards compatibility with older
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,
@ -36,11 +26,6 @@ try:
except ImportError:
ProhibitNullCharactersValidator = None
try:
from unittest import mock
except ImportError:
mock = None
def get_original_route(urlpattern):
"""
@ -89,23 +74,6 @@ def make_url_resolver(regex, urlpatterns):
return URLResolver(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)
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
def unicode_http_header(value):
# Coerce HTTP header value to unicode.
if isinstance(value, bytes):
@ -168,15 +136,6 @@ def is_guardian_installed():
"""
django-guardian is optional and only imported if in INSTALLED_APPS.
"""
try:
import guardian
except ImportError:
guardian = None
if six.PY2 and (not guardian or guardian.VERSION >= (1, 5)):
# 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
@ -289,17 +248,12 @@ except ImportError:
# `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
@ -309,7 +263,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):

View File

@ -6,13 +6,10 @@ There are also various decorators for setting the API policies on function
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
from django.forms.utils import pretty_name
from django.utils import six
from rest_framework import RemovedInDRF310Warning
from rest_framework.views import APIView
@ -28,7 +25,7 @@ def api_view(http_method_names=None):
def decorator(func):
WrappedAPIView = type(
six.PY3 and 'WrappedAPIView' or b'WrappedAPIView',
'WrappedAPIView',
(APIView,),
{'__doc__': func.__doc__}
)

View File

@ -4,18 +4,14 @@ Handled exceptions raised by REST framework.
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
from django.http import JsonResponse
from django.utils import six
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext
from rest_framework import status
from rest_framework.compat import unicode_to_repr
from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList
@ -64,19 +60,19 @@ def _get_full_details(detail):
}
class ErrorDetail(six.text_type):
class ErrorDetail(str):
"""
A string-like object that can additionally have a code.
"""
code = None
def __new__(cls, string, code=None):
self = super(ErrorDetail, cls).__new__(cls, string)
self = super().__new__(cls, string)
self.code = code
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:
@ -86,10 +82,10 @@ class ErrorDetail(six.text_type):
return not self.__eq__(other)
def __repr__(self):
return unicode_to_repr('ErrorDetail(string=%r, code=%r)' % (
six.text_type(self),
return 'ErrorDetail(string=%r, code=%r)' % (
str(self),
self.code,
))
)
def __hash__(self):
return hash(str(self))
@ -113,7 +109,7 @@ class APIException(Exception):
self.detail = _get_error_details(detail, code)
def __str__(self):
return six.text_type(self.detail)
return str(self.detail)
def get_codes(self):
"""
@ -196,7 +192,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 +202,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 +213,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 +234,7 @@ class Throttled(APIException):
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):

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import copy
import datetime
import decimal
@ -17,7 +15,7 @@ from django.core.validators import (
)
from django.forms import FilePathField as DjangoFilePathField
from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone
from django.utils import timezone
from django.utils.dateparse import (
parse_date, parse_datetime, parse_duration, parse_time
)
@ -33,8 +31,7 @@ from pytz.exceptions import InvalidTimeError
from rest_framework import ISO_8601
from rest_framework.compat import (
Mapping, MaxLengthValidator, MaxValueValidator, MinLengthValidator,
MinValueValidator, ProhibitNullCharactersValidator, unicode_repr,
unicode_to_repr
MinValueValidator, ProhibitNullCharactersValidator
)
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.settings import api_settings
@ -51,8 +48,7 @@ class empty:
pass
if six.PY3:
def is_simple_callable(obj):
def is_simple_callable(obj):
"""
True if the object is a callable that takes no arguments.
"""
@ -68,23 +64,6 @@ if six.PY3:
for param in params
)
else:
def is_simple_callable(obj):
function = inspect.isfunction(obj)
method = inspect.ismethod(obj)
if not (function or method):
return False
if method:
is_unbound = obj.im_self is None
args, _, _, defaults = inspect.getargspec(obj)
len_args = len(args) if function or is_unbound else len(args) - 1
len_defaults = len(defaults) if defaults else 0
return len_args <= len_defaults
def get_attribute(instance, attrs):
"""
@ -108,7 +87,7 @@ def get_attribute(instance, attrs):
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc))
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
@ -185,18 +164,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 +230,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
@ -273,12 +252,10 @@ class CreateOnlyDefault(object):
return self.default
def __repr__(self):
return unicode_to_repr(
'%s(%s)' % (self.__class__.__name__, unicode_repr(self.default))
)
return '%s(%s)' % (self.__class__.__name__, repr(self.default))
class CurrentUserDefault(object):
class CurrentUserDefault:
def set_context(self, serializer_field):
self.user = serializer_field.context['request'].user
@ -286,7 +263,7 @@ class CurrentUserDefault(object):
return self.user
def __repr__(self):
return unicode_to_repr('%s()' % self.__class__.__name__)
return '%s()' % self.__class__.__name__
class SkipField(Exception):
@ -305,7 +282,7 @@ MISSING_ERROR_MESSAGE = (
)
class Field(object):
class Field:
_creation_counter = 0
default_error_messages = {
@ -618,7 +595,7 @@ class Field(object):
When a field is instantiated, we store the arguments that were used,
so that we can present a helpful representation of the object.
"""
instance = super(Field, cls).__new__(cls)
instance = super().__new__(cls)
instance._args = args
instance._kwargs = kwargs
return instance
@ -647,7 +624,7 @@ class Field(object):
This allows us to create descriptive representations for serializer
instances that show all the declared fields on the serializer.
"""
return unicode_to_repr(representation.field_repr(self))
return representation.field_repr(self)
# Boolean types...
@ -724,7 +701,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,17 +741,14 @@ class CharField(Field):
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,
six.text_type)(max_length=self.max_length)
message = lazy(self.error_messages['max_length'].format, str)(max_length=self.max_length)
self.validators.append(
MaxLengthValidator(self.max_length, message=message))
if self.min_length is not None:
message = lazy(
self.error_messages['min_length'].format,
six.text_type)(min_length=self.min_length)
self.error_messages['min_length'].format, str)(min_length=self.min_length)
self.validators.append(
MinLengthValidator(self.min_length, message=message))
@ -786,23 +760,23 @@ class CharField(Field):
# Test for the empty string here so that it does not get validated,
# and so that subclasses do not need to handle it explicitly
# inside the `to_internal_value()` method.
if data == '' or (self.trim_whitespace and six.text_type(data).strip() == ''):
if data == '' or (self.trim_whitespace and str(data).strip() == ''):
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,
# but other types should fail. Eg. unclear if booleans should represent as `true` or `True`,
# and composites such as lists are likely user error.
if isinstance(data, bool) or not isinstance(data, six.string_types + six.integer_types + (float,)):
if isinstance(data, bool) or not isinstance(data, (str, int, float,)):
self.fail('invalid')
value = six.text_type(data)
value = str(data)
return value.strip() if self.trim_whitespace else value
def to_representation(self, value):
return six.text_type(value)
return str(value)
class EmailField(CharField):
@ -811,7 +785,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 +796,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 +808,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 +823,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)
@ -866,16 +840,16 @@ class UUIDField(Field):
if self.uuid_format not in self.valid_formats:
raise ValueError(
'Invalid format for uuid representation. '
'Must be one of "{0}"'.format('", "'.join(self.valid_formats))
'Must be one of "{}"'.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):
try:
if isinstance(data, six.integer_types):
if isinstance(data, int):
return uuid.UUID(int=data)
elif isinstance(data, six.string_types):
elif isinstance(data, str):
return uuid.UUID(hex=data)
else:
self.fail('invalid', value=data)
@ -900,12 +874,12 @@ 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)
def to_internal_value(self, data):
if not isinstance(data, six.string_types):
if not isinstance(data, str):
self.fail('invalid', value=data)
if ':' in data:
@ -915,7 +889,7 @@ class IPAddressField(CharField):
except DjangoValidationError:
self.fail('invalid', value=data)
return super(IPAddressField, self).to_internal_value(data)
return super().to_internal_value(data)
# Number types...
@ -933,22 +907,20 @@ 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,
six.text_type)(max_value=self.max_value)
self.error_messages['max_value'].format, str)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None:
message = lazy(
self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
self.error_messages['min_value'].format, str)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data):
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH:
self.fail('max_string_length')
try:
@ -973,23 +945,23 @@ 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,
six.text_type)(max_value=self.max_value)
str)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None:
message = lazy(
self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
str)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, data):
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH:
self.fail('max_string_length')
try:
@ -1031,18 +1003,17 @@ class DecimalField(Field):
else:
self.max_whole_digits = None
super(DecimalField, self).__init__(**kwargs)
super().__init__(**kwargs)
if self.max_value is not None:
message = lazy(
self.error_messages['max_value'].format,
six.text_type)(max_value=self.max_value)
str)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None:
message = lazy(
self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
self.error_messages['min_value'].format, str)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
@ -1121,7 +1092,7 @@ class DecimalField(Field):
coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING)
if not isinstance(value, decimal.Decimal):
value = decimal.Decimal(six.text_type(value).strip())
value = decimal.Decimal(str(value).strip())
quantized = self.quantize(value)
@ -1130,7 +1101,7 @@ class DecimalField(Field):
if self.localize:
return localize_input(quantized)
return '{0:f}'.format(quantized)
return '{:f}'.format(quantized)
def quantize(self, value):
"""
@ -1167,7 +1138,7 @@ class DateTimeField(Field):
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):
"""
@ -1226,7 +1197,7 @@ class DateTimeField(Field):
output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
if output_format is None or isinstance(value, six.string_types):
if output_format is None or isinstance(value, str):
return value
value = self.enforce_timezone(value)
@ -1251,7 +1222,7 @@ class DateField(Field):
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)
@ -1288,7 +1259,7 @@ class DateField(Field):
output_format = getattr(self, 'format', api_settings.DATE_FORMAT)
if output_format is None or isinstance(value, six.string_types):
if output_format is None or isinstance(value, str):
return value
# Applying a `DateField` to a datetime value is almost always
@ -1317,7 +1288,7 @@ class TimeField(Field):
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)
@ -1351,7 +1322,7 @@ class TimeField(Field):
output_format = getattr(self, 'format', api_settings.TIME_FORMAT)
if output_format is None or isinstance(value, six.string_types):
if output_format is None or isinstance(value, str):
return value
# Applying a `TimeField` to a datetime value is almost always
@ -1378,24 +1349,24 @@ 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,
six.text_type)(max_value=self.max_value)
str)(max_value=self.max_value)
self.validators.append(
MaxValueValidator(self.max_value, message=message))
if self.min_value is not None:
message = lazy(
self.error_messages['min_value'].format,
six.text_type)(min_value=self.min_value)
str)(min_value=self.min_value)
self.validators.append(
MinValueValidator(self.min_value, message=message))
def to_internal_value(self, value):
if isinstance(value, datetime.timedelta):
return value
parsed = parse_duration(six.text_type(value))
parsed = parse_duration(str(value))
if parsed is not None:
return parsed
self.fail('invalid', format='[DD] [HH:[MM:]]ss[.uuuuuu]')
@ -1420,21 +1391,21 @@ class ChoiceField(Field):
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:
return ''
try:
return self.choice_strings_to_values[six.text_type(data)]
return self.choice_strings_to_values[str(data)]
except KeyError:
self.fail('invalid_choice', input=data)
def to_representation(self, value):
if value in ('', None):
return value
return self.choice_strings_to_values.get(six.text_type(value), value)
return self.choice_strings_to_values.get(str(value), value)
def iter_options(self):
"""
@ -1457,7 +1428,7 @@ class ChoiceField(Field):
# Allows us to deal with eg. integer choices while supporting either
# integer or string input, but still get the correct datatype out.
self.choice_strings_to_values = {
six.text_type(key): key for key in self.choices
str(key): key for key in self.choices
}
choices = property(_get_choices, _set_choices)
@ -1473,7 +1444,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:
@ -1486,7 +1457,7 @@ class MultipleChoiceField(ChoiceField):
return dictionary.get(self.field_name, empty)
def to_internal_value(self, data):
if isinstance(data, six.text_type) or not hasattr(data, '__iter__'):
if isinstance(data, str) or not hasattr(data, '__iter__'):
self.fail('not_a_list', input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail('empty')
@ -1498,7 +1469,7 @@ class MultipleChoiceField(ChoiceField):
def to_representation(self, value):
return {
self.choice_strings_to_values.get(six.text_type(item), item) for item in value
self.choice_strings_to_values.get(str(item), item) for item in value
}
@ -1516,7 +1487,7 @@ class FilePathField(ChoiceField):
allow_folders=allow_folders, required=required
)
kwargs['choices'] = field.choices
super(FilePathField, self).__init__(**kwargs)
super().__init__(**kwargs)
# File types...
@ -1535,7 +1506,7 @@ class FileField(Field):
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 +1552,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 +1568,7 @@ class ImageField(FileField):
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 +1601,7 @@ class ListField(Field):
"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)
@ -1660,7 +1631,7 @@ class ListField(Field):
"""
if html.is_html_input(data):
data = html.parse_html_list(data, default=[])
if isinstance(data, (six.text_type, Mapping)) or not hasattr(data, '__iter__'):
if isinstance(data, (str, Mapping)) or not hasattr(data, '__iter__'):
self.fail('not_a_list', input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail('empty')
@ -1703,7 +1674,7 @@ class DictField(Field):
"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):
@ -1725,7 +1696,7 @@ class DictField(Field):
def to_representation(self, value):
return {
six.text_type(key): self.child.to_representation(val) if val is not None else None
str(key): self.child.to_representation(val) if val is not None else None
for key, val in value.items()
}
@ -1734,7 +1705,7 @@ class DictField(Field):
errors = OrderedDict()
for key, value in data.items():
key = six.text_type(key)
key = str(key)
try:
result[key] = self.child.run_validation(value)
@ -1750,7 +1721,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,15 +1735,15 @@ 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:
# When HTML form input is used, mark up the input
# as being a JSON string, rather than a JSON primitive.
class JSONString(six.text_type):
class JSONString(str):
def __new__(self, value):
ret = six.text_type.__new__(self, value)
ret = str.__new__(self, value)
ret.is_json_string = True
return ret
return JSONString(dictionary[self.field_name])
@ -1795,7 +1766,7 @@ class JSONField(Field):
value = json.dumps(value)
# On python 2.x the return type for json.dumps() is underspecified.
# On python 3.x json.dumps() returns unicode strings.
if isinstance(value, six.text_type):
if isinstance(value, str):
value = bytes(value.encode('utf-8'))
return value
@ -1817,7 +1788,7 @@ class ReadOnlyField(Field):
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 +1805,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 +1835,7 @@ class SerializerMethodField(Field):
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 +1853,7 @@ class SerializerMethodField(Field):
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,11 +1876,10 @@ class ModelField(Field):
# 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,
six.text_type)(max_length=self.max_length)
self.error_messages['max_length'].format, str)(max_length=self.max_length)
self.validators.append(
MaxLengthValidator(self.max_length, message=message))

View File

@ -2,8 +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
from functools import reduce
@ -13,7 +11,6 @@ from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.sql.constants import ORDER_PATTERN
from django.template import loader
from django.utils import six
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
@ -24,7 +21,7 @@ from rest_framework.compat import (
from rest_framework.settings import api_settings
class BaseFilterBackend(object):
class BaseFilterBackend:
"""
A base class from which all filter backend classes should inherit.
"""
@ -109,7 +106,7 @@ class SearchFilter(BaseFilterBackend):
return queryset
orm_lookups = [
self.construct_search(six.text_type(search_field))
self.construct_search(str(search_field))
for search_field in search_fields
]
@ -188,7 +185,7 @@ class OrderingFilter(BaseFilterBackend):
def get_default_ordering(self, view):
ordering = getattr(view, 'ordering', None)
if isinstance(ordering, six.string_types):
if isinstance(ordering, str):
return (ordering,)
return ordering
@ -237,7 +234,7 @@ class OrderingFilter(BaseFilterBackend):
]
else:
valid_fields = [
(item, item) if isinstance(item, six.string_types) else item
(item, item) if isinstance(item, str) else item
for item in valid_fields
]

View File

@ -1,8 +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
from django.http import Http404

View File

@ -6,8 +6,6 @@ some fairly ad-hoc information about the view.
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
from django.core.exceptions import PermissionDenied
@ -19,7 +17,7 @@ from rest_framework.request import clone_request
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.

View File

@ -4,14 +4,12 @@ Basic building blocks for generic class based views.
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 +30,7 @@ class CreateModelMixin(object):
return {}
class ListModelMixin(object):
class ListModelMixin:
"""
List a queryset.
"""
@ -48,7 +46,7 @@ class ListModelMixin(object):
return Response(serializer.data)
class RetrieveModelMixin(object):
class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
@ -58,7 +56,7 @@ class RetrieveModelMixin(object):
return Response(serializer.data)
class UpdateModelMixin(object):
class UpdateModelMixin:
"""
Update a model instance.
"""
@ -84,7 +82,7 @@ class UpdateModelMixin(object):
return self.update(request, *args, **kwargs)
class DestroyModelMixin(object):
class DestroyModelMixin:
"""
Destroy a model instance.
"""

View File

@ -2,8 +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
from rest_framework import HTTP_HEADER_ENCODING, exceptions
@ -13,7 +11,7 @@ from rest_framework.utils.mediatypes import (
)
class BaseContentNegotiation(object):
class BaseContentNegotiation:
def select_parser(self, request, parsers):
raise NotImplementedError('.select_parser() must be implemented')
@ -66,7 +64,7 @@ class DefaultContentNegotiation(BaseContentNegotiation):
# Accepted media type is 'application/json'
full_media_type = ';'.join(
(renderer.media_type,) +
tuple('{0}={1}'.format(
tuple('{}={}'.format(
key, value.decode(HTTP_HEADER_ENCODING))
for key, value in media_type_wrapper.params.items()))
return renderer, full_media_type

View File

@ -1,19 +1,15 @@
# coding: utf-8
"""
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
from urllib import parse
from django.core.paginator import InvalidPage
from django.core.paginator import Paginator as DjangoPaginator
from django.template import loader
from django.utils import six
from django.utils.encoding import force_text
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _
from rest_framework.compat import coreapi, coreschema
@ -133,7 +129,7 @@ PageLink = namedtuple('PageLink', ['url', 'number', 'is_active', 'is_break'])
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
@ -204,7 +200,7 @@ class PageNumberPagination(BasePagination):
self.page = paginator.page(page_number)
except InvalidPage as exc:
msg = self.invalid_page_message.format(
page_number=page_number, message=six.text_type(exc)
page_number=page_number, message=str(exc)
)
raise NotFound(msg)
@ -716,13 +712,13 @@ class CursorPagination(BasePagination):
'nearly-unique field on the model, such as "-created" or "pk".'
)
assert isinstance(ordering, (six.string_types, list, tuple)), (
assert isinstance(ordering, (str, list, tuple)), (
'Invalid ordering. Expected string or tuple, but got {type}'.format(
type=type(ordering).__name__
)
)
if isinstance(ordering, six.string_types):
if isinstance(ordering, str):
return (ordering,)
return tuple(ordering)
@ -737,7 +733,7 @@ class CursorPagination(BasePagination):
try:
querystring = b64decode(encoded.encode('ascii')).decode('ascii')
tokens = urlparse.parse_qs(querystring, keep_blank_values=True)
tokens = parse.parse_qs(querystring, keep_blank_values=True)
offset = tokens.get('o', ['0'])[0]
offset = _positive_int(offset, cutoff=self.offset_cutoff)
@ -763,7 +759,7 @@ class CursorPagination(BasePagination):
if cursor.position is not None:
tokens['p'] = cursor.position
querystring = urlparse.urlencode(tokens, doseq=True)
querystring = parse.urlencode(tokens, doseq=True)
encoded = b64encode(querystring.encode('ascii')).decode('ascii')
return replace_query_param(self.base_url, self.cursor_query_param, encoded)
@ -773,7 +769,7 @@ class CursorPagination(BasePagination):
attr = instance[field_name]
else:
attr = getattr(instance, field_name)
return six.text_type(attr)
return str(attr)
def get_paginated_response(self, data):
return Response(OrderedDict([

View File

@ -4,9 +4,8 @@ Parsers are used to parse the content of incoming HTTP requests.
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
from urllib import parse
from django.conf import settings
from django.core.files.uploadhandler import StopFutureHandlers
@ -15,9 +14,7 @@ from django.http.multipartparser import ChunkIter
from django.http.multipartparser import \
MultiPartParser as DjangoMultiPartParser
from django.http.multipartparser import MultiPartParserError, parse_header
from django.utils import six
from django.utils.encoding import force_text
from django.utils.six.moves.urllib import parse as urlparse
from rest_framework import renderers
from rest_framework.exceptions import ParseError
@ -25,13 +22,13 @@ from rest_framework.settings import api_settings
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.
@ -67,7 +64,7 @@ class JSONParser(BaseParser):
parse_constant = json.strict_constant if self.strict else None
return json.load(decoded_stream, parse_constant=parse_constant)
except ValueError as exc:
raise ParseError('JSON parse error - %s' % six.text_type(exc))
raise ParseError('JSON parse error - %s' % str(exc))
class FormParser(BaseParser):
@ -113,7 +110,7 @@ class MultiPartParser(BaseParser):
data, files = parser.parse()
return DataAndFiles(data, files)
except MultiPartParserError as exc:
raise ParseError('Multipart form parse error - %s' % six.text_type(exc))
raise ParseError('Multipart form parse error - %s' % str(exc))
class FileUploadParser(BaseParser):
@ -221,7 +218,7 @@ class FileUploadParser(BaseParser):
encoded_filename = force_text(filename_parm['filename*'])
try:
charset, lang, filename = encoded_filename.split('\'', 2)
filename = urlparse.unquote(filename)
filename = parse.unquote(filename)
except (ValueError, LookupError):
filename = force_text(filename_parm['filename'])
return filename

View File

@ -1,10 +1,7 @@
"""
Provides a set of pluggable permission policies.
"""
from __future__ import unicode_literals
from django.http import Http404
from django.utils import six
from rest_framework import exceptions
@ -101,8 +98,7 @@ class BasePermissionMetaclass(OperationHolderMixin, type):
pass
@six.add_metaclass(BasePermissionMetaclass)
class BasePermission(object):
class BasePermission(metaclass=BasePermissionMetaclass):
"""
A base class from which all permission classes should inherit.
"""

View File

@ -1,18 +1,12 @@
# coding: utf-8
from __future__ import unicode_literals
import sys
from collections import OrderedDict
from urllib import parse
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.db.models import Manager
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.six.moves.urllib import parse as urlparse
from django.utils.encoding import smart_text, uri_to_iri
from django.utils.translation import ugettext_lazy as _
from rest_framework.fields import (
@ -46,14 +40,14 @@ class ObjectTypeError(TypeError):
"""
class Hyperlink(six.text_type):
class Hyperlink(str):
"""
A string like object that additionally has an associated name.
We use this for hyperlinked URLs that may render as a named link
in some contexts, or render as a plain URL in others.
"""
def __new__(self, url, obj):
ret = six.text_type.__new__(self, url)
ret = str.__new__(self, url)
ret.obj = obj
return ret
@ -65,13 +59,12 @@ class Hyperlink(six.text_type):
# This ensures that we only called `__str__` lazily,
# as in some cases calling __str__ on a model instances *might*
# involve a database lookup.
return six.text_type(self.obj)
return str(self.obj)
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,14 +114,14 @@ class RelatedField(Field):
)
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
# `ManyRelatedField` classes instead when `many=True` is set.
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
return super(RelatedField, cls).__new__(cls, *args, **kwargs)
return super().__new__(cls, *args, **kwargs)
@classmethod
def many_init(cls, *args, **kwargs):
@ -157,7 +150,7 @@ class RelatedField(Field):
# 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 +182,7 @@ class RelatedField(Field):
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()
@ -225,7 +218,7 @@ class RelatedField(Field):
)
def display_value(self, instance):
return six.text_type(instance)
return str(instance)
class StringRelatedField(RelatedField):
@ -236,10 +229,10 @@ 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)
return str(value)
class PrimaryKeyRelatedField(RelatedField):
@ -251,7 +244,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 +290,7 @@ class HyperlinkedRelatedField(RelatedField):
# 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'
@ -317,10 +310,10 @@ class HyperlinkedRelatedField(RelatedField):
return queryset.get(**lookup_kwargs)
except ValueError:
exc = ObjectValueError(str(sys.exc_info()[1]))
six.reraise(type(exc), exc, sys.exc_info()[2])
raise exc.with_traceback(sys.exc_info()[2])
except TypeError:
exc = ObjectTypeError(str(sys.exc_info()[1]))
six.reraise(type(exc), exc, sys.exc_info()[2])
raise exc.with_traceback(sys.exc_info()[2])
def get_url(self, obj, view_name, request, format):
"""
@ -346,7 +339,7 @@ class HyperlinkedRelatedField(RelatedField):
if http_prefix:
# If needed convert absolute URLs to relative path
data = urlparse.urlparse(data).path
data = parse.urlparse(data).path
prefix = get_script_prefix()
if data.startswith(prefix):
data = '/' + data[len(prefix):]
@ -432,7 +425,7 @@ class HyperlinkedIdentityField(HyperlinkedRelatedField):
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 +446,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 +495,7 @@ class ManyRelatedField(Field):
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):
@ -518,7 +511,7 @@ class ManyRelatedField(Field):
return dictionary.get(self.field_name, empty)
def to_internal_value(self, data):
if isinstance(data, six.text_type) or not hasattr(data, '__iter__'):
if isinstance(data, str) or not hasattr(data, '__iter__'):
self.fail('not_a_list', input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail('empty')

View File

@ -6,10 +6,9 @@ on the response, such as JSON encoded data or HTML output.
REST framework also provides an HTML renderer that renders the browsable API.
"""
from __future__ import unicode_literals
import base64
from collections import OrderedDict
from urllib import parse
from django import forms
from django.conf import settings
@ -19,9 +18,7 @@ from django.http.multipartparser import parse_header
from django.template import engines, loader
from django.test.client import encode_multipart
from django.urls import NoReverseMatch
from django.utils import six
from django.utils.html import mark_safe
from django.utils.six.moves.urllib import parse as urlparse
from rest_framework import VERSION, exceptions, serializers, status
from rest_framework.compat import (
@ -40,7 +37,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.
@ -111,7 +108,7 @@ class JSONRenderer(BaseRenderer):
# but if ensure_ascii=False, the return type is underspecified,
# and may (or may not) be unicode.
# On python 3.x json.dumps() returns unicode strings.
if isinstance(ret, six.text_type):
if isinstance(ret, str):
# We always fully escape \u2028 and \u2029 to ensure we output JSON
# that is a strict javascript subset. If bytes were returned
# by json.dumps() then we don't have these characters in any case.
@ -349,7 +346,7 @@ class HTMLFormRenderer(BaseRenderer):
# Get a clone of the field with text-only value representation.
field = field.as_form_field()
if style.get('input_type') == 'datetime-local' and isinstance(field.value, six.text_type):
if style.get('input_type') == 'datetime-local' and isinstance(field.value, str):
field.value = field.value.rstrip('Z')
if 'template' in style:
@ -791,7 +788,7 @@ class AdminRenderer(BrowsableAPIRenderer):
"""
Render the HTML for the browsable API representation.
"""
context = super(AdminRenderer, self).get_context(
context = super().get_context(
data, accepted_media_type, renderer_context
)
@ -995,14 +992,14 @@ class _BaseOpenAPIRenderer:
tag = None
for name, link in document.links.items():
path = urlparse.urlparse(link.url).path
path = parse.urlparse(link.url).path
method = link.action.lower()
paths.setdefault(path, {})
paths[path][method] = self.get_operation(link, name, tag=tag)
for tag, section in document.data.items():
for name, link in section.links.items():
path = urlparse.urlparse(link.url).path
path = parse.urlparse(link.url).path
method = link.action.lower()
paths.setdefault(path, {})
paths[path][method] = self.get_operation(link, name, tag=tag)

View File

@ -8,8 +8,6 @@ The wrapped request then offers a richer API, in particular :
- 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
from contextlib import contextmanager
@ -18,7 +16,6 @@ from django.conf import settings
from django.http import HttpRequest, QueryDict
from django.http.multipartparser import parse_header
from django.http.request import RawPostDataException
from django.utils import six
from django.utils.datastructures import MultiValueDict
from rest_framework import HTTP_HEADER_ENCODING, exceptions
@ -34,7 +31,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.
@ -78,10 +75,10 @@ def wrap_attributeerrors():
except AttributeError:
info = sys.exc_info()
exc = WrappedAttributeError(str(info[1]))
six.reraise(type(exc), exc, info[2])
raise exc.with_traceback(info[2])
class Empty(object):
class Empty:
"""
Placeholder for unset attributes.
Cannot use `None`, as that may be a valid value.
@ -126,7 +123,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 +137,7 @@ class ForcedAuthentication(object):
return (self.force_user, self.force_token)
class Request(object):
class Request:
"""
Wrapper allowing to enhance a standard `HttpRequest` instance.

View File

@ -4,11 +4,9 @@ it is initialized with unrendered data, instead of a pre-rendered string.
The appropriate renderer is called during Django's template response rendering.
"""
from __future__ import unicode_literals
from http.client import responses
from django.template.response import SimpleTemplateResponse
from django.utils import six
from django.utils.six.moves.http_client import responses
from rest_framework.serializers import Serializer
@ -29,7 +27,7 @@ class Response(SimpleTemplateResponse):
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 = (
@ -45,7 +43,7 @@ class Response(SimpleTemplateResponse):
self.content_type = content_type
if headers:
for name, value in six.iteritems(headers):
for name, value in headers.items():
self[name] = value
@property
@ -64,13 +62,13 @@ class Response(SimpleTemplateResponse):
content_type = self.content_type
if content_type is None and charset is not None:
content_type = "{0}; charset={1}".format(media_type, charset)
content_type = "{}; charset={}".format(media_type, charset)
elif content_type is None:
content_type = media_type
self['Content-Type'] = content_type
ret = renderer.render(self.data, accepted_media_type, context)
if isinstance(ret, six.text_type):
if isinstance(ret, str):
assert charset, (
'renderer returned unicode, and did not specify '
'a charset value.'
@ -94,7 +92,7 @@ class Response(SimpleTemplateResponse):
"""
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'

View File

@ -1,11 +1,8 @@
"""
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
from django.utils import six
from django.utils.functional import lazy
from rest_framework.settings import api_settings
@ -66,4 +63,4 @@ def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extr
return url
reverse_lazy = lazy(reverse, six.text_type)
reverse_lazy = lazy(reverse, str)

View File

@ -13,8 +13,6 @@ For example, you might have a `urls.py` that looks something like this:
urlpatterns = router.urls
"""
from __future__ import unicode_literals
import itertools
import warnings
from collections import OrderedDict, namedtuple
@ -22,7 +20,6 @@ from collections import OrderedDict, namedtuple
from django.conf.urls import url
from django.core.exceptions import ImproperlyConfigured
from django.urls import NoReverseMatch
from django.utils import six
from django.utils.deprecation import RenameMethodsBase
from rest_framework import (
@ -39,7 +36,7 @@ Route = namedtuple('Route', ['url', 'mapping', 'name', 'detail', 'initkwargs'])
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 +47,7 @@ class DynamicDetailRoute(object):
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 "
@ -83,7 +80,7 @@ class RenameRouterMethods(RenameMethodsBase):
)
class BaseRouter(six.with_metaclass(RenameRouterMethods)):
class BaseRouter(metaclass=RenameRouterMethods):
def __init__(self):
self.registry = []
@ -173,7 +170,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 +362,7 @@ class DefaultRouter(SimpleRouter):
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 +380,7 @@ class DefaultRouter(SimpleRouter):
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)

View File

@ -11,7 +11,6 @@ from django.conf import settings
from django.contrib.admindocs.views import simplify_regex
from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.utils import six
from rest_framework import exceptions
from rest_framework.compat import (
@ -68,7 +67,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 +139,7 @@ _PATH_PARAMETER_COMPONENT_RE = re.compile(
)
class EndpointEnumerator(object):
class EndpointEnumerator:
"""
A class to determine the available API endpoints that a project exposes.
"""
@ -151,7 +150,7 @@ class EndpointEnumerator(object):
urlconf = settings.ROOT_URLCONF
# Load the given URLconf module
if isinstance(urlconf, six.string_types):
if isinstance(urlconf, str):
urls = import_module(urlconf)
else:
urls = urlconf
@ -232,7 +231,7 @@ class EndpointEnumerator(object):
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',

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
inspectors.py # Per-endpoint view introspection
@ -7,11 +6,11 @@ See schemas.__init__.py for package overview.
import re
import warnings
from collections import OrderedDict
from urllib import parse
from weakref import WeakKeyDictionary
from django.db import models
from django.utils.encoding import force_text, smart_text
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions, serializers
@ -125,7 +124,7 @@ def get_pk_description(model, model_field):
)
class ViewInspector(object):
class ViewInspector:
"""
Descriptor class on APIView.
@ -207,7 +206,7 @@ class AutoSchema(ViewInspector):
* `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
@ -232,7 +231,7 @@ class AutoSchema(ViewInspector):
path = path[1:]
return coreapi.Link(
url=urlparse.urljoin(base_url, path),
url=parse.urljoin(base_url, path),
action=method.lower(),
encoding=encoding,
fields=fields,
@ -475,7 +474,7 @@ class ManualSchema(ViewInspector):
* `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
@ -487,7 +486,7 @@ class ManualSchema(ViewInspector):
path = path[1:]
return coreapi.Link(
url=urlparse.urljoin(base_url, path),
url=parse.urljoin(base_url, path),
action=method.lower(),
encoding=self._encoding,
fields=self._fields,
@ -498,7 +497,7 @@ class ManualSchema(ViewInspector):
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

View File

@ -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,
@ -38,4 +38,4 @@ class SchemaView(APIView):
self.renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
neg = self.perform_content_negotiation(self.request, force=True)
self.request.accepted_renderer, self.request.accepted_media_type = neg
return super(SchemaView, self).handle_exception(exc)
return super().handle_exception(exc)

View File

@ -10,8 +10,6 @@ python primitives.
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
import traceback
@ -23,11 +21,11 @@ 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 import timezone
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from rest_framework.compat import Mapping, postgres_fields, unicode_to_repr
from rest_framework.compat import Mapping, postgres_fields
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.fields import get_error_detail, set_value
from rest_framework.settings import api_settings
@ -115,14 +113,14 @@ class BaseSerializer(Field):
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super(BaseSerializer, self).__init__(**kwargs)
super().__init__(**kwargs)
def __new__(cls, *args, **kwargs):
# We override this method in order to automagically create
# `ListSerializer` classes instead when `many=True` is set.
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
return super().__new__(cls, *args, **kwargs)
@classmethod
def many_init(cls, *args, **kwargs):
@ -315,7 +313,7 @@ class SerializerMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)
return super().__new__(cls, name, bases, attrs)
def as_serializer_error(exc):
@ -344,8 +342,7 @@ def as_serializer_error(exc):
}
@six.add_metaclass(SerializerMetaclass)
class Serializer(BaseSerializer):
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
default_error_messages = {
'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
}
@ -466,7 +463,7 @@ class Serializer(BaseSerializer):
to_validate.update(value)
else:
to_validate = value
super(Serializer, self).run_validators(to_validate)
super().run_validators(to_validate)
def to_internal_value(self, data):
"""
@ -535,7 +532,7 @@ class Serializer(BaseSerializer):
return attrs
def __repr__(self):
return unicode_to_repr(representation.serializer_repr(self, indent=1))
return representation.serializer_repr(self, indent=1)
# The following are used for accessing `BoundField` instances on the
# serializer, for the purposes of presenting a form-like API onto the
@ -560,12 +557,12 @@ class Serializer(BaseSerializer):
@property
def data(self):
ret = super(Serializer, self).data
ret = super().data
return ReturnDict(ret, serializer=self)
@property
def errors(self):
ret = super(Serializer, self).errors
ret = super().errors
if isinstance(ret, list) and len(ret) == 1 and getattr(ret[0], 'code', None) == 'null':
# Edge case. Provide a more descriptive error than
# "this field may not be null", when no data is passed.
@ -591,11 +588,11 @@ class ListSerializer(BaseSerializer):
self.allow_empty = kwargs.pop('allow_empty', True)
assert self.child is not None, '`child` is a required argument.'
assert not inspect.isclass(self.child), '`child` has not been instantiated.'
super(ListSerializer, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)
def bind(self, field_name, parent):
super(ListSerializer, self).bind(field_name, parent)
super().bind(field_name, parent)
self.partial = self.parent.partial
def get_initial(self):
@ -758,19 +755,19 @@ class ListSerializer(BaseSerializer):
return not bool(self._errors)
def __repr__(self):
return unicode_to_repr(representation.list_repr(self, indent=1))
return representation.list_repr(self, indent=1)
# Include a backlink to the serializer class on return objects.
# Allows renderers such as HTMLFormRenderer to get the full field info.
@property
def data(self):
ret = super(ListSerializer, self).data
ret = super().data
return ReturnList(ret, serializer=self)
@property
def errors(self):
ret = super(ListSerializer, self).errors
ret = super().errors
if isinstance(ret, list) and len(ret) == 1 and getattr(ret[0], 'code', None) == 'null':
# Edge case. Provide a more descriptive error than
# "this field may not be null", when no data is passed.

View File

@ -18,13 +18,10 @@ This module provides the `api_setting` object, that is used to access
REST framework settings, checking for user settings first, then falling
back to the defaults.
"""
from __future__ import unicode_literals
from importlib import import_module
from django.conf import settings
from django.test.signals import setting_changed
from django.utils import six
from rest_framework import ISO_8601
@ -166,7 +163,7 @@ def perform_import(val, setting_name):
"""
if val is None:
return None
elif isinstance(val, six.string_types):
elif isinstance(val, str):
return import_from_string(val, setting_name)
elif isinstance(val, (list, tuple)):
return [import_from_string(item, setting_name) for item in val]
@ -187,7 +184,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:

View File

@ -5,7 +5,6 @@ See RFC 2616 - https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
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):

View File

@ -1,12 +1,9 @@
from __future__ import absolute_import, unicode_literals
import re
from collections import OrderedDict
from django import template
from django.template import loader
from django.urls import NoReverseMatch, reverse
from django.utils import six
from django.utils.encoding import force_text, iri_to_uri
from django.utils.html import escape, format_html, smart_urlquote
from django.utils.safestring import SafeData, mark_safe
@ -187,7 +184,7 @@ def add_class(value, css_class):
In the case of REST Framework, the filter is used to add Bootstrap-specific
classes to the forms.
"""
html = six.text_type(value)
html = str(value)
match = class_re.search(html)
if match:
m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class,
@ -204,7 +201,7 @@ def add_class(value, css_class):
@register.filter
def format_value(value):
if getattr(value, 'is_hyperlink', False):
name = six.text_type(value.obj)
name = str(value.obj)
return mark_safe('<a href=%s>%s</a>' % (value, escape(name)))
if value is None or isinstance(value, bool):
return mark_safe('<code>%s</code>' % {True: 'true', False: 'false', None: 'null'}[value])
@ -219,7 +216,7 @@ def format_value(value):
template = loader.get_template('rest_framework/admin/dict_value.html')
context = {'value': value}
return template.render(context)
elif isinstance(value, six.string_types):
elif isinstance(value, str):
if (
(value.startswith('http:') or value.startswith('https:')) and not
re.search(r'\s', value)
@ -229,7 +226,7 @@ def format_value(value):
return mark_safe('<a href="mailto:{value}">{value}</a>'.format(value=escape(value)))
elif '\n' in value:
return mark_safe('<pre>%s</pre>' % escape(value))
return six.text_type(value)
return str(value)
@register.filter

View File

@ -1,9 +1,5 @@
# -- 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
@ -14,7 +10,6 @@ from django.test import override_settings, testcases
from django.test.client import Client as DjangoClient
from django.test.client import ClientHandler
from django.test.client import RequestFactory as DjangoRequestFactory
from django.utils import six
from django.utils.encoding import force_bytes
from django.utils.http import urlencode
@ -32,7 +27,7 @@ if requests is not None:
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
@ -109,7 +104,7 @@ if requests is not None:
class RequestsClient(requests.Session):
def __init__(self, *args, **kwargs):
super(RequestsClient, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
adapter = DjangoTestAdapter()
self.mount('http://', adapter)
self.mount('https://', adapter)
@ -117,7 +112,7 @@ if requests is not None:
def request(self, method, url, *args, **kwargs):
if not url.startswith('http'):
raise ValueError('Missing "http:" or "https:". Use a fully qualified URL, eg "http://testserver%s"' % url)
return super(RequestsClient, self).request(method, url, *args, **kwargs)
return super().request(method, url, *args, **kwargs)
else:
def RequestsClient(*args, **kwargs):
@ -129,7 +124,7 @@ if coreapi is not None:
def __init__(self, *args, **kwargs):
self._session = RequestsClient()
kwargs['transports'] = [coreapi.transports.HTTPTransport(session=self.session)]
return super(CoreAPIClient, self).__init__(*args, **kwargs)
return super().__init__(*args, **kwargs)
@property
def session(self):
@ -149,7 +144,7 @@ class APIRequestFactory(DjangoRequestFactory):
self.renderer_classes = {}
for cls in self.renderer_classes_list:
self.renderer_classes[cls.format] = cls
super(APIRequestFactory, self).__init__(**defaults)
super().__init__(**defaults)
def _encode_data(self, data, format=None, content_type=None):
"""
@ -171,7 +166,7 @@ class APIRequestFactory(DjangoRequestFactory):
format = format or self.default_format
assert format in self.renderer_classes, (
"Invalid format '{0}'. Available formats are {1}. "
"Invalid format '{}'. Available formats are {}. "
"Set TEST_REQUEST_RENDERER_CLASSES to enable "
"extra request formats.".format(
format,
@ -184,12 +179,12 @@ class APIRequestFactory(DjangoRequestFactory):
ret = renderer.render(data)
# Determine the content-type header from the renderer
content_type = "{0}; charset={1}".format(
content_type = "{}; charset={}".format(
renderer.media_type, renderer.charset
)
# Coerce text to bytes if required.
if isinstance(ret, six.text_type):
if isinstance(ret, str):
ret = bytes(ret.encode(renderer.charset))
return ret, content_type
@ -202,7 +197,6 @@ class APIRequestFactory(DjangoRequestFactory):
# Fix to support old behavior where you have the arguments in the
# url. See #1461.
query_string = force_bytes(path.split('?')[1])
if six.PY3:
query_string = query_string.decode('iso-8859-1')
r['QUERY_STRING'] = query_string
r.update(extra)
@ -234,11 +228,11 @@ class APIRequestFactory(DjangoRequestFactory):
if content_type is not None:
extra['CONTENT_TYPE'] = str(content_type)
return super(APIRequestFactory, self).generic(
return super().generic(
method, path, data, content_type, secure, **extra)
def request(self, **kwargs):
request = super(APIRequestFactory, self).request(**kwargs)
request = super().request(**kwargs)
request._dont_enforce_csrf_checks = not self.enforce_csrf_checks
return request
@ -252,18 +246,18 @@ class ForceAuthClientHandler(ClientHandler):
def __init__(self, *args, **kwargs):
self._force_user = None
self._force_token = None
super(ForceAuthClientHandler, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def get_response(self, request):
# This is the simplest place we can hook into to patch the
# request object.
force_authenticate(request, self._force_user, self._force_token)
return super(ForceAuthClientHandler, self).get_response(request)
return super().get_response(request)
class APIClient(APIRequestFactory, DjangoClient):
def __init__(self, enforce_csrf_checks=False, **defaults):
super(APIClient, self).__init__(**defaults)
super().__init__(**defaults)
self.handler = ForceAuthClientHandler(enforce_csrf_checks)
self._credentials = {}
@ -286,17 +280,17 @@ class APIClient(APIRequestFactory, DjangoClient):
def request(self, **kwargs):
# Ensure that any credentials set get added to every request.
kwargs.update(self._credentials)
return super(APIClient, self).request(**kwargs)
return super().request(**kwargs)
def get(self, path, data=None, follow=False, **extra):
response = super(APIClient, self).get(path, data=data, **extra)
response = super().get(path, data=data, **extra)
if follow:
response = self._handle_redirects(response, **extra)
return response
def post(self, path, data=None, format=None, content_type=None,
follow=False, **extra):
response = super(APIClient, self).post(
response = super().post(
path, data=data, format=format, content_type=content_type, **extra)
if follow:
response = self._handle_redirects(response, **extra)
@ -304,7 +298,7 @@ class APIClient(APIRequestFactory, DjangoClient):
def put(self, path, data=None, format=None, content_type=None,
follow=False, **extra):
response = super(APIClient, self).put(
response = super().put(
path, data=data, format=format, content_type=content_type, **extra)
if follow:
response = self._handle_redirects(response, **extra)
@ -312,7 +306,7 @@ class APIClient(APIRequestFactory, DjangoClient):
def patch(self, path, data=None, format=None, content_type=None,
follow=False, **extra):
response = super(APIClient, self).patch(
response = super().patch(
path, data=data, format=format, content_type=content_type, **extra)
if follow:
response = self._handle_redirects(response, **extra)
@ -320,7 +314,7 @@ class APIClient(APIRequestFactory, DjangoClient):
def delete(self, path, data=None, format=None, content_type=None,
follow=False, **extra):
response = super(APIClient, self).delete(
response = super().delete(
path, data=data, format=format, content_type=content_type, **extra)
if follow:
response = self._handle_redirects(response, **extra)
@ -328,7 +322,7 @@ class APIClient(APIRequestFactory, DjangoClient):
def options(self, path, data=None, format=None, content_type=None,
follow=False, **extra):
response = super(APIClient, self).options(
response = super().options(
path, data=data, format=format, content_type=content_type, **extra)
if follow:
response = self._handle_redirects(response, **extra)
@ -342,7 +336,7 @@ class APIClient(APIRequestFactory, DjangoClient):
self.handler._force_token = None
if self.session:
super(APIClient, self).logout()
super().logout()
class APITransactionTestCase(testcases.TransactionTestCase):
@ -389,11 +383,11 @@ class URLPatternsTestCase(testcases.SimpleTestCase):
cls._module.urlpatterns = cls.urlpatterns
cls._override.enable()
super(URLPatternsTestCase, cls).setUpClass()
super().setUpClass()
@classmethod
def tearDownClass(cls):
super(URLPatternsTestCase, cls).tearDownClass()
super().tearDownClass()
cls._override.disable()
if hasattr(cls, '_module_urlpatterns'):

View File

@ -1,8 +1,6 @@
"""
Provides various throttling policies.
"""
from __future__ import unicode_literals
import time
from django.core.cache import cache as default_cache
@ -11,7 +9,7 @@ from django.core.exceptions import ImproperlyConfigured
from rest_framework.settings import api_settings
class BaseThrottle(object):
class BaseThrottle:
"""
Rate throttling of requests.
"""
@ -232,7 +230,7 @@ class ScopedRateThrottle(SimpleRateThrottle):
self.num_requests, self.duration = self.parse_rate(self.rate)
# We can now proceed as normal.
return super(ScopedRateThrottle, self).allow_request(request, view)
return super().allow_request(request, view)
def get_cache_key(self, request, view):
"""

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.conf.urls import include, url
from rest_framework.compat import (

View File

@ -11,8 +11,6 @@ your API requires authentication:
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

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.urls import get_script_prefix, resolve

View File

@ -1,15 +1,13 @@
"""
Helper classes for parsers.
"""
from __future__ import absolute_import, unicode_literals
import datetime
import decimal
import json # noqa
import uuid
from django.db.models.query import QuerySet
from django.utils import six, timezone
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.functional import Promise
@ -39,12 +37,12 @@ class JSONEncoder(json.JSONEncoder):
representation = obj.isoformat()
return representation
elif isinstance(obj, datetime.timedelta):
return six.text_type(obj.total_seconds())
return str(obj.total_seconds())
elif isinstance(obj, decimal.Decimal):
# Serializers will coerce decimals to strings by default.
return float(obj)
elif isinstance(obj, uuid.UUID):
return six.text_type(obj)
return str(obj)
elif isinstance(obj, QuerySet):
return tuple(obj)
elif isinstance(obj, bytes):
@ -65,4 +63,4 @@ class JSONEncoder(json.JSONEncoder):
pass
elif hasattr(obj, '__iter__'):
return tuple(item for item in obj)
return super(JSONEncoder, self).default(obj)
return super().default(obj)

View File

@ -16,7 +16,7 @@ NUMERIC_FIELD_TYPES = (
)
class ClassLookupDict(object):
class ClassLookupDict:
"""
Takes a dictionary with classes as keys.
Lookups against this object will traverses the object's inheritance

View File

@ -1,8 +1,6 @@
"""
Utility functions to return a formatted name and description for a given view.
"""
from __future__ import unicode_literals
import re
from django.utils.encoding import force_text

View File

@ -5,9 +5,6 @@ REST framework should always import this wrapper module in order to maintain
spec-compliant encoding/decoding. Support for non-standard features should be
handled by users at the renderer and parser layer.
"""
from __future__ import absolute_import
import functools
import json # noqa

View File

@ -3,10 +3,7 @@ Handling of media types, as found in HTTP Content-Type and Accept headers.
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 +43,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))

View File

@ -2,16 +2,12 @@
Helper functions for creating user-friendly representations
of serializer classes and serializer fields.
"""
from __future__ import unicode_literals
import re
from django.db import models
from django.utils.encoding import force_text
from django.utils.functional import Promise
from rest_framework.compat import unicode_repr
def manager_repr(value):
model = value.model
@ -34,7 +30,7 @@ def smart_repr(value):
if isinstance(value, Promise) and value._delegate_text:
value = force_text(value)
value = unicode_repr(value)
value = repr(value)
# Representations like u'help text'
# should simply be presented as 'help text'

View File

@ -1,10 +1,8 @@
from __future__ import unicode_literals
from collections import OrderedDict
from django.utils.encoding import force_text
from rest_framework.compat import MutableMapping, unicode_to_repr
from rest_framework.compat import MutableMapping
from rest_framework.utils import json
@ -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 @@ class ReturnList(list):
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,
@ -73,9 +71,9 @@ class BoundField(object):
return self._field.__class__
def __repr__(self):
return unicode_to_repr('<%s value=%s errors=%s>' % (
return '<%s value=%s errors=%s>' % (
self.__class__.__name__, self.value, self.errors
))
)
def as_form_field(self):
value = '' if (self.value is None or self.value is False) else self.value
@ -103,9 +101,9 @@ class NestedBoundField(BoundField):
"""
def __init__(self, field, value, errors, prefix=''):
if value is None or value is '':
if value is None or value == '':
value = {}
super(NestedBoundField, self).__init__(field, value, errors, prefix)
super().__init__(field, value, errors, prefix)
def __iter__(self):
for field in self.fields.values():

View File

@ -1,5 +1,6 @@
from urllib import parse
from django.utils.encoding import force_str
from django.utils.six.moves.urllib import parse as urlparse
def replace_query_param(url, key, val):
@ -7,11 +8,11 @@ def replace_query_param(url, key, val):
Given a URL and a key/val pair, set or replace an item in the query
parameters of the URL, and return the new URL.
"""
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(force_str(url))
query_dict = urlparse.parse_qs(query, keep_blank_values=True)
(scheme, netloc, path, query, fragment) = parse.urlsplit(force_str(url))
query_dict = parse.parse_qs(query, keep_blank_values=True)
query_dict[force_str(key)] = [force_str(val)]
query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True)
return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
query = parse.urlencode(sorted(list(query_dict.items())), doseq=True)
return parse.urlunsplit((scheme, netloc, path, query, fragment))
def remove_query_param(url, key):
@ -19,8 +20,8 @@ def remove_query_param(url, key):
Given a URL and a key/val pair, remove an item in the query
parameters of the URL, and return the new URL.
"""
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(force_str(url))
query_dict = urlparse.parse_qs(query, keep_blank_values=True)
(scheme, netloc, path, query, fragment) = parse.urlsplit(force_str(url))
query_dict = parse.parse_qs(query, keep_blank_values=True)
query_dict.pop(key, None)
query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True)
return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
query = parse.urlencode(sorted(list(query_dict.items())), doseq=True)
return parse.urlunsplit((scheme, netloc, path, query, fragment))

View File

@ -6,12 +6,9 @@ This gives us better separation of concerns, allows us to use single-step
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 _
from rest_framework.compat import unicode_to_repr
from rest_framework.exceptions import ValidationError
from rest_framework.utils.representation import smart_repr
@ -33,7 +30,7 @@ def qs_filter(queryset, **kwargs):
return queryset.none()
class UniqueValidator(object):
class UniqueValidator:
"""
Validator that corresponds to `unique=True` on a model field.
@ -82,13 +79,13 @@ class UniqueValidator(object):
raise ValidationError(self.message, code='unique')
def __repr__(self):
return unicode_to_repr('<%s(queryset=%s)>' % (
return '<%s(queryset=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset)
))
)
class UniqueTogetherValidator(object):
class UniqueTogetherValidator:
"""
Validator that corresponds to `unique_together = (...)` on a model class.
@ -170,14 +167,14 @@ class UniqueTogetherValidator(object):
raise ValidationError(message, code='unique')
def __repr__(self):
return unicode_to_repr('<%s(queryset=%s, fields=%s)>' % (
return '<%s(queryset=%s, fields=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset),
smart_repr(self.fields)
))
)
class BaseUniqueForValidator(object):
class BaseUniqueForValidator:
message = None
missing_message = _('This field is required.')
@ -236,12 +233,12 @@ class BaseUniqueForValidator(object):
}, code='unique')
def __repr__(self):
return unicode_to_repr('<%s(queryset=%s, field=%s, date_field=%s)>' % (
return '<%s(queryset=%s, field=%s, date_field=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset),
smart_repr(self.field),
smart_repr(self.date_field)
))
)
class UniqueForDateValidator(BaseUniqueForValidator):

View File

@ -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.templatetags.rest_framework import replace_query_param
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
@ -87,7 +84,7 @@ class URLPathVersioning(BaseVersioning):
kwargs = {} if (kwargs is None) else kwargs
kwargs[self.version_param] = request.version
return super(URLPathVersioning, self).reverse(
return super().reverse(
viewname, args, kwargs, request, format, **extra
)
@ -133,7 +130,7 @@ class NamespaceVersioning(BaseVersioning):
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request.version is not None:
viewname = self.get_versioned_viewname(viewname, request)
return super(NamespaceVersioning, self).reverse(
return super().reverse(
viewname, args, kwargs, request, format, **extra
)
@ -179,7 +176,7 @@ class QueryParameterVersioning(BaseVersioning):
return version
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
url = super(QueryParameterVersioning, self).reverse(
url = super().reverse(
viewname, args, kwargs, request, format, **extra
)
if request.version is not None:

View File

@ -1,8 +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
from django.db import connection, models, transaction
@ -137,7 +135,7 @@ class APIView(View):
)
cls.queryset._fetch_all = force_evaluation
view = super(APIView, cls).as_view(**initkwargs)
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs

View File

@ -16,8 +16,6 @@ automatically.
router.register(r'users', UserViewSet, 'user')
urlpatterns = router.urls
"""
from __future__ import unicode_literals
from collections import OrderedDict
from functools import update_wrapper
from inspect import getmembers
@ -34,7 +32,7 @@ def _is_extra_action(attr):
return hasattr(attr, 'mapping')
class ViewSetMixin(object):
class ViewSetMixin:
"""
This is the magic.
@ -134,7 +132,7 @@ class ViewSetMixin(object):
"""
Set the `.action` attribute on the view, depending on the request method.
"""
request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
request = super().initialize_request(request, *args, **kwargs)
method = request.method.lower()
if method == 'options':
# This is a special case as we always provide handling for the

View File

@ -1,6 +1,4 @@
#! /usr/bin/env python
from __future__ import print_function
#! /usr/bin/env python3
import subprocess
import sys

View File

@ -1,6 +1,3 @@
[bdist_wheel]
universal = 1
[metadata]
license_file = LICENSE.md

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
import os
import re
import shutil
@ -8,6 +7,34 @@ from io import open
from setuptools import find_packages, setup
CURRENT_PYTHON = sys.version_info[:2]
REQUIRED_PYTHON = (3, 4)
# This check and everything above must remain compatible with Python 2.7.
if CURRENT_PYTHON < REQUIRED_PYTHON:
sys.stderr.write("""
==========================
Unsupported Python version
==========================
This version of Django REST Framework requires Python {}.{}, but you're trying
to install it on Python {}.{}.
This may be because you are using a version of pip that doesn't
understand the python_requires classifier. Make sure you
have pip >= 9.0 and setuptools >= 24.2, then try again:
$ python -m pip install --upgrade pip setuptools
$ python -m pip install djangorestframework
This will install the latest version of Django REST Framework which works on
your version of Python. If you can't upgrade your pip (or Python), request
an older version of Django REST Framework:
$ python -m pip install "django<3.10"
""".format(*(REQUIRED_PYTHON + CURRENT_PYTHON)))
sys.exit(1)
def read(f):
return open(f, 'r', encoding='utf-8').read()
@ -52,7 +79,7 @@ setup(
packages=find_packages(exclude=['tests*']),
include_package_data=True,
install_requires=[],
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
python_requires=">=3.4",
zip_safe=False,
classifiers=[
'Development Status :: 5 - Production/Stable',
@ -66,13 +93,12 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Internet :: WWW/HTTP',
]
)

View File

@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models

View File

@ -1,6 +1,3 @@
# coding: utf-8
from __future__ import unicode_literals
from django.conf import settings
from django.db import models

View File

@ -1,7 +1,3 @@
# coding: utf-8
from __future__ import unicode_literals
import base64
import pytest
@ -10,7 +6,6 @@ from django.conf.urls import include, url
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.test import TestCase, override_settings
from django.utils import six
from rest_framework import (
HTTP_HEADER_ENCODING, exceptions, permissions, renderers, status
@ -253,7 +248,7 @@ class SessionAuthTests(TestCase):
assert response.status_code == status.HTTP_403_FORBIDDEN
class BaseTokenAuthTests(object):
class BaseTokenAuthTests:
"""Token authentication"""
model = None
path = None
@ -381,7 +376,7 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
"""Ensure generate_key returns a string"""
token = self.model()
key = token.generate_key()
assert isinstance(key, six.string_types)
assert isinstance(key, str)
def test_token_login_json(self):
"""Ensure token login view using JSON POST works."""
@ -534,7 +529,7 @@ class BasicAuthenticationUnitTests(TestCase):
def test_basic_authentication_raises_error_if_user_not_active(self):
from rest_framework import authentication
class MockUser(object):
class MockUser:
is_active = False
old_authenticate = authentication.authenticate
authentication.authenticate = lambda **kwargs: MockUser()

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.conf.urls import include, url
from .views import MockView

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.conf.urls import url
from .views import MockView

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.test import TestCase, override_settings

View File

@ -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

View File

@ -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

View File

@ -1,14 +1,10 @@
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.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 +18,6 @@ class Tag(models.Model):
return self.tag
@python_2_unicode_compatible
class Bookmark(models.Model):
"""
A URL bookmark that may have multiple tags attached.
@ -34,7 +29,6 @@ class Bookmark(models.Model):
return 'Bookmark: %s' % self.url
@python_2_unicode_compatible
class Note(models.Model):
"""
A textual note that may have multiple tags attached.

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.test import TestCase
from rest_framework import serializers

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import uuid
from django.db import models

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import os
import tempfile
import unittest

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import unittest
from django.conf.urls import url
@ -38,7 +36,7 @@ class APIExceptionView(APIView):
class NonAtomicAPIExceptionView(APIView):
@transaction.non_atomic_requests
def dispatch(self, *args, **kwargs):
return super(NonAtomicAPIExceptionView, self).dispatch(*args, **kwargs)
return super().dispatch(*args, **kwargs)
def get(self, request, *args, **kwargs):
BasicModel.objects.all()

View File

@ -1,9 +1,10 @@
from io import StringIO
import pytest
from django.contrib.admin import site
from django.contrib.auth.models import User
from django.core.management import CommandError, call_command
from django.test import TestCase
from django.utils.six import StringIO
from rest_framework.authtoken.admin import TokenAdmin
from rest_framework.authtoken.management.commands.drf_create_token import \

View File

@ -28,7 +28,7 @@ class TestSimpleBoundField:
assert serializer['text'].value == 'abc'
assert serializer['text'].errors is None
assert serializer['text'].name == 'text'
assert serializer['amount'].value is 123
assert serializer['amount'].value == 123
assert serializer['amount'].errors is None
assert serializer['amount'].name == 'amount'
@ -43,7 +43,7 @@ class TestSimpleBoundField:
assert serializer['text'].value == 'x' * 1000
assert serializer['text'].errors == ['Ensure this field has no more than 100 characters.']
assert serializer['text'].name == 'text'
assert serializer['amount'].value is 123
assert serializer['amount'].value == 123
assert serializer['amount'].errors is None
assert serializer['amount'].name == 'amount'

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import pytest
from django.test import TestCase

View File

@ -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 TestViewNamesAndDescriptions(TestCase):
"""
# 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

View File

@ -10,7 +10,7 @@ from rest_framework.compat import coreapi
from rest_framework.utils.encoders import JSONEncoder
class MockList(object):
class MockList:
def tolist(self):
return [1, 2, 3]

View File

@ -1,8 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.test import RequestFactory, TestCase
from django.utils import six, translation
from django.utils import translation
from django.utils.translation import ugettext_lazy as _
from rest_framework.exceptions import (
@ -46,12 +43,12 @@ class ExceptionTestCase(TestCase):
exception = Throttled(wait=2)
assert exception.get_full_details() == {
'message': 'Request was throttled. Expected available in {} seconds.'.format(2 if six.PY3 else 2.),
'message': 'Request was throttled. Expected available in {} seconds.'.format(2),
'code': 'throttled'}
exception = Throttled(wait=2, detail='Slow down!')
assert exception.get_full_details() == {
'message': 'Slow down! Expected available in {} seconds.'.format(2 if six.PY3 else 2.),
'message': 'Slow down! Expected available in {} seconds.'.format(2),
'code': 'throttled'}
@ -92,7 +89,7 @@ class TranslationTests(TestCase):
def test_message(self):
# this test largely acts as a sanity test to ensure the translation files are present.
self.assertEqual(_('A server error occurred.'), 'Une erreur du serveur est survenue.')
self.assertEqual(six.text_type(APIException()), 'Une erreur du serveur est survenue.')
self.assertEqual(str(APIException()), 'Une erreur du serveur est survenue.')
def test_server_error():

View File

@ -10,7 +10,6 @@ import pytz
from django.core.exceptions import ValidationError as DjangoValidationError
from django.http import QueryDict
from django.test import TestCase, override_settings
from django.utils import six
from django.utils.timezone import activate, deactivate, override, utc
import rest_framework
@ -167,7 +166,7 @@ class TestEmpty:
"""
field = serializers.IntegerField(default=123)
output = field.run_validation()
assert output is 123
assert output == 123
class TestSource:
@ -193,7 +192,7 @@ class TestSource:
class ExampleSerializer(serializers.Serializer):
example_field = serializers.CharField(source='example_callable')
class ExampleInstance(object):
class ExampleInstance:
def example_callable(self):
return 'example callable value'
@ -204,7 +203,7 @@ class TestSource:
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')
@ -754,7 +753,7 @@ class TestCharField(FieldValues):
def raise_exception(value):
raise exceptions.ValidationError('Raised error')
for validators in ([raise_exception], (raise_exception,), set([raise_exception])):
for validators in ([raise_exception], (raise_exception,), {raise_exception}):
field = serializers.CharField(validators=validators)
with pytest.raises(serializers.ValidationError) as exc_info:
field.run_validation(value)
@ -822,7 +821,7 @@ class TestSlugField(FieldValues):
validation_error = False
try:
field.run_validation(u'slug-99-\u0420')
field.run_validation('slug-99-\u0420')
except serializers.ValidationError:
validation_error = True
@ -1148,7 +1147,7 @@ class TestLocalizedDecimalField(TestCase):
def test_localize_forces_coerce_to_string(self):
field = serializers.DecimalField(max_digits=2, decimal_places=1, coerce_to_string=False, localize=True)
assert isinstance(field.to_representation(Decimal('1.1')), six.string_types)
assert isinstance(field.to_representation(Decimal('1.1')), str)
class TestQuantizedValueForDecimal(TestCase):
@ -1219,7 +1218,7 @@ class TestDateField(FieldValues):
outputs = {
datetime.date(2001, 1, 1): '2001-01-01',
'2001-01-01': '2001-01-01',
six.text_type('2016-01-10'): '2016-01-10',
str('2016-01-10'): '2016-01-10',
None: None,
'': None,
}
@ -1286,7 +1285,7 @@ class TestDateTimeField(FieldValues):
datetime.datetime(2001, 1, 1, 13, 00): '2001-01-01T13:00:00Z',
datetime.datetime(2001, 1, 1, 13, 00, tzinfo=utc): '2001-01-01T13:00:00Z',
'2001-01-01T00:00:00': '2001-01-01T00:00:00',
six.text_type('2016-01-10T00:00:00'): '2016-01-10T00:00:00',
str('2016-01-10T00:00:00'): '2016-01-10T00:00:00',
None: None,
'': None,
}
@ -1628,7 +1627,7 @@ class TestChoiceField(FieldValues):
]
)
field.choices = [1]
assert field.run_validation(1) is 1
assert field.run_validation(1) == 1
with pytest.raises(serializers.ValidationError) as exc_info:
field.run_validation(2)
assert exc_info.value.detail == ['"2" is not a valid choice.']

View File

@ -1,6 +1,5 @@
from __future__ import unicode_literals
import datetime
from importlib import reload as reload_module
import pytest
from django.core.exceptions import ImproperlyConfigured
@ -8,7 +7,6 @@ from django.db import models
from django.db.models.functions import Concat, Upper
from django.test import TestCase
from django.test.utils import override_settings
from django.utils.six.moves import reload_module
from rest_framework import filters, generics, serializers
from rest_framework.compat import coreschema
@ -163,7 +161,7 @@ class SearchFilterTests(TestCase):
def get_search_fields(self, view, request):
if request.query_params.get('title_only'):
return ('$title',)
return super(CustomSearchFilter, self).get_search_fields(view, request)
return super().get_search_fields(view, request)
class SearchListView(generics.ListAPIView):
queryset = SearchFilterModel.objects.all()

View File

@ -1,11 +1,10 @@
from __future__ import unicode_literals
import io
import pytest
from django.conf.urls import url
from django.core.management import call_command
from django.test import TestCase
from django.test.utils import override_settings
from django.utils import six
from rest_framework.compat import coreapi
from rest_framework.utils import formatting, json
@ -28,9 +27,8 @@ class GenerateSchemaTests(TestCase):
"""Tests for management command generateschema."""
def setUp(self):
self.out = six.StringIO()
self.out = io.StringIO()
@pytest.mark.skipif(six.PY2, reason='PyYAML unicode output is malformed on PY2.')
def test_renders_default_schema_with_custom_title_url_and_description(self):
expected_out = """info:
description: Sample description

View File

@ -1,11 +1,8 @@
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
@ -245,7 +242,7 @@ class TestInstanceView(TestCase):
with self.assertNumQueries(2):
response = self.view(request, pk=1).render()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert response.content == six.b('')
assert response.content == b''
ids = [obj.id for obj in self.objects.all()]
assert ids == [2, 3]
@ -291,7 +288,7 @@ class TestInstanceView(TestCase):
"""
data = {'text': 'foo'}
filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk
request = factory.put('/{0}'.format(filtered_out_pk), data, format='json')
request = factory.put('/{}'.format(filtered_out_pk), data, format='json')
response = self.view(request, pk=filtered_out_pk).render()
assert response.status_code == status.HTTP_404_NOT_FOUND
@ -446,12 +443,12 @@ class TestM2MBrowsableAPI(TestCase):
assert response.status_code == status.HTTP_200_OK
class InclusiveFilterBackend(object):
class InclusiveFilterBackend:
def filter_queryset(self, request, queryset, view):
return queryset.filter(text='foo')
class ExclusiveFilterBackend(object):
class ExclusiveFilterBackend:
def filter_queryset(self, request, queryset, view):
return queryset.filter(text='other')
@ -653,7 +650,7 @@ class ApiViewsTests(TestCase):
class GetObjectOr404Tests(TestCase):
def setUp(self):
super(GetObjectOr404Tests, self).setUp()
super().setUp()
self.uuid_object = UUIDForeignKeyTarget.objects.create(name='bar')
def test_get_object_or_404_with_valid_uuid(self):

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import django.template.loader
import pytest
from django.conf.urls import url
@ -7,7 +5,6 @@ from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.http import Http404
from django.template import TemplateDoesNotExist, engines
from django.test import TestCase, override_settings
from django.utils import six
from rest_framework import status
from rest_framework.decorators import api_view, renderer_classes
@ -47,7 +44,7 @@ urlpatterns = [
@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()
@ -85,13 +82,13 @@ class TemplateHTMLRendererTests(TestCase):
def test_not_found_html_view(self):
response = self.client.get('/not_found')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.content, six.b("404 Not Found"))
self.assertEqual(response.content, b"404 Not Found")
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
def test_permission_denied_html_view(self):
response = self.client.get('/permission_denied')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(response.content, six.b("403 Forbidden"))
self.assertEqual(response.content, b"403 Forbidden")
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
# 2 tests below are based on order of if statements in corresponding method
@ -105,14 +102,14 @@ class TemplateHTMLRendererTests(TestCase):
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,
@ -156,12 +153,11 @@ class TemplateHTMLRendererExceptionTests(TestCase):
response = self.client.get('/not_found')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertTrue(response.content in (
six.b("404: Not found"), six.b("404 Not Found")))
b"404: Not found", b"404 Not Found"))
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
def test_permission_denied_html_view_with_template(self):
response = self.client.get('/permission_denied')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertTrue(response.content in (
six.b("403: Permission denied"), six.b("403 Forbidden")))
self.assertTrue(response.content in (b"403: Permission denied", b"403 Forbidden"))
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import pytest
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models

View File

@ -22,7 +22,7 @@ urlpatterns = [
]
class RequestUserMiddleware(object):
class RequestUserMiddleware:
def __init__(self, get_response):
self.get_response = get_response
@ -34,7 +34,7 @@ class RequestUserMiddleware(object):
return response
class RequestPOSTMiddleware(object):
class RequestPOSTMiddleware:
def __init__(self, get_response):
self.get_response = get_response

View File

@ -5,8 +5,6 @@ shortcuts for automatically creating serializers based on a given model class.
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
@ -20,10 +18,9 @@ from django.core.validators import (
)
from django.db import models
from django.test import TestCase
from django.utils import six
from rest_framework import serializers
from rest_framework.compat import postgres_fields, unicode_repr
from rest_framework.compat import postgres_fields
from .models import NestedForeignKeySource
@ -193,7 +190,7 @@ class TestRegularFieldMappings(TestCase):
file_path_field = FilePathField(path='/tmp/')
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_field_options(self):
class TestSerializer(serializers.ModelSerializer):
@ -212,14 +209,7 @@ class TestRegularFieldMappings(TestCase):
descriptive_field = IntegerField(help_text='Some help text', label='A label')
choices_field = ChoiceField(choices=(('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')))
""")
if six.PY2:
# This particular case is too awkward to resolve fully across
# both py2 and py3.
expected = expected.replace(
"('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')",
"(u'red', u'Red'), (u'blue', u'Blue'), (u'green', u'Green')"
)
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
# merge this into test_regular_fields / RegularFieldsModel when
# Django 2.1 is the minimum supported version
@ -238,7 +228,7 @@ class TestRegularFieldMappings(TestCase):
field = BooleanField(allow_null=True, required=False)
""")
self.assertEqual(unicode_repr(NullableBooleanSerializer()), expected)
self.assertEqual(repr(NullableBooleanSerializer()), expected)
def test_method_field(self):
"""
@ -382,7 +372,7 @@ class TestDurationFieldMapping(TestCase):
id = IntegerField(label='ID', read_only=True)
duration_field = DurationField()
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_duration_field_with_validators(self):
class ValidatedDurationFieldModel(models.Model):
@ -407,7 +397,7 @@ class TestDurationFieldMapping(TestCase):
id = IntegerField(label='ID', read_only=True)
duration_field = DurationField(max_value=datetime.timedelta(days=3), min_value=datetime.timedelta(days=1))
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
class TestGenericIPAddressFieldValidation(TestCase):
@ -424,7 +414,7 @@ class TestGenericIPAddressFieldValidation(TestCase):
self.assertFalse(s.is_valid())
self.assertEqual(1, len(s.errors['address']),
'Unexpected number of validation errors: '
'{0}'.format(s.errors))
'{}'.format(s.errors))
@pytest.mark.skipif('not postgres_fields')
@ -442,7 +432,7 @@ class TestPosgresFieldsMapping(TestCase):
TestSerializer():
hstore_field = HStoreField()
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_array_field(self):
class ArrayFieldModel(models.Model):
@ -457,7 +447,7 @@ class TestPosgresFieldsMapping(TestCase):
TestSerializer():
array_field = ListField(child=CharField(label='Array field', validators=[<django.core.validators.MaxLengthValidator object>]))
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_json_field(self):
class JSONFieldModel(models.Model):
@ -472,7 +462,7 @@ class TestPosgresFieldsMapping(TestCase):
TestSerializer():
json_field = JSONField(style={'base_template': 'textarea.html'})
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
# Tests for relational field mappings.
@ -530,7 +520,7 @@ class TestRelationalFieldMappings(TestCase):
many_to_many = PrimaryKeyRelatedField(allow_empty=False, many=True, queryset=ManyToManyTargetModel.objects.all())
through = PrimaryKeyRelatedField(many=True, read_only=True)
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_nested_relations(self):
class TestSerializer(serializers.ModelSerializer):
@ -555,7 +545,7 @@ class TestRelationalFieldMappings(TestCase):
id = IntegerField(label='ID', read_only=True)
name = CharField(max_length=100)
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_hyperlinked_relations(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@ -571,7 +561,7 @@ class TestRelationalFieldMappings(TestCase):
many_to_many = HyperlinkedRelatedField(allow_empty=False, many=True, queryset=ManyToManyTargetModel.objects.all(), view_name='manytomanytargetmodel-detail')
through = HyperlinkedRelatedField(many=True, read_only=True, view_name='throughtargetmodel-detail')
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_nested_hyperlinked_relations(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@ -596,7 +586,7 @@ class TestRelationalFieldMappings(TestCase):
url = HyperlinkedIdentityField(view_name='throughtargetmodel-detail')
name = CharField(max_length=100)
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_nested_hyperlinked_relations_starred_source(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@ -627,7 +617,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
""")
self.maxDiff = None
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_nested_unique_together_relations(self):
class TestSerializer(serializers.HyperlinkedModelSerializer):
@ -646,14 +636,7 @@ class TestRelationalFieldMappings(TestCase):
url = HyperlinkedIdentityField(view_name='onetoonetargetmodel-detail')
name = CharField(max_length=100)
""")
if six.PY2:
# This case is also too awkward to resolve fully across both py2
# and py3. (See above)
expected = expected.replace(
"('foreign_key', 'one_to_one')",
"(u'foreign_key', u'one_to_one')"
)
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_pk_reverse_foreign_key(self):
class TestSerializer(serializers.ModelSerializer):
@ -667,7 +650,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_foreign_key = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_pk_reverse_one_to_one(self):
class TestSerializer(serializers.ModelSerializer):
@ -681,7 +664,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_one_to_one = PrimaryKeyRelatedField(queryset=RelationalModel.objects.all())
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_pk_reverse_many_to_many(self):
class TestSerializer(serializers.ModelSerializer):
@ -695,7 +678,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_many_to_many = PrimaryKeyRelatedField(many=True, queryset=RelationalModel.objects.all())
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
def test_pk_reverse_through(self):
class TestSerializer(serializers.ModelSerializer):
@ -709,7 +692,7 @@ class TestRelationalFieldMappings(TestCase):
name = CharField(max_length=100)
reverse_through = PrimaryKeyRelatedField(many=True, read_only=True)
""")
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
class DisplayValueTargetModel(models.Model):
@ -1078,9 +1061,9 @@ class TestMetaInheritance(TestCase):
char_field = CharField(max_length=100)
non_model_field = CharField()
""")
self.assertEqual(unicode_repr(ChildSerializer()), child_expected)
self.assertEqual(unicode_repr(TestSerializer()), test_expected)
self.assertEqual(unicode_repr(ChildSerializer()), child_expected)
self.assertEqual(repr(ChildSerializer()), child_expected)
self.assertEqual(repr(TestSerializer()), test_expected)
self.assertEqual(repr(ChildSerializer()), child_expected)
class OneToOneTargetTestModel(models.Model):
@ -1149,14 +1132,14 @@ class Issue3674Test(TestCase):
title = CharField(max_length=64)
children = PrimaryKeyRelatedField(many=True, queryset=TestChildModel.objects.all())
""")
self.assertEqual(unicode_repr(TestParentModelSerializer()), parent_expected)
self.assertEqual(repr(TestParentModelSerializer()), parent_expected)
child_expected = dedent("""
TestChildModelSerializer():
value = CharField(max_length=64, validators=[<UniqueValidator(queryset=TestChildModel.objects.all())>])
parent = PrimaryKeyRelatedField(queryset=TestParentModel.objects.all())
""")
self.assertEqual(unicode_repr(TestChildModelSerializer()), child_expected)
self.assertEqual(repr(TestChildModelSerializer()), child_expected)
def test_nonID_PK_foreignkey_model_serializer(self):
@ -1248,7 +1231,7 @@ class TestFieldSource(TestCase):
number_field = IntegerField(source='integer_field')
""")
self.maxDiff = None
self.assertEqual(unicode_repr(TestSerializer()), expected)
self.assertEqual(repr(TestSerializer()), expected)
class Issue6110TestModel(models.Model):

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.db import models
from django.test import TestCase

View File

@ -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 @@ class TestAcceptedMediaType(TestCase):
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):

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.db import models
from django.test import TestCase

View File

@ -1,11 +1,7 @@
# coding: utf-8
from __future__ import unicode_literals
import pytest
from django.core.paginator import Paginator as DjangoPaginator
from django.db import models
from django.test import TestCase
from django.utils import six
from rest_framework import (
exceptions, filters, generics, pagination, serializers, status
@ -208,7 +204,7 @@ class TestPageNumberPagination:
]
}
assert self.pagination.display_page_controls
assert isinstance(self.pagination.to_html(), six.text_type)
assert isinstance(self.pagination.to_html(), str)
def test_second_page(self):
request = Request(factory.get('/', {'page': 2}))
@ -314,7 +310,7 @@ class TestPageNumberPaginationOverride:
]
}
assert not self.pagination.display_page_controls
assert isinstance(self.pagination.to_html(), six.text_type)
assert isinstance(self.pagination.to_html(), str)
def test_invalid_page(self):
request = Request(factory.get('/', {'page': 'invalid'}))
@ -369,7 +365,7 @@ class TestLimitOffset:
]
}
assert self.pagination.display_page_controls
assert isinstance(self.pagination.to_html(), six.text_type)
assert isinstance(self.pagination.to_html(), str)
def test_pagination_not_applied_if_limit_or_default_limit_not_set(self):
class MockPagination(pagination.LimitOffsetPagination):
@ -503,7 +499,7 @@ class TestLimitOffset:
content = self.get_paginated_content(queryset)
next_limit = self.pagination.default_limit
next_offset = self.pagination.default_limit
next_url = 'http://testserver/?limit={0}&offset={1}'.format(next_limit, next_offset)
next_url = 'http://testserver/?limit={}&offset={}'.format(next_limit, next_offset)
assert queryset == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert content.get('next') == next_url
@ -516,7 +512,7 @@ class TestLimitOffset:
content = self.get_paginated_content(queryset)
next_limit = self.pagination.default_limit
next_offset = self.pagination.default_limit
next_url = 'http://testserver/?limit={0}&offset={1}'.format(next_limit, next_offset)
next_url = 'http://testserver/?limit={}&offset={}'.format(next_limit, next_offset)
assert queryset == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert content.get('next') == next_url
@ -532,9 +528,9 @@ class TestLimitOffset:
max_limit = self.pagination.max_limit
next_offset = offset + max_limit
prev_offset = offset - max_limit
base_url = 'http://testserver/?limit={0}'.format(max_limit)
next_url = base_url + '&offset={0}'.format(next_offset)
prev_url = base_url + '&offset={0}'.format(prev_offset)
base_url = 'http://testserver/?limit={}'.format(max_limit)
next_url = base_url + '&offset={}'.format(next_offset)
prev_url = base_url + '&offset={}'.format(prev_offset)
assert queryset == list(range(51, 66))
assert content.get('next') == next_url
assert content.get('previous') == prev_url
@ -632,7 +628,7 @@ class CursorPaginationTestsMixin:
assert current == [1, 1, 1, 1, 1]
assert next == [1, 2, 3, 4, 4]
assert isinstance(self.pagination.to_html(), six.text_type)
assert isinstance(self.pagination.to_html(), str)
def test_cursor_pagination_with_page_size(self):
(previous, current, next, previous_url, next_url) = self.get_pages('/?page_size=20')
@ -799,11 +795,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

View File

@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import io
import math
@ -11,7 +8,6 @@ from django.core.files.uploadhandler import (
)
from django.http.request import RawPostDataException
from django.test import TestCase
from django.utils.six import StringIO
from rest_framework.exceptions import ParseError
from rest_framework.parsers import (
@ -34,7 +30,7 @@ class TestFormParser(TestCase):
""" Make sure the `QueryDict` works OK """
parser = FormParser()
stream = StringIO(self.string)
stream = io.StringIO(self.string)
data = parser.parse(stream)
assert Form(data).is_valid() is True
@ -42,7 +38,7 @@ class TestFormParser(TestCase):
class TestFileUploadParser(TestCase):
def setUp(self):
class MockRequest(object):
class MockRequest:
pass
self.stream = io.BytesIO(
"Test text file".encode('utf-8')

View File

@ -1,8 +1,7 @@
from __future__ import unicode_literals
import base64
import unittest
import warnings
from unittest import mock
import django
import pytest
@ -15,7 +14,7 @@ from rest_framework import (
HTTP_HEADER_ENCODING, RemovedInDRF310Warning, authentication, generics,
permissions, serializers, status, views
)
from rest_framework.compat import PY36, is_guardian_installed, mock
from rest_framework.compat import PY36, is_guardian_installed
from rest_framework.filters import DjangoObjectPermissionsFilter
from rest_framework.routers import DefaultRouter
from rest_framework.test import APIRequestFactory
@ -331,14 +330,14 @@ class ObjectPermissionsIntegrationTests(TestCase):
everyone = Group.objects.create(name='everyone')
model_name = BasicPermModel._meta.model_name
app_label = BasicPermModel._meta.app_label
f = '{0}_{1}'.format
f = '{}_{}'.format
perms = {
'view': f('view', model_name),
'change': f('change', model_name),
'delete': f('delete', model_name)
}
for perm in perms.values():
perm = '{0}.{1}'.format(app_label, perm)
perm = '{}.{}'.format(app_label, perm)
assign_perm(perm, everyone)
everyone.user_set.add(*users.values())

View File

@ -26,7 +26,7 @@ class TestStringRelatedField(APISimpleTestCase):
assert representation == '<MockObject name=foo, pk=1>'
class MockApiSettings(object):
class MockApiSettings:
def __init__(self, cutoff, cutoff_text):
self.HTML_SELECT_CUTOFF = cutoff
self.HTML_SELECT_CUTOFF_TEXT = cutoff_text

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.conf.urls import url
from django.test import TestCase, override_settings

View File

@ -1,7 +1,4 @@
from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
from rest_framework import serializers
from tests.models import (
@ -263,7 +260,7 @@ class PKForeignKeyTests(TestCase):
instance = ForeignKeySource.objects.get(pk=1)
serializer = ForeignKeySourceSerializer(instance, data=data)
assert not serializer.is_valid()
assert serializer.errors == {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]}
assert serializer.errors == {'target': ['Incorrect type. Expected pk value, received str.']}
def test_reverse_foreign_key_update(self):
data = {'id': 2, 'name': 'target-2', 'sources': [1, 3]}
@ -562,7 +559,7 @@ class OneToOnePrimaryKeyTests(TestCase):
# When: Trying to create a second object
second_source = OneToOnePKSourceSerializer(data=data)
self.assertFalse(second_source.is_valid())
expected = {'target': [u'one to one pk source with this target already exists.']}
expected = {'target': ['one to one pk source with this target already exists.']}
self.assertDictEqual(second_source.errors, expected)
def test_one_to_one_when_primary_key_does_not_exist(self):

View File

@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import re
from collections import OrderedDict
@ -11,7 +8,6 @@ from django.db import models
from django.http.request import HttpRequest
from django.template import loader
from django.test import TestCase, override_settings
from django.utils import six
from django.utils.safestring import SafeText
from django.utils.translation import ugettext_lazy as _
@ -175,7 +171,7 @@ class RendererEndToEndTests(TestCase):
resp = self.client.head('/')
self.assertEqual(resp.status_code, DUMMYSTATUS)
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, six.b(''))
self.assertEqual(resp.content, b'')
def test_default_renderer_serializes_content_on_accept_any(self):
"""If the Accept header is set to */* the default renderer should serialize the response."""
@ -348,7 +344,7 @@ class JSONRendererTests(TestCase):
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 +643,7 @@ class BrowsableAPIRendererTests(URLPatternsTestCase):
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

View File

@ -1,8 +1,6 @@
"""
Tests for content parsing, and form-overloaded content parsing.
"""
from __future__ import unicode_literals
import os.path
import tempfile
@ -15,7 +13,6 @@ from django.contrib.sessions.middleware import SessionMiddleware
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http.request import RawPostDataException
from django.test import TestCase, override_settings
from django.utils import six
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
@ -82,7 +79,7 @@ class TestContentParsing(TestCase):
Ensure request.data returns content for POST request with
non-form content.
"""
content = six.b('qwerty')
content = b'qwerty'
content_type = 'text/plain'
request = Request(factory.post('/', content, content_type=content_type))
request.parsers = (PlainTextParser(),)
@ -121,7 +118,7 @@ class TestContentParsing(TestCase):
Ensure request.data returns content for PUT request with
non-form content.
"""
content = six.b('qwerty')
content = b'qwerty'
content_type = 'text/plain'
request = Request(factory.put('/', content, content_type=content_type))
request.parsers = (PlainTextParser(), )
@ -235,7 +232,7 @@ class TestUserSetter(TestCase):
This proves that when an AttributeError is raised inside of the request.user
property, that we can handle this and report the true, underlying error.
"""
class AuthRaisesAttributeError(object):
class AuthRaisesAttributeError:
def authenticate(self, request):
self.MISSPELLED_NAME_THAT_DOESNT_EXIST
@ -249,10 +246,6 @@ class TestUserSetter(TestCase):
with pytest.raises(WrappedAttributeError, match=expected):
request.user
# python 2 hasattr fails for *any* exception, not just AttributeError
if six.PY2:
return
with pytest.raises(WrappedAttributeError, match=expected):
hasattr(request, 'user')

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import unittest
from django.conf.urls import url

View File

@ -1,8 +1,5 @@
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 rest_framework import generics, routers, serializers, status, viewsets
from rest_framework.parsers import JSONParser
@ -150,7 +147,7 @@ class RendererIntegrationTests(TestCase):
resp = self.client.head('/')
self.assertEqual(resp.status_code, DUMMYSTATUS)
self.assertEqual(resp['Content-Type'], RendererA.media_type + '; charset=utf-8')
self.assertEqual(resp.content, six.b(''))
self.assertEqual(resp.content, b'')
def test_default_renderer_serializes_content_on_accept_any(self):
"""If the Accept header is set to */* the default renderer should serialize the response."""
@ -260,7 +257,7 @@ class Issue807Tests(TestCase):
"""
headers = {"HTTP_ACCEPT": RendererA.media_type}
resp = self.client.get('/', **headers)
expected = "{0}; charset={1}".format(RendererA.media_type, 'utf-8')
expected = "{}; charset={}".format(RendererA.media_type, 'utf-8')
self.assertEqual(expected, resp['Content-Type'])
def test_if_there_is_charset_specified_on_renderer_it_gets_appended(self):
@ -270,7 +267,7 @@ class Issue807Tests(TestCase):
"""
headers = {"HTTP_ACCEPT": RendererC.media_type}
resp = self.client.get('/', **headers)
expected = "{0}; charset={1}".format(RendererC.media_type, RendererC.charset)
expected = "{}; charset={}".format(RendererC.media_type, RendererC.charset)
self.assertEqual(expected, resp['Content-Type'])
def test_content_type_set_explicitly_on_response(self):

View File

@ -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 @@ urlpatterns = [
]
class MockVersioningScheme(object):
class MockVersioningScheme:
def __init__(self, raise_error=False):
self.raise_error = raise_error

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
import warnings
from collections import namedtuple

View File

@ -29,7 +29,7 @@ from .models import BasicModel, ForeignKeySource, ManyToManySource
factory = APIRequestFactory()
class MockUser(object):
class MockUser:
def is_authenticated(self):
return True
@ -112,7 +112,7 @@ class ExampleViewSet(ModelViewSet):
def get_serializer(self, *args, **kwargs):
assert self.request
assert self.action
return super(ExampleViewSet, self).get_serializer(*args, **kwargs)
return super().get_serializer(*args, **kwargs)
@action(methods=['get', 'post'], detail=False)
def documented_custom_action(self, request):
@ -1303,7 +1303,7 @@ def test_head_and_options_methods_are_excluded():
@pytest.mark.skipif(not coreapi, reason='coreapi is not installed')
class TestAutoSchemaAllowsFilters(object):
class TestAutoSchemaAllowsFilters:
class MockAPIView(APIView):
filter_backends = [filters.OrderingFilter]

View File

@ -1,16 +1,13 @@
# coding: utf-8
from __future__ import unicode_literals
import inspect
import pickle
import re
import unittest
from collections import ChainMap
import pytest
from django.db import models
from rest_framework import exceptions, fields, relations, serializers
from rest_framework.compat import Mapping, unicode_repr
from rest_framework.compat import Mapping
from rest_framework.fields import Field
from .models import (
@ -18,15 +15,9 @@ from .models import (
)
from .utils import MockObject
try:
from collections import ChainMap
except ImportError:
ChainMap = False
# Test serializer fields imports.
# -------------------------------
class TestFieldImports:
def is_field(self, name, value):
return (
@ -130,7 +121,6 @@ class TestSerializer:
assert not serializer.is_valid()
assert serializer.errors == {'non_field_errors': ['No data provided']}
@unittest.skipUnless(ChainMap, 'requires python 3.3')
def test_serialize_chainmap(self):
data = ChainMap({'char': 'abc'}, {'integer': 123})
serializer = self.Serializer(data=data)
@ -160,7 +150,7 @@ class TestSerializer:
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)
@ -171,7 +161,7 @@ class TestSerializer:
latitude = serializers.FloatField(source='y')
def to_internal_value(self, data):
kwargs = super(NestedPointSerializer, self).to_internal_value(data)
kwargs = super().to_internal_value(data)
return Point(srid=4326, **kwargs)
serializer = NestedPointSerializer(data={'longitude': 6.958307, 'latitude': 50.941357})
@ -201,7 +191,7 @@ class TestSerializer:
def raise_exception(value):
raise exceptions.ValidationError('Raised error')
for validators in ([raise_exception], (raise_exception,), set([raise_exception])):
for validators in ([raise_exception], (raise_exception,), {raise_exception}):
class ExampleSerializer(serializers.Serializer):
char = serializers.CharField(validators=validators)
integer = serializers.IntegerField()
@ -397,7 +387,7 @@ class TestIncorrectlyConfigured:
class TestUnicodeRepr:
def test_unicode_repr(self):
def test_repr(self):
class ExampleSerializer(serializers.Serializer):
example = serializers.CharField()
@ -406,7 +396,7 @@ class TestUnicodeRepr:
self.example = '한국'
def __repr__(self):
return unicode_repr(self.example)
return repr(self.example)
instance = ExampleObject()
serializer = ExampleSerializer(instance)
@ -609,7 +599,7 @@ class Test2555Regression:
def test_serializer_context(self):
class NestedSerializer(serializers.Serializer):
def __init__(self, *args, **kwargs):
super(NestedSerializer, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
# .context should not cache
self.context

View File

@ -1,10 +1,7 @@
"""
Tests to cover bulk create and update using serializers.
"""
from __future__ import unicode_literals
from django.test import TestCase
from django.utils import six
from rest_framework import serializers
@ -87,8 +84,7 @@ class BulkCreateSerializerTests(TestCase):
serializer = self.BookSerializer(data=data, many=True)
assert serializer.is_valid() is False
text_type_string = six.text_type.__name__
message = 'Invalid data. Expected a dictionary, but got %s.' % text_type_string
message = 'Invalid data. Expected a dictionary, but got str.'
expected_errors = [
{'non_field_errors': [message]},
{'non_field_errors': [message]},

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.test import TestCase, override_settings
from rest_framework.settings import APISettings, api_settings

View File

@ -1,5 +1,3 @@
from __future__ import unicode_literals
from django.test import TestCase
from rest_framework.status import (

Some files were not shown because too many files have changed in this diff Show More