Fixed #29363 -- Added SimpleTestCase.assertWarnsMessage().

This commit is contained in:
Morgan Aubert 2018-04-27 17:18:15 -04:00 committed by Tim Graham
parent 7ba040de77
commit 704443acac
21 changed files with 210 additions and 285 deletions

View File

@ -585,10 +585,23 @@ class SimpleTestCase(unittest.TestCase):
) )
@contextmanager @contextmanager
def _assert_raises_message_cm(self, expected_exception, expected_message): def _assert_raises_or_warns_cm(self, func, cm_attr, expected_exception, expected_message):
with self.assertRaises(expected_exception) as cm: with func(expected_exception) as cm:
yield cm yield cm
self.assertIn(expected_message, str(cm.exception)) self.assertIn(expected_message, str(getattr(cm, cm_attr)))
def _assertFooMessage(self, func, cm_attr, expected_exception, expected_message, *args, **kwargs):
callable_obj = None
if args:
callable_obj = args[0]
args = args[1:]
cm = self._assert_raises_or_warns_cm(func, cm_attr, expected_exception, expected_message)
# Assertion used in context manager fashion.
if callable_obj is None:
return cm
# Assertion was passed a callable.
with cm:
callable_obj(*args, **kwargs)
def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs): def assertRaisesMessage(self, expected_exception, expected_message, *args, **kwargs):
""" """
@ -601,18 +614,20 @@ class SimpleTestCase(unittest.TestCase):
args: Function to be called and extra positional args. args: Function to be called and extra positional args.
kwargs: Extra kwargs. kwargs: Extra kwargs.
""" """
callable_obj = None return self._assertFooMessage(
if args: self.assertRaises, 'exception', expected_exception, expected_message,
callable_obj = args[0] *args, **kwargs
args = args[1:] )
cm = self._assert_raises_message_cm(expected_exception, expected_message) def assertWarnsMessage(self, expected_warning, expected_message, *args, **kwargs):
# Assertion used in context manager fashion. """
if callable_obj is None: Same as assertRaisesMessage but for assertWarns() instead of
return cm assertRaises().
# Assertion was passed a callable. """
with cm: return self._assertFooMessage(
callable_obj(*args, **kwargs) self.assertWarns, 'warning', expected_warning, expected_message,
*args, **kwargs
)
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None, def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
field_kwargs=None, empty_value=''): field_kwargs=None, empty_value=''):

View File

@ -62,10 +62,14 @@ Python style
* In docstrings, follow the style of existing docstrings and :pep:`257`. * In docstrings, follow the style of existing docstrings and :pep:`257`.
* In tests, use :meth:`~django.test.SimpleTestCase.assertRaisesMessage` instead * In tests, use
of :meth:`~unittest.TestCase.assertRaises` so you can check the exception :meth:`~django.test.SimpleTestCase.assertRaisesMessage` and
message. Use :meth:`~unittest.TestCase.assertRaisesRegex` only if you need :meth:`~django.test.SimpleTestCase.assertWarnsMessage`
regular expression matching. instead of :meth:`~unittest.TestCase.assertRaises` and
:meth:`~unittest.TestCase.assertWarns` so you can check the
exception or warning message. Use :meth:`~unittest.TestCase.assertRaisesRegex`
and :meth:`~unittest.TestCase.assertWarnsRegex` only if you need regular
expression matching.
* In test docstrings, state the expected behavior that each test demonstrates. * In test docstrings, state the expected behavior that each test demonstrates.
Don't include preambles such as "Tests that" or "Ensures that". Don't include preambles such as "Tests that" or "Ensures that".

View File

@ -277,6 +277,9 @@ Tests
dictionary as JSON if ``content_type='application/json'``. You can customize dictionary as JSON if ``content_type='application/json'``. You can customize
the JSON encoder with test client's ``json_encoder`` parameter. the JSON encoder with test client's ``json_encoder`` parameter.
* The new :meth:`.SimpleTestCase.assertWarnsMessage` method is a simpler
version of :meth:`~unittest.TestCase.assertWarnsRegex`.
URLs URLs
~~~~ ~~~~

View File

