From 0d49fdb573d44794cc78c6af4761cc79c5330315 Mon Sep 17 00:00:00 2001
From: Preston Holmes <preston@ptone.com>
Date: Fri, 16 Nov 2012 16:50:50 -0800
Subject: [PATCH] [1.5.x] 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
---
 django/conf/__init__.py                      | 10 +++++++
 django/utils/log.py                          |  3 ++
 docs/releases/1.5.txt                        |  7 +++++
 tests/regressiontests/logging_tests/tests.py | 29 ++++++++++++++++++++
 4 files changed, 49 insertions(+)

diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index 4e6f0f9211..dec4cf9418 100644
--- a/django/conf/__init__.py
+++ b/django/conf/__init__.py
@@ -6,6 +6,7 @@ variable, and then from django.conf.global_settings; see the global settings fil
 a list of all possible variables.
 """
 
+import logging
 import os
 import time     # Needed for Windows
 import warnings
@@ -55,6 +56,15 @@ class LazySettings(LazyObject):
         """
         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:
             from django.utils.log import DEFAULT_LOGGING
             # First find the logging configuration function ...
diff --git a/django/utils/log.py b/django/utils/log.py
index ea0122794b..3852271bf1 100644
--- a/django/utils/log.py
+++ b/django/utils/log.py
@@ -62,6 +62,9 @@ DEFAULT_LOGGING = {
             'level': 'ERROR',
             'propagate': False,
         },
+        'py.warnings': {
+            'handlers': ['console'],
+        },
     }
 }
 
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index 8b7af2cf36..c53518feaa 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -306,6 +306,13 @@ Django 1.5 also includes several smaller improvements worth noting:
   :attr:`~django.db.models.Options.index_together` documentation for more
   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
 =====================================
 
diff --git a/tests/regressiontests/logging_tests/tests.py b/tests/regressiontests/logging_tests/tests.py
index 96f81981c6..0e56195c41 100644
--- a/tests/regressiontests/logging_tests/tests.py
+++ b/tests/regressiontests/logging_tests/tests.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import copy
 import logging
+import sys
 import warnings
 
 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.utils.log import CallbackFilter, RequireDebugFalse
 from django.utils.six import StringIO
+from django.utils.unittest import skipUnless
 
 from ..admin_scripts.tests import AdminScriptTestCase
 
+PYVERS = sys.version_info[:2]
 
 # logging config prior to using filter with mail_admins
 OLD_LOGGING = {
@@ -131,6 +134,32 @@ class DefaultLoggingTest(TestCase):
             self.logger.error("Hey, this is an error.")
             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):
     def test_sense(self):