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
def _assert_raises_message_cm(self, expected_exception, expected_message):
with self.assertRaises(expected_exception) as cm:
def _assert_raises_or_warns_cm(self, func, cm_attr, expected_exception, expected_message):
with func(expected_exception) as 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):
"""
@ -601,18 +614,20 @@ class SimpleTestCase(unittest.TestCase):
args: Function to be called and extra positional args.
kwargs: Extra kwargs.
"""
callable_obj = None
if args:
callable_obj = args[0]
args = args[1:]
return self._assertFooMessage(
self.assertRaises, 'exception', expected_exception, expected_message,
*args, **kwargs
)
cm = self._assert_raises_message_cm(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 assertWarnsMessage(self, expected_warning, expected_message, *args, **kwargs):
"""
Same as assertRaisesMessage but for assertWarns() instead of
assertRaises().
"""
return self._assertFooMessage(
self.assertWarns, 'warning', expected_warning, expected_message,
*args, **kwargs
)
def assertFieldOutput(self, fieldclass, valid, invalid, field_args=None,
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 tests, use :meth:`~django.test.SimpleTestCase.assertRaisesMessage` instead
of :meth:`~unittest.TestCase.assertRaises` so you can check the exception
message. Use :meth:`~unittest.TestCase.assertRaisesRegex` only if you need
regular expression matching.
* In tests, use
:meth:`~django.test.SimpleTestCase.assertRaisesMessage` and
:meth:`~django.test.SimpleTestCase.assertWarnsMessage`
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.
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
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
~~~~

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
<SimpleTestCase.assertRaisesMessage>`.
* Checking that a callable :meth:`triggers a certain warning
<SimpleTestCase.assertWarnsMessage>`.
* Testing form field :meth:`rendering and error treatment
<SimpleTestCase.assertFieldOutput>`.
* 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()'):
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='')
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.staticfiles.storage import staticfiles_storage
from django.test import SimpleTestCase
@ -19,12 +17,8 @@ class AdminStaticDeprecationTests(SimpleTestCase):
old_url = staticfiles_storage.base_url
staticfiles_storage.base_url = '/test/'
try:
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
url = static('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:
staticfiles_storage.base_url = old_url

View File

@ -1,5 +1,4 @@
import unittest
import warnings
from unittest import mock
from django.core.exceptions import ImproperlyConfigured
@ -24,7 +23,14 @@ class Tests(TestCase):
self.assertIsNone(nodb_conn.settings_dict['NAME'])
# 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',
side_effect=mocked_connect, autospec=True):
with mock.patch.object(
@ -32,13 +38,9 @@ class Tests(TestCase):
'settings_dict',
{**connection.settings_dict, 'NAME': 'postgres'},
):
warnings.simplefilter('always', RuntimeWarning)
nodb_conn = connection._nodb_connection
self.assertIsNotNone(nodb_conn.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):
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 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(1, len(w))
self.assertEqual(
str(w[0].message),
"Limit for query logging exceeded, only the last 3 queries will be returned."
)
finally:
BaseDatabaseWrapper.queries_limit = old_queries_limit
new_connection.close()

View File

@ -10,7 +10,6 @@ import tempfile
import threading
import time
import unittest
import warnings
from unittest import mock
from django.conf import settings
@ -632,12 +631,8 @@ class BaseCacheTests:
cache.key_func = func
try:
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
with self.assertWarnsMessage(CacheKeyWarning, expected_warning):
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:
cache.key_func = old_func

View File

@ -23,62 +23,53 @@ class RenameMethodsTests(SimpleTestCase):
Ensure a warning is raised upon class definition to suggest renaming
the faulty method.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
msg = '`Manager.old` method should be renamed `new`.'
with self.assertWarnsMessage(DeprecationWarning, msg):
class Manager(metaclass=RenameManagerMethods):
def old(self):
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):
"""
Ensure `old` complains and not `new` when only `new` is defined.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Manager(metaclass=RenameManagerMethods):
def new(self):
pass
warnings.simplefilter('always')
manager = Manager()
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
manager.new()
self.assertEqual(len(recorded), 0)
msg = '`Manager.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
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):
"""
Ensure `old` complains when only `old` is defined.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Manager(metaclass=RenameManagerMethods):
def old(self):
pass
warnings.simplefilter('always')
manager = Manager()
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
manager.new()
self.assertEqual(len(recorded), 0)
msg = '`Manager.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
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):
"""
Ensure the correct warnings are raised when a class that didn't rename
`old` subclass one that did.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Renamed(metaclass=RenameManagerMethods):
def new(self):
pass
@ -86,29 +77,22 @@ class RenameMethodsTests(SimpleTestCase):
class Deprecated(Renamed):
def old(self):
super().old()
warnings.simplefilter('always')
deprecated = Deprecated()
msg = '`Renamed.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.new()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message)
self.assertEqual(msg, '`Renamed.old` is deprecated, use `new` instead.')
recorded[:] = []
msg = '`Deprecated.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
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):
"""
Ensure the correct warnings are raised when a class that renamed
`old` subclass one that didn't.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Deprecated(metaclass=RenameManagerMethods):
def old(self):
pass
@ -116,14 +100,17 @@ class RenameMethodsTests(SimpleTestCase):
class Renamed(Deprecated):
def new(self):
super().new()
warnings.simplefilter('always')
renamed = Renamed()
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
renamed.new()
self.assertEqual(len(recorded), 0)
msg = '`Renamed.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
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):
"""
@ -131,9 +118,6 @@ class RenameMethodsTests(SimpleTestCase):
class that renamed `old` and mixins that may or may not have renamed
`new`.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('ignore')
class Renamed(metaclass=RenameManagerMethods):
def new(self):
pass
@ -148,19 +132,16 @@ class RenameMethodsTests(SimpleTestCase):
class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
pass
warnings.simplefilter('always')
deprecated = Deprecated()
msg = '`RenamedMixin.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
deprecated.new()
self.assertEqual(len(recorded), 1)
msg = str(recorded.pop().message)
self.assertEqual(msg, '`RenamedMixin.old` is deprecated, use `new` instead.')
msg = '`DeprecatedMixin.old` is deprecated, use `new` instead.'
with self.assertWarnsMessage(DeprecationWarning, msg):
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):
@ -170,7 +151,5 @@ class DeprecationInstanceCheckTest(SimpleTestCase):
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):
with self.assertWarnsMessage(RemovedInNextVersionWarning, msg):
isinstance(object, Manager)

