Skip to content

Commit 65d6cba

Browse files
committed
Merge pull request #2200 from maryokhin/master
Clean up compat code
2 parents 9fb1b39 + d993018 commit 65d6cba

30 files changed

+90
-156
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Some tips on good issue reporting:
3333
* When describing issues try to phrase your ticket in terms of the *behavior* you think needs changing rather than the *code* you think need changing.
3434
* Search the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue.
3535
* If reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one.
36-
* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintainence overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.
36+
* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.
3737
* Closing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.
3838

3939
## Triaging issues
@@ -82,7 +82,7 @@ GitHub's documentation for working on pull requests is [available here][pull-req
8282

8383
Always run the tests before submitting pull requests, and ideally run `tox` in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django.
8484

85-
Once you've made a pull request take a look at the travis build status in the GitHub interface and make sure the tests are runnning as you'd expect.
85+
Once you've made a pull request take a look at the travis build status in the GitHub interface and make sure the tests are running as you'd expect.
8686

8787
![Travis status][travis-status]
8888

rest_framework/authentication.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ def authenticate(self, request):
267267
def authenticate_header(self, request):
268268
"""
269269
If permission is denied, return a '401 Unauthorized' response,
270-
with an appropraite 'WWW-Authenticate' header.
270+
with an appropriate 'WWW-Authenticate' header.
271271
"""
272272
return 'OAuth realm="%s"' % self.www_authenticate_realm
273273

rest_framework/authtoken/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import binascii
22
import os
3+
34
from django.conf import settings
45
from django.db import models
6+
from django.utils.encoding import python_2_unicode_compatible
57

68

79
# Prior to Django 1.5, the AUTH_USER_MODEL setting does not exist.
@@ -11,6 +13,7 @@
1113
AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
1214

1315

