Commit bc795faf authored by Brian May's avatar Brian May

record new upstream branch created by importing django-model-utils_2.5.2.orig.tar.gz and merge it

parents a80fac91 3896a377
......@@ -6,6 +6,7 @@ env:
- TOXENV=py26-django14
- TOXENV=py26-django15
- TOXENV=py26-django16
- TOXENV=py27-django110
- TOXENV=py27-django14
- TOXENV=py27-django15
- TOXENV=py27-django15_nosouth
......@@ -14,20 +15,19 @@ env:
- TOXENV=py27-django18
- TOXENV=py27-django19
- TOXENV=py27-django_trunk
- TOXENV=py32-django15
- TOXENV=py32-django16
- TOXENV=py32-django17
- TOXENV=py32-django18
- TOXENV=py32-django_trunk
- TOXENV=py33-django15
- TOXENV=py33-django16
- TOXENV=py33-django17
- TOXENV=py33-django18
- TOXENV=py33-django_trunk
- TOXENV=py34-django110
- TOXENV=py34-django17
- TOXENV=py34-django18
- TOXENV=py34-django19
- TOXENV=py34-django_trunk
- TOXENV=py35-django110
- TOXENV=py35-django18
- TOXENV=py35-django19
- TOXENV=py35-django_trunk
install:
- pip install --upgrade pip setuptools tox virtualenv coveralls
......@@ -37,9 +37,11 @@ script:
matrix:
allow_failures:
- env: TOXENV=py27-django110
- env: TOXENV=py34-django110
- env: TOXENV=py35-django110
- env: TOXENV=py27-django_trunk
- env: TOXENV=py32-django_trunk
- env: TOXENV=py33-django_trunk
- env: TOXENV=py34-django_trunk
- env: TOXENV=py35-django_trunk
after_success: coveralls
......@@ -2,6 +2,7 @@ ad-m <github.com/ad-m>
Alejandro Varas <alej0varas@gmail.com>
Alex Orange <crazycasta@gmail.com>
Andy Freeland <andy@andyfreeland.net>
Artis Avotins <artis.avotins@gmail.com>
Bram Boogaard <b.boogaard@auto-interactive.nl>
Carl Meyer <carl@dirtcircle.com>
Curtis Maloney <curtis@tinbrain.net>
......@@ -22,6 +23,7 @@ Jeff Elmore <jeffelmore.org>
Keryn Knight <kerynknight.com>
Matthew Schinckel <matt@schinckel.net>
Michael van Tellingen <michaelvantellingen@gmail.com>
Mike Bryant <mike@mikebryant.me.uk>
Mikhail Silonov <silonov.pro>
Patryk Zawadzki <patrys@room-303.com>
Paul McLanahan <paul@mclanahan.net>
......
CHANGES
=======
2.4 (2015-12-03)
2.5.2 (2016.08.09)
------------------
* Include `runtests.py` in sdist.
2.5.1 (2016.08.03)
------------------
* Fix `InheritanceQuerySet` raising an `AttributeError` exception
under Django 1.9.
* Django 1.10 support regressed with changes between pre-alpha and final
release; 1.10 currently not supported.
2.5 (2016.04.18)
----------------
* Add support for Django 1.9. Drop support for Django 1.6 and earlier.
* Drop support for Python 3.2.
* Add support for Django 1.10 pre-alpha.
* Track foreign keys on parent models properly when a tracker
is defined on a child model. Fixes GH-214.
2.4 (2015.12.03)
----------------
* Remove `PassThroughManager`. Use Django's built-in `QuerySet.as_manager()`
and/or `Manager.from_queryset()` utilities instead.
* Add support for Django 1.9.
2.3.1 (2015-07-20)
------------------
......
Contributing
============
Below is a list of tips for submitting issues and pull requests. These are
suggestions and not requirements.
Below is a list of tips for submitting issues and pull requests.
Submitting Issues
-----------------
Issues are often easier to reproduce/resolve when they have:
Issues are easier to reproduce/resolve when they have:
- A pull request with a failing test demonstrating the issue
- A code example that produces the issue consistently
- A traceback (when applicable)
Pull Requests
-------------
When creating a pull request, try to:
When creating a pull request:
- Write tests if applicable
- Note important changes in the `CHANGES`_ file
- Update the documentation if needed
- Write tests
- Note user-facing changes in the `CHANGES`_ file
- Update the documentation
- Add yourself to the `AUTHORS`_ file
- If you have added or changed translated strings, run ``make messages`` to
update the ``.po`` translation files, and update translations for any
......@@ -47,6 +47,7 @@ After you finished editing add yourself to the list of translators.
If you have created a new translation, make sure to copy the header from one
of the existing translation files.
Testing
-------
......
......@@ -4,4 +4,5 @@ include LICENSE.txt
include MANIFEST.in
include README.rst
include TODO.rst
locale/*/LC_MESSAGES/django.po
\ No newline at end of file
recursive-include locale django.po
include runtests.py
......@@ -11,35 +11,29 @@ django-model-utils
Django model mixins and utilities.
``django-model-utils`` supports `Django`_ 1.4.10 and later on Python 2.6, 2.7,
3.2, 3.3 and 3.4.
``django-model-utils`` supports `Django`_ 1.4 through 1.9 (latest bugfix
release in each series only) on Python 2.6 (through Django 1.6 only), 2.7, 3.3
(through Django 1.8 only), 3.4 and 3.5.
.. _Django: http://www.djangoproject.com/
This app is available on `PyPI`_.
Getting Help
============
.. _PyPI: https://pypi.python.org/pypi/django-model-utils/
Documentation for django-model-utils is available at https://django-model-utils.readthedocs.org/
This app is available on `PyPI`_.
Getting Help
============
.. _PyPI: https://pypi.python.org/pypi/django-model-utils/
Documentation for django-model-utils is available at https://django-model-utils.readthedocs.io/
Contributing
============
Please file bugs and send pull requests to the `GitHub repository`_ and `issue
tracker`_.
tracker`_. See `CONTRIBUTING.rst`_ for details.
.. _GitHub repository: https://github.com/carljm/django-model-utils/
.. _issue tracker: https://github.com/carljm/django-model-utils/issues
(Until January 2013 django-model-utils primary development was hosted at
`BitBucket`_; the issue tracker there will remain open until all issues and
pull requests tracked in it are closed, but all new issues should be filed at
GitHub.)
.. _BitBucket: https://bitbucket.org/carljm/django-model-utils/overview
.. _CONTRIBUTING.rst: https://github.com/carljm/django-model-utils/blob/master/CONTRIBUTING.rst
TODO
====
* Switch to proper test skips once Django 1.3 is minimum supported.
# see git-dpm(1) from git-dpm package
c0b30b27ddf45636f54c8dde126a6fc0a8a8ddb9
c0b30b27ddf45636f54c8dde126a6fc0a8a8ddb9
c0b30b27ddf45636f54c8dde126a6fc0a8a8ddb9
c0b30b27ddf45636f54c8dde126a6fc0a8a8ddb9
django-model-utils_2.4.orig.tar.gz
6e7fcf0e527391eb4757f53a4f3c0cfaedf975c0
40684
3896a3775fa50d001bf7fe4104550e3055fb2cc0
3896a3775fa50d001bf7fe4104550e3055fb2cc0
3896a3775fa50d001bf7fe4104550e3055fb2cc0
3896a3775fa50d001bf7fe4104550e3055fb2cc0
django-model-utils_2.5.2.orig.tar.gz
d441ebadb9f6594fe5c385fa516bad022d604a61
41124
debianTag="debian/%e%v"
patchedTag="patched/%e%v"
upstreamTag="upstream/%e%u"
......@@ -128,50 +128,9 @@ not required).
PassThroughManager
------------------
A common "gotcha" when defining methods on a custom manager class is that those
same methods are not automatically also available on the QuerySets returned by
that manager, so are not "chainable". This can be counterintuitive, as most of
the public QuerySet API is mirrored on managers. It is possible to create a
custom Manager that returns QuerySets that have the same additional methods,
but this requires boilerplate code. The ``PassThroughManager`` class
(`contributed by Paul McLanahan`_) removes this boilerplate.
.. _contributed by Paul McLanahan: http://paulm.us/post/3717466639/passthroughmanager-for-django
To use ``PassThroughManager``, rather than defining a custom manager with
additional methods, define a custom ``QuerySet`` subclass with the additional
methods you want, and pass that ``QuerySet`` subclass to the
``PassThroughManager.for_queryset_class()`` class method. The returned
``PassThroughManager`` subclass will always return instances of your custom
``QuerySet``, and you can also call methods of your custom ``QuerySet``
directly on the manager:
.. code-block:: python
from datetime import datetime
from django.db import models
from django.db.models.query import QuerySet
from model_utils.managers import PassThroughManager
class PostQuerySet(QuerySet):
def by_author(self, user):
return self.filter(user=user)
def published(self):
return self.filter(published__lte=datetime.now())
def unpublished(self):
return self.filter(published__gte=datetime.now())
class Post(models.Model):
user = models.ForeignKey(User)
published = models.DateTimeField()
objects = PassThroughManager.for_queryset_class(PostQuerySet)()
Post.objects.published()
Post.objects.by_author(user=request.user).unpublished()
`PassThroughManager` was removed in django-model-utils 2.4. Use Django's
built-in `QuerySet.as_manager()` and/or `Manager.from_queryset()` utilities
instead.
Mixins
------
......
......@@ -153,7 +153,7 @@ Returns ``None`` when the model instance isn't saved yet.
has_changed
~~~~~~~~~~~
Returns ``True`` if the given field has changed since the last save:
Returns ``True`` if the given field has changed since the last save. The ``has_changed`` method expects a single field:
.. code-block:: pycon
......
from .choices import Choices
from .tracker import FieldTracker, ModelTracker
__version__ = '2.4'
__version__ = '2.5.2'
from __future__ import unicode_literals
import django
from django.db import models
from django.db.models.fields.related import OneToOneField
from django.db.models.fields.related import OneToOneField, OneToOneRel
from django.db.models.query import QuerySet
from django.core.exceptions import ObjectDoesNotExist
......@@ -101,12 +101,20 @@ class InheritanceQuerySetMixin(object):
recursively, returning a `list` of strings representing the
relations for select_related
"""
if django.VERSION < (1, 8):
related_objects = model._meta.get_all_related_objects()
else:
related_objects = [
f for f in model._meta.get_fields()
if isinstance(f, OneToOneRel)]
rels = [
rel for rel in model._meta.get_all_related_objects()
rel for rel in related_objects
if isinstance(rel.field, OneToOneField)
and issubclass(rel.field.model, model)
and model is not rel.field.model
]
subclasses = []
if levels:
levels -= 1
......@@ -135,12 +143,16 @@ class InheritanceQuerySetMixin(object):
if levels:
levels -= 1
while parent_link is not None:
ancestry.insert(0, parent_link.related.get_accessor_name())
if django.VERSION < (1, 8):
related = parent_link.related
else:
related = parent_link.rel
ancestry.insert(0, related.get_accessor_name())
if levels or levels is None:
if django.VERSION < (1, 8):
parent_model = parent_link.related.parent_model
parent_model = related.parent_model
else:
parent_model = parent_link.related.model
parent_model = related.model
parent_link = parent_model._meta.get_ancestor_link(
self.model)
else:
......@@ -149,6 +161,12 @@ class InheritanceQuerySetMixin(object):
def _get_sub_obj_recurse(self, obj, s):
rel, _, s = s.partition(LOOKUP_SEP)
# Django 1.9: If a primitive type gets passed to this recursive function,
# return None as non-models are not part of inheritance.
if not isinstance(obj, models.Model):
return None
try:
node = getattr(obj, rel)
except ObjectDoesNotExist:
......
......@@ -246,6 +246,11 @@ class InheritedTracked(Tracked):
name2 = models.CharField(max_length=20)
class InheritedTrackedFK(TrackedFK):
custom_tracker = FieldTracker(fields=['fk_id'])
custom_tracker_without_id = FieldTracker(fields=['fk'])
class ModelTracked(models.Model):
name = models.CharField(max_length=20)
number = models.IntegerField()
......
......@@ -26,7 +26,7 @@ from model_utils.tests.models import (
StatusPlainTuple, TimeFrame, Monitored, MonitorWhen, MonitorWhenEmpty, StatusManagerAdded,
TimeFrameManagerAdded, SplitFieldAbstractParent,
ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked,
Tracked, TrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
InheritedTracked, StatusFieldDefaultFilled, StatusFieldDefaultNotFilled,
InheritanceManagerTestChild3, StatusFieldChoicesName)
......@@ -768,6 +768,54 @@ class InheritanceManagerTests(TestCase):
self.assertEqual(list(queryset), [{'id': self.child1.pk}])
@skipUnless(django.VERSION >= (1, 9, 0), "test only applies to Django 1.9+")
def test_dj19_values_list_on_select_subclasses(self):
"""
Using `select_subclasses` in conjunction with `values_list()` raised an
exception in `_get_sub_obj_recurse()` because the result of `values_list()`
is either a `tuple` or primitive objects if `flat=True` is specified,
because no type checking was done prior to fetching child nodes.
Django versions below 1.9 are not affected by this bug.
"""
# Querysets are cast to lists to force immediate evaluation.
# No exceptions must be thrown.
# No argument to select_subclasses
objs_1 = list(
self.get_manager().
select_subclasses().
values_list('id')
)
# String argument to select_subclasses
objs_2 = list(
self.get_manager().
select_subclasses(
"inheritancemanagertestchild2"
).
values_list('id')
)
# String argument to select_subclasses
objs_3 = list(
self.get_manager().
select_subclasses(
InheritanceManagerTestChild2
).
values_list('id')
)
assert all((
isinstance(objs_1, list),
isinstance(objs_2, list),
isinstance(objs_3, list),
))
assert objs_1 == objs_2 == objs_3
class InheritanceManagerUsingModelsTests(TestCase):
def setUp(self):
......@@ -1682,6 +1730,11 @@ class InheritedFieldTrackerTests(FieldTrackerTests):
self.assertRaises(FieldError, self.tracker.has_changed, 'name2')
class FieldTrackerInheritedForeignKeyTests(FieldTrackerForeignKeyTests):
tracked_class = InheritedTrackedFK
class ModelTrackerTests(FieldTrackerTests):
tracked_class = ModelTracked
......
......@@ -63,7 +63,7 @@ class FieldInstanceTracker(object):
def init_deferred_fields(self):
self.instance._deferred_fields = []
if not self.instance._deferred:
if hasattr(self.instance, '_deferred') and not self.instance._deferred:
return
class DeferredAttributeTracker(DeferredAttribute):
......@@ -101,7 +101,7 @@ class FieldTracker(object):
def get_field_map(self, cls):
"""Returns dict mapping fields names to model attribute names"""
field_map = dict((field, field) for field in self.fields)
all_fields = dict((f.name, f.attname) for f in cls._meta.local_fields)
all_fields = dict((f.name, f.attname) for f in cls._meta.fields)
field_map.update(**dict((k, v) for (k, v) in all_fields.items()
if k in field_map))
return field_map
......@@ -113,7 +113,7 @@ class FieldTracker(object):
def finalize_class(self, sender, **kwargs):
if self.fields is None:
self.fields = (field.attname for field in sender._meta.local_fields)
self.fields = (field.attname for field in sender._meta.fields)
self.fields = set(self.fields)
self.field_map = self.get_field_map(sender)
models.signals.post_init.connect(self.initialize_tracker)
......
from os.path import join
import os
from setuptools import setup, find_packages
long_description = (open('README.rst').read() +
open('CHANGES.rst').read() +
open('TODO.rst').read())
def long_desc(root_path):
FILES = ['README.rst', 'CHANGES.rst']
for filename in FILES:
filepath = os.path.realpath(os.path.join(root_path, filename))
if os.path.isfile(filepath):
with open(filepath, mode='r') as f:
yield f.read()
def get_version():
with open(join('model_utils', '__init__.py')) as f:
HERE = os.path.abspath(os.path.dirname(__file__))
long_description = "\n\n".join(long_desc(HERE))
def get_version(root_path):
with open(os.path.join(root_path, 'model_utils', '__init__.py')) as f:
for line in f:
if line.startswith('__version__ ='):
return line.split('=')[1].strip().strip('"\'')
setup(
name='django-model-utils',
version=get_version(),
version=get_version(HERE),
description='Django model mixins and utilities',
long_description=long_description,
author='Carl Meyer',
......@@ -33,9 +41,9 @@ setup(
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Framework :: Django',
],
zip_safe=False,
......
[tox]
envlist =
py26-django{14,15,16},
py27-django14, py27-django15_nosouth,
py{27,32,33}-django{15,16,17,18,_trunk},
py27-django19,
py34-django{17,18,19,_trunk},
py27-django{14,19,110,_trunk}, py27-django15_nosouth,
py{27,33}-django{15,16,17,18},
py34-django{17,18,19,110,_trunk},
py35-django{18,19,110,_trunk},
[testenv]
basepython =
py26: python2.6
py27: python2.7
py32: python3.2
py33: python3.3
py34: python3.4
py35: python3.5
deps =
coverage == 3.6
django14: Django==1.4.18
django15{,_nosouth}: Django==1.5.12
django16: Django==1.6.10
django17: Django==1.7.7
django18: Django==1.8.5
django19: Django==1.9
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
django19: Django>=1.9,<1.10
django110: Django>=1.10,<1.11
django_trunk: https://github.com/django/django/tarball/master
django{14,15,16}: South==1.0.2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment