From 796baab86f81543019f5757eb0a3ec077dd14d49 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 15:47:11 +0200 Subject: [PATCH 1/9] Drop Pythons 3.2, 3.3 for Django `master` No longer supported --- .travis.yml | 4 ---- tox.ini | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87db5e0465..7513b4db24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,16 +24,12 @@ env: - TOX_ENV=py27-django15 - TOX_ENV=py26-django15 - TOX_ENV=py27-djangomaster - - TOX_ENV=py32-djangomaster - - TOX_ENV=py33-djangomaster - TOX_ENV=py34-djangomaster matrix: fast_finish: true allow_failures: - env: TOX_ENV=py27-djangomaster - - env: TOX_ENV=py32-djangomaster - - env: TOX_ENV=py33-djangomaster - env: TOX_ENV=py34-djangomaster install: diff --git a/tox.ini b/tox.ini index ef505248bb..89d43771ad 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,8 @@ addopts=--tb=short envlist = py27-{lint,docs}, {py26,py27,py32,py33,py34}-django{15,16}, - {py27,py32,py33,py34}-django{17,18,master} + {py27,py32,py33,py34}-django{17,18}, + {py27,py34}-django{master} [testenv] commands = ./runtests.py --fast {posargs} --coverage From 366dff4f26afe5139f1628052c84258f2bc2a388 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 15:58:34 +0200 Subject: [PATCH 2/9] Test Python 3.5 against Django `master` --- .travis.yml | 2 ++ tox.ini | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7513b4db24..a714b80138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,12 +25,14 @@ env: - TOX_ENV=py26-django15 - TOX_ENV=py27-djangomaster - TOX_ENV=py34-djangomaster + - TOX_ENV=py35-djangomaster matrix: fast_finish: true allow_failures: - env: TOX_ENV=py27-djangomaster - env: TOX_ENV=py34-djangomaster + - env: TOX_ENV=py35-djangomaster install: - pip install tox diff --git a/tox.ini b/tox.ini index 89d43771ad..924d11df59 100644 --- a/tox.ini +++ b/tox.ini @@ -6,9 +6,17 @@ envlist = py27-{lint,docs}, {py26,py27,py32,py33,py34}-django{15,16}, {py27,py32,py33,py34}-django{17,18}, - {py27,py34}-django{master} + {py27,py34,py35}-django{master} [testenv] +basepython = + py26: python2.6 + py27: python2.7 + py32: python3.2 + py33: python3.3 + py34: python3.4 + py35: python3.5 + commands = ./runtests.py --fast {posargs} --coverage setenv = PYTHONDONTWRITEBYTECODE=1 From 8edb9d3c1f6d4582f558fcc1d1024c35353ac9bf Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 16:08:56 +0200 Subject: [PATCH 3/9] Drop testing against Django 1.5 --- .travis.yml | 5 ----- tox.ini | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a714b80138..4a7fdd42f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,11 +18,6 @@ env: - TOX_ENV=py32-django16 - TOX_ENV=py27-django16 - TOX_ENV=py26-django16 - - TOX_ENV=py34-django15 - - TOX_ENV=py33-django15 - - TOX_ENV=py32-django15 - - TOX_ENV=py27-django15 - - TOX_ENV=py26-django15 - TOX_ENV=py27-djangomaster - TOX_ENV=py34-djangomaster - TOX_ENV=py35-djangomaster diff --git a/tox.ini b/tox.ini index 924d11df59..135ca4407d 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ addopts=--tb=short [tox] envlist = py27-{lint,docs}, - {py26,py27,py32,py33,py34}-django{15,16}, + {py26,py27,py32,py33,py34}-django16, {py27,py32,py33,py34}-django{17,18}, {py27,py34,py35}-django{master} @@ -21,7 +21,6 @@ commands = ./runtests.py --fast {posargs} --coverage setenv = PYTHONDONTWRITEBYTECODE=1 deps = - django15: Django==1.5.6 # Should track minimum supported django16: Django==1.6.3 # Should track minimum supported django17: Django==1.7.10 # Should track maximum supported django18: Django==1.8.4 # Should track maximum supported From 9216dc9a254160a9903359fbf0db2b2c5826212c Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 16:20:07 +0200 Subject: [PATCH 4/9] Remove Django 1.5 EmailValidator fallback --- rest_framework/compat.py | 13 ------------- rest_framework/fields.py | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 4d3b29ddd1..fa737f42a3 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -183,19 +183,6 @@ def __init__(self, *args, **kwargs): super(URLValidator, self).__init__(*args, **kwargs) -# EmailValidator requires explicit regex prior to 1.6+ -if django.VERSION >= (1, 6): - from django.core.validators import EmailValidator -else: - from django.core.validators import EmailValidator as DjangoEmailValidator - from django.core.validators import email_re - - - class EmailValidator(DjangoEmailValidator): - def __init__(self, *args, **kwargs): - super(EmailValidator, self).__init__(email_re, *args, **kwargs) - - # PATCH method is not implemented by Django if 'patch' not in View.http_method_names: View.http_method_names = View.http_method_names + ['patch'] diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 7c48c621ed..63e0b2dbf2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -11,7 +11,7 @@ from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ObjectDoesNotExist -from django.core.validators import RegexValidator, ip_address_validators +from django.core.validators import EmailValidator, RegexValidator, ip_address_validators from django.forms import FilePathField as DjangoFilePathField from django.forms import ImageField as DjangoImageField from django.utils import six, timezone @@ -23,7 +23,7 @@ from rest_framework import ISO_8601 from rest_framework.compat import ( - EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, + MaxLengthValidator, MaxValueValidator, MinLengthValidator, MinValueValidator, OrderedDict, URLValidator, duration_string, parse_duration, unicode_repr, unicode_to_repr ) From e625cff8a5e4e4353d280fdd4c305dc6dbeed999 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 16:22:46 +0200 Subject: [PATCH 5/9] Remove Django 1.5 URLValidator fallback --- rest_framework/compat.py | 13 ------------- rest_framework/fields.py | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index fa737f42a3..c1074b7f8b 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -170,19 +170,6 @@ def __init__(self, *args, **kwargs): super(MaxLengthValidator, self).__init__(*args, **kwargs) -# URLValidator only accepts `message` in 1.6+ -if django.VERSION >= (1, 6): - from django.core.validators import URLValidator -else: - from django.core.validators import URLValidator as DjangoURLValidator - - - class URLValidator(DjangoURLValidator): - def __init__(self, *args, **kwargs): - self.message = kwargs.pop('message', self.message) - super(URLValidator, self).__init__(*args, **kwargs) - - # PATCH method is not implemented by Django if 'patch' not in View.http_method_names: View.http_method_names = View.http_method_names + ['patch'] diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 63e0b2dbf2..c44440ecdf 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -11,7 +11,7 @@ from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ObjectDoesNotExist -from django.core.validators import EmailValidator, RegexValidator, ip_address_validators +from django.core.validators import EmailValidator, RegexValidator, ip_address_validators, URLValidator from django.forms import FilePathField as DjangoFilePathField from django.forms import ImageField as DjangoImageField from django.utils import six, timezone @@ -24,7 +24,7 @@ from rest_framework import ISO_8601 from rest_framework.compat import ( MaxLengthValidator, MaxValueValidator, MinLengthValidator, - MinValueValidator, OrderedDict, URLValidator, duration_string, + MinValueValidator, OrderedDict, duration_string, parse_duration, unicode_repr, unicode_to_repr ) from rest_framework.exceptions import ValidationError From 4a1ab3c18c7c85c9d962e7b6605e7d57423d29fe Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 16:29:33 +0200 Subject: [PATCH 6/9] Fix isort errors --- rest_framework/fields.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index c44440ecdf..1e23b35f0a 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -11,7 +11,9 @@ from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ObjectDoesNotExist -from django.core.validators import EmailValidator, RegexValidator, ip_address_validators, URLValidator +from django.core.validators import ( + EmailValidator, RegexValidator, URLValidator, ip_address_validators +) from django.forms import FilePathField as DjangoFilePathField from django.forms import ImageField as DjangoImageField from django.utils import six, timezone @@ -24,8 +26,8 @@ from rest_framework import ISO_8601 from rest_framework.compat import ( MaxLengthValidator, MaxValueValidator, MinLengthValidator, - MinValueValidator, OrderedDict, duration_string, - parse_duration, unicode_repr, unicode_to_repr + MinValueValidator, OrderedDict, duration_string, parse_duration, + unicode_repr, unicode_to_repr ) from rest_framework.exceptions import ValidationError from rest_framework.settings import api_settings From 25de8c960fcbb79f6d1097da22cab2dfeefb4e6e Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 19:57:20 +0200 Subject: [PATCH 7/9] Remove Django 1.5 get_model_name fallback --- rest_framework/compat.py | 8 -------- rest_framework/filters.py | 6 ++---- rest_framework/permissions.py | 6 ++---- tests/test_permissions.py | 4 ++-- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index c1074b7f8b..b348f05a9c 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -127,14 +127,6 @@ def clean_manytomany_helptext(text): pass -def get_model_name(model_cls): - try: - return model_cls._meta.model_name - except AttributeError: - # < 1.6 used module_name instead of model_name - return model_cls._meta.module_name - - # MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+ if django.VERSION >= (1, 8): from django.core.validators import MinValueValidator, MaxValueValidator diff --git a/rest_framework/filters.py b/rest_framework/filters.py index 90c19aba08..c1e0ae054a 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -11,9 +11,7 @@ from django.db import models from django.utils import six -from rest_framework.compat import ( - distinct, django_filters, get_model_name, guardian -) +from rest_framework.compat import distinct, django_filters, guardian from rest_framework.settings import api_settings FilterSet = django_filters and django_filters.FilterSet or None @@ -202,7 +200,7 @@ def filter_queryset(self, request, queryset, view): model_cls = queryset.model kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } permission = self.perm_format % kwargs if guardian.VERSION >= (1, 3): diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 628538903a..292952cfab 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -5,8 +5,6 @@ from django.http import Http404 -from rest_framework.compat import get_model_name - SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS') @@ -104,7 +102,7 @@ def get_required_permissions(self, method, model_cls): """ kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } return [perm % kwargs for perm in self.perms_map[method]] @@ -166,7 +164,7 @@ class DjangoObjectPermissions(DjangoModelPermissions): def get_required_object_permissions(self, method, model_cls): kwargs = { 'app_label': model_cls._meta.app_label, - 'model_name': get_model_name(model_cls) + 'model_name': model_cls._meta.model_name } return [perm % kwargs for perm in self.perms_map[method]] diff --git a/tests/test_permissions.py b/tests/test_permissions.py index ffc262a412..f0d77e957b 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -11,7 +11,7 @@ HTTP_HEADER_ENCODING, authentication, generics, permissions, serializers, status ) -from rest_framework.compat import get_model_name, guardian, unittest +from rest_framework.compat import guardian, unittest from rest_framework.filters import DjangoObjectPermissionsFilter from rest_framework.routers import DefaultRouter from rest_framework.test import APIRequestFactory @@ -278,7 +278,7 @@ def setUp(self): # give everyone model level permissions, as we are not testing those everyone = Group.objects.create(name='everyone') - model_name = get_model_name(BasicPermModel) + model_name = BasicPermModel._meta.model_name app_label = BasicPermModel._meta.app_label f = '{0}_{1}'.format perms = { From 8ea1606abf5eee6a3e97c71b3cc93a81e362d782 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 20:16:52 +0200 Subject: [PATCH 8/9] Remove Django 1.5 clean_manytomany_helptext fallback --- rest_framework/compat.py | 11 ----------- rest_framework/utils/field_mapping.py | 3 +-- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index b348f05a9c..fcca2dcbf8 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -106,17 +106,6 @@ def distinct(queryset, base): except ImportError: django_filters = None -if django.VERSION >= (1, 6): - def clean_manytomany_helptext(text): - return text -else: - # Up to version 1.5 many to many fields automatically suffix - # the `help_text` attribute with hardcoded text. - def clean_manytomany_helptext(text): - if text.endswith(' Hold down "Control", or "Command" on a Mac, to select more than one.'): - text = text[:-69] - return text - # Django-guardian is optional. Import only if guardian is in INSTALLED_APPS # Fixes (#1712). We keep the try/except for the test suite. guardian = None diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index f2598974ef..a285536933 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -8,7 +8,6 @@ from django.db import models from django.utils.text import capfirst -from rest_framework.compat import clean_manytomany_helptext from rest_framework.validators import UniqueValidator NUMERIC_FIELD_TYPES = ( @@ -222,7 +221,7 @@ def get_relation_kwargs(field_name, relation_info): if model_field: if model_field.verbose_name and needs_label(model_field, field_name): kwargs['label'] = capfirst(model_field.verbose_name) - help_text = clean_manytomany_helptext(model_field.help_text) + help_text = model_field.help_text if help_text: kwargs['help_text'] = help_text if not model_field.editable: From 2aa33ed54460f016c157cbf13e7e122b7040704b Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 21 Sep 2015 20:23:39 +0200 Subject: [PATCH 9/9] Adjust README and Release Notes --- README.md | 2 +- docs/topics/release-notes.md | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b183e14df0..c2a686f4ce 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements * Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.5.6+, 1.6.3+, 1.7, 1.8) +* Django (1.6.3+, 1.7, 1.8) # Installation diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 68803a5b14..be2586f02d 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -38,6 +38,14 @@ You can determine your currently installed version using `pip freeze`: --- +## 3.3.x series + +### 3.0.0 + +**Date**: NOT YET RELEASED + +* Removed support for Django Version 1.5 ([#3421][gh3421]) + ## 3.2.x series ### 3.2.3 @@ -514,5 +522,6 @@ For older release notes, [please see the version 2.x documentation][old-release- [gh3321]: https://github.com/tomchristie/django-rest-framework/issues/3321 - + +[gh3421]: https://github.com/tomchristie/django-rest-framework/pulls/3421