mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-24 02:24:03 +03:00
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:
parent
5c992baf32
commit
0407a0df8a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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__}
|
||||
)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,39 +48,21 @@ class empty:
|
|||
pass
|
||||
|
||||
|
||||
if six.PY3:
|
||||
def is_simple_callable(obj):
|
||||
"""
|
||||
True if the object is a callable that takes no arguments.
|
||||
"""
|
||||
if not (inspect.isfunction(obj) or inspect.ismethod(obj) or isinstance(obj, functools.partial)):
|
||||
return False
|
||||
def is_simple_callable(obj):
|
||||
"""
|
||||
True if the object is a callable that takes no arguments.
|
||||
"""
|
||||
if not (inspect.isfunction(obj) or inspect.ismethod(obj) or isinstance(obj, functools.partial)):
|
||||
return False
|
||||
|
||||
sig = inspect.signature(obj)
|
||||
params = sig.parameters.values()
|
||||
return all(
|
||||
param.kind == param.VAR_POSITIONAL or
|
||||
param.kind == param.VAR_KEYWORD or
|
||||
param.default != param.empty
|
||||
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
|
||||
sig = inspect.signature(obj)
|
||||
params = sig.parameters.values()
|
||||
return all(
|
||||
param.kind == param.VAR_POSITIONAL or
|
||||
param.kind == param.VAR_KEYWORD or
|
||||
param.default != param.empty
|
||||
for param in params
|
||||
)
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,8 +197,7 @@ 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')
|
||||
query_string = query_string.decode('iso-8859-1')
|
||||
r['QUERY_STRING'] = query_string
|
||||
r.update(extra)
|
||||
return self.generic('GET', path, **r)
|
||||
|
@ -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'):
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from rest_framework.compat import (
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.urls import get_script_prefix, resolve
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#! /usr/bin/env python
|
||||
from __future__ import print_function
|
||||
|
||||
#! /usr/bin/env python3
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[metadata]
|
||||
license_file = LICENSE.md
|
||||
|
||||
|
|
36
setup.py
36
setup.py
|
@ -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',
|
||||
]
|
||||
)
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from .views import MockView
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import MockView
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework import serializers
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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.']
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import pytest
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.test import TestCase
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.test import TestCase
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
from django.conf.urls import url
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]},
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from rest_framework.settings import APISettings, api_settings
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue
Block a user