Drop unsupported django versions

This commit is contained in:
Ryan P Kilby 2016-03-26 20:02:49 -04:00
parent 625e1041cc
commit fda2d39ec4
15 changed files with 44 additions and 199 deletions

View file

@ -3,30 +3,18 @@ language: python
python: 2.7 python: 2.7
env: env:
- TOXENV=py26-django14
- TOXENV=py26-django15
- TOXENV=py26-django16
- TOXENV=py27-django110
- TOXENV=py27-django14
- TOXENV=py27-django15
- TOXENV=py27-django15_nosouth
- TOXENV=py27-django16
- TOXENV=py27-django17
- TOXENV=py27-django18 - TOXENV=py27-django18
- TOXENV=py27-django19 - TOXENV=py27-django19
- TOXENV=py27-django110
- TOXENV=py27-django_trunk - TOXENV=py27-django_trunk
- TOXENV=py33-django15
- TOXENV=py33-django16
- TOXENV=py33-django17
- TOXENV=py33-django18 - TOXENV=py33-django18
- TOXENV=py34-django110
- TOXENV=py34-django17
- TOXENV=py34-django18 - TOXENV=py34-django18
- TOXENV=py34-django19 - TOXENV=py34-django19
- TOXENV=py34-django110
- TOXENV=py34-django_trunk - TOXENV=py34-django_trunk
- TOXENV=py35-django110
- TOXENV=py35-django18 - TOXENV=py35-django18
- TOXENV=py35-django19 - TOXENV=py35-django19
- TOXENV=py35-django110
- TOXENV=py35-django_trunk - TOXENV=py35-django_trunk
install: install:

View file

@ -4,6 +4,11 @@ CHANGES
master (unreleased) master (unreleased)
------------------- -------------------
* Drop support for Python 2.6.
* Drop support for Django 1.4, 1.5, 1.6, 1.7.
2.6.1 (2017.01.11) 2.6.1 (2017.01.11)
------------------ ------------------

View file

@ -11,9 +11,8 @@ django-model-utils
Django model mixins and utilities. Django model mixins and utilities.
``django-model-utils`` supports `Django`_ 1.4 through 1.9 (latest bugfix ``django-model-utils`` supports `Django`_ 1.8 through 1.10 (latest bugfix
release in each series only) on Python 2.6 (through Django 1.6 only), 2.7, 3.3 release in each series only) on Python 2.7, 3.3 (Django 1.8 only), 3.4 and 3.5.
(through Django 1.8 only), 3.4 and 3.5.
.. _Django: http://www.djangoproject.com/ .. _Django: http://www.djangoproject.com/

View file

@ -241,30 +241,3 @@ class SplitField(models.TextField):
name, path, args, kwargs = super(SplitField, self).deconstruct() name, path, args, kwargs = super(SplitField, self).deconstruct()
kwargs['no_excerpt_field'] = True kwargs['no_excerpt_field'] = True
return name, path, args, kwargs return name, path, args, kwargs
# allow South to handle these fields smoothly
try:
from south.modelsinspector import add_introspection_rules
# For a normal MarkupField, the add_excerpt_field attribute is
# always True, which means no_excerpt_field arg will always be
# True in a frozen MarkupField, which is what we want.
add_introspection_rules(rules=[
(
(SplitField,),
[],
{'no_excerpt_field': ('add_excerpt_field', {})}
),
(
(MonitorField,),
[],
{'monitor': ('monitor', {})}
),
(
(StatusField,),
[],
{'no_check_for_status': ('check_for_status', {})}
),
], patterns=['model_utils\.fields\.'])
except ImportError:
pass

View file

@ -5,12 +5,8 @@ from django.db.models.fields.related import OneToOneField, OneToOneRel
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
try: from django.db.models.constants import LOOKUP_SEP
from django.db.models.constants import LOOKUP_SEP from django.utils.six import string_types
from django.utils.six import string_types
except ImportError: # Django < 1.5
from django.db.models.sql.constants import LOOKUP_SEP
string_types = (basestring,)
class InheritanceQuerySetMixin(object): class InheritanceQuerySetMixin(object):