@ -692,6 +692,8 @@ A subclass of :class:`unittest.TestCase` that adds this functionality:
* Checking that a callable :meth:`raises a certain exception * Checking that a callable :meth:`raises a certain exception
<SimpleTestCase.assertRaisesMessage>`. <SimpleTestCase.assertRaisesMessage>`.
* Checking that a callable :meth:`triggers a certain warning
<SimpleTestCase.assertWarnsMessage>`.
* Testing form field :meth:`rendering and error treatment * Testing form field :meth:`rendering and error treatment
<SimpleTestCase.assertFieldOutput>`. <SimpleTestCase.assertFieldOutput>`.
* Testing :meth:`HTML responses for the presence/lack of a given fragment * Testing :meth:`HTML responses for the presence/lack of a given fragment
@ -1362,6 +1364,15 @@ your test suite.
with self.assertRaisesMessage(ValueError, 'invalid literal for int()'): with self.assertRaisesMessage(ValueError, 'invalid literal for int()'):
int('a') int('a')
.. method:: SimpleTestCase.assertWarnsMessage(expected_warning, expected_message, callable, *args, **kwargs)
SimpleTestCase.assertWarnsMessage(expected_warning, expected_message)
.. versionadded:: 2.1
Analogous to :meth:`SimpleTestCase.assertRaisesMessage` but for
:meth:`~unittest.TestCase.assertWarnsRegex` instead of
:meth:`~unittest.TestCase.assertRaisesRegex`.
.. method:: SimpleTestCase.assertFieldOutput(fieldclass, valid, invalid, field_args=None, field_kwargs=None, empty_value='') .. method:: SimpleTestCase.assertFieldOutput(fieldclass, valid, invalid, field_args=None, field_kwargs=None, empty_value='')
Asserts that a form field behaves correctly with various inputs. Asserts that a form field behaves correctly with various inputs.

View File

@ -1,5 +1,3 @@
import warnings
from django.contrib.admin.templatetags.admin_static import static from django.contrib.admin.templatetags.admin_static import static
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -19,12 +17,8 @@ class AdminStaticDeprecationTests(SimpleTestCase):
old_url = staticfiles_storage.base_url old_url = staticfiles_storage.base_url
staticfiles_storage.base_url = '/test/' staticfiles_storage.base_url = '/test/'
try: try:
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
warnings.simplefilter('always')
url = static('path') url = static('path')
self.assertEqual(url, '/test/path') self.assertEqual(url, '/test/path')
self.assertEqual(len(recorded), 1)
self.assertIs(recorded[0].category, RemovedInDjango30Warning)
self.assertEqual(str(recorded[0].message), msg)
finally: finally:
staticfiles_storage.base_url = old_url staticfiles_storage.base_url = old_url

View File

@ -1,5 +1,4 @@
import unittest import unittest
import warnings
from unittest import mock from unittest import mock
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -24,7 +23,14 @@ class Tests(TestCase):
self.assertIsNone(nodb_conn.settings_dict['NAME']) self.assertIsNone(nodb_conn.settings_dict['NAME'])
# Now assume the 'postgres' db isn't available # Now assume the 'postgres' db isn't available
with warnings.catch_warnings(record=True) as w: msg = (
"Normally Django will use a connection to the 'postgres' database "
"to avoid running initialization queries against the production "
"database when it's not needed (for example, when running tests). "
"Django was unable to create a connection to the 'postgres' "
"database and will use the first PostgreSQL database instead."
)
with self.assertWarnsMessage(RuntimeWarning, msg):
with mock.patch('django.db.backends.base.base.BaseDatabaseWrapper.connect', with mock.patch('django.db.backends.base.base.BaseDatabaseWrapper.connect',
side_effect=mocked_connect, autospec=True): side_effect=mocked_connect, autospec=True):
with mock.patch.object( with mock.patch.object(
@ -32,13 +38,9 @@ class Tests(TestCase):
'settings_dict', 'settings_dict',
{**connection.settings_dict, 'NAME': 'postgres'}, {**connection.settings_dict, 'NAME': 'postgres'},
): ):
warnings.simplefilter('always', RuntimeWarning)
nodb_conn = connection._nodb_connection nodb_conn = connection._nodb_connection
self.assertIsNotNone(nodb_conn.settings_dict['NAME']) self.assertIsNotNone(nodb_conn.settings_dict['NAME'])
self.assertEqual(nodb_conn.settings_dict['NAME'], connections['other'].settings_dict['NAME']) self.assertEqual(nodb_conn.settings_dict['NAME'], connections['other'].settings_dict['NAME'])
# Check a RuntimeWarning has been emitted
self.assertEqual(len(w), 1)
self.assertEqual(w[0].message.__class__, RuntimeWarning)
def test_database_name_too_long(self): def test_database_name_too_long(self):
from django.db.backends.postgresql.base import DatabaseWrapper from django.db.backends.postgresql.base import DatabaseWrapper

View File

