summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2012-12-16 09:43:41 +1300
committerRobert Collins <robertc@robertcollins.net>2012-12-16 09:43:41 +1300
commitb9dac139cb0d92f3f72d64aff4486defbb59510f (patch)
treeb8c8f0234082ea86d0c6784a1846d93c93ff0b12
parentf1441f4d1cabebbe0664bd9d10cf032f54e90158 (diff)
parent1663737e38deb18972190a56e951e913e20cd82a (diff)
downloadfixtures-b9dac139cb0d92f3f72d64aff4486defbb59510f.tar.gz
* ``FakeLogger`` has been split out into a ``LogHandler`` fixture that can
inject arbitrary handlers, giving more flexability. (Jonathan Lange)
-rw-r--r--NEWS6
-rw-r--r--lib/fixtures/__init__.py2
-rw-r--r--lib/fixtures/_fixtures/__init__.py2
-rw-r--r--lib/fixtures/_fixtures/logger.py51
-rw-r--r--lib/fixtures/tests/_fixtures/test_logger.py67
5 files changed, 115 insertions, 13 deletions
diff --git a/NEWS b/NEWS
index 3c802a8..4f82b24 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,12 @@ fixtures release notes
NEXT
~~~~
+CHANGES
+-------
+
+* ``FakeLogger`` has been split out into a ``LogHandler`` fixture that can
+ inject arbitrary handlers, giving more flexability. (Jonathan Lange)
+
0.3.10
~~~~~~
diff --git a/lib/fixtures/__init__.py b/lib/fixtures/__init__.py
index 89009cc..1390ac8 100644
--- a/lib/fixtures/__init__.py
+++ b/lib/fixtures/__init__.py
@@ -47,6 +47,7 @@ __all__ = [
'Fixture',
'FunctionFixture',
'LoggerFixture',
+ 'LogHandler',
'MethodFixture',
'MonkeyPatch',
'NestedTempfile',
@@ -74,6 +75,7 @@ from fixtures._fixtures import (
FakeLogger,
FakePopen,
LoggerFixture,
+ LogHandler,
MonkeyPatch,
NestedTempfile,
PackagePathEntry,
diff --git a/lib/fixtures/_fixtures/__init__.py b/lib/fixtures/_fixtures/__init__.py
index d6a8700..e113e1e 100644
--- a/lib/fixtures/_fixtures/__init__.py
+++ b/lib/fixtures/_fixtures/__init__.py
@@ -23,6 +23,7 @@ __all__ = [
'FakeLogger',
'FakePopen',
'LoggerFixture',
+ 'LogHandler',
'MonkeyPatch',
'NestedTempfile',
'PackagePathEntry',
@@ -44,6 +45,7 @@ from fixtures._fixtures.environ import (
from fixtures._fixtures.logger import (
FakeLogger,
LoggerFixture,
+ LogHandler,
)
from fixtures._fixtures.monkeypatch import MonkeyPatch
from fixtures._fixtures.popen import (
diff --git a/lib/fixtures/_fixtures/logger.py b/lib/fixtures/_fixtures/logger.py
index ec5a767..0beb170 100644
--- a/lib/fixtures/_fixtures/logger.py
+++ b/lib/fixtures/_fixtures/logger.py
@@ -21,9 +21,45 @@ from fixtures._fixtures.detailstream import DetailStream
__all__ = [
'FakeLogger',
'LoggerFixture',
+ 'LogHandler',
]
+class LogHandler(Fixture):
+ """Replace a logger's handlers."""
+
+ def __init__(self, handler, name="", level=None, nuke_handlers=True):
+ """Create a LogHandler fixture.
+
+ :param handler: The handler to replace other handlers with.
+ If nuke_handlers is False, then added as an extra handler.
+ :param name: The name of the logger to replace. Defaults to "".
+ :param level: The log level to set, defaults to not changing the level.
+ :param nuke_handlers: If True remove all existing handles (prevents
+ existing messages going to e.g. stdout). Defaults to True.
+ """
+ super(LogHandler, self).__init__()
+ self.handler = handler
+ self._name = name
+ self._level = level
+ self._nuke_handlers = nuke_handlers
+
+ def setUp(self):
+ super(LogHandler, self).setUp()
+ logger = getLogger(self._name)
+ if self._level:
+ self.addCleanup(logger.setLevel, logger.level)
+ logger.setLevel(self._level)
+ if self._nuke_handlers:
+ for handler in reversed(logger.handlers):
+ self.addCleanup(logger.addHandler, handler)
+ logger.removeHandler(handler)
+ try:
+ logger.addHandler(self.handler)
+ finally:
+ self.addCleanup(logger.removeHandler, self.handler)
+
+
class FakeLogger(Fixture):
"""Replace a logger and capture its output."""
@@ -55,21 +91,12 @@ class FakeLogger(Fixture):
name = u"pythonlogging:'%s'" % self._name
output = self.useFixture(DetailStream(name)).stream
self._output = output
- logger = getLogger(self._name)
- if self._level:
- self.addCleanup(logger.setLevel, logger.level)
- logger.setLevel(self._level)
- if self._nuke_handlers:
- for handler in reversed(logger.handlers):
- logger.removeHandler(handler)
- self.addCleanup(logger.addHandler, handler)
handler = StreamHandler(output)
if self._format:
handler.setFormatter(Formatter(self._format))
- try:
- logger.addHandler(handler)
- finally:
- self.addCleanup(logger.removeHandler, handler)
+ self.useFixture(
+ LogHandler(handler, name=self._name, level=self._level,
+ nuke_handlers=self._nuke_handlers))
@property
def output(self):
diff --git a/lib/fixtures/tests/_fixtures/test_logger.py b/lib/fixtures/tests/_fixtures/test_logger.py
index 9b88b5f..c05e862 100644
--- a/lib/fixtures/tests/_fixtures/test_logger.py
+++ b/lib/fixtures/tests/_fixtures/test_logger.py
@@ -18,7 +18,11 @@ import logging
from testtools import TestCase
from cStringIO import StringIO
-from fixtures import FakeLogger, TestWithFixtures
+from fixtures import (
+ FakeLogger,
+ LogHandler,
+ TestWithFixtures,
+ )
class FakeLoggerTest(TestCase, TestWithFixtures):
@@ -90,3 +94,64 @@ class FakeLoggerTest(TestCase, TestWithFixtures):
self.assertEqual("some message\n", content.as_text())
# A new one returns the new output:
self.assertEqual("", fixture.getDetails()[detail_name].as_text())
+
+
+class LogHandlerTest(TestCase, TestWithFixtures):
+
+ class CustomHandler(logging.Handler):
+
+ def __init__(self, *args, **kwargs):
+ """Create the instance, and add a records attribute."""
+ logging.Handler.__init__(self, *args, **kwargs)
+ self.msgs = []
+
+ def emit(self, record):
+ self.msgs.append(record.msg)
+
+ def setUp(self):
+ super(LogHandlerTest, self).setUp()
+ self.logger = logging.getLogger()
+ self.addCleanup(self.removeHandlers, self.logger)
+
+ def removeHandlers(self, logger):
+ for handler in logger.handlers:
+ logger.removeHandler(handler)
+
+ def test_captures_logging(self):
+ fixture = self.useFixture(LogHandler(self.CustomHandler()))
+ logging.info("some message")
+ self.assertEqual(["some message"], fixture.handler.msgs)
+
+ def test_replace_and_restore_handlers(self):
+ stream = StringIO()
+ logger = logging.getLogger()
+ logger.addHandler(logging.StreamHandler(stream))
+ logger.setLevel(logging.INFO)
+ logging.info("one")
+ fixture = LogHandler(self.CustomHandler())
+ with fixture:
+ logging.info("two")
+ logging.info("three")
+ self.assertEqual(["two"], fixture.handler.msgs)
+ self.assertEqual("one\nthree\n", stream.getvalue())
+
+ def test_preserving_existing_handlers(self):
+ stream = StringIO()
+ self.logger.addHandler(logging.StreamHandler(stream))
+ self.logger.setLevel(logging.INFO)
+ fixture = LogHandler(self.CustomHandler(), nuke_handlers=False)
+ with fixture:
+ logging.info("message")
+ self.assertEqual(["message"], fixture.handler.msgs)
+ self.assertEqual("message\n", stream.getvalue())
+
+ def test_logging_level_restored(self):
+ self.logger.setLevel(logging.DEBUG)
+ fixture = LogHandler(self.CustomHandler(), level=logging.WARNING)
+ with fixture:
+ # The fixture won't capture this, because the DEBUG level
+ # is lower than the WARNING one
+ logging.debug("debug message")
+ self.assertEqual(logging.WARNING, self.logger.level)
+ self.assertEqual([], fixture.handler.msgs)
+ self.assertEqual(logging.DEBUG, self.logger.level)