diff --git a/django/template/__init__.py b/django/template/__init__.py index b55b4491c6..9cf25754f8 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -58,7 +58,8 @@ from .exceptions import TemplateDoesNotExist, TemplateSyntaxError # NOQA i # Template parts from .base import ( # NOQA isort:skip - Context, Node, NodeList, Origin, RequestContext, Template, Variable, + Context, Node, NodeList, Origin, RequestContext, StringOrigin, Template, + Variable, ) # Library management diff --git a/django/template/base.py b/django/template/base.py index bb2456ad05..a7042adc4a 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -59,6 +59,9 @@ from django.template.context import ( # NOQA: imported for backwards compatibil BaseContext, Context, ContextPopException, RequestContext, ) from django.utils import six +from django.utils.deprecation import ( + DeprecationInstanceCheck, RemovedInDjango20Warning, +) from django.utils.encoding import ( force_str, force_text, python_2_unicode_compatible, ) @@ -156,6 +159,11 @@ class Origin(object): ) +class StringOrigin(six.with_metaclass(DeprecationInstanceCheck, Origin)): + alternative = 'django.template.Origin' + deprecation_warning = RemovedInDjango20Warning + + class Template(object): def __init__(self, template_string, origin=None, name=None, engine=None): try: diff --git a/django/template/loader.py b/django/template/loader.py index 38dfabc9f5..98e56817bf 100644 --- a/django/template/loader.py +++ b/django/template/loader.py @@ -1,4 +1,10 @@ +from django.utils import six +from django.utils.deprecation import ( + DeprecationInstanceCheck, RemovedInDjango20Warning, +) + from . import engines +from .base import Origin from .exceptions import TemplateDoesNotExist @@ -57,3 +63,8 @@ def render_to_string(template_name, context=None, request=None, using=None): def _engine_list(using=None): return engines.all() if using is None else [engines[using]] + + +class LoaderOrigin(six.with_metaclass(DeprecationInstanceCheck, Origin)): + alternative = 'django.template.Origin' + deprecation_warning = RemovedInDjango20Warning diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py index 33c384d1f8..905bbc4f6d 100644 --- a/django/utils/deprecation.py +++ b/django/utils/deprecation.py @@ -8,7 +8,8 @@ class RemovedInDjango20Warning(PendingDeprecationWarning): pass -RemovedInNextVersionWarning = DeprecationWarning +class RemovedInNextVersionWarning(DeprecationWarning): + pass class warn_about_renamed_method(object): @@ -69,3 +70,12 @@ class RenameMethodsBase(type): setattr(base, old_method_name, wrapper(new_method)) return new_class + + +class DeprecationInstanceCheck(type): + def __instancecheck__(self, instance): + warnings.warn( + "`%s` is deprecated, use `%s` instead." % (self.__name__, self.alternative), + self.deprecation_warning, 2 + ) + return super(DeprecationInstanceCheck, self).__instancecheck__(instance) diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 3bc858742b..5a4d2c6526 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -100,6 +100,10 @@ details on these changes. * The ``enclosure`` keyword argument to ``SyndicationFeed.add_item()`` will be removed. +* The ``django.template.loader.LoaderOrigin`` and + ``django.template.base.StringOrigin`` aliases for + ``django.template.base.Origin`` will be removed. + .. _deprecation-removed-in-1.10: 1.10 diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index c63ae1c351..1f8a127c4f 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -818,7 +818,9 @@ debug as ``True``, an instance of ``django.template.loader.LoaderOrigin`` or ``django.template.base.StringOrigin`` was set as the origin attribute on the template object. These classes have been combined into :class:`~django.template.base.Origin` and is now always set regardless of the -engine debug setting. +engine debug setting. For a minimal level of backwards compatibility, the old +class names will be kept as aliases to the new ``Origin`` class until +Django 2.0. .. _default-logging-changes-19: @@ -1335,6 +1337,10 @@ Miscellaneous deprecated. Use the new ``enclosures`` argument which accepts a list of ``Enclosure`` objects instead of a single one. +* The ``django.template.loader.LoaderOrigin`` and + ``django.template.base.StringOrigin`` aliases for + ``django.template.base.Origin`` are deprecated. + .. _removed-features-1.9: Features removed in 1.9 diff --git a/tests/deprecation/tests.py b/tests/deprecation/tests.py index e1ff2c8d2c..f50b2b624d 100644 --- a/tests/deprecation/tests.py +++ b/tests/deprecation/tests.py @@ -5,7 +5,9 @@ import warnings from django.test import SimpleTestCase from django.test.utils import reset_warning_registry from django.utils import six -from django.utils.deprecation import RenameMethodsBase +from django.utils.deprecation import ( + DeprecationInstanceCheck, RemovedInNextVersionWarning, RenameMethodsBase, +) class RenameManagerMethods(RenameMethodsBase): @@ -170,3 +172,16 @@ class RenameMethodsTests(SimpleTestCase): '`DeprecatedMixin.old` is deprecated, use `new` instead.', '`RenamedMixin.old` is deprecated, use `new` instead.', ]) + + +class DeprecationInstanceCheckTest(SimpleTestCase): + def test_warning(self): + class Manager(six.with_metaclass(DeprecationInstanceCheck)): + alternative = 'fake.path.Foo' + deprecation_warning = RemovedInNextVersionWarning + + msg = '`Manager` is deprecated, use `fake.path.Foo` instead.' + with warnings.catch_warnings(): + warnings.simplefilter('error', category=RemovedInNextVersionWarning) + with self.assertRaisesMessage(RemovedInNextVersionWarning, msg): + isinstance(object, Manager) diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py index b363514b2c..e3f4a8f4b6 100644 --- a/tests/test_runner/tests.py +++ b/tests/test_runner/tests.py @@ -352,9 +352,9 @@ class DeprecationDisplayTest(AdminScriptTestCase): args = ['test', '--settings=test_project.settings', 'test_runner_deprecation_app'] out, err = self.run_django_admin(args) self.assertIn("Ran 1 test", force_text(err)) - # change "Deprecation" to "RemovedInDjango\d+" in Django 1.11. - six.assertRegex(self, err, r"DeprecationWarning: warning from test") - six.assertRegex(self, err, r"DeprecationWarning: module-level warning from deprecation_app") + # change "NextVersion" to "RemovedInDjango\d+" in Django 1.11. + six.assertRegex(self, err, r"RemovedInNextVersionWarning: warning from test") + six.assertRegex(self, err, r"RemovedInNextVersionWarning: module-level warning from deprecation_app") def test_runner_deprecation_verbosity_zero(self): args = ['test', '--settings=test_project.settings', '--verbosity=0', 'test_runner_deprecation_app']