@ -441,13 +441,10 @@ class BackendTestCase(TransactionTestCase):
cursor.execute("SELECT 3" + new_connection.features.bare_select_suffix) cursor.execute("SELECT 3" + new_connection.features.bare_select_suffix)
cursor.execute("SELECT 4" + new_connection.features.bare_select_suffix) cursor.execute("SELECT 4" + new_connection.features.bare_select_suffix)
with warnings.catch_warnings(record=True) as w: msg = "Limit for query logging exceeded, only the last 3 queries will be returned."
with self.assertWarnsMessage(UserWarning, msg):
self.assertEqual(3, len(new_connection.queries)) self.assertEqual(3, len(new_connection.queries))
self.assertEqual(1, len(w))
self.assertEqual(
str(w[0].message),
"Limit for query logging exceeded, only the last 3 queries will be returned."
)
finally: finally:
BaseDatabaseWrapper.queries_limit = old_queries_limit BaseDatabaseWrapper.queries_limit = old_queries_limit
new_connection.close() new_connection.close()

View File

@ -10,7 +10,6 @@ import tempfile
import threading import threading
import time import time
import unittest import unittest
import warnings
from unittest import mock from unittest import mock
from django.conf import settings from django.conf import settings
@ -632,12 +631,8 @@ class BaseCacheTests:
cache.key_func = func cache.key_func = func
try: try:
with warnings.catch_warnings(record=True) as w: with self.assertWarnsMessage(CacheKeyWarning, expected_warning):
warnings.simplefilter("always")
cache.set(key, 'value') cache.set(key, 'value')
self.assertEqual(len(w), 1)
self.assertIsInstance(w[0].message, CacheKeyWarning)
self.assertEqual(str(w[0].message.args[0]), expected_warning)
finally: finally:
cache.key_func = old_func cache.key_func = old_func

View File