16+
@python_2_unicode_compatible
1417
class Token(models.Model):
1518
"""
1619
The default authorization token model.
@@ -35,5 +38,5 @@ def save(self, *args, **kwargs):
3538
def generate_key(self):
3639
return binascii.hexlify(os.urandom(20)).decode()
3740

38-
def __unicode__(self):
41+
def __str__(self):
3942
return self.key

rest_framework/compat.py

Lines changed: 14 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,14 @@
66
# flake8: noqa
77
from __future__ import unicode_literals
88

9+
import inspect
10+
911
from django.core.exceptions import ImproperlyConfigured
12+
from django.utils.encoding import force_text
13+
from django.utils.six.moves.urllib import parse as urlparse
1014
from django.conf import settings
1115
from django.utils import six
1216
import django
13-
import inspect
14-
15-
16-
# Handle django.utils.encoding rename in 1.5 onwards.
17-
# smart_unicode -> smart_text
18-
# force_unicode -> force_text
19-
try:
20-
from django.utils.encoding import smart_text
21-
except ImportError:
22-
from django.utils.encoding import smart_unicode as smart_text
23-
try:
24-
from django.utils.encoding import force_text
25-
except ImportError:
26-
from django.utils.encoding import force_unicode as force_text
2717

2818

2919
# OrderedDict only available in Python 2.7.
@@ -32,7 +22,7 @@
3222
# For Django <= 1.6 and Python 2.6 fall back to OrderedDict.
3323
try:
3424
from collections import OrderedDict
35-
except:
25+
except ImportError:
3626
from django.utils.datastructures import SortedDict as OrderedDict
3727

3828

@@ -49,7 +39,6 @@
4939
except ImportError:
5040
django_filters = None
5141

52-
5342
if django.VERSION >= (1, 6):
5443
def clean_manytomany_helptext(text):
5544
return text
@@ -72,30 +61,6 @@ def clean_manytomany_helptext(text):
7261
pass
7362

7463

75-
# cStringIO only if it's available, otherwise StringIO
76-
try:
77-
import cStringIO.StringIO as StringIO
78-
except ImportError:
79-
StringIO = six.StringIO
80-
81-
BytesIO = six.BytesIO
82-
83-
84-
# urlparse compat import (Required because it changed in python 3.x)
85-
try:
86-
from urllib import parse as urlparse
87-
except ImportError:
88-
import urlparse
89-
90-
# UserDict moves in Python 3
91-
try:
92-
from UserDict import UserDict
93-
from UserDict import DictMixin
94-
except ImportError:
95-
from collections import UserDict
96-
from collections import MutableMapping as DictMixin
97-
98-
9964
def get_model_name(model_cls):
10065
try:
10166
return model_cls._meta.model_name
@@ -104,14 +69,6 @@ def get_model_name(model_cls):
10469
return model_cls._meta.module_name
10570

10671

107-
def get_concrete_model(model_cls):
108-
try:
109-
return model_cls._meta.concrete_model
110-
except AttributeError:
111-
# 1.3 does not include concrete model
112-
return model_cls
113-
114-
11572
# View._allowed_methods only present from 1.5 onwards
11673
if django.VERSION >= (1, 5):
11774
from django.views.generic import View
@@ -123,7 +80,6 @@ def _allowed_methods(self):
12380
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
12481

12582

126-
12783
# MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+
12884
if django.VERSION >= (1, 8):
12985
from django.core.validators import MinValueValidator, MaxValueValidator
@@ -187,33 +143,30 @@ def __init__(self, *args, **kwargs):
187143
# RequestFactory only provides `generic` from 1.5 onwards
188144
from django.test.client import RequestFactory as DjangoRequestFactory
189145
from django.test.client import FakePayload
146+
190147
try:
191148
# In 1.5 the test client uses force_bytes
192149
from django.utils.encoding import force_bytes as force_bytes_or_smart_bytes
193150
except ImportError:
194151
# In 1.4 the test client just uses smart_str
195152
from django.utils.encoding import smart_str as force_bytes_or_smart_bytes
196153

154+
197155
class RequestFactory(DjangoRequestFactory):
198156
def generic(self, method, path,
199157
data='', content_type='application/octet-stream', **extra):
200158
parsed = urlparse.urlparse(path)
201159
data = force_bytes_or_smart_bytes(data, settings.DEFAULT_CHARSET)
202160
r = {
203-
'PATH_INFO': self._get_path(parsed),
204-
'QUERY_STRING': force_text(parsed[4]),
161+
'PATH_INFO': self._get_path(parsed),
162+
'QUERY_STRING': force_text(parsed[4]),
205163
'REQUEST_METHOD': six.text_type(method),
206164
}
207165
if data:
208166
r.update({
209167
'CONTENT_LENGTH': len(data),
210-
'CONTENT_TYPE': six.text_type(content_type),
211-
'wsgi.input': FakePayload(data),
212-
})
213-
elif django.VERSION <= (1, 4):
214-
# For 1.3 we need an empty WSGI payload
215-
r.update({
216-
'wsgi.input': FakePayload('')
168+
'CONTENT_TYPE': six.text_type(content_type),
169+
'wsgi.input': FakePayload(data),
217170
})
218171
r.update(extra)
219172
return self.request(**r)
@@ -287,10 +240,12 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp):
287240
import provider as oauth2_provider
288241
from provider import scope as oauth2_provider_scope
289242
from provider import constants as oauth2_constants
243+
290244
if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
291245
# 0.2.3 and 0.2.4 are supported version that do not support
292246
# timezone aware datetimes
293247
import datetime
248+
294249
provider_now = datetime.datetime.now
295250
else:
296251
# Any other supported version does use timezone aware datetimes
@@ -301,45 +256,11 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp):
301256
oauth2_constants = None
302257
provider_now = None
303258

304-
# `seperators` argument to `json.dumps()` differs between 2.x and 3.x
259+
# `separators` argument to `json.dumps()` differs between 2.x and 3.x
305260
# See: http://bugs.python.org/issue22767
306261
if six.PY3:
307262
SHORT_SEPARATORS = (',', ':')
308263
LONG_SEPARATORS = (', ', ': ')
309264
else:
310265
SHORT_SEPARATORS = (b',', b':')
311266
LONG_SEPARATORS = (b', ', b': ')
312-
313-
314-
# Handle lazy strings across Py2/Py3
315-
from django.utils.functional import Promise
316-
317-
if six.PY3:
318-
def is_non_str_iterable(obj):
319-
if (isinstance(obj, str) or
320-
(isinstance(obj, Promise) and obj._delegate_text)):
321-
return False
322-
return hasattr(obj, '__iter__')
323-
else:
324-
def is_non_str_iterable(obj):
325-
return hasattr(obj, '__iter__')
326-
327-
328-
try:
329-
from django.utils.encoding import python_2_unicode_compatible
330-
except ImportError:
331-
def python_2_unicode_compatible(klass):
332-
"""
333-
A decorator that defines __unicode__ and __str__ methods under Python 2.
334-
Under Python 3 it does nothing.
335-
336-
To support Python 2 and 3 with a single code base, define a __str__ method
337-
returning text and apply this decorator to the class.
338-
"""
339-
if '__str__' not in klass.__dict__:
340-
raise ValueError("@python_2_unicode_compatible cannot be applied "
341-
"to %s because it doesn't define __str__()." %
342-
klass.__name__)
343-
klass.__unicode__ = klass.__str__
344-
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
345-
return klass

rest_framework/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
(`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
66
"""
77
from __future__ import unicode_literals
8+
from django.utils.encoding import force_text
89

910
from django.utils.translation import ugettext_lazy as _
1011
from django.utils.translation import ungettext_lazy
1112
from rest_framework import status
12-
from rest_framework.compat import force_text
1313
import math
1414

1515

