Skip to content

Commit 0407a0d

Browse files
carltongibsonauvipyRizwan Mansuri
authored
Dropped Python 2 compatibility. (encode#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>
1 parent 5c992ba commit 0407a0d

File tree

111 files changed

+473
-795
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+473
-795
lines changed

.travis.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ dist: xenial
44
matrix:
55
fast_finish: true
66
include:
7-
- { python: "2.7", env: DJANGO=1.11 }
87

98
- { python: "3.4", env: DJANGO=1.11 }
109
- { python: "3.4", env: DJANGO=2.0 }
@@ -26,8 +25,8 @@ matrix:
2625
- { python: "3.7", env: DJANGO=master }
2726

2827
- { python: "3.7", env: TOXENV=base }
29-
- { python: "2.7", env: TOXENV=lint }
30-
- { python: "2.7", env: TOXENV=docs }
28+
- { python: "3.7", env: TOXENV=lint }
29+
- { python: "3.7", env: TOXENV=docs }
3130

3231
- python: "3.7"
3332
env: TOXENV=dist

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ There is a live example API for testing purposes, [available here][sandbox].
5353

5454
# Requirements
5555

56-
* Python (2.7, 3.4, 3.5, 3.6, 3.7)
56+
* Python (3.4, 3.5, 3.6, 3.7)
5757
* Django (1.11, 2.0, 2.1, 2.2)
5858

5959
We **highly recommend** and only officially support the latest patch release of

docs/api-guide/fields.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ Our `ColorField` class above currently does not perform any data validation.
629629
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
630630

631631
def to_internal_value(self, data):
632-
if not isinstance(data, six.text_type):
632+
if not isinstance(data, str):
633633
msg = 'Incorrect type. Expected a string, but got %s'
634634
raise ValidationError(msg % type(data).__name__)
635635

@@ -653,7 +653,7 @@ The `.fail()` method is a shortcut for raising `ValidationError` that takes a me
653653
}
654654

655655
def to_internal_value(self, data):
656-
if not isinstance(data, six.text_type):
656+
if not isinstance(data, str):
657657
self.fail('incorrect_type', input_type=type(data).__name__)
658658

659659
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):

rest_framework/authentication.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
"""
22
Provides various authentication policies.
33
"""
4-
from __future__ import unicode_literals
5-
64
import base64
75
import binascii
86

97
from django.contrib.auth import authenticate, get_user_model
108
from django.middleware.csrf import CsrfViewMiddleware
11-
from django.utils.six import text_type
129
from django.utils.translation import ugettext_lazy as _
1310

1411
from rest_framework import HTTP_HEADER_ENCODING, exceptions
@@ -21,7 +18,7 @@ def get_authorization_header(request):
2118
Hide some test client ickyness where the header can be unicode.
2219
"""
2320
auth = request.META.get('HTTP_AUTHORIZATION', b'')
24-
if isinstance(auth, text_type):
21+
if isinstance(auth, str):
2522
# Work around django test client oddness
2623
auth = auth.encode(HTTP_HEADER_ENCODING)
2724
return auth
@@ -33,7 +30,7 @@ def _reject(self, request, reason):
3330
return reason
3431

3532

36-
class BaseAuthentication(object):
33+
class BaseAuthentication:
3734
"""
3835
All authentication classes should extend BaseAuthentication.
3936
"""

rest_framework/authtoken/management/commands/drf_create_token.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ def handle(self, *args, **options):
3838
token = self.create_user_token(username, reset_token)
3939
except UserModel.DoesNotExist:
4040
raise CommandError(
41-
'Cannot create the Token: user {0} does not exist'.format(
41+
'Cannot create the Token: user {} does not exist'.format(
4242
username)
4343
)
4444
self.stdout.write(
45-
'Generated token {0} for user {1}'.format(token.key, username))
45+
'Generated token {} for user {}'.format(token.key, username))

rest_framework/authtoken/migrations/0001_initial.py

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
from __future__ import unicode_literals
3-
41
from django.conf import settings
52
from django.db import migrations, models
63

rest_framework/authtoken/migrations/0002_auto_20160226_1747.py

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
from __future__ import unicode_literals
3-
41
from django.conf import settings
52
from django.db import migrations, models
63

rest_framework/authtoken/models.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33

44
from django.conf import settings
55
from django.db import models
6-
from django.utils.encoding import python_2_unicode_compatible
76
from django.utils.translation import ugettext_lazy as _
87

98

10-
@python_2_unicode_compatible
119
class Token(models.Model):
1210
"""
1311
The default authorization token model.
@@ -32,7 +30,7 @@ class Meta:
3230
def save(self, *args, **kwargs):
3331
if not self.key:
3432
self.key = self.generate_key()
35-
return super(Token, self).save(*args, **kwargs)
33+
return super().save(*args, **kwargs)
3634