@ -23,107 +23,94 @@ class RenameMethodsTests(SimpleTestCase):
Ensure a warning is raised upon class definition to suggest renaming Ensure a warning is raised upon class definition to suggest renaming
the faulty method. the faulty method.
""" """
with warnings.catch_warnings(record=True) as recorded: msg = '`Manager.old` method should be renamed `new`.'
warnings.simplefilter('always') with self.assertWarnsMessage(DeprecationWarning, msg):
class Manager(metaclass=RenameManagerMethods): class Manager(metaclass=RenameManagerMethods):
def old(self): def old(self):
pass pass
self.assertEqual(len(recorded), 1)
msg = str(recorded[0].message)
self.assertEqual(msg, '`Manager.old` method should be renamed `new`.')
def test_get_new_defined(self): def test_get_new_defined(self):
""" """
Ensure `old` complains and not `new` when only `new` is defined. Ensure `old` complains and not `new` when only `new` is defined.
""" """
with warnings.catch_warnings(record=True) as recorded: class Manager(metaclass=RenameManagerMethods):
warnings.simplefilter('ignore') def new(self):
pass
manager = Manager()
class Manager(metaclass=RenameManagerMethods): with warnings.catch_warnings(record=True) as recorded:
def new(self):
pass
warnings.simplefilter('always') warnings.simplefilter('always')
manager = Manager()
manager.new() manager.new()
self.assertEqual(len(recorded), 0) self.assertEqual(len(recorded), 0)
msg = '`Manager.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
manager.old() manager.old()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message)
self.assertEqual(msg, '`Manager.old` is deprecated, use `new` instead.')
def test_get_old_defined(self): def test_get_old_defined(self):
""" """
Ensure `old` complains when only `old` is defined. Ensure `old` complains when only `old` is defined.
""" """
with warnings.catch_warnings(record=True) as recorded: class Manager(metaclass=RenameManagerMethods):
warnings.simplefilter('ignore') def old(self):
pass
manager = Manager()
class Manager(metaclass=RenameManagerMethods): with warnings.catch_warnings(record=True) as recorded:
def old(self):
pass
warnings.simplefilter('always') warnings.simplefilter('always')
manager = Manager()
manager.new() manager.new()
self.assertEqual(len(recorded), 0) self.assertEqual(len(recorded), 0)
msg = '`Manager.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
manager.old() manager.old()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message)
self.assertEqual(msg, '`Manager.old` is deprecated, use `new` instead.')
def test_deprecated_subclass_renamed(self): def test_deprecated_subclass_renamed(self):
""" """
Ensure the correct warnings are raised when a class that didn't rename Ensure the correct warnings are raised when a class that didn't rename
`old` subclass one that did. `old` subclass one that did.
""" """
with warnings.catch_warnings(record=True) as recorded: class Renamed(metaclass=RenameManagerMethods):
warnings.simplefilter('ignore') def new(self):
pass
class Renamed(metaclass=RenameManagerMethods): class Deprecated(Renamed):
def new(self): def old(self):
pass super().old()
class Deprecated(Renamed): deprecated = Deprecated()
def old(self):
super().old() msg = '`Renamed.old` is deprecated, use `new` instead.'
warnings.simplefilter('always') with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated = Deprecated()
deprecated.new() deprecated.new()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message) msg = '`Deprecated.old` is deprecated, use `new` instead.'
self.assertEqual(msg, '`Renamed.old` is deprecated, use `new` instead.') with self.assertWarnsMessage(DeprecationWarning, msg):
recorded[:] = []
deprecated.old() deprecated.old()
self.assertEqual(len(recorded), 2)
msgs = [str(warning.message) for warning in recorded]
self.assertEqual(msgs, [
'`Deprecated.old` is deprecated, use `new` instead.',
'`Renamed.old` is deprecated, use `new` instead.',
])
def test_renamed_subclass_deprecated(self): def test_renamed_subclass_deprecated(self):
""" """
Ensure the correct warnings are raised when a class that renamed Ensure the correct warnings are raised when a class that renamed
`old` subclass one that didn't. `old` subclass one that didn't.
""" """
class Deprecated(metaclass=RenameManagerMethods):
def old(self):
pass
class Renamed(Deprecated):
def new(self):
super().new()
renamed = Renamed()
with warnings.catch_warnings(record=True) as recorded: with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Deprecated(metaclass=RenameManagerMethods):
def old(self):
pass
class Renamed(Deprecated):
def new(self):
super().new()
warnings.simplefilter('always') warnings.simplefilter('always')
renamed = Renamed()
renamed.new() renamed.new()
self.assertEqual(len(recorded), 0) self.assertEqual(len(recorded), 0)
msg = '`Renamed.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
renamed.old() renamed.old()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message)
self.assertEqual(msg, '`Renamed.old` is deprecated, use `new` instead.')
def test_deprecated_subclass_renamed_and_mixins(self): def test_deprecated_subclass_renamed_and_mixins(self):
""" """
@ -131,36 +118,30 @@ class RenameMethodsTests(SimpleTestCase):
class that renamed `old` and mixins that may or may not have renamed class that renamed `old` and mixins that may or may not have renamed
`new`. `new`.
""" """
with warnings.catch_warnings(record=True) as recorded: class Renamed(metaclass=RenameManagerMethods):
warnings.simplefilter('ignore') def new(self):
class Renamed(metaclass=RenameManagerMethods):
def new(self):
pass
class RenamedMixin:
def new(self):
super().new()
class DeprecatedMixin:
def old(self):
super().old()
class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
pass pass
warnings.simplefilter('always')
deprecated = Deprecated() class RenamedMixin:
def new(self):
super().new()
class DeprecatedMixin:
def old(self):
super().old()
class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
pass
deprecated = Deprecated()
msg = '`RenamedMixin.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.new() deprecated.new()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message) msg = '`DeprecatedMixin.old` is deprecated, use `new` instead.'
self.assertEqual(msg, '`RenamedMixin.old` is deprecated, use `new` instead.') with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.old() deprecated.old()
self.assertEqual(len(recorded), 2)
msgs = [str(warning.message) for warning in recorded]
self.assertEqual(msgs, [
'`DeprecatedMixin.old` is deprecated, use `new` instead.',
'`RenamedMixin.old` is deprecated, use `new` instead.',
])
class DeprecationInstanceCheckTest(SimpleTestCase): class DeprecationInstanceCheckTest(SimpleTestCase):
@ -170,7 +151,5 @@ class DeprecationInstanceCheckTest(SimpleTestCase):
deprecation_warning = RemovedInNextVersionWarning deprecation_warning = RemovedInNextVersionWarning
msg = '`Manager` is deprecated, use `fake.path.Foo` instead.' msg = '`Manager` is deprecated, use `fake.path.Foo` instead.'
with warnings.catch_warnings(): with self.assertWarnsMessage(RemovedInNextVersionWarning, msg):
warnings.simplefilter('error', category=RemovedInNextVersionWarning) isinstance(object, Manager)
with self.assertRaisesMessage(RemovedInNextVersionWarning, msg):
isinstance(object, Manager)

View File

@ -495,16 +495,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
parent. parent.
""" """
ProxySpy.objects.create(name='Paul') ProxySpy.objects.create(name='Paul')
msg = "fixtures.ProxySpy is a proxy model and won't be serialized."
with warnings.catch_warnings(record=True) as warning_list: with self.assertWarnsMessage(ProxyModelWarning, msg):
warnings.simplefilter('always')
self._dumpdata_assert(['fixtures.ProxySpy'], '[]') self._dumpdata_assert(['fixtures.ProxySpy'], '[]')
warning = warning_list.pop()
self.assertEqual(warning.category, ProxyModelWarning)
self.assertEqual(
str(warning.message),
"fixtures.ProxySpy is a proxy model and won't be serialized."
)
def test_dumpdata_proxy_with_concrete(self): def test_dumpdata_proxy_with_concrete(self):
""" """

