[Python-modules-commits] [django-model-utils] 01/03: Import django-model-utils_2.4.orig.tar.gz

Brian May bam at moszumanska.debian.org
Wed Dec 2 22:03:13 UTC 2015


This is an automated email from the git hooks/post-receive script.

bam pushed a commit to branch master
in repository django-model-utils.

commit c0b30b27ddf45636f54c8dde126a6fc0a8a8ddb9
Author: Brian May <bam at debian.org>
Date:   Thu Dec 3 08:56:29 2015 +1100

    Import django-model-utils_2.4.orig.tar.gz
---
 .travis.yml                 |   2 +
 AUTHORS.rst                 |   2 +
 CHANGES.rst                 |   5 ++
 model_utils/__init__.py     |   2 +-
 model_utils/fields.py       |   5 ++
 model_utils/managers.py     |  94 ++------------------------------
 model_utils/models.py       |   8 ++-
 model_utils/tests/fields.py |  61 +++++++++++++--------
 model_utils/tests/models.py |  76 ++------------------------
 model_utils/tests/tests.py  | 128 ++++----------------------------------------
 setup.py                    |   1 +
 tox.ini                     |   8 +--
 12 files changed, 83 insertions(+), 309 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index b24d579..b23f12e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,7 @@ env:
   - TOXENV=py27-django16
   - TOXENV=py27-django17
   - TOXENV=py27-django18
+  - TOXENV=py27-django19
   - TOXENV=py27-django_trunk
   - TOXENV=py32-django15
   - TOXENV=py32-django16
@@ -25,6 +26,7 @@ env:
   - TOXENV=py33-django_trunk
   - TOXENV=py34-django17
   - TOXENV=py34-django18
+  - TOXENV=py34-django19
   - TOXENV=py34-django_trunk
 
 install:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index b25a3cf..1776b2b 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -16,6 +16,7 @@ Gregor Müllegger <gregor at muellegger.de>
 ivirabyan
 James Oakley <jfunk at funktronics.ca>
 Jannis Leidel <jannis at leidel.info>
+Jarek Glowacki <github.com/jarekwg>
 Javier García Sogo <jgsogo at gmail.com>
 Jeff Elmore <jeffelmore.org>
 Keryn Knight <kerynknight.com>
@@ -34,4 +35,5 @@ sayane
 Tony Aldridge <zaragopha at hotmail.com>
 Travis Swicegood <travis at domain51.com>
 Trey Hunner <trey at treyhunner.com>
+Karl Wan Nan Wo <karl.wnw at gmail.com>
 zyegfryed
diff --git a/CHANGES.rst b/CHANGES.rst
index 1fc9a62..0c450d7 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,11 @@
 CHANGES
 =======
 
+2.4 (2015-12-03)
+----------------
+
+* Add support for Django 1.9. Drop support for Django 1.6 and earlier.
+
 2.3.1 (2015-07-20)
 ------------------
 
diff --git a/model_utils/__init__.py b/model_utils/__init__.py
index 272f4ca..782fa33 100644
--- a/model_utils/__init__.py
+++ b/model_utils/__init__.py
@@ -1,4 +1,4 @@
 from .choices import Choices
 from .tracker import FieldTracker, ModelTracker
 
-__version__ = '2.3.1'
+__version__ = '2.4'
diff --git a/model_utils/fields.py b/model_utils/fields.py
index 74c44b2..805c707 100644
--- a/model_utils/fields.py
+++ b/model_utils/fields.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals
 
+import django
 from django.db import models
 from django.conf import settings
 from django.utils.encoding import python_2_unicode_compatible
@@ -59,6 +60,8 @@ class StatusField(models.CharField):
                 "To use StatusField, the model '%s' must have a %s choices class attribute." \
                 % (sender.__name__, self.choices_name)
             self._choices = getattr(sender, self.choices_name)
+            if django.VERSION >= (1, 9, 0):
+                self.choices = self._choices
             if not self.has_default():
                 self.default = tuple(getattr(sender, self.choices_name))[0][0]  # set first as default
 
@@ -68,6 +71,8 @@ class StatusField(models.CharField):
         # the STATUS class attr being available), but we need to set some dummy
         # choices now so the super method will add the get_FOO_display method
         self._choices = [(0, 'dummy')]
+        if django.VERSION >= (1, 9, 0):
+            self.choices = self._choices
         super(StatusField, self).contribute_to_class(cls, name)
 
     def deconstruct(self):