3735
def generate_key(self):
3836
return binascii.hexlify(os.urandom(20)).decode()

rest_framework/compat.py

+6-52
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,13 @@
22
The `compat` module provides support for backwards compatibility with older
33
versions of Django/Python, and compatibility wrappers around optional packages.
44
"""
5-
6-
from __future__ import unicode_literals
7-
85
import sys
6+
from collections.abc import Mapping, MutableMapping # noqa
97

108
from django.conf import settings
119
from django.core import validators
12-
from django.utils import six
1310
from django.views.generic import View
1411

15-
try:
16-
# Python 3
17-
from collections.abc import Mapping, MutableMapping # noqa
18-
except ImportError:
19-
# Python 2.7
20-
from collections import Mapping, MutableMapping # noqa
21-
2212
try:
2313
from django.urls import ( # noqa
2414
URLPattern,
@@ -36,11 +26,6 @@
3626
except ImportError:
3727
ProhibitNullCharactersValidator = None
3828

39-
try:
40-
from unittest import mock
41-
except ImportError:
42-
mock = None
43-
4429

4530
def get_original_route(urlpattern):
4631
"""
@@ -89,23 +74,6 @@ def make_url_resolver(regex, urlpatterns):
8974
return URLResolver(regex, urlpatterns)
9075

9176

92-
def unicode_repr(instance):
93-
# Get the repr of an instance, but ensure it is a unicode string
94-
# on both python 3 (already the case) and 2 (not the case).
95-
if six.PY2:
96-
return repr(instance).decode('utf-8')
97-
return repr(instance)
98-
99-
100-
def unicode_to_repr(value):
101-
# Coerce a unicode string to the correct repr return type, depending on
102-
# the Python version. We wrap all our `__repr__` implementations with
103-
# this and then use unicode throughout internally.
104-
if six.PY2:
105-
return value.encode('utf-8')
106-
return value
107-
108-
10977
def unicode_http_header(value):
11078
# Coerce HTTP header value to unicode.
11179
if isinstance(value, bytes):
@@ -168,15 +136,6 @@ def is_guardian_installed():
168136
"""
169137
django-guardian is optional and only imported if in INSTALLED_APPS.
170138
"""
171-
try:
172-
import guardian
173-
except ImportError:
174-
guardian = None
175-
176-
if six.PY2 and (not guardian or guardian.VERSION >= (1, 5)):
177-
# Guardian 1.5.0, for Django 2.2 is NOT compatible with Python 2.7.
178-
# Remove when dropping PY2.
179-
return False
180139
return 'guardian' in settings.INSTALLED_APPS
181140

182141

@@ -289,17 +248,12 @@ def md_filter_add_syntax_highlight(md):
289248

290249
# `separators` argument to `json.dumps()` differs between 2.x and 3.x
291250
# See: https://bugs.python.org/issue22767
292-
if six.PY3:
293-
SHORT_SEPARATORS = (',', ':')
294-
LONG_SEPARATORS = (', ', ': ')
295-
INDENT_SEPARATORS = (',', ': ')
296-
else:
297-
SHORT_SEPARATORS = (b',', b':')
298-
LONG_SEPARATORS = (b', ', b': ')
299-
INDENT_SEPARATORS = (b',', b': ')
251+
SHORT_SEPARATORS = (',', ':')
252+
LONG_SEPARATORS = (', ', ': ')
253+
INDENT_SEPARATORS = (',', ': ')
300254

301255

302-
class CustomValidatorMessage(object):
256+
class CustomValidatorMessage:
303257
"""
304258
We need to avoid evaluation of `lazy` translated `message` in `django.core.validators.BaseValidator.__init__`.
305259
https://github.com/django/django/blob/75ed5900321d170debef4ac452b8b3cf8a1c2384/django/core/validators.py#L297
@@ -309,7 +263,7 @@ class CustomValidatorMessage(object):
309263

310264
def __init__(self, *args, **kwargs):
311265
self.message = kwargs.pop('message', self.message)
312-
super(CustomValidatorMessage, self).__init__(*args, **kwargs)
266+
super().__init__(*args, **kwargs)
313267

314268

315269
class MinValueValidator(CustomValidatorMessage, validators.MinValueValidator):

rest_framework/decorators.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@
66
based views, as well as the `@detail_route` and `@list_route` decorators, which are
77
used to annotate methods on viewsets that should be included by routers.
88
"""
9-
from __future__ import unicode_literals
10-
119
import types
1210
import warnings
1311