View File

@ -2,7 +2,6 @@
import json import json
import os import os
import re import re
import warnings
from io import StringIO from io import StringIO
from django.core import management, serializers from django.core import management, serializers
@ -209,19 +208,13 @@ class TestFixtures(TestCase):
using explicit filename. using explicit filename.
Test for ticket #18213 -- warning conditions are caught correctly Test for ticket #18213 -- warning conditions are caught correctly
""" """
with warnings.catch_warnings(record=True) as warning_list: msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
warnings.simplefilter("always") with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command( management.call_command(
'loaddata', 'loaddata',
'bad_fixture2.xml', 'bad_fixture2.xml',
verbosity=0, verbosity=0,
) )
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_invalid_data_no_ext(self): def test_invalid_data_no_ext(self):
""" """
@ -229,55 +222,40 @@ class TestFixtures(TestCase):
without file extension. without file extension.
Test for ticket #18213 -- warning conditions are caught correctly Test for ticket #18213 -- warning conditions are caught correctly
""" """
with warnings.catch_warnings(record=True) as warning_list: msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
warnings.simplefilter("always") with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command( management.call_command(
'loaddata', 'loaddata',
'bad_fixture2', 'bad_fixture2',
verbosity=0, verbosity=0,
) )
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_empty(self): def test_empty(self):
""" """
Test for ticket #18213 -- Loading a fixture file with no data output a warning. Test for ticket #18213 -- Loading a fixture file with no data output a warning.
Previously empty fixture raises an error exception, see ticket #4371. Previously empty fixture raises an error exception, see ticket #4371.
""" """
with warnings.catch_warnings(record=True) as warning_list: msg = "No fixture data found for 'empty'. (File format may be invalid.)"
warnings.simplefilter("always") with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command( management.call_command(
'loaddata', 'loaddata',
'empty', 'empty',
verbosity=0, verbosity=0,
) )
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)")
def test_error_message(self): def test_error_message(self):
""" """
Regression for #9011 - error message is correct. Regression for #9011 - error message is correct.
Change from error to warning for ticket #18213. Change from error to warning for ticket #18213.
""" """
with warnings.catch_warnings(record=True) as warning_list: msg = "No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
warnings.simplefilter("always") with self.assertWarnsMessage(RuntimeWarning, msg):
management.call_command( management.call_command(
'loaddata', 'loaddata',
'bad_fixture2', 'bad_fixture2',
'animal', 'animal',
verbosity=0, verbosity=0,
) )
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_pg_sequence_resetting_checks(self): def test_pg_sequence_resetting_checks(self):
""" """

View File

@ -1,5 +1,3 @@
import warnings
from django.forms import CharField, Form, Media, MultiWidget, TextInput from django.forms import CharField, Form, Media, MultiWidget, TextInput
from django.template import Context, Template from django.template import Context, Template
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
@ -540,10 +538,6 @@ class FormsMediaTestCase(SimpleTestCase):
self.assertEqual(Media.merge(list1, list2), expected) self.assertEqual(Media.merge(list1, list2), expected)
def test_merge_warning(self): def test_merge_warning(self):
with warnings.catch_warnings(record=True) as w: msg = 'Detected duplicate Media files in an opposite order:\n1\n2'
warnings.simplefilter('always') with self.assertWarnsMessage(RuntimeWarning, msg):
self.assertEqual(Media.merge([1, 2], [2, 1]), [1, 2]) self.assertEqual(Media.merge([1, 2], [2, 1]), [1, 2])
self.assertEqual(
str(w[-1].message),
'Detected duplicate Media files in an opposite order:\n1\n2'
)

View File

@ -1,6 +1,5 @@
import warnings
from django.test import TestCase from django.test import TestCase
from django.utils.deprecation import RemovedInDjango30Warning
from .models import Cash, CashModelDeprecated from .models import Cash, CashModelDeprecated
@ -8,15 +7,11 @@ from .models import Cash, CashModelDeprecated
class FromDBValueDeprecationTests(TestCase): class FromDBValueDeprecationTests(TestCase):
def test_deprecation(self): def test_deprecation(self):
CashModelDeprecated.objects.create(cash='12.50') msg = (
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
instance = CashModelDeprecated.objects.get()
self.assertIsInstance(instance.cash, Cash)
self.assertEqual(len(warns), 1)
msg = str(warns[0].message)
self.assertEqual(
msg,
'Remove the context parameter from CashFieldDeprecated.from_db_value(). ' 'Remove the context parameter from CashFieldDeprecated.from_db_value(). '
'Support for it will be removed in Django 3.0.' 'Support for it will be removed in Django 3.0.'
) )
CashModelDeprecated.objects.create(cash='12.50')
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
instance = CashModelDeprecated.objects.get()
self.assertIsInstance(instance.cash, Cash)