diff --git a/model_utils/managers.py b/model_utils/managers.py
index b6496ba..9392e69 100644
--- a/model_utils/managers.py
+++ b/model_utils/managers.py
@@ -57,8 +57,10 @@ class InheritanceQuerySetMixin(object):
         for name in ['subclasses', '_annotated']:
             if hasattr(self, name):
                 kwargs[name] = getattr(self, name)
-        return super(InheritanceQuerySetMixin, self)._clone(
-            klass, setup, **kwargs)
+        if django.VERSION < (1, 9):
+            kwargs['klass'] = klass
+            kwargs['setup'] = setup
+        return super(InheritanceQuerySetMixin, self)._clone(**kwargs)
 
     def annotate(self, *args, **kwargs):
         qset = super(InheritanceQuerySetMixin, self).annotate(*args, **kwargs)
@@ -224,91 +226,3 @@ class QueryManagerMixin(object):
 
 class QueryManager(QueryManagerMixin, models.Manager):
     pass
-
-
-class PassThroughManagerMixin(object):
-    """
-    A mixin that enables you to call custom QuerySet methods from your manager.
-    """
-
-    # pickling causes recursion errors
-    _deny_methods = ['__getstate__', '__setstate__', '__getinitargs__',
-                     '__getnewargs__', '__copy__', '__deepcopy__', '_db',
-                     '__slots__']
-
-    def __init__(self, queryset_cls=None):
-        self._queryset_cls = queryset_cls
-        super(PassThroughManagerMixin, self).__init__()
-
-    def __getattr__(self, name):
-        if name in self._deny_methods:
-            raise AttributeError(name)
-        if django.VERSION < (1, 6, 0):
-            return getattr(self.get_query_set(), name)
-        return getattr(self.get_queryset(), name)
-
-    def __dir__(self):
-        """
-        Allow introspection via dir() and ipythonesque tab-discovery.
-
-        We do dir(type(self)) because to do dir(self) would be a recursion
-        error.
-        We call dir(self.get_query_set()) because it is possible that the
-        queryset returned by get_query_set() is interesting, even if
-        self._queryset_cls is None.
-        """
-        my_values = frozenset(dir(type(self)))
-        my_values |= frozenset(dir(self.get_query_set()))
-        return list(my_values)
-
-    def get_queryset(self):
-        try:
-            qs = super(PassThroughManagerMixin, self).get_queryset()
-        except AttributeError:
-            qs = super(PassThroughManagerMixin, self).get_query_set()
-        if self._queryset_cls is not None:
-            qs = qs._clone(klass=self._queryset_cls)
-        return qs
-
-    get_query_set = get_queryset
-
-    @classmethod
-    def for_queryset_class(cls, queryset_cls):
-        return create_pass_through_manager_for_queryset_class(
-            cls, queryset_cls)
-
-
-class PassThroughManager(PassThroughManagerMixin, models.Manager):
-    """
-    Inherit from this Manager to enable you to call any methods from your
-    custom QuerySet class from your manager. Simply define your QuerySet
-    class, and return an instance of it from your manager's `get_queryset`
-    method.
-
-    Alternately, if you don't need any extra methods on your manager that
-    aren't on your QuerySet, then just pass your QuerySet class to the
-    ``for_queryset_class`` class method.
-
-    class PostQuerySet(QuerySet):
-        def enabled(self):
-            return self.filter(disabled=False)
-
-    class Post(models.Model):
-        objects = PassThroughManager.for_queryset_class(PostQuerySet)()
-
-    """
-    pass
-
-
-def create_pass_through_manager_for_queryset_class(base, queryset_cls):
-    class _PassThroughManager(base):
-        def __init__(self, *args, **kwargs):
-            return super(_PassThroughManager, self).__init__(*args, **kwargs)
-
-        def get_queryset(self):
-            qs = super(_PassThroughManager, self).get_queryset()
-            return qs._clone(klass=queryset_cls)
-
-        get_query_set = get_queryset
-
-    return _PassThroughManager
diff --git a/model_utils/models.py b/model_utils/models.py
index f343dfb..3db4073 100644
--- a/model_utils/models.py
+++ b/model_utils/models.py
@@ -1,10 +1,14 @@
 from __future__ import unicode_literals
 
+import django
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
-from django.db.models.fields import FieldDoesNotExist
 from django.core.exceptions import ImproperlyConfigured
-from django.utils.timezone import now
+if django.VERSION >= (1, 9, 0):
+    from django.db.models.functions import Now
+    now = Now()
+else:
+    from django.utils.timezone import now
 
 from model_utils.managers import QueryManager
 from model_utils.fields import AutoCreatedField, AutoLastModifiedField, \
