Skip to content

Commit

Permalink
Fixed #14508 - test suite silences warnings.
Browse files Browse the repository at this point in the history
Utility functions get_warnings_state and save_warnings_state have been added
to django.test.utils, and methods to django.test.TestCase for convenience.

The implementation is based on the catch_warnings context manager from
Python 2.6.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14526 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
spookylukey committed Nov 11, 2010
1 parent 7beca4d commit 02fc627
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 25 deletions.
4 changes: 2 additions & 2 deletions django/contrib/auth/tests/auth_backends.py
Expand Up @@ -154,13 +154,13 @@ def setUp(self):
self.user1 = User.objects.create_user('test', 'test@example.com', 'test') self.user1 = User.objects.create_user('test', 'test@example.com', 'test')
self.user2 = User.objects.create_user('test2', 'test2@example.com', 'test') self.user2 = User.objects.create_user('test2', 'test2@example.com', 'test')
self.user3 = User.objects.create_user('test3', 'test3@example.com', 'test') self.user3 = User.objects.create_user('test3', 'test3@example.com', 'test')
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth') module='django.contrib.auth')


def tearDown(self): def tearDown(self):
settings.AUTHENTICATION_BACKENDS = self.curr_auth settings.AUTHENTICATION_BACKENDS = self.curr_auth
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)


def test_has_perm(self): def test_has_perm(self):
self.assertEqual(self.user1.has_perm('perm', TestObj()), False) self.assertEqual(self.user1.has_perm('perm', TestObj()), False)
Expand Down
4 changes: 2 additions & 2 deletions django/contrib/messages/tests/base.py
Expand Up @@ -51,6 +51,7 @@ def setUp(self):
self._message_storage = settings.MESSAGE_STORAGE self._message_storage = settings.MESSAGE_STORAGE
settings.MESSAGE_STORAGE = '%s.%s' % (self.storage_class.__module__, settings.MESSAGE_STORAGE = '%s.%s' % (self.storage_class.__module__,
self.storage_class.__name__) self.storage_class.__name__)
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth.models') module='django.contrib.auth.models')


Expand All @@ -63,8 +64,7 @@ def tearDown(self):
self._template_context_processors self._template_context_processors
settings.INSTALLED_APPS = self._installed_apps settings.INSTALLED_APPS = self._installed_apps
settings.MESSAGE_STORAGE = self._message_storage settings.MESSAGE_STORAGE = self._message_storage
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)


def restore_setting(self, setting): def restore_setting(self, setting):
if setting in self._remembered_settings: if setting in self._remembered_settings:
Expand Down
14 changes: 14 additions & 0 deletions django/test/testcases.py
Expand Up @@ -11,6 +11,7 @@
from django.http import QueryDict from django.http import QueryDict
from django.test import _doctest as doctest from django.test import _doctest as doctest
from django.test.client import Client from django.test.client import Client
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import simplejson, unittest as ut2 from django.utils import simplejson, unittest as ut2
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.functional import wraps from django.utils.functional import wraps
Expand Down Expand Up @@ -328,6 +329,19 @@ def _urlconf_teardown(self):
settings.ROOT_URLCONF = self._old_root_urlconf settings.ROOT_URLCONF = self._old_root_urlconf
clear_url_caches() clear_url_caches()


def save_warnings_state(self):
"""
Saves the state of the warnings module
"""
self._warnings_state = get_warnings_state()

def restore_warnings_state(self):
"""
Restores the sate of the warnings module to the state
saved by save_warnings_state()
"""
restore_warnings_state(self._warnings_state)

def assertRedirects(self, response, expected_url, status_code=302, def assertRedirects(self, response, expected_url, status_code=302,
target_status_code=200, host=None, msg_prefix=''): target_status_code=200, host=None, msg_prefix=''):
"""Asserts that a response redirected to a specific URL, and that the """Asserts that a response redirected to a specific URL, and that the
Expand Down
22 changes: 22 additions & 0 deletions django/test/utils.py
@@ -1,6 +1,7 @@
import sys import sys
import time import time
import os import os
import warnings
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.core.mail.backends import locmem from django.core.mail.backends import locmem
Expand Down Expand Up @@ -46,6 +47,7 @@ def __contains__(self, key):
return False return False
return True return True