View file

@ -1,5 +0,0 @@
try:
from unittest import skipUnless
except ImportError: # Python 2.6
from django.utils.unittest import skipUnless

View file

@ -1,5 +0,0 @@
# Needed for Django 1.4/1.5 test runner
from .test_field_tracker import *
from .test_monitor_field import *
from .test_split_field import *
from .test_status_field import *

View file

@ -1,11 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from unittest import skipUnless
import django import django
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.test import TestCase from django.test import TestCase
from model_utils import FieldTracker from model_utils import FieldTracker
from model_utils.tests.helpers import skipUnless
from model_utils.tests.models import ( from model_utils.tests.models import (
Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple, Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
InheritedTracked, TrackedFileField, InheritedTracked, TrackedFileField,
@ -97,15 +98,14 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
self.assertPrevious(name=None, number=None, mutable=None) self.assertPrevious(name=None, number=None, mutable=None)
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3]) self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
self.assertChanged(name=None, number=None, mutable=None) self.assertChanged(name=None, number=None, mutable=None)
# Django 1.4 doesn't have update_fields
if django.VERSION >= (1, 5, 0): self.instance.save(update_fields=[])
self.instance.save(update_fields=[]) self.assertHasChanged(name=True, number=True, mutable=True)
self.assertHasChanged(name=True, number=True, mutable=True) self.assertPrevious(name=None, number=None, mutable=None)
self.assertPrevious(name=None, number=None, mutable=None) self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3]) self.assertChanged(name=None, number=None, mutable=None)
self.assertChanged(name=None, number=None, mutable=None) with self.assertRaises(ValueError):
with self.assertRaises(ValueError): self.instance.save(update_fields=['number'])
self.instance.save(update_fields=['number'])
def test_post_save_has_changed(self): def test_post_save_has_changed(self):
self.update_instance(name='retro', number=4, mutable=[1,2,3]) self.update_instance(name='retro', number=4, mutable=[1,2,3])
@ -153,8 +153,6 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
self.instance.save() self.instance.save()
self.assertCurrent(id=self.instance.id, name='new age', number=8, mutable=[1,4,3]) self.assertCurrent(id=self.instance.id, name='new age', number=8, mutable=[1,4,3])
@skipUnless(
django.VERSION >= (1, 5, 0), "Django 1.4 doesn't have update_fields")
def test_update_fields(self): def test_update_fields(self):
self.update_instance(name='retro', number=4, mutable=[1,2,3]) self.update_instance(name='retro', number=4, mutable=[1,2,3])
self.assertChanged() self.assertChanged()
@ -280,8 +278,6 @@ class FieldTrackedModelCustomTests(FieldTrackerTestCase,
self.instance.save() self.instance.save()
self.assertCurrent(name='new age') self.assertCurrent(name='new age')
@skipUnless(
django.VERSION >= (1, 5, 0), "Django 1.4 doesn't have update_fields")
def test_update_fields(self): def test_update_fields(self):
self.update_instance(name='retro', number=4) self.update_instance(name='retro', number=4)
self.assertChanged() self.assertChanged()
@ -622,15 +618,14 @@ class ModelTrackerTests(FieldTrackerTests):
self.assertPrevious(name=None, number=None, mutable=None) self.assertPrevious(name=None, number=None, mutable=None)
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3]) self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
self.assertChanged() self.assertChanged()
# Django 1.4 doesn't have update_fields
if django.VERSION >= (1, 5, 0): self.instance.save(update_fields=[])
self.instance.save(update_fields=[]) self.assertHasChanged(name=True, number=True, mutable=True)
self.assertHasChanged(name=True, number=True, mutable=True) self.assertPrevious(name=None, number=None, mutable=None)
self.assertPrevious(name=None, number=None, mutable=None) self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3])
self.assertCurrent(name='retro', number=4, id=None, mutable=[1,2,3]) self.assertChanged()
self.assertChanged() with self.assertRaises(ValueError):
with self.assertRaises(ValueError): self.instance.save(update_fields=['number'])
self.instance.save(update_fields=['number'])
def test_pre_save_has_changed(self): def test_pre_save_has_changed(self):
self.assertHasChanged(name=True, number=True) self.assertHasChanged(name=True, number=True)