diff --git a/model_utils/tests/fields.py b/model_utils/tests/fields.py
index 3f1503a..7c29aa4 100644
--- a/model_utils/tests/fields.py
+++ b/model_utils/tests/fields.py
@@ -1,26 +1,43 @@
+import django
 from django.db import models
 from django.utils.six import with_metaclass, string_types
 
 
-class MutableField(with_metaclass(models.SubfieldBase, models.TextField)):
-
-    def to_python(self, value):
-        if value == '':
-            return None
-
-        try:
-            if isinstance(value, string_types):
-                return [int(i) for i in value.split(',')]
-        except ValueError:
-            pass
-
-        return value
-
-    def get_db_prep_save(self, value, connection):
-        if value is None:
-            return ''
-
-        if isinstance(value, list):
-            value = ','.join((str(i) for i in value))
-
-        return super(MutableField, self).get_db_prep_save(value, connection)
+def mutable_from_db(value):
+    if value == '':
+        return None
+    try:
+        if isinstance(value, string_types):
+            return [int(i) for i in value.split(',')]
+    except ValueError:
+        pass
+    return value
+
+
+def mutable_to_db(value):
+    if value is None:
+        return ''
+    if isinstance(value, list):
+        value = ','.join((str(i) for i in value))
+    return str(value)
+
+
+if django.VERSION >= (1, 9, 0):
+    class MutableField(models.TextField):
+        def to_python(self, value):
+            return mutable_from_db(value)
+
+        def from_db_value(self, value, expression, connection, context):
+            return mutable_from_db(value)
+
+        def get_db_prep_save(self, value, connection):
+            value = super(MutableField, self).get_db_prep_save(value, connection)
+            return mutable_to_db(value)
+else:
+    class MutableField(with_metaclass(models.SubfieldBase, models.TextField)):
+        def to_python(self, value):
+            return mutable_from_db(value)
+
+        def get_db_prep_save(self, value, connection):
+            value = mutable_to_db(value)
+            return super(MutableField, self).get_db_prep_save(value, connection)
diff --git a/model_utils/tests/models.py b/model_utils/tests/models.py
index ea46d0f..6b82541 100644
--- a/model_utils/tests/models.py
+++ b/model_utils/tests/models.py
@@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
 
 from model_utils.models import TimeStampedModel, StatusModel, TimeFramedModel
 from model_utils.tracker import FieldTracker, ModelTracker
-from model_utils.managers import QueryManager, InheritanceManager, PassThroughManager
+from model_utils.managers import QueryManager, InheritanceManager
 from model_utils.fields import SplitField, MonitorField, StatusField
 from model_utils.tests.fields import MutableField
 from model_utils import Choices
@@ -201,80 +201,10 @@ class FeaturedManager(models.Manager):
     get_query_set = get_queryset
 
 
-class DudeQuerySet(models.query.QuerySet):
-    def abiding(self):
-        return self.filter(abides=True)
-
-    def rug_positive(self):
-        return self.filter(has_rug=True)
-
-    def rug_negative(self):
-        return self.filter(has_rug=False)
-
-    def by_name(self, name):
-        return self.filter(name__iexact=name)
-
-
-
-class AbidingManager(PassThroughManager):
-    def get_queryset(self):
-        return DudeQuerySet(self.model).abiding()
-
-    get_query_set = get_queryset
-
-    def get_stats(self):
-        return {
-            "abiding_count": self.count(),
-            "rug_count": self.rug_positive().count(),
-        }
-
-
-
-class Dude(models.Model):
-    abides = models.BooleanField(default=True)
-    name = models.CharField(max_length=20)
-    has_rug = models.BooleanField(default=False)
-
-    objects = PassThroughManager(DudeQuerySet)
-    abiders = AbidingManager()
-
-
-class Car(models.Model):
-    name = models.CharField(max_length=20)
-    owner = models.ForeignKey(Dude, related_name='cars_owned')
-
-    objects = PassThroughManager(DudeQuerySet)
-
-
-class SpotManager(PassThroughManager):
-    def get_queryset(self):
-        return super(SpotManager, self).get_queryset().filter(secret=False)
-
-    get_query_set = get_queryset
-
-
-class SpotQuerySet(models.query.QuerySet):
-    def closed(self):
-        return self.filter(closed=True)
-
-    def secured(self):
-        return self.filter(secure=True)
-
-
-class Spot(models.Model):
-    name = models.CharField(max_length=20)
-    secure = models.BooleanField(default=True)
-    closed = models.BooleanField(default=False)
-    secret = models.BooleanField(default=False)
-    owner = models.ForeignKey(Dude, related_name='spots_owned')
-
-    objects = SpotManager.for_queryset_class(SpotQuerySet)()
-
-
 class Tracked(models.Model):
     name = models.CharField(max_length=20)
     number = models.IntegerField()
