Commits

Floris Bruynooghe committed 81a8de0

Add capturelog funcarg

This can be used to change the loglevel of the captured log. Either
by using it as a normal handler object or by using it as a context
manager.

Comments (0)

Files changed (3)

     text going to stderr
     ==================== 2 failed in 0.02 seconds =====================
 
+Inside tests it is possible to change the loglevel for the captured
+log messages.  This is supported by the ``capturelog`` funcarg::
+
+    def test_foo(capturelog):
+        capturelog.setLevel(logging.INFO)
+        pass
+
+It is also possible to use the capturelog as a context manager to
+temporarily change the log level::
+
+    def test_bar(capturelog):
+        with capturelog(logging.INFO):
+            pass
+
 Installation
 ------------
 

pytest_capturelog.py

-"""capture output of logging module. 
+"""capture output of logging module.
 
 Installation
 ------------
 
-You can install the `pytest-capturelog pypi`_ package 
+You can install the `pytest-capturelog pypi`_ package
 with pip::
 
-    pip install pytest-capturelog 
+    pip install pytest-capturelog
 
 or with easy install::
 
     text going to stderr
     ==================== 2 failed in 0.02 seconds =====================
 
+
+Inside tests it is possible to change the loglevel for the captured
+log messages.  This is supported by the ``capturelog`` funcarg::
+
+    def test_foo(capturelog):
+        capturelog.setLevel(logging.INFO)
+        pass
+
+It is also possible to use the capturelog as a context manager to
+temporarily change the log level::
+
+    def test_bar(capturelog):
+        with capturelog(logging.INFO):
+            pass
+
 """
 
 import py
     if config.getvalue('capturelog'):
         config.pluginmanager.register(Capturer(config), '_capturelog')
 
+
+class CapturelogHandler(logging.StreamHandler):
+    def __call__(self, level):
+        self.__tmp_level = level
+        return self
+
+    def __enter__(self):
+        self.__enter_level = self.level
+        self.level = self.__tmp_level
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.level = self.__enter_level
+
+
 class Capturer(object):
     """Attaches to the logging module and captures log messages for each test."""
 
 
         # Create a handler and stream for this test.
         item.capturelog_stream = py.io.TextIO()
-        item.capturelog_handler = logging.StreamHandler(item.capturelog_stream)
+        item.capturelog_handler = CapturelogHandler(item.capturelog_stream)
         item.capturelog_handler.setFormatter(self.formatter)
+        item.function.capturelog_handler = item.capturelog_handler
+        item.capturelog_loglevel = logging.getLogger().level
 
         # Attach the handler to the root logger and ensure that the
         # root logger is set to log all levels.
             del item.capturelog_handler
             del item.capturelog_stream
 
+            # Restore loglevel
+            root_logger.setLevel(item.capturelog_loglevel)
+
         return report
+
+    def pytest_funcarg__capturelog(self, request):
+        """Returns the log handler configured for this logger
+
+        This can be used to modify the loglevel or format inside a
+        test.
+        """
+        return request.function.capturelog_handler

test_pytest_capturelog.py

     assert fnmatch(['*- Captured log -*', '*text going to logger*'])
     assert fnmatch(['*- Captured stdout -*', 'text going to stdout'])
     assert fnmatch(['*- Captured stderr -*', 'text going to stderr'])
+
+def test_change_level(testdir):
+    testdir.makepyfile('''
+        import sys
+        import logging
+
+        pytest_plugins = 'capturelog'
+
+        def test_foo(capturelog):
+            capturelog.setLevel(logging.INFO)
+            log = logging.getLogger()
+            log.debug('DEBUG level')
+            log.info('INFO level')
+            assert False
+        ''')
+    result = testdir.runpytest()
+    assert result.ret == 1
+    fnmatch = result.stdout.fnmatch_lines
+    assert fnmatch(['*- Captured log -*', '*INFO level*'])
+    py.test.raises(AssertionError,
+                   fnmatch, ['*- Captured log -*', '*DEBUG level*'])
+
+@py.test.mark.skipif('sys.version_info < (2,5)')
+def test_with_statement(testdir):
+    testdir.makepyfile('''
+        from __future__ import with_statement
+        import sys
+        import logging
+
+        pytest_plugins = 'capturelog'
+
+        def test_foo(capturelog):
+            log = logging.getLogger()
+            with capturelog(logging.INFO):
+                log.debug('DEBUG level')
+                log.info('INFO level')
+            assert False
+        ''')
+    result = testdir.runpytest()
+    assert result.ret == 1
+    fnmatch = result.stdout.fnmatch_lines
+    assert fnmatch(['*- Captured log -*', '*INFO level*'])
+    py.test.raises(AssertionError,
+                   fnmatch, ['*- Captured log -*', '*DEBUG level*'])
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.