summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/logging.rst15
-rw-r--r--Lib/logging/__init__.py59
-rw-r--r--Lib/test/test_logging.py31
-rw-r--r--Misc/NEWS8
4 files changed, 108 insertions, 5 deletions
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index dac6aeb1..c5fde33 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -461,6 +461,12 @@ should have the desired effect. If an organisation produces a number of
libraries, then the logger name specified can be "orgname.foo" rather than
just "foo".
+.. versionadded:: 2.7
+
+The :class:`NullHandler` class was not present in previous versions, but is now
+included, so that it need not be defined in library code.
+
+
Logging Levels
--------------
@@ -553,6 +559,15 @@ provided:
#. :class:`HTTPHandler` instances send error messages to an HTTP server using
either ``GET`` or ``POST`` semantics.
+#. :class:`NullHandler` instances do nothing with error messages. They are used
+ by library developers who want to use logging, but want to avoid the "No
+ handlers could be found for logger XXX" message which can be displayed if
+ the library user has not configured logging.
+
+.. versionadded:: 2.7
+
+The :class:`NullHandler` class was not present in previous versions.
+
The :class:`StreamHandler` and :class:`FileHandler` classes are defined in the
core logging package. The other handlers are defined in a sub- module,
:mod:`logging.handlers`. (There is also another sub-module,
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 7b790d2..c28d7c8 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -46,8 +46,8 @@ except ImportError:
__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
__status__ = "production"
-__version__ = "0.5.0.5"
-__date__ = "24 January 2008"
+__version__ = "0.5.0.6"
+__date__ = "03 December 2008"
#---------------------------------------------------------------------------
# Miscellaneous module data
@@ -1488,3 +1488,58 @@ except ImportError: # for Python versions < 2.0
old_exit(status)
sys.exit = exithook
+
+# Null handler
+
+class NullHandler(Handler):
+ """
+ This handler does nothing. It's intended to be used to avoid the
+ "No handlers could be found for logger XXX" one-off warning. This is
+ important for library code, which may contain code to log events. If a user
+ of the library does not configure logging, the one-off warning might be
+ produced; to avoid this, the library developer simply needs to instantiate
+ a NullHandler and add it to the top-level logger of the library module or
+ package.
+ """
+ def emit(self, record):
+ pass
+
+# Warnings integration
+
+_warnings_showwarning = None
+
+def _showwarning(message, category, filename, lineno, file=None, line=None):
+ """
+ Implementation of showwarnings which redirects to logging, which will first
+ check to see if the file parameter is None. If a file is specified, it will
+ delegate to the original warnings implementation of showwarning. Otherwise,
+ it will call warnings.formatwarning and will log the resulting string to a
+ warnings logger named "py.warnings" with level logging.WARNING.
+ """
+ if file is not None:
+ if _warnings_showwarning is not None:
+ _warnings_showwarning(message, category, filename, lineno, file, line)
+ else:
+ import warnings
+ s = warnings.formatwarning(message, category, filename, lineno, line)
+ logger = getLogger("py.warnings")
+ if not logger.handlers:
+ logger.addHandler(NullHandler())
+ logger.warning("%s", s)
+
+def captureWarnings(capture):
+ """
+ If capture is true, redirect all warnings to the logging package.
+ If capture is False, ensure that warnings are not redirected to logging
+ but to their original destinations.
+ """
+ import warnings
+ global _warnings_showwarning
+ if capture:
+ if _warnings_showwarning is None:
+ _warnings_showwarning = warnings.showwarning
+ warnings.showwarning = _showwarning
+ else:
+ if _warnings_showwarning is not None:
+ warnings.showwarning = _warnings_showwarning
+ _warnings_showwarning = None
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index e837d41..09fdf4b 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -18,7 +18,7 @@
"""Test harness for the logging module. Run all tests.
-Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
"""
import logging
@@ -44,6 +44,7 @@ import threading
import time
import types
import unittest
+import warnings
import weakref
@@ -885,6 +886,32 @@ class EncodingTest(BaseTest):
if os.path.isfile(fn):
os.remove(fn)
+class WarningsTest(BaseTest):
+ def test_warnings(self):
+ logging.captureWarnings(True)
+ warnings.filterwarnings("always", category=UserWarning)
+ try:
+ file = cStringIO.StringIO()
+ h = logging.StreamHandler(file)
+ logger = logging.getLogger("py.warnings")
+ logger.addHandler(h)
+ warnings.warn("I'm warning you...")
+ logger.removeHandler(h)
+ s = file.getvalue()
+ h.close()
+ self.assertTrue(s.find("UserWarning: I'm warning you...\n") > 0)
+
+ #See if an explicit file uses the original implementation
+ file = cStringIO.StringIO()
+ warnings.showwarning("Explicit", UserWarning, "dummy.py", 42, file,
+ "Dummy line")
+ s = file.getvalue()
+ file.close()
+ self.assertEqual(s, "dummy.py:42: UserWarning: Explicit\n Dummy line\n")
+ finally:
+ warnings.resetwarnings()
+ logging.captureWarnings(False)
+
# Set the locale to the platform-dependent default. I have no idea
# why the test does this, but in any case we save the current locale
# first and restore it at the end.
@@ -893,7 +920,7 @@ def test_main():
run_unittest(BuiltinLevelsTest, BasicFilterTest,
CustomLevelsAndFiltersTest, MemoryHandlerTest,
ConfigFileTest, SocketHandlerTest, MemoryTest,
- EncodingTest)
+ EncodingTest, WarningsTest)
if __name__ == "__main__":
test_main()
diff --git a/Misc/NEWS b/Misc/NEWS
index 025ca4c..78578e3 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,7 +22,7 @@ Core and Builtins
- Issue #4367: Python would segfault during compiling when the unicodedata
module couldn't be imported and \N escapes were present.
-- Issue #4233: Changed semantic of ``_fileio.FileIO``'s ``close()``
+- Issue #4233: Changed semantic of ``_fileio.FileIO``'s ``close()``
method on file objects with closefd=False. The file descriptor is still
kept open but the file object behaves like a closed file. The ``FileIO``
object also got a new readonly attribute ``closefd``.
@@ -60,6 +60,12 @@ Core and Builtins
Library
-------
+- Issue #4384: Added integration with warnings module using captureWarnings().
+ This change includes a NullHandler which does nothing; it will be of use to
+ library developers who want to avoid the "No handlers could be found for
+ logger XXX" message which can appear if the library user doesn't configure
+ logging.
+
- Issue #3741: DISTUTILS_USE_SDK set causes msvc9compiler.py to raise an
exception.