View File

@ -1,7 +1,7 @@
import warnings
from datetime import datetime from datetime import datetime
from django.test import TestCase from django.test import TestCase
from django.utils.deprecation import RemovedInDjango30Warning
from .models import Article, IndexErrorArticle, Person from .models import Article, IndexErrorArticle, Person
@ -169,16 +169,12 @@ class EarliestOrLatestTests(TestCase):
def test_field_name_kwarg_deprecation(self): def test_field_name_kwarg_deprecation(self):
Person.objects.create(name='Deprecator', birthday=datetime(1950, 1, 1)) Person.objects.create(name='Deprecator', birthday=datetime(1950, 1, 1))
with warnings.catch_warnings(record=True) as warns: msg = (
warnings.simplefilter('always')
Person.objects.latest(field_name='birthday')
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
'The field_name keyword argument to earliest() and latest() ' 'The field_name keyword argument to earliest() and latest() '
'is deprecated in favor of passing positional arguments.', 'is deprecated in favor of passing positional arguments.'
) )
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
Person.objects.latest(field_name='birthday')
class TestFirstLast(TestCase): class TestFirstLast(TestCase):

View File

@ -1,5 +1,3 @@
import warnings
from django.db.migrations.exceptions import ( from django.db.migrations.exceptions import (
CircularDependencyError, NodeNotFoundError, CircularDependencyError, NodeNotFoundError,
) )
@ -193,22 +191,14 @@ class GraphTests(SimpleTestCase):
expected.append(child) expected.append(child)
leaf = expected[-1] leaf = expected[-1]
with warnings.catch_warnings(record=True) as w: with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
warnings.simplefilter('always', RuntimeWarning)
forwards_plan = graph.forwards_plan(leaf) forwards_plan = graph.forwards_plan(leaf)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
self.assertEqual(str(w[-1].message), RECURSION_DEPTH_WARNING)
self.assertEqual(expected, forwards_plan) self.assertEqual(expected, forwards_plan)
with warnings.catch_warnings(record=True) as w: with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
warnings.simplefilter('always', RuntimeWarning)
backwards_plan = graph.backwards_plan(root) backwards_plan = graph.backwards_plan(root)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
self.assertEqual(str(w[-1].message), RECURSION_DEPTH_WARNING)
self.assertEqual(expected[::-1], backwards_plan) self.assertEqual(expected[::-1], backwards_plan)
def test_plan_invalid_node(self): def test_plan_invalid_node(self):

View File

@ -1,5 +1,3 @@
import warnings
from django.contrib.admin.options import ModelAdmin, TabularInline from django.contrib.admin.options import ModelAdmin, TabularInline
from django.utils.deprecation import RemovedInDjango30Warning from django.utils.deprecation import RemovedInDjango30Warning
@ -52,12 +50,9 @@ class HasAddPermissionObjTests(CheckTestCase):
class BandAdmin(ModelAdmin): class BandAdmin(ModelAdmin):
inlines = [SongInlineAdmin] inlines = [SongInlineAdmin]
with warnings.catch_warnings(record=True) as recorded: msg = (
warnings.simplefilter('always')
self.assertIsValid(BandAdmin, Band)
self.assertEqual(len(recorded), 1)
self.assertIs(recorded[0].category, RemovedInDjango30Warning)
self.assertEqual(str(recorded[0].message), (
"Update SongInlineAdmin.has_add_permission() to accept a " "Update SongInlineAdmin.has_add_permission() to accept a "
"positional `obj` argument." "positional `obj` argument."
)) )
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
self.assertIsValid(BandAdmin, Band)

View File