View File

@ -495,16 +495,9 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
parent.
"""
ProxySpy.objects.create(name='Paul')
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter('always')
msg = "fixtures.ProxySpy is a proxy model and won't be serialized."
with self.assertWarnsMessage(ProxyModelWarning, msg):
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):
"""

View File

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

View File

@ -1,5 +1,3 @@
import warnings
from django.forms import CharField, Form, Media, MultiWidget, TextInput
from django.template import Context, Template
from django.test import SimpleTestCase, override_settings
@ -540,10 +538,6 @@ class FormsMediaTestCase(SimpleTestCase):
self.assertEqual(Media.merge(list1, list2), expected)
def test_merge_warning(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
msg = 'Detected duplicate Media files in an opposite order:\n1\n2'
with self.assertWarnsMessage(RuntimeWarning, msg):
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.utils.deprecation import RemovedInDjango30Warning
from .models import Cash, CashModelDeprecated
@ -8,15 +7,11 @@ from .models import Cash, CashModelDeprecated
class FromDBValueDeprecationTests(TestCase):
def test_deprecation(self):
CashModelDeprecated.objects.create(cash='12.50')
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,
msg = (
'Remove the context parameter from CashFieldDeprecated.from_db_value(). '
'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 django.test import TestCase
from django.utils.deprecation import RemovedInDjango30Warning
from .models import Article, IndexErrorArticle, Person
@ -169,16 +169,12 @@ class EarliestOrLatestTests(TestCase):
def test_field_name_kwarg_deprecation(self):
Person.objects.create(name='Deprecator', birthday=datetime(1950, 1, 1))
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
Person.objects.latest(field_name='birthday')
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
msg = (
'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):

View File

@ -1,5 +1,3 @@
import warnings
from django.db.migrations.exceptions import (
CircularDependencyError, NodeNotFoundError,
)
@ -193,22 +191,14 @@ class GraphTests(SimpleTestCase):
expected.append(child)
leaf = expected[-1]
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always', RuntimeWarning)
with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
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)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always', RuntimeWarning)
with self.assertWarnsMessage(RuntimeWarning, RECURSION_DEPTH_WARNING):
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)
def test_plan_invalid_node(self):

View File

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

View File

@ -1,5 +1,4 @@
import unittest
import warnings
from datetime import datetime
from django.core.paginator import (
@ -359,20 +358,15 @@ class ModelPaginationTests(TestCase):
self.assertIsInstance(p.object_list, list)
def test_paginating_unordered_queryset_raises_warning(self):
with warnings.catch_warnings(record=True) as warns:
# 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), (
msg = (
"Pagination may yield inconsistent results with an unordered "
"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
# is appropriate).
self.assertEqual(warning.filename, __file__)
self.assertEqual(cm.filename, __file__)
def test_paginating_unordered_object_list_raises_warning(self):
"""
@ -382,11 +376,9 @@ class ModelPaginationTests(TestCase):
class ObjectList:
ordered = False
object_list = ObjectList()
with warnings.catch_warnings(record=True) as warns:
warnings.filterwarnings('always', category=UnorderedObjectListWarning)
Paginator(object_list, 5)
self.assertEqual(len(warns), 1)
self.assertEqual(str(warns[0].message), (
msg = (
"Pagination may yield inconsistent results with an unordered "
"object_list: {!r}.".format(object_list)
))
)
with self.assertWarnsMessage(UnorderedObjectListWarning, msg):
Paginator(object_list, 5)

View File

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

View File

@ -1,4 +1,3 @@
import warnings
from urllib.parse import urljoin
from django.contrib.staticfiles import storage
@ -22,24 +21,16 @@ class StaticDeprecationTests(SimpleTestCase):
def test_templatetag_deprecated(self):
msg = '{% load staticfiles %} is deprecated in favor of {% load static %}.'
template = "{% load staticfiles %}{% static 'main.js' %}"
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
template = Template(template)
rendered = template.render(Context())
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):
msg = (
'django.contrib.staticfiles.templatetags.static() is deprecated in '
'favor of django.templatetags.static.static().'
)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RemovedInDjango30Warning, msg):
url = static('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 unittest
import warnings
from io import StringIO
from unittest import mock
@ -864,6 +865,30 @@ class AssertRaisesMsgTest(SimpleTestCase):
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):
def test_assert_field_output(self):

View File

@ -1,7 +1,6 @@
import datetime
import re
import sys
import warnings
from contextlib import contextmanager
from unittest import SkipTest, skipIf
from xml.dom.minidom import parseString
@ -226,17 +225,13 @@ class LegacyDatabaseTests(TestCase):
@override_settings(TIME_ZONE='Africa/Nairobi', USE_TZ=True)
class NewDatabaseTests(TestCase):
naive_warning = 'DateTimeField Event.dt received a naive datetime'
@requires_tz_support
def test_naive_datetime(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
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()
# naive datetimes are interpreted in local time
self.assertEqual(event.dt, dt.replace(tzinfo=EAT))
@ -244,26 +239,16 @@ class NewDatabaseTests(TestCase):
@requires_tz_support
def test_datetime_from_date(self):
dt = datetime.date(2011, 9, 1)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
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()
self.assertEqual(event.dt, datetime.datetime(2011, 9, 1, tzinfo=EAT))
@requires_tz_support
def test_naive_datetime_with_microsecond(self):
dt = datetime.datetime(2011, 9, 1, 13, 20, 30, 405060)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
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()
# naive datetimes are interpreted in local time
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)
Event.objects.create(dt=dt)
dt = dt.replace(tzinfo=None)
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
# naive datetimes are interpreted in local time
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
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)
with self.assertWarnsMessage(RuntimeWarning, self.naive_warning):
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')
def test_query_datetime_lookups(self):