def instrumented_test_render(self, context): def instrumented_test_render(self, context):
""" """
An instrumented Template render method, providing a signal An instrumented Template render method, providing a signal
Expand Down Expand Up @@ -75,6 +77,7 @@ def setup_test_environment():


deactivate() deactivate()



def teardown_test_environment(): def teardown_test_environment():
"""Perform any global post-test teardown. This involves: """Perform any global post-test teardown. This involves:
Expand All @@ -93,6 +96,25 @@ def teardown_test_environment():


del mail.outbox del mail.outbox



def get_warnings_state():
"""
Returns an object containing the state of the warnings module
"""
# There is no public interface for doing this, but this implementation of
# get_warnings_state and restore_warnings_state appears to work on Python
# 2.4 to 2.7.
return warnings.filters[:]


def restore_warnings_state(state):
"""
Restores the state of the warnings module when passed an object that was
returned by get_warnings_state()
"""
warnings.filters = state[:]


def get_runner(settings): def get_runner(settings):
test_path = settings.TEST_RUNNER.split('.') test_path = settings.TEST_RUNNER.split('.')
# Allow for Python 2.5 relative paths # Allow for Python 2.5 relative paths
Expand Down
22 changes: 9 additions & 13 deletions tests/regressiontests/cache/tests.py
Expand Up @@ -15,6 +15,7 @@
from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning
from django.http import HttpResponse, HttpRequest from django.http import HttpResponse, HttpRequest
from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import translation from django.utils import translation
from django.utils import unittest from django.utils import unittest
from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
Expand Down Expand Up @@ -379,21 +380,16 @@ def test_invalid_keys(self):
# manager to test this warning nicely. Since we can't do that # manager to test this warning nicely. Since we can't do that
# yet, the cleanest option is to temporarily ask for # yet, the cleanest option is to temporarily ask for
# CacheKeyWarning to be raised as an exception. # CacheKeyWarning to be raised as an exception.
_warnings_state = get_warnings_state()
warnings.simplefilter("error", CacheKeyWarning) warnings.simplefilter("error", CacheKeyWarning)


# memcached does not allow whitespace or control characters in keys try:
self.assertRaises(CacheKeyWarning, self.cache.set, 'key with spaces', 'value') # memcached does not allow whitespace or control characters in keys
# memcached limits key length to 250 self.assertRaises(CacheKeyWarning, self.cache.set, 'key with spaces', 'value')
self.assertRaises(CacheKeyWarning, self.cache.set, 'a' * 251, 'value') # memcached limits key length to 250

self.assertRaises(CacheKeyWarning, self.cache.set, 'a' * 251, 'value')
# The warnings module has no public API for getting the finally:
# current list of warning filters, so we can't save that off restore_warnings_state(_warnings_state)
# and reset to the previous value, we have to globally reset
# it. The effect will be the same, as long as the Django test
# runner doesn't add any global warning filters (it currently
# does not).
warnings.resetwarnings()
warnings.simplefilter("ignore", PendingDeprecationWarning)


class DBCacheTests(unittest.TestCase, BaseCacheTests): class DBCacheTests(unittest.TestCase, BaseCacheTests):
def setUp(self): def setUp(self):
Expand Down
4 changes: 2 additions & 2 deletions tests/regressiontests/context_processors/tests.py
Expand Up @@ -48,14 +48,14 @@ class AuthContextProcessorTests(TestCase):
fixtures = ['context-processors-users.xml'] fixtures = ['context-processors-users.xml']


def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth.models') module='django.contrib.auth.models')
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.core.context_processors') module='django.core.context_processors')


def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)