@ -1,5 +1,4 @@
import unittest import unittest
import warnings
from datetime import datetime from datetime import datetime
from django.core.paginator import ( from django.core.paginator import (
@ -359,20 +358,15 @@ class ModelPaginationTests(TestCase):
self.assertIsInstance(p.object_list, list) self.assertIsInstance(p.object_list, list)
def test_paginating_unordered_queryset_raises_warning(self): def test_paginating_unordered_queryset_raises_warning(self):
with warnings.catch_warnings(record=True) as warns: msg = (
# Prevent the RuntimeWarning subclass from appearing as an
# exception due to the warnings.simplefilter() in runtests.py.
warnings.filterwarnings('always', category=UnorderedObjectListWarning)
Paginator(Article.objects.all(), 5)
self.assertEqual(len(warns), 1)
warning = warns[0]
self.assertEqual(str(warning.message), (
"Pagination may yield inconsistent results with an unordered " "Pagination may yield inconsistent results with an unordered "
"object_list: <class 'pagination.models.Article'> QuerySet." "object_list: <class 'pagination.models.Article'> QuerySet."
)) )
with self.assertWarnsMessage(UnorderedObjectListWarning, msg) as cm:
Paginator(Article.objects.all(), 5)
# The warning points at the Paginator caller (i.e. the stacklevel # The warning points at the Paginator caller (i.e. the stacklevel
# is appropriate). # is appropriate).
self.assertEqual(warning.filename, __file__) self.assertEqual(cm.filename, __file__)
def test_paginating_unordered_object_list_raises_warning(self): def test_paginating_unordered_object_list_raises_warning(self):
""" """
@ -382,11 +376,9 @@ class ModelPaginationTests(TestCase):
class ObjectList: class ObjectList:
ordered = False ordered = False
object_list = ObjectList() object_list = ObjectList()
with warnings.catch_warnings(record=True) as warns: msg = (
warnings.filterwarnings('always', category=UnorderedObjectListWarning)
Paginator(object_list, 5)
self.assertEqual(len(warns), 1)
self.assertEqual(str(warns[0].message), (
"Pagination may yield inconsistent results with an unordered " "Pagination may yield inconsistent results with an unordered "
"object_list: {!r}.".format(object_list) "object_list: {!r}.".format(object_list)
)) )
with self.assertWarnsMessage(UnorderedObjectListWarning, msg):
Paginator(object_list, 5)

View File

@ -1,7 +1,6 @@
import os import os
import sys import sys
import unittest import unittest
import warnings
from types import ModuleType from types import ModuleType
from unittest import mock from unittest import mock
@ -349,15 +348,11 @@ class TestComplexSettingOverride(SimpleTestCase):
def test_complex_override_warning(self): def test_complex_override_warning(self):
"""Regression test for #19031""" """Regression test for #19031"""
with warnings.catch_warnings(record=True) as w: msg = 'Overriding setting TEST_WARN can lead to unexpected behavior.'
warnings.simplefilter("always") with self.assertWarnsMessage(UserWarning, msg) as cm:
with override_settings(TEST_WARN='override'): with override_settings(TEST_WARN='override'):
self.assertEqual(settings.TEST_WARN, 'override') self.assertEqual(settings.TEST_WARN, 'override')
self.assertEqual(cm.filename, __file__)
self.assertEqual(len(w), 1)
self.assertEqual(w[0].filename, __file__)
self.assertEqual(str(w[0].message), 'Overriding setting TEST_WARN can lead to unexpected behavior.')
class SecureProxySslHeaderTest(SimpleTestCase): class SecureProxySslHeaderTest(SimpleTestCase):

View File

@ -1,4 +1,3 @@
import warnings
from urllib.parse import urljoin from urllib.parse import urljoin
from django.contrib.staticfiles import storage from django.contrib.staticfiles import storage
@ -22,24 +21,16 @@ class StaticDeprecationTests(SimpleTestCase):
def test_templatetag_deprecated(self): def test_templatetag_deprecated(self):
msg = '{% load staticfiles %} is deprecated in favor of {% load static %}.' msg = '{% load staticfiles %} is deprecated in favor of {% load static %}.'
template = "{% load staticfiles %}{% static 'main.js' %}" template = "{% load staticfiles %}{% static 'main.js' %}"
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
warnings.simplefilter('always')
template = Template(template) template = Template(template)
rendered = template.render(Context()) rendered = template.render(Context())
self.assertEqual(rendered, 'https://example.com/assets/main.js') self.assertEqual(rendered, 'https://example.com/assets/main.js')
self.assertEqual(len(recorded), 1)
self.assertIs(recorded[0].category, RemovedInDjango30Warning)
self.assertEqual(str(recorded[0].message), msg)
def test_static_deprecated(self): def test_static_deprecated(self):
msg = ( msg = (
'django.contrib.staticfiles.templatetags.static() is deprecated in ' 'django.contrib.staticfiles.templatetags.static() is deprecated in '
'favor of django.templatetags.static.static().' 'favor of django.templatetags.static.static().'
) )
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
warnings.simplefilter('always')
url = static('main.js') url = static('main.js')
self.assertEqual(url, 'https://example.com/assets/main.js') self.assertEqual(url, 'https://example.com/assets/main.js')
self.assertEqual(len(recorded), 1)
self.assertIs(recorded[0].category, RemovedInDjango30Warning)
self.assertEqual(str(recorded[0].message), msg)

View File

@ -1,5 +1,6 @@
import os import os
import unittest import unittest
import warnings
from io import StringIO from io import StringIO
from unittest import mock from unittest import mock
@ -864,6 +865,30 @@ class AssertRaisesMsgTest(SimpleTestCase):
func1() func1()
class AssertWarnsMessageTests(SimpleTestCase):
def test_context_manager(self):
with self.assertWarnsMessage(UserWarning, 'Expected message'):
warnings.warn('Expected message', UserWarning)
def test_context_manager_failure(self):
msg = "Expected message' not found in 'Unexpected message'"
with self.assertRaisesMessage(AssertionError, msg):
with self.assertWarnsMessage(UserWarning, 'Expected message'):
warnings.warn('Unexpected message', UserWarning)
def test_callable(self):
def func():
warnings.warn('Expected message', UserWarning)
self.assertWarnsMessage(UserWarning, 'Expected message', func)
def test_special_re_chars(self):
def func1():
warnings.warn('[.*x+]y?', UserWarning)
with self.assertWarnsMessage(UserWarning, '[.*x+]y?'):
func1()
class AssertFieldOutputTests(SimpleTestCase): class AssertFieldOutputTests(SimpleTestCase):
def test_assert_field_output(self): def test_assert_field_output(self):

View File

@ -1,7 +1,6 @@
import datetime import datetime
import re import re
import sys import sys
import warnings
from contextlib import contextmanager from contextlib import contextmanager
from unittest import SkipTest, skipIf from unittest import SkipTest, skipIf
from xml.dom.minidom import parseString from xml.dom.minidom import parseString
@ -226,17 +225,13 @@ class LegacyDatabaseTests(TestCase):
@override_settings(TIME_ZONE='Africa/Nairobi', USE_TZ=True) @override_settings(TIME_ZONE='Africa/Nairobi', USE_TZ=True)
class NewDatabaseTests(TestCase): class NewDatabaseTests(TestCase):
naive_warning = 'DateTimeField Event.dt received a naive datetime'
@requires_tz_support @requires_tz_support
def test_naive_datetime(self): def test_naive_datetime(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30) dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
warnings.simplefilter('always')
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
self.assertEqual(len(recorded), 1)
msg = str(recorded[0].message)
self.assertTrue(msg.startswith("DateTimeField Event.dt received "
"a naive datetime"))
event = Event.objects.get() event = Event.objects.get()
# naive datetimes are interpreted in local time # naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT)) self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@ -244,26 +239,16 @@ class NewDatabaseTests(TestCase):
@requires_tz_support @requires_tz_support
def test_datetime_from_date(self): def test_datetime_from_date(self):
dt = datetime.date(2011, 9, 1) dt = datetime.date(2011, 9, 1)
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
warnings.simplefilter('always')
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
self.assertEqual(len(recorded), 1)
msg = str(recorded[0].message)
self.assertTrue(msg.startswith("DateTimeField Event.dt received "
"a naive datetime"))
event = Event.objects.get() event = Event.objects.get()
self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT)) self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
@requires_tz_support @requires_tz_support
def test_naive_datetime_with_microsecond(self): def test_naive_datetime_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060) dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
with warnings.catch_warnings(record=True) as recorded: with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
warnings.simplefilter('always')
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
self.assertEqual(len(recorded), 1)
msg = str(recorded[0].message)
self.assertTrue(msg.startswith("DateTimeField Event.dt received "
"a naive datetime"))
event = Event.objects.get() event = Event.objects.get()
# naive datetimes are interpreted in local time # naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT)) self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@ -330,17 +315,13 @@ class NewDatabaseTests(TestCase):
dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT) dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)
Event.objects.create(dt=dt) Event.objects.create(dt=dt)
dt = dt.replace(tzinfo=None) dt = dt.replace(tzinfo=None)
with warnings.catch_warnings(record=True) as recorded: # naive datetimes are interpreted in local time
warnings.simplefilter('always') with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
# naive datetimes are interpreted in local time
self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1) self.assertEqual(Event.objects.filter(dt__exact=dt).count(), 1)
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
self.assertEqual(Event.objects.filter(dt__lte=dt).count(), 1) self.assertEqual(Event.objects.filter(dt__lte=dt).count(), 1)
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
self.assertEqual(Event.objects.filter(dt__gt=dt).count(), 0) self.assertEqual(Event.objects.filter(dt__gt=dt).count(), 0)
self.assertEqual(len(recorded), 3)
for warning in recorded:
msg = str(warning.message)
self.assertTrue(msg.startswith("DateTimeField Event.dt "
"received a naive datetime"))
@skipUnlessDBFeature('has_zoneinfo_database') @skipUnlessDBFeature('has_zoneinfo_database')
def test_query_datetime_lookups(self): def test_query_datetime_lookups(self):