View file

@ -1,5 +0,0 @@
# Needed for Django 1.4/1.5 test runner
from .test_inheritance_manager import *
from .test_query_manager import *
from .test_status_manager import *
from .test_softdelete_manager import *

View file

@ -1,10 +1,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from unittest import skipUnless
import django import django
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from model_utils.tests.helpers import skipUnless
from model_utils.tests.models import (InheritanceManagerTestRelated, InheritanceManagerTestGrandChild1, from model_utils.tests.models import (InheritanceManagerTestRelated, InheritanceManagerTestGrandChild1,
InheritanceManagerTestGrandChild1_2, InheritanceManagerTestParent, InheritanceManagerTestGrandChild1_2, InheritanceManagerTestParent,
InheritanceManagerTestChild1, InheritanceManagerTestChild1,
@ -34,12 +35,8 @@ class InheritanceManagerTests(TestCase):
def test_select_all_subclasses(self): def test_select_all_subclasses(self):
children = set([self.child1, self.child2]) children = set([self.child1, self.child2])
if django.VERSION >= (1, 6, 0): children.add(self.grandchild1)
children.add(self.grandchild1) children.add(self.grandchild1_2)
children.add(self.grandchild1_2)
else:
children.add(InheritanceManagerTestChild1(pk=self.grandchild1.pk))
children.add(InheritanceManagerTestChild1(pk=self.grandchild1_2.pk))
self.assertEqual( self.assertEqual(
set(self.get_manager().select_subclasses()), children) set(self.get_manager().select_subclasses()), children)
@ -68,7 +65,6 @@ class InheritanceManagerTests(TestCase):
children, children,
) )
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_select_specific_grandchildren(self): def test_select_specific_grandchildren(self):
children = set([ children = set([
InheritanceManagerTestParent(pk=self.child1.pk), InheritanceManagerTestParent(pk=self.child1.pk),
@ -85,7 +81,6 @@ class InheritanceManagerTests(TestCase):
children, children,
) )
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_children_and_grandchildren(self): def test_children_and_grandchildren(self):
children = set([ children = set([
self.child1, self.child1,
@ -120,39 +115,9 @@ class InheritanceManagerTests(TestCase):
"inheritancemanagertestchild2").get(pk=self.child1.pk) "inheritancemanagertestchild2").get(pk=self.child1.pk)
obj.inheritancemanagertestchild1 obj.inheritancemanagertestchild1
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_version_determining_any_depth(self): def test_version_determining_any_depth(self):
self.assertIsNone(self.get_manager().all()._get_maximum_depth()) self.assertIsNone(self.get_manager().all()._get_maximum_depth())
@skipUnless(django.VERSION < (1, 6, 0), "test only applies to Django < 1.6")
def test_version_determining_only_child_depth(self):
self.assertEqual(1, self.get_manager().all()._get_maximum_depth())
@skipUnless(django.VERSION < (1, 6, 0), "test only applies to Django < 1.6")
def test_manually_specifying_parent_fk_only_children(self):
"""
given a Model which inherits from another Model, but also declares
the OneToOne link manually using `related_name` and `parent_link`,
ensure that the relation names and subclasses are obtained correctly.
"""
child3 = InheritanceManagerTestChild3.objects.create()
results = InheritanceManagerTestParent.objects.all().select_subclasses()
expected_objs = [self.child1, self.child2,
InheritanceManagerTestChild1(pk=self.grandchild1.pk),
InheritanceManagerTestChild1(pk=self.grandchild1_2.pk),
child3]
self.assertEqual(list(results), expected_objs)
expected_related_names = [
'inheritancemanagertestchild1',
'inheritancemanagertestchild2',
'manual_onetoone', # this was set via parent_link & related_name
]
self.assertEqual(set(results.subclasses),
set(expected_related_names))
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_manually_specifying_parent_fk_including_grandchildren(self): def test_manually_specifying_parent_fk_including_grandchildren(self):
""" """
given a Model which inherits from another Model, but also declares given a Model which inherits from another Model, but also declares
@ -267,7 +232,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
self.assertEqual(objs.subclasses, objsmodels.subclasses) self.assertEqual(objs.subclasses, objsmodels.subclasses)
self.assertEqual(list(objs), list(objsmodels)) self.assertEqual(list(objs), list(objsmodels))
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_select_subclass_by_grandchild_model(self): def test_select_subclass_by_grandchild_model(self):
""" """
Confirm that passing a grandchild model works the same as passing the Confirm that passing a grandchild model works the same as passing the
@ -281,7 +245,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
self.assertEqual(objs.subclasses, objsmodels.subclasses) self.assertEqual(objs.subclasses, objsmodels.subclasses)
self.assertEqual(list(objs), list(objsmodels)) self.assertEqual(list(objs), list(objsmodels))
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_selecting_all_subclasses_specifically_grandchildren(self): def test_selecting_all_subclasses_specifically_grandchildren(self):
""" """
A bare select_subclasses() should achieve the same results as doing A bare select_subclasses() should achieve the same results as doing
@ -310,16 +273,11 @@ class InheritanceManagerUsingModelsTests(TestCase):
""" """
objs = InheritanceManagerTestParent.objects.select_subclasses().order_by('pk') objs = InheritanceManagerTestParent.objects.select_subclasses().order_by('pk')
if django.VERSION >= (1, 6, 0): models = (InheritanceManagerTestChild1,
models = (InheritanceManagerTestChild1, InheritanceManagerTestChild2,
InheritanceManagerTestChild2, InheritanceManagerTestChild3,
InheritanceManagerTestChild3, InheritanceManagerTestGrandChild1,
InheritanceManagerTestGrandChild1, InheritanceManagerTestGrandChild1_2)
InheritanceManagerTestGrandChild1_2)
else:
models = (InheritanceManagerTestChild1,
InheritanceManagerTestChild2,
InheritanceManagerTestChild3)
objsmodels = InheritanceManagerTestParent.objects.select_subclasses( objsmodels = InheritanceManagerTestParent.objects.select_subclasses(
*models).order_by('pk') *models).order_by('pk')
@ -353,7 +311,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
InheritanceManagerTestParent.objects.select_subclasses( InheritanceManagerTestParent.objects.select_subclasses(
TimeFrame).order_by('pk') TimeFrame).order_by('pk')
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_mixing_strings_and_classes_with_grandchildren(self): def test_mixing_strings_and_classes_with_grandchildren(self):
""" """
Given arguments consisting of both strings and model classes, Given arguments consisting of both strings and model classes,
@ -414,7 +371,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
InheritanceManagerTestParent(pk=self.grandchild1_2.pk), InheritanceManagerTestParent(pk=self.grandchild1_2.pk),
]) ])
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
def test_child_doesnt_accidentally_get_parent(self): def test_child_doesnt_accidentally_get_parent(self):
""" """
Given a Child model which also has an InheritanceManager, Given a Child model which also has an InheritanceManager,

