From 962194802b867b31d678e2fb46aa12510192caa7 Mon Sep 17 00:00:00 2001 From: Tymur Maryokhin Date: Thu, 4 Dec 2014 00:27:51 +0100 Subject: [PATCH] Removed custom python2_unicode_compatible. Closes #2138 (thanks @sh4r3m4n) --- rest_framework/authtoken/models.py | 5 +++- rest_framework/compat.py | 47 +++++++----------------------- rest_framework/utils/mediatypes.py | 5 ++-- tests/test_description.py | 5 ++-- tests/test_relations_generic.py | 2 +- 5 files changed, 19 insertions(+), 45 deletions(-) diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py index db21d44c356..a9676e11d6a 100644 --- a/rest_framework/authtoken/models.py +++ b/rest_framework/authtoken/models.py @@ -8,9 +8,12 @@ # Note that we don't perform this code in the compat module due to # bug report #1297 # See: https://github.com/tomchristie/django-rest-framework/issues/1297 +from django.utils.encoding import python_2_unicode_compatible + AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') +@python_2_unicode_compatible class Token(models.Model): """ The default authorization token model. @@ -35,5 +38,5 @@ def save(self, *args, **kwargs): def generate_key(self): return binascii.hexlify(os.urandom(20)).decode() - def __unicode__(self): + def __str__(self): return self.key diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 5bd85e74310..07cb342d2ea 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -49,7 +49,6 @@ except ImportError: django_filters = None - if django.VERSION >= (1, 6): def clean_manytomany_helptext(text): return text @@ -104,14 +103,6 @@ def get_model_name(model_cls): return model_cls._meta.module_name -def get_concrete_model(model_cls): - try: - return model_cls._meta.concrete_model - except AttributeError: - # 1.3 does not include concrete model - return model_cls - - # View._allowed_methods only present from 1.5 onwards if django.VERSION >= (1, 5): from django.views.generic import View @@ -123,7 +114,6 @@ def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)] - # MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+ if django.VERSION >= (1, 8): from django.core.validators import MinValueValidator, MaxValueValidator @@ -187,6 +177,7 @@ def __init__(self, *args, **kwargs): # RequestFactory only provides `generic` from 1.5 onwards from django.test.client import RequestFactory as DjangoRequestFactory from django.test.client import FakePayload + try: # In 1.5 the test client uses force_bytes from django.utils.encoding import force_bytes as force_bytes_or_smart_bytes @@ -194,21 +185,22 @@ def __init__(self, *args, **kwargs): # In 1.4 the test client just uses smart_str from django.utils.encoding import smart_str as force_bytes_or_smart_bytes + class RequestFactory(DjangoRequestFactory): def generic(self, method, path, data='', content_type='application/octet-stream', **extra): parsed = urlparse.urlparse(path) data = force_bytes_or_smart_bytes(data, settings.DEFAULT_CHARSET) r = { - 'PATH_INFO': self._get_path(parsed), - 'QUERY_STRING': force_text(parsed[4]), + 'PATH_INFO': self._get_path(parsed), + 'QUERY_STRING': force_text(parsed[4]), 'REQUEST_METHOD': six.text_type(method), } if data: r.update({ 'CONTENT_LENGTH': len(data), - 'CONTENT_TYPE': six.text_type(content_type), - 'wsgi.input': FakePayload(data), + 'CONTENT_TYPE': six.text_type(content_type), + 'wsgi.input': FakePayload(data), }) elif django.VERSION <= (1, 4): # For 1.3 we need an empty WSGI payload @@ -287,10 +279,12 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp): import provider as oauth2_provider from provider import scope as oauth2_provider_scope from provider import constants as oauth2_constants + if oauth2_provider.__version__ in ('0.2.3', '0.2.4'): # 0.2.3 and 0.2.4 are supported version that do not support # timezone aware datetimes import datetime + provider_now = datetime.datetime.now else: # Any other supported version does use timezone aware datetimes @@ -301,7 +295,7 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp): oauth2_constants = None provider_now = None -# `seperators` argument to `json.dumps()` differs between 2.x and 3.x +# `separators` argument to `json.dumps()` differs between 2.x and 3.x # See: http://bugs.python.org/issue22767 if six.PY3: SHORT_SEPARATORS = (',', ':') @@ -316,30 +310,9 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp): if six.PY3: def is_non_str_iterable(obj): - if (isinstance(obj, str) or - (isinstance(obj, Promise) and obj._delegate_text)): + if isinstance(obj, str) or (isinstance(obj, Promise) and obj._delegate_text): return False return hasattr(obj, '__iter__') else: def is_non_str_iterable(obj): return hasattr(obj, '__iter__') - - -try: - from django.utils.encoding import python_2_unicode_compatible -except ImportError: - def python_2_unicode_compatible(klass): - """ - A decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass diff --git a/rest_framework/utils/mediatypes.py b/rest_framework/utils/mediatypes.py index 87b3cc6a33f..de2931c2867 100644 --- a/rest_framework/utils/mediatypes.py +++ b/rest_framework/utils/mediatypes.py @@ -5,6 +5,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 @@ -43,6 +44,7 @@ def order_by_precedence(media_type_lst): return [media_types for media_types in ret if media_types] +@python_2_unicode_compatible class _MediaType(object): def __init__(self, media_type_str): if media_type_str is None: @@ -79,9 +81,6 @@ def precedence(self): return 3 def __str__(self): - return self.__unicode__().encode('utf-8') - - def __unicode__(self): ret = "%s/%s" % (self.main_type, self.sub_type) for key, val in self.params.items(): ret += "; %s=%s" % (key, val) diff --git a/tests/test_description.py b/tests/test_description.py index 0675d209c4d..6cd871ed0da 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -2,6 +2,7 @@ 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, smart_text from rest_framework.views import APIView from .description import ViewWithNonASCIICharactersInDocstring @@ -107,6 +108,7 @@ class that can be converted to a string. """ # use a mock object instead of gettext_lazy to ensure that we can't end # up with a test case string in our l10n catalog + @python_2_unicode_compatible class MockLazyStr(object): def __init__(self, string): self.s = string @@ -114,9 +116,6 @@ def __init__(self, string): def __str__(self): return self.s - def __unicode__(self): - return self.s - class MockView(APIView): __doc__ = MockLazyStr("a gettext string") diff --git a/tests/test_relations_generic.py b/tests/test_relations_generic.py index 380ad91dbe5..b600b3333e8 100644 --- a/tests/test_relations_generic.py +++ b/tests/test_relations_generic.py @@ -3,8 +3,8 @@ from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey from django.db import models from django.test import TestCase +from django.utils.encoding import python_2_unicode_compatible from rest_framework import serializers -from rest_framework.compat import python_2_unicode_compatible @python_2_unicode_compatible