1412
from django.forms.utils import pretty_name
15-
from django.utils import six
1613

1714
from rest_framework import RemovedInDRF310Warning
1815
from rest_framework.views import APIView
@@ -28,7 +25,7 @@ def api_view(http_method_names=None):
2825
def decorator(func):
2926

3027
WrappedAPIView = type(
31-
six.PY3 and 'WrappedAPIView' or b'WrappedAPIView',
28+
'WrappedAPIView',
3229
(APIView,),
3330
{'__doc__': func.__doc__}
3431
)

rest_framework/exceptions.py

+11-15
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,14 @@
44
In addition Django's built in 403 and 404 exceptions are handled.
55
(`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
66
"""
7-
from __future__ import unicode_literals
8-
97
import math
108

119
from django.http import JsonResponse
12-
from django.utils import six
1310
from django.utils.encoding import force_text
1411
from django.utils.translation import ugettext_lazy as _
1512
from django.utils.translation import ungettext
1613

1714
from rest_framework import status
18-
from rest_framework.compat import unicode_to_repr
1915
from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList
2016

2117

@@ -64,19 +60,19 @@ def _get_full_details(detail):
6460
}
6561

6662

67-
class ErrorDetail(six.text_type):
63+
class ErrorDetail(str):
6864
"""
6965
A string-like object that can additionally have a code.
7066
"""
7167
code = None
7268

7369
def __new__(cls, string, code=None):
74-
self = super(ErrorDetail, cls).__new__(cls, string)
70+
self = super().__new__(cls, string)
7571
self.code = code
7672
return self
7773

7874
def __eq__(self, other):
79-
r = super(ErrorDetail, self).__eq__(other)
75+
r = super().__eq__(other)
8076
try:
8177
return r and self.code == other.code
8278
except AttributeError:
@@ -86,10 +82,10 @@ def __ne__(self, other):
8682
return not self.__eq__(other)
8783

8884
def __repr__(self):
89-
return unicode_to_repr('ErrorDetail(string=%r, code=%r)' % (
90-
six.text_type(self),
85+
return 'ErrorDetail(string=%r, code=%r)' % (
86+
str(self),
9187
self.code,
92-
))
88+
)
9389

9490
def __hash__(self):
9591
return hash(str(self))
@@ -113,7 +109,7 @@ def __init__(self, detail=None, code=None):
113109
self.detail = _get_error_details(detail, code)
114110

115111
def __str__(self):
116-
return six.text_type(self.detail)
112+
return str(self.detail)
117113

118114
def get_codes(self):
119115
"""
@@ -196,7 +192,7 @@ class MethodNotAllowed(APIException):
196192
def __init__(self, method, detail=None, code=None):
197193
if detail is None:
198194
detail = force_text(self.default_detail).format(method=method)
199-
super(MethodNotAllowed, self).__init__(detail, code)
195+
super().__init__(detail, code)
200196

201197

202198
class NotAcceptable(APIException):
@@ -206,7 +202,7 @@ class NotAcceptable(APIException):
206202

207203
def __init__(self, detail=None, code=None, available_renderers=None):
208204
self.available_renderers = available_renderers
209-
super(NotAcceptable, self).__init__(detail, code)
205+
super().__init__(detail, code)
210206

211207

212208
class UnsupportedMediaType(APIException):
@@ -217,7 +213,7 @@ class UnsupportedMediaType(APIException):
217213
def __init__(self, media_type, detail=None, code=None):
218214
if detail is None:
219215
detail = force_text(self.default_detail).format(media_type=media_type)
220-
super(UnsupportedMediaType, self).__init__(detail, code)
216+
super().__init__(detail, code)
221217

222218

223219
class Throttled(APIException):
@@ -238,7 +234,7 @@ def __init__(self, wait=None, detail=None, code=None):
238234
self.extra_detail_plural.format(wait=wait),
239235
wait))))
240236
self.wait = wait
241-
super(Throttled, self).__init__(detail, code)
237+
super().__init__(detail, code)
242238

243239

244240
def server_error(request, *args, **kwargs):

0 commit comments

Comments
 (0)