Fixed #18985 -- made DeprecationWarnings loud

Capture warnings in Python >= 2.7 and route through
console handler, which is subject to DEBUG==True

Thanks to dstufft for the idea, and claudep for initial patch
This commit is contained in:
Preston Holmes 2012-11-16 16:50:50 -08:00
parent b4a98e028a
commit 44046e8a38
4 changed files with 49 additions and 0 deletions

View File

@ -6,6 +6,7 @@ variable, and then from django.conf.global_settings; see the global settings fil
a list of all possible variables. a list of all possible variables.
""" """
import logging
import os import os
import time # Needed for Windows import time # Needed for Windows
import warnings import warnings
@ -55,6 +56,15 @@ class LazySettings(LazyObject):
""" """
Setup logging from LOGGING_CONFIG and LOGGING settings. Setup logging from LOGGING_CONFIG and LOGGING settings.
""" """
try:
# Route warnings through python logging
logging.captureWarnings(True)
# Allow DeprecationWarnings through the warnings filters
warnings.simplefilter("default", DeprecationWarning)
except AttributeError:
# No captureWarnings on Python 2.6, DeprecationWarnings are on anyway
pass
if self.LOGGING_CONFIG: if self.LOGGING_CONFIG:
from django.utils.log import DEFAULT_LOGGING from django.utils.log import DEFAULT_LOGGING
# First find the logging configuration function ... # First find the logging configuration function ...

View File

@ -62,6 +62,9 @@ DEFAULT_LOGGING = {
'level': 'ERROR', 'level': 'ERROR',
'propagate': False, 'propagate': False,
}, },
'py.warnings': {
'handlers': ['console'],
},
} }
} }

View File

@ -306,6 +306,13 @@ Django 1.5 also includes several smaller improvements worth noting:
:attr:`~django.db.models.Options.index_together` documentation for more :attr:`~django.db.models.Options.index_together` documentation for more
information. information.
* During Django's logging configuration verbose Deprecation warnings are
enabled and warnings are captured into the logging system. Logged warnings
are routed through the ``console`` logging handler, which by default requires
:setting:`DEBUG` to be True for output to be generated. The result is that
DeprecationWarnings should be printed to the console in development
environments the way they have been in Python versions < 2.7.
Backwards incompatible changes in 1.5 Backwards incompatible changes in 1.5
===================================== =====================================

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import copy import copy
import logging import logging
import sys
import warnings import warnings
from django.conf import compat_patch_logging_config, LazySettings from django.conf import compat_patch_logging_config, LazySettings
@ -10,9 +11,11 @@ from django.test import TestCase, RequestFactory
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.log import CallbackFilter, RequireDebugFalse from django.utils.log import CallbackFilter, RequireDebugFalse
from django.utils.six import StringIO from django.utils.six import StringIO
from django.utils.unittest import skipUnless
from ..admin_scripts.tests import AdminScriptTestCase from ..admin_scripts.tests import AdminScriptTestCase
PYVERS = sys.version_info[:2]
# logging config prior to using filter with mail_admins # logging config prior to using filter with mail_admins
OLD_LOGGING = { OLD_LOGGING = {
@ -131,6 +134,32 @@ class DefaultLoggingTest(TestCase):
self.logger.error("Hey, this is an error.") self.logger.error("Hey, this is an error.")
self.assertEqual(output.getvalue(), 'Hey, this is an error.\n') self.assertEqual(output.getvalue(), 'Hey, this is an error.\n')
@skipUnless(PYVERS > (2,6), "warnings captured only in Python >= 2.7")
class WarningLoggerTests(TestCase):
"""
Tests that warnings output for DeprecationWarnings is enabled
and captured to the logging system
"""
def setUp(self):
self.logger = logging.getLogger('py.warnings')
self.old_stream = self.logger.handlers[0].stream
def tearDown(self):
self.logger.handlers[0].stream = self.old_stream
@override_settings(DEBUG=True)
def test_warnings_capture(self):
output = StringIO()
self.logger.handlers[0].stream = output
warnings.warn('Foo Deprecated', DeprecationWarning)
self.assertTrue('Foo Deprecated' in output.getvalue())
def test_warnings_capture_debug_false(self):
output = StringIO()
self.logger.handlers[0].stream = output
warnings.warn('Foo Deprecated', DeprecationWarning)
self.assertFalse('Foo Deprecated' in output.getvalue())
class CallbackFilterTest(TestCase): class CallbackFilterTest(TestCase):
def test_sense(self): def test_sense(self):