diff -Nru django-polymorphic-2.0/AUTHORS.rst django-polymorphic-2.0.2/AUTHORS.rst --- django-polymorphic-2.0/AUTHORS.rst 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/AUTHORS.rst 2018-02-05 12:28:40.000000000 +0000 @@ -3,33 +3,67 @@ * Chris Glass * Diederik van der Boor +* Charlie Denton +* Jerome Leclanche Contributors ============= * Abel Daniel +* Adam Chainz * Adam Wentz * Andrew Ingram (contributed setup.py) +* Al Johri +* Alex Alvarez +* Andrew Dodd +* Angel Velasquez +* Austin Matsick * Ben Konrath +* Bert Constantin * Bertrand Bordage * Chad Shryock * Charles Leifer (python 2.4 compatibility) +* Chris Barna +* Chris Brantley +* Christopher Glass * David Sanders +* Éric Araujo * Evan Borgstrom +* Frankie Dintino * Gavin Wahl * Germán M. Bravo +* Gonzalo Bustos +* Gregory Avery-Weir * Hugo Osvaldo Barrera * Jacob Rief +* James Murty * Jedediah Smith (proxy models support) -* Jerome Leclanche * John Furr +* Jonas Haag * Jonas Obrist * Julian Wachholz +* Kamil Bar +* Kelsey Gilmore-Innis * Kevin Armenat +* Krzysztof Gromadzki +* Krzysztof Nazarewski +* Luis Zárate * Marius Lueck * Martin Brochhaus +* Martin Maillard +* Michael Fladischer +* Nick Ward +* Oleg Myltsyn +* Omer Strumpf +* Paweł Adamczak +* Petr Dlouhý +* Sander van Leeuwen +* Sobolev Nikita +* Tadas Dailyda +* Tai Lee * Tomas Peterka +* Tony Narlock * Vail Gold diff -Nru django-polymorphic-2.0/debian/changelog django-polymorphic-2.0.2/debian/changelog --- django-polymorphic-2.0/debian/changelog 2018-02-04 13:12:43.000000000 +0000 +++ django-polymorphic-2.0.2/debian/changelog 2018-02-16 08:46:38.000000000 +0000 @@ -1,3 +1,14 @@ +django-polymorphic (2.0.2-1) unstable; urgency=low + + [ Ondřej Nový ] + * d/control: Set Vcs-* to salsa.debian.org + + [ Michael Fladischer ] + * New upstream release. + * Refresh patches. + + -- Michael Fladischer Fri, 16 Feb 2018 09:46:38 +0100 + django-polymorphic (2.0-1) unstable; urgency=low * New upstream release. diff -Nru django-polymorphic-2.0/debian/control django-polymorphic-2.0.2/debian/control --- django-polymorphic-2.0/debian/control 2018-02-04 13:12:43.000000000 +0000 +++ django-polymorphic-2.0.2/debian/control 2018-02-16 08:46:38.000000000 +0000 @@ -20,8 +20,8 @@ X-Python-Version: >= 2.6 X-Python3-Version: >= 3.2 Homepage: https://github.com/django-polymorphic/django-polymorphic -Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/django-polymorphic.git -Vcs-Browser: https://anonscm.debian.org/cgit/python-modules/packages/django-polymorphic.git +Vcs-Git: https://salsa.debian.org/python-team/modules/django-polymorphic.git +Vcs-Browser: https://salsa.debian.org/python-team/modules/django-polymorphic Testsuite: autopkgtest-pkg-python Package: python-django-polymorphic diff -Nru django-polymorphic-2.0/debian/patches/0001-use-local-objects.inv-where-possible.patch django-polymorphic-2.0.2/debian/patches/0001-use-local-objects.inv-where-possible.patch --- django-polymorphic-2.0/debian/patches/0001-use-local-objects.inv-where-possible.patch 2018-02-04 13:12:43.000000000 +0000 +++ django-polymorphic-2.0.2/debian/patches/0001-use-local-objects.inv-where-possible.patch 2018-02-16 08:46:38.000000000 +0000 @@ -10,7 +10,7 @@ 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py -index 20da1fb..79ba56f 100644 +index ae39fad..e68de86 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -256,11 +256,22 @@ texinfo_documents = [ diff -Nru django-polymorphic-2.0/debian/patches/0002-Remove-dependency-on-dj_database_url-in-tests.patch django-polymorphic-2.0.2/debian/patches/0002-Remove-dependency-on-dj_database_url-in-tests.patch --- django-polymorphic-2.0/debian/patches/0002-Remove-dependency-on-dj_database_url-in-tests.patch 2018-02-04 13:12:43.000000000 +0000 +++ django-polymorphic-2.0.2/debian/patches/0002-Remove-dependency-on-dj_database_url-in-tests.patch 2018-02-16 08:46:38.000000000 +0000 @@ -7,18 +7,18 @@ 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/runtests.py b/runtests.py -index bb3074d..2125821 100755 +index 90b3352..6616d05 100755 --- a/runtests.py +++ b/runtests.py -@@ -2,7 +2,6 @@ - import sys +@@ -3,7 +3,6 @@ import sys + import warnings from os.path import abspath, dirname -import dj_database_url import django from django.conf import settings from django.core.management import execute_from_command_line -@@ -19,14 +18,14 @@ if not settings.configured: +@@ -23,14 +22,14 @@ if not settings.configured: settings.configure( DEBUG=False, DATABASES={ diff -Nru django-polymorphic-2.0/docs/changelog.rst django-polymorphic-2.0.2/docs/changelog.rst --- django-polymorphic-2.0/docs/changelog.rst 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/docs/changelog.rst 2018-02-05 12:28:40.000000000 +0000 @@ -1,6 +1,27 @@ Changelog ========= +Changes in 2.0.2 (2018-02-05) +----------------------------- + +* Fixed manager inheritance behavior for Django 1.11, by automatically enabling ``Meta.manager_inheritance_from_future`` if it's not defined. + This restores the manager inheritance behavior that *django-polymorphic 1.3* provided for Django 1.x projects. +* Fixed internal ``base_objects`` usage. + + +Changes in 2.0.1 (2018-02-05) +----------------------------- + +* Fixed manager inheritance detection for Django 1.11. + + It's recommended to use ``Meta.manager_inheritance_from_future`` so Django 1.x code also inherit + the ``PolymorphicManager`` in all subclasses. Django 2.0 already does this by default. + +* Deprecated the ``base_objects`` manager. Use ``objects.non_polymorphic()`` instead. +* Optimized detection for dumpdata behavior, avoiding the performance hit of ``__getattribute__()``. +* Fixed test management commands + + Changes in 2.0 (2018-01-22) --------------------------- diff -Nru django-polymorphic-2.0/docs/conf.py django-polymorphic-2.0.2/docs/conf.py --- django-polymorphic-2.0/docs/conf.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/docs/conf.py 2018-02-05 12:28:40.000000000 +0000 @@ -61,9 +61,9 @@ # built documents. # # The short X.Y version. -version = '2.0' +version = '2.0.2' # The full version, including alpha/beta/rc tags. -release = '2.0' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -Nru django-polymorphic-2.0/example/pexp/management/commands/p2cmd.py django-polymorphic-2.0.2/example/pexp/management/commands/p2cmd.py --- django-polymorphic-2.0/example/pexp/management/commands/p2cmd.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/example/pexp/management/commands/p2cmd.py 2018-02-05 12:28:40.000000000 +0000 @@ -7,7 +7,7 @@ import time from pprint import pprint from random import Random -from django.core.management.base import NoArgsCommand +from django.core.management import BaseCommand from django.db import connection from pexp.models import * @@ -46,7 +46,7 @@ return wrapper -class Command(NoArgsCommand): +class Command(BaseCommand): help = "" def handle_noargs(self, **options): diff -Nru django-polymorphic-2.0/example/pexp/management/commands/polybench.py django-polymorphic-2.0.2/example/pexp/management/commands/polybench.py --- django-polymorphic-2.0/example/pexp/management/commands/polybench.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/example/pexp/management/commands/polybench.py 2018-02-05 12:28:40.000000000 +0000 @@ -6,7 +6,7 @@ import time import sys -from django.core.management.base import NoArgsCommand +from django.core.management import BaseCommand from django.db import connection from pprint import pprint from pexp.models import * @@ -60,7 +60,7 @@ # benchmarks def bench_create(model): - for i in xrange(num_objects): + for i in range(num_objects): model.objects.create(field1='abc' + str(i), field2='abcd' + str(i), field3='abcde' + str(i)) # print 'count:',model.objects.count() @@ -71,7 +71,7 @@ def bench_load1_short(model): - for i in xrange(num_objects / 100): + for i in range(num_objects / 100): for o in model.objects.all()[:100]: pass @@ -84,7 +84,7 @@ def bench_load2_short(model): - for i in xrange(num_objects / 100): + for i in range(num_objects / 100): for o in model.objects.all()[:100]: f1 = o.field1 f2 = o.field2 @@ -98,7 +98,7 @@ # Command -class Command(NoArgsCommand): +class Command(BaseCommand): help = "" def handle_noargs(self, **options): @@ -112,5 +112,3 @@ ] for f, iterations in func_list: run_vanilla_any_poly(f, iterations=iterations) - - print diff -Nru django-polymorphic-2.0/example/pexp/management/commands/polymorphic_create_test_data.py django-polymorphic-2.0.2/example/pexp/management/commands/polymorphic_create_test_data.py --- django-polymorphic-2.0/example/pexp/management/commands/polymorphic_create_test_data.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/example/pexp/management/commands/polymorphic_create_test_data.py 2018-02-05 12:28:40.000000000 +0000 @@ -3,12 +3,12 @@ This module is a scratchpad for general development, testing & debugging """ -from django.core.management.base import NoArgsCommand +from django.core.management import BaseCommand from pexp.models import * -class Command(NoArgsCommand): +class Command(BaseCommand): help = "" def handle_noargs(self, **options): @@ -16,5 +16,4 @@ o = Project.objects.create(topic="John's gathering") o = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") o = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") - print Project.objects.all() - print + print(Project.objects.all()) diff -Nru django-polymorphic-2.0/polymorphic/base.py django-polymorphic-2.0.2/polymorphic/base.py --- django-polymorphic-2.0/polymorphic/base.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/polymorphic/base.py 2018-02-05 12:28:40.000000000 +0000 @@ -7,7 +7,10 @@ import inspect import os import sys +import warnings +import django +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.db.models.base import ModelBase from django.db.models.manager import ManagerDescriptor @@ -22,6 +25,10 @@ DUMPDATA_COMMAND = os.path.join('django', 'core', 'management', 'commands', 'dumpdata.py') +class ManagerInheritanceWarning(RuntimeWarning): + pass + + ################################################################################### # PolymorphicModel meta class @@ -56,6 +63,15 @@ if not attrs and model_name == 'NewBase': return super(PolymorphicModelBase, self).__new__(self, model_name, bases, attrs) + # Make sure that manager_inheritance_from_future is set, since django-polymorphic 1.x already + # simulated that behavior on the polymorphic manager to all subclasses behave like polymorphics + if django.VERSION < (2, 0): + if 'Meta' in attrs: + if not hasattr(attrs['Meta'], 'manager_inheritance_from_future'): + attrs['Meta'].manager_inheritance_from_future = True + else: + attrs['Meta'] = type('Meta', (object,), {'manager_inheritance_from_future': True}) + # create new model new_class = self.call_superclass_new_method(model_name, bases, attrs) @@ -134,33 +150,62 @@ and its querysets from PolymorphicQuerySet - throw AssertionError if not""" if not issubclass(type(manager), PolymorphicManager): - e = 'PolymorphicModel: "' + model_name + '.' + manager_name + '" manager is of type "' + type(manager).__name__ - e += '", but must be a subclass of PolymorphicManager' - raise AssertionError(e) + if django.VERSION < (2, 0): + extra = "\nConsider using Meta.manager_inheritance_from_future = True for Django 1.x projects" + else: + extra = '' + e = ('PolymorphicModel: "{0}.{1}" manager is of type "{2}", but must be a subclass of' + ' PolymorphicManager.{extra} to support retrieving subclasses'.format( + model_name, manager_name, type(manager).__name__, extra=extra)) + warnings.warn(e, ManagerInheritanceWarning, stacklevel=3) + return manager + if not getattr(manager, 'queryset_class', None) or not issubclass(manager.queryset_class, PolymorphicQuerySet): - e = 'PolymorphicModel: "' + model_name + '.' + manager_name + '" (PolymorphicManager) has been instantiated with a queryset class which is' - e += ' not a subclass of PolymorphicQuerySet (which is required)' - raise AssertionError(e) + e = ('PolymorphicModel: "{0}.{1}" has been instantiated with a queryset class ' + 'which is not a subclass of PolymorphicQuerySet (which is required)'.format( + model_name, manager_name)) + warnings.warn(e, ManagerInheritanceWarning, stacklevel=3) return manager - # hack: a small patch to Django would be a better solution. - # Django's management command 'dumpdata' relies on non-polymorphic - # behaviour of the _default_manager. Therefore, we catch any access to _default_manager - # here and return the non-polymorphic default manager instead if we are called from 'dumpdata.py' - # Otherwise, the base objects will be upcasted to polymorphic models, and be outputted as such. - # (non-polymorphic default manager is 'base_objects' for polymorphic models). - # This way we don't need to patch django.core.management.commands.dumpdata - # for all supported Django versions. - if len(sys.argv) > 1 and sys.argv[1] == 'dumpdata': - # manage.py dumpdata is running - - def __getattribute__(self, name): - if name == '_default_manager': - frm = inspect.stack()[1] # frm[1] is caller file name, frm[3] is caller function name - if DUMPDATA_COMMAND in frm[1]: - return self.base_objects - # caller_mod_name = inspect.getmodule(frm[0]).__name__ # does not work with python 2.4 - # if caller_mod_name == 'django.core.management.commands.dumpdata': + @property + def base_objects(self): + warnings.warn( + "Using PolymorphicModel.base_objects is deprecated.\n" + "Use {0}.objects.non_polymorphic() instead.".format(self.__class__.__name__), + DeprecationWarning, stacklevel=2) + return self._base_objects + + @property + def _base_objects(self): + # Create a manager so the API works as expected. Just don't register it + # anymore in the Model Meta, so it doesn't substitute our polymorphic + # manager as default manager for the third level of inheritance when + # that third level doesn't define a manager at all. + manager = models.Manager() + manager.name = 'base_objects' + manager.model = self + return manager + + @property + def _default_manager(self): + if len(sys.argv) > 1 and sys.argv[1] == 'dumpdata': + # TODO: investigate Django how this can be avoided + # hack: a small patch to Django would be a better solution. + # Django's management command 'dumpdata' relies on non-polymorphic + # behaviour of the _default_manager. Therefore, we catch any access to _default_manager + # here and return the non-polymorphic default manager instead if we are called from 'dumpdata.py' + # Otherwise, the base objects will be upcasted to polymorphic models, and be outputted as such. + # (non-polymorphic default manager is 'base_objects' for polymorphic models). + # This way we don't need to patch django.core.management.commands.dumpdata + # for all supported Django versions. + frm = inspect.stack()[1] # frm[1] is caller file name, frm[3] is caller function name + if DUMPDATA_COMMAND in frm[1]: + return self._base_objects + + manager = super(PolymorphicModelBase, self)._default_manager + if not isinstance(manager, PolymorphicManager): + warnings.warn("{0}._default_manager is not a PolymorphicManager".format( + self.__class__.__name__ + ), ManagerInheritanceWarning) - return super(PolymorphicModelBase, self).__getattribute__(name) - # TODO: investigate Django how this can be avoided + return manager diff -Nru django-polymorphic-2.0/polymorphic/models.py django-polymorphic-2.0.2/polymorphic/models.py --- django-polymorphic-2.0/polymorphic/models.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/polymorphic/models.py 2018-02-05 12:28:40.000000000 +0000 @@ -54,7 +54,6 @@ # Note that Django 1.5 removes these managers because the model is abstract. # They are pretended to be there by the metaclass in PolymorphicModelBase.get_inherited_managers() objects = PolymorphicManager() - base_objects = models.Manager() class Meta: abstract = True @@ -173,7 +172,7 @@ def create_accessor_function_for_model(model, accessor_name): def accessor_function(self): - attr = model.base_objects.get(pk=self.pk) + attr = model._base_objects.get(pk=self.pk) return attr return accessor_function diff -Nru django-polymorphic-2.0/polymorphic/query.py django-polymorphic-2.0.2/polymorphic/query.py --- django-polymorphic-2.0/polymorphic/query.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/polymorphic/query.py 2018-02-05 12:28:40.000000000 +0000 @@ -20,40 +20,6 @@ Polymorphic_QuerySet_objects_per_request = 100 -def _polymorphic_iterator(queryset, base_iter): - """ - Here we do the same as:: - - real_results = queryset._get_real_instances(list(base_iter)) - for o in real_results: yield o - - but it requests the objects in chunks from the database, - with Polymorphic_QuerySet_objects_per_request per chunk - """ - while True: - base_result_objects = [] - reached_end = False - - # Make sure the base iterator is read in chunks instead of - # reading it completely, in case our caller read only a few objects. - for i in range(Polymorphic_QuerySet_objects_per_request): - - try: - o = next(base_iter) - base_result_objects.append(o) - except StopIteration: - reached_end = True - break - - real_results = queryset._get_real_instances(base_result_objects) - - for o in real_results: - yield o - - if reached_end: - return - - class PolymorphicModelIterable(ModelIterable): """ ModelIterable for PolymorphicModel @@ -66,7 +32,40 @@ base_iter = super(PolymorphicModelIterable, self).__iter__() if self.queryset.polymorphic_disabled: return base_iter - return _polymorphic_iterator(self.queryset, base_iter) + return self._polymorphic_iterator(base_iter) + + def _polymorphic_iterator(self, base_iter): + """ + Here we do the same as:: + + real_results = queryset._get_real_instances(list(base_iter)) + for o in real_results: yield o + + but it requests the objects in chunks from the database, + with Polymorphic_QuerySet_objects_per_request per chunk + """ + while True: + base_result_objects = [] + reached_end = False + + # Make sure the base iterator is read in chunks instead of + # reading it completely, in case our caller read only a few objects. + for i in range(Polymorphic_QuerySet_objects_per_request): + + try: + o = next(base_iter) + base_result_objects.append(o) + except StopIteration: + reached_end = True + break + + real_results = self.queryset._get_real_instances(base_result_objects) + + for o in real_results: + yield o + + if reached_end: + return def transmogrify(cls, obj): @@ -380,7 +379,7 @@ # Then we copy the extra() select fields from the base objects to the real objects. # TODO: defer(), only(): support for these would be around here for real_concrete_class, idlist in idlist_per_model.items(): - real_objects = real_concrete_class.base_objects.db_manager(self.db).filter(**{ + real_objects = real_concrete_class._base_objects.db_manager(self.db).filter(**{ ('%s__in' % pk_name): idlist, }) real_objects.query.select_related = self.query.select_related # copy select related configuration to new qs diff -Nru django-polymorphic-2.0/polymorphic/tests/models.py django-polymorphic-2.0.2/polymorphic/tests/models.py --- django-polymorphic-2.0/polymorphic/tests/models.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/polymorphic/tests/models.py 2018-02-05 12:28:40.000000000 +0000 @@ -191,7 +191,9 @@ class MROBase2(MROBase1): - pass # Django vanilla inheritance does not inherit MyManager as _default_manager here + class Meta: + # Django 1.x inheritance does not inherit MyManager as _default_manager here + manager_inheritance_from_future = True class MROBase3(models.Model): @@ -200,7 +202,8 @@ class MRODerived(MROBase2, MROBase3): - pass + class Meta: + manager_inheritance_from_future = True class ParentModelWithManager(PolymorphicModel): diff -Nru django-polymorphic-2.0/runtests.py django-polymorphic-2.0.2/runtests.py --- django-polymorphic-2.0/runtests.py 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/runtests.py 2018-02-05 12:28:40.000000000 +0000 @@ -1,5 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python -Wd import sys +import warnings from os.path import abspath, dirname import dj_database_url @@ -8,6 +9,9 @@ from django.core.management import execute_from_command_line +# python -Wd, or run via coverage: +warnings.simplefilter('always', DeprecationWarning) + # Give feedback on used versions sys.stderr.write('Using Python version {0} from {1}\n'.format(sys.version[:5], sys.executable)) sys.stderr.write('Using Django version {0} from {1}\n'.format( @@ -41,24 +45,24 @@ MIDDLEWARE_CLASSES=(), SITE_ID=3, TEMPLATES=[{ - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": (), - "OPTIONS": { - "loaders": ( - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ), - "context_processors": ( - "django.template.context_processors.debug", - "django.template.context_processors.i18n", - "django.template.context_processors.media", - "django.template.context_processors.request", - "django.template.context_processors.static", - "django.contrib.messages.context_processors.messages", - "django.contrib.auth.context_processors.auth", - ), - }, + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": (), + "OPTIONS": { + "loaders": ( + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + ), + "context_processors": ( + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.request", + "django.template.context_processors.static", + "django.contrib.messages.context_processors.messages", + "django.contrib.auth.context_processors.auth", + ), }, + }, ], POLYMORPHIC_TEST_SWAPPABLE='polymorphic.swappedmodel', ROOT_URLCONF=None, diff -Nru django-polymorphic-2.0/setup.cfg django-polymorphic-2.0.2/setup.cfg --- django-polymorphic-2.0/setup.cfg 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/setup.cfg 2018-02-05 12:28:40.000000000 +0000 @@ -1,6 +1,6 @@ [metadata] name = django-polymorphic -version = 2.0 +version = 2.0.2 description = Seamless polymorphic inheritance for Django models long_description = file:README.rst author = Bert Constantin diff -Nru django-polymorphic-2.0/.travis.yml django-polymorphic-2.0.2/.travis.yml --- django-polymorphic-2.0/.travis.yml 2018-01-22 09:18:51.000000000 +0000 +++ django-polymorphic-2.0.2/.travis.yml 2018-02-05 12:28:40.000000000 +0000 @@ -21,6 +21,8 @@ services: - postgres +addons: + postgresql: "9.6" matrix: fast_finish: true