-    mutable = MutableField()
+    mutable = MutableField(default=None)
 
     tracker = FieldTracker()
 
@@ -319,7 +249,7 @@ class InheritedTracked(Tracked):
 class ModelTracked(models.Model):
     name = models.CharField(max_length=20)
     number = models.IntegerField()
-    mutable = MutableField()
+    mutable = MutableField(default=None)
 
     tracker = ModelTracker()
 
diff --git a/model_utils/tests/tests.py b/model_utils/tests/tests.py
index bbacfd1..d32bf86 100644
--- a/model_utils/tests/tests.py
+++ b/model_utils/tests/tests.py
@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 from datetime import datetime, timedelta
-import pickle
 try:
     from unittest import skipUnless
 except ImportError: # Python 2.6
@@ -25,7 +24,7 @@ from model_utils.tests.models import (
     InheritanceManagerTestParent, InheritanceManagerTestChild1,
     InheritanceManagerTestChild2, TimeStamp, Post, Article, Status,
     StatusPlainTuple, TimeFrame, Monitored, MonitorWhen, MonitorWhenEmpty, StatusManagerAdded,
-    TimeFrameManagerAdded, Dude, SplitFieldAbstractParent, Car, Spot,
+    TimeFrameManagerAdded, SplitFieldAbstractParent,
     ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked,
     Tracked, TrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
     InheritedTracked, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled,
@@ -764,6 +763,11 @@ class InheritanceManagerTests(TestCase):
                          set(expected_related_names))
 
 
+    def test_filter_on_values_queryset(self):
+        queryset = InheritanceManagerTestChild1.objects.values('id').filter(pk=self.child1.pk)
+        self.assertEqual(list(queryset), [{'id': self.child1.pk}])
+
+
 class InheritanceManagerUsingModelsTests(TestCase):
 
     def setUp(self):
@@ -872,11 +876,10 @@ class InheritanceManagerUsingModelsTests(TestCase):
         """
         Confirming that giving a stupid model doesn't work.
         """
-        from django.contrib.auth.models import User
         regex = '^.+? is not a subclass of .+$'
         with self.assertRaisesRegexp(ValueError, regex):
             InheritanceManagerTestParent.objects.select_subclasses(
-                User).order_by('pk')
+                TimeFrame).order_by('pk')
 
 
 
@@ -1206,115 +1209,6 @@ class SouthFreezingTests(TestCase):
         self.assertEqual(kwargs['no_check_for_status'], 'True')
 
 
-
-class PassThroughManagerTests(TestCase):
-    def setUp(self):
-        Dude.objects.create(name='The Dude', abides=True, has_rug=False)
-        Dude.objects.create(name='His Dudeness', abides=False, has_rug=True)
-        Dude.objects.create(name='Duder', abides=False, has_rug=False)
-        Dude.objects.create(name='El Duderino', abides=True, has_rug=True)
-
-
-    def test_chaining(self):
-        self.assertEqual(Dude.objects.by_name('Duder').count(), 1)
-        self.assertEqual(Dude.objects.all().by_name('Duder').count(), 1)
-        self.assertEqual(Dude.abiders.rug_positive().count(), 1)
-        self.assertEqual(Dude.abiders.all().rug_positive().count(), 1)
-
-
-    def test_manager_only_methods(self):
-        stats = Dude.abiders.get_stats()
-        self.assertEqual(stats['rug_count'], 1)
-        with self.assertRaises(AttributeError):
-            Dude.abiders.all().get_stats()
-
-
-    def test_queryset_pickling(self):
-        qs = Dude.objects.all()
-        saltyqs = pickle.dumps(qs)
-        unqs = pickle.loads(saltyqs)
-        self.assertEqual(unqs.by_name('The Dude').count(), 1)
-
-
-    def test_queryset_not_available_on_related_manager(self):
-        dude = Dude.objects.by_name('Duder').get()
-        Car.objects.create(name='Ford', owner=dude)
-        self.assertFalse(hasattr(dude.cars_owned, 'by_name'))
-
-
-    def test_using_dir(self):
-        # make sure introspecing via dir() doesn't actually cause queries,
-        # just as a sanity check.
-        with self.assertNumQueries(0):
-            querysets_to_dir = (
-                Dude.objects,
-                Dude.objects.by_name('Duder'),
-                Dude.objects.all().by_name('Duder'),
-                Dude.abiders,
-                Dude.abiders.rug_positive(),
-                Dude.abiders.all().rug_positive()
-            )
-            for qs in querysets_to_dir:
-                self.assertTrue('by_name' in dir(qs))
-                self.assertTrue('abiding' in dir(qs))
-                self.assertTrue('rug_positive' in dir(qs))
-                self.assertTrue('rug_negative' in dir(qs))
-                # some standard qs methods
-                self.assertTrue('count' in dir(qs))
-                self.assertTrue('order_by' in dir(qs))
-                self.assertTrue('select_related' in dir(qs))
-                # make sure it's been de-duplicated
-                self.assertEqual(1, dir(qs).count('distinct'))
-
-            # manager only method.
-            self.assertTrue('get_stats' in dir(Dude.abiders))
-            # manager only method shouldn't appear on the non AbidingManager
-            self.assertFalse('get_stats' in dir(Dude.objects))
-            # standard manager methods
-            self.assertTrue('get_query_set' in dir(Dude.abiders))
-            self.assertTrue('contribute_to_class' in dir(Dude.abiders))
-
-
-
-class CreatePassThroughManagerTests(TestCase):
-    def setUp(self):
-        self.dude = Dude.objects.create(name='El Duderino')
-        self.other_dude = Dude.objects.create(name='Das Dude')
-
-    def test_reverse_manager(self):
-        Spot.objects.create(
-            name='The Crib', owner=self.dude, closed=True, secure=True,
-            secret=False)
-        self.assertEqual(self.dude.spots_owned.closed().count(), 1)
-        Spot.objects.create(
-            name='The Crux', owner=self.other_dude, closed=True, secure=True,
-            secret=False
-        )
-        self.assertEqual(self.dude.spots_owned.closed().all().count(), 1)
-        self.assertEqual(self.dude.spots_owned.closed().count(), 1)
-
-    def test_related_queryset_pickling(self):
-        Spot.objects.create(
-            name='The Crib', owner=self.dude, closed=True, secure=True,
-            secret=False)
-        qs = self.dude.spots_owned.closed()
-        pickled_qs = pickle.dumps(qs)
-        unpickled_qs = pickle.loads(pickled_qs)
-        self.assertEqual(unpickled_qs.secured().count(), 1)
-
-    def test_related_queryset_superclass_method(self):
-        Spot.objects.create(
-            name='The Crib', owner=self.dude, closed=True, secure=True,
-            secret=False)
-        Spot.objects.create(
-            name='The Secret Crib', owner=self.dude, closed=False, secure=True,
-            secret=True)
-        self.assertEqual(self.dude.spots_owned.count(), 1)
-
-    def test_related_manager_create(self):
-        self.dude.spots_owned.create(name='The Crib', closed=True, secure=True)
-
-
 class FieldTrackerTestCase(TestCase):
 
     tracker = None
@@ -1502,15 +1396,13 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
 class FieldTrackerMultipleInstancesTests(TestCase):
 
     def test_with_deferred_fields_access_multiple(self):
-        instances = [
-            Tracked.objects.create(pk=1, name='foo', number=1),
-            Tracked.objects.create(pk=2, name='bar', number=2)
-        ]
+        Tracked.objects.create(pk=1, name='foo', number=1)
+        Tracked.objects.create(pk=2, name='bar', number=2)
 
         queryset = Tracked.objects.only('id')
 
         for instance in queryset:
-            name = instance.name
+            instance.name
 
 
 class FieldTrackedModelCustomTests(FieldTrackerTestCase,
diff --git a/setup.py b/setup.py
index a1b49b6..feb5ffc 100644
--- a/setup.py
+++ b/setup.py
@@ -35,6 +35,7 @@ setup(
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.2',
         'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: 3.4',
         'Framework :: Django',
     ],
     zip_safe=False,
diff --git a/tox.ini b/tox.ini
index 5255cf5..40aa033 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,7 +3,8 @@ envlist =
     py26-django{14,15,16},
     py27-django14, py27-django15_nosouth,
     py{27,32,33}-django{15,16,17,18,_trunk},
-    py34-django{17,18,_trunk},
+    py27-django19,
+    py34-django{17,18,19,_trunk},
 
 [testenv]
 basepython =
@@ -18,8 +19,9 @@ deps =
     django14: Django==1.4.18
     django15{,_nosouth}: Django==1.5.12
     django16: Django==1.6.10
-    django17: Django==1.7.3
-    django18: Django==1.8a1
+    django17: Django==1.7.7
+    django18: Django==1.8.5
+    django19: Django==1.9
     django_trunk: https://github.com/django/django/tarball/master
     django{14,15,16}: South==1.0.2
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-model-utils.git



More information about the Python-modules-commits mailing list