rest_framework/fields.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
from django.forms import ImageField as DjangoImageField
66
from django.utils import six, timezone
77
from django.utils.dateparse import parse_date, parse_datetime, parse_time
8-
from django.utils.encoding import is_protected_type
8+
from django.utils.encoding import is_protected_type, smart_text
99
from django.utils.translation import ugettext_lazy as _
1010
from rest_framework import ISO_8601
1111
from rest_framework.compat import (
12-
smart_text, EmailValidator, MinValueValidator, MaxValueValidator,
12+
EmailValidator, MinValueValidator, MaxValueValidator,
1313
MinLengthValidator, MaxLengthValidator, URLValidator, OrderedDict
1414
)
1515
from rest_framework.exceptions import ValidationError

rest_framework/metadata.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
"""
2-
The metadata API is used to allow cusomization of how `OPTIONS` requests
2+
The metadata API is used to allow customization of how `OPTIONS` requests
33
are handled. We currently provide a single default implementation that returns
44
some fairly ad-hoc information about the view.
55
6-
Future implementations might use JSON schema or other definations in order
6+
Future implementations might use JSON schema or other definitions in order
77
to return this information in a more standardized way.
88
"""
99
from __future__ import unicode_literals
1010

1111
from django.core.exceptions import PermissionDenied
1212
from django.http import Http404
13+
from django.utils.encoding import force_text
1314
from rest_framework import exceptions, serializers
14-
from rest_framework.compat import force_text, OrderedDict
15+
from rest_framework.compat import OrderedDict
1516
from rest_framework.request import clone_request
1617
from rest_framework.utils.field_mapping import ClassLookupDict
1718

rest_framework/parsers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
1313
from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter
1414
from django.utils import six
15-
from rest_framework.compat import etree, yaml, force_text, urlparse
15+
from django.utils.six.moves.urllib import parse as urlparse
16+
from django.utils.encoding import force_text
17+
from rest_framework.compat import etree, yaml
1618
from rest_framework.exceptions import ParseError
1719
from rest_framework import renderers
1820
import json

rest_framework/permissions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def has_object_permission(self, request, view, obj):
184184
if not user.has_perms(perms, obj):
185185
# If the user does not have permissions we need to determine if
186186
# they have read permissions to see 403, or not, and simply see
187-
# a 404 reponse.
187+
# a 404 response.
188188

189189
if request.method in ('GET', 'OPTIONS', 'HEAD'):
190190
# Read permissions already checked and failed, no need

rest_framework/relations.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
from rest_framework.compat import smart_text, urlparse
1+
from django.utils.encoding import smart_text
22
from rest_framework.fields import get_attribute, empty, Field
33
from rest_framework.reverse import reverse
44
from rest_framework.utils import html
55
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
66
from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch, Resolver404
77
from django.db.models.query import QuerySet
88
from django.utils import six
9+
from django.utils.six.moves.urllib import parse as urlparse
910
from django.utils.translation import ugettext_lazy as _
1011

1112

@@ -141,7 +142,7 @@ def get_attribute(self, instance):
141142
def get_iterable(self, instance, source_attrs):
142143
# For consistency with `get_attribute` we're using `serializable_value()`
143144
# here. Typically there won't be any difference, but some custom field
144-
# types might return a non-primative value for the pk otherwise.
145+
# types might return a non-primitive value for the pk otherwise.
145146
#
146147
# We could try to get smart with `values_list('pk', flat=True)`, which
147148
# would be better in some case, but would actually end up with *more*

rest_framework/renderers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
from django.template import Context, RequestContext, loader, Template
1717
from django.test.client import encode_multipart
1818
from django.utils import six
19+
from django.utils.encoding import smart_text
1920
from django.utils.xmlutils import SimplerXMLGenerator
21+
from django.utils.six.moves import StringIO
2022
from rest_framework import exceptions, serializers, status, VERSION
21-
from rest_framework.compat import (
22-
SHORT_SEPARATORS, LONG_SEPARATORS, StringIO, smart_text, yaml
23-
)
23+
from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, yaml
2424
from rest_framework.exceptions import ParseError
2525
from rest_framework.settings import api_settings
2626
from rest_framework.request import is_form_media_type, override_method
@@ -287,7 +287,9 @@ def get_template_names(self, response, view):
287287
return view.get_template_names()
288288
elif hasattr(view, 'template_name'):
289289
return [view.template_name]
290-
raise ImproperlyConfigured('Returned a template response with no `template_name` attribute set on either the view or response')
290+
raise ImproperlyConfigured(
291+
'Returned a template response with no `template_name` attribute set on either the view or response'
292+
)
291293

292294
def get_exception_template(self, response):
293295
template_names = [name % {'status_code': response.status_code}

rest_framework/request.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from django.http.multipartparser import parse_header
1515
from django.utils.datastructures import MultiValueDict
1616
from django.utils.datastructures import MergeDict as DjangoMergeDict
17+
from django.utils.six import BytesIO
1718
from rest_framework import HTTP_HEADER_ENCODING
1819
from rest_framework import exceptions
19-
from rest_framework.compat import BytesIO
2020
from rest_framework.settings import api_settings
2121
import warnings
2222

0 commit comments

Comments
 (0)