View file

@ -1,20 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import django
from django.db.models.fields import FieldDoesNotExist
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase from django.test import TestCase
from model_utils.fields import get_excerpt from model_utils.fields import get_excerpt
from model_utils.tests.models import (
Article,
StatusFieldDefaultFilled,
)
from model_utils.tests.helpers import skipUnless
class MigrationsTests(TestCase): class MigrationsTests(TestCase):
@skipUnless(django.VERSION >= (1, 7, 0), "test only applies to Django 1.7+")
def test_makemigrations(self): def test_makemigrations(self):
call_command('makemigrations', dry_run=True) call_command('makemigrations', dry_run=True)
@ -35,26 +27,3 @@ class GetExcerptTests(TestCase):
def test_middle_of_line(self): def test_middle_of_line(self):
e = get_excerpt("some text <!-- split --> more text") e = get_excerpt("some text <!-- split --> more text")
self.assertEqual(e, "some text <!-- split --> more text") self.assertEqual(e, "some text <!-- split --> more text")
try:
from south.modelsinspector import introspector
except ImportError:
introspector = None
@skipUnless(introspector, 'South is not installed')
class SouthFreezingTests(TestCase):
def test_introspector_adds_no_excerpt_field(self):
mf = Article._meta.get_field('body')
args, kwargs = introspector(mf)
self.assertEqual(kwargs['no_excerpt_field'], 'True')
def test_no_excerpt_field_works(self):
from .models import NoRendered
with self.assertRaises(FieldDoesNotExist):
NoRendered._meta.get_field('_body_excerpt')
def test_status_field_no_check_for_status(self):
sf = StatusFieldDefaultFilled._meta.get_field('status')
args, kwargs = introspector(sf)
self.assertEqual(kwargs['no_check_for_status'], 'True')

