diff options
author | Robert Collins <robertc@robertcollins.net> | 2012-12-16 09:43:41 +1300 |
---|---|---|
committer | Robert Collins <robertc@robertcollins.net> | 2012-12-16 09:43:41 +1300 |
commit | b9dac139cb0d92f3f72d64aff4486defbb59510f (patch) | |
tree | b8c8f0234082ea86d0c6784a1846d93c93ff0b12 | |
parent | f1441f4d1cabebbe0664bd9d10cf032f54e90158 (diff) | |
parent | 1663737e38deb18972190a56e951e913e20cd82a (diff) | |
download | fixtures-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-- | NEWS | 6 | ||||
-rw-r--r-- | lib/fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/logger.py | 51 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/test_logger.py | 67 |
5 files changed, 115 insertions, 13 deletions
@@ -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) |