def test_session_not_accessed(self): def test_session_not_accessed(self):
""" """
Expand Down
4 changes: 2 additions & 2 deletions tests/regressiontests/csrf_tests/tests.py
Expand Up @@ -71,12 +71,12 @@ class CsrfMiddlewareTest(TestCase):
_secret_key_for_session_test= "test" _secret_key_for_session_test= "test"


def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.middleware.csrf') module='django.middleware.csrf')


def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)


def _get_GET_no_csrf_cookie_request(self): def _get_GET_no_csrf_cookie_request(self):
return TestingHttpRequest() return TestingHttpRequest()
Expand Down
4 changes: 2 additions & 2 deletions tests/regressiontests/syndication/tests.py
Expand Up @@ -315,14 +315,14 @@ class DeprecatedSyndicationFeedTest(FeedTestCase):
Tests for the deprecated API (feed() view and the feed_dict etc). Tests for the deprecated API (feed() view and the feed_dict etc).
""" """
def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.syndication.feeds') module='django.contrib.syndication.feeds')
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.syndication.views') module='django.contrib.syndication.views')


def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)


def test_empty_feed_dict(self): def test_empty_feed_dict(self):
""" """
Expand Down
5 changes: 3 additions & 2 deletions tests/regressiontests/templates/loaders.py
Expand Up @@ -20,6 +20,7 @@
from django.template.loaders.eggs import load_template_source as lts_egg from django.template.loaders.eggs import load_template_source as lts_egg
from django.template.loaders.eggs import Loader as EggLoader from django.template.loaders.eggs import Loader as EggLoader
from django.template import loader from django.template import loader
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import unittest from django.utils import unittest




Expand Down Expand Up @@ -68,13 +69,13 @@ def setUp(self):
}) })
self._old_installed_apps = settings.INSTALLED_APPS self._old_installed_apps = settings.INSTALLED_APPS
settings.INSTALLED_APPS = [] settings.INSTALLED_APPS = []
self._warnings_state = get_warnings_state()
warnings.filterwarnings("ignore", category=DeprecationWarning, warnings.filterwarnings("ignore", category=DeprecationWarning,
module='django.template.loaders.eggs') module='django.template.loaders.eggs')


def tearDown(self): def tearDown(self):
settings.INSTALLED_APPS = self._old_installed_apps settings.INSTALLED_APPS = self._old_installed_apps
warnings.resetwarnings() restore_warnings_state(self._warnings_state)
warnings.simplefilter("ignore", PendingDeprecationWarning)


def test_existing(self): def test_existing(self):
"A template can be loaded from an egg" "A template can be loaded from an egg"
Expand Down
29 changes: 29 additions & 0 deletions tests/regressiontests/test_utils/tests.py
Expand Up @@ -26,6 +26,35 @@ def test_func():
self.assertRaises(ValueError, test_func) self.assertRaises(ValueError, test_func)




class SaveRestoreWarningState(TestCase):

def test_save_restore_warnings_state(self):
"""
Ensure save_warnings_state/restore_warnings_state work correctly.
"""
# In reality this test could be satisfied by many broken implementations
# of save_warnings_state/restore_warnings_state (e.g. just
# warnings.resetwarnings()) , but it is difficult to test more.
import warnings
self.save_warnings_state()

class MyWarning(Warning):
pass

# Add a filter that causes an exception to be thrown, so we can catch it
warnings.simplefilter("error", MyWarning)
self.assertRaises(Warning, lambda: warnings.warn("warn", MyWarning))

# Now restore.
self.restore_warnings_state()
# After restoring, we shouldn't get an exception. But we don't want a
# warning printed either, so we have to silence the warning.
warnings.simplefilter("ignore", MyWarning)
warnings.warn("warn", MyWarning)

# Remove the filter we just added.
self.restore_warnings_state()

__test__ = {"API_TEST": r""" __test__ = {"API_TEST": r"""
# Some checks of the doctest output normalizer. # Some checks of the doctest output normalizer.
# Standard doctests do fairly # Standard doctests do fairly
Expand Down

0 comments on commit 02fc627

Please sign in to comment.