View file

@ -1,5 +0,0 @@
# Needed for Django 1.4/1.5 test runner
from .test_softdeletable_model import *
from .test_status_model import *
from .test_timeframed_model import *
from .test_timestamped_model import *

View file

@ -1,9 +0,0 @@
import django
# Needed for Django 1.4/1.5 test runner
if django.VERSION < (1, 6):
from .test_fields import *
from .test_managers import *
from .test_models import *
from .test_choices import *
from .test_miscellaneous import *

View file

@ -30,7 +30,7 @@ setup(
author_email='carl@oddbird.net', author_email='carl@oddbird.net',
url='https://github.com/carljm/django-model-utils/', url='https://github.com/carljm/django-model-utils/',
packages=find_packages(), packages=find_packages(),
install_requires=['Django>=1.4.2'], install_requires=['Django>=1.8'],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment', 'Environment :: Web Environment',
@ -47,7 +47,7 @@ setup(
'Framework :: Django', 'Framework :: Django',
], ],
zip_safe=False, zip_safe=False,
tests_require=["Django>=1.4.2"], tests_require=['Django>=1.8'],
test_suite='runtests.runtests', test_suite='runtests.runtests',
package_data={ package_data={
'model_utils': [ 'model_utils': [

13
tox.ini
View file

@ -1,14 +1,12 @@
[tox] [tox]
envlist = envlist =
py26-django{14,15,16}, py27-django{18,19,110,_trunk},
py27-django{14,19,110,_trunk}, py27-django15_nosouth, py33-django{18},
py{27,33}-django{15,16,17,18}, py34-django{18,19,110,_trunk},
py34-django{17,18,19,110,_trunk},
py35-django{18,19,110,_trunk}, py35-django{18,19,110,_trunk},
[testenv] [testenv]
basepython = basepython =
py26: python2.6
py27: python2.7 py27: python2.7
py33: python3.3 py33: python3.3
py34: python3.4 py34: python3.4
@ -16,15 +14,10 @@ basepython =
deps = deps =
coverage == 3.6 coverage == 3.6
django14: Django>=1.4,<1.5
django15{,_nosouth}: Django>=1.5,<1.6
django16: Django>=1.6,<1.7
django17: Django>=1.7,<1.8
django18: Django>=1.8,<1.9 django18: Django>=1.8,<1.9
django19: Django>=1.9,<1.10 django19: Django>=1.9,<1.10
django110: Django>=1.10,<1.11 django110: Django>=1.10,<1.11
django_trunk: https://github.com/django/django/tarball/master django_trunk: https://github.com/django/django/tarball/master
django{14,15,16}: South==1.0.2
freezegun == 0.3.8 freezegun == 0.3.8
commands = coverage run -a setup.py test commands = coverage run -a setup.py test