]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-134567: Add the formatter parameter in unittest.TestCase.assertLogs (GH-134570)
authorGarry Cairns <2401853+garry-cairns@users.noreply.github.com>
Wed, 2 Jul 2025 09:51:19 +0000 (10:51 +0100)
committerGitHub <noreply@github.com>
Wed, 2 Jul 2025 09:51:19 +0000 (09:51 +0000)
Doc/library/unittest.rst
Doc/whatsnew/3.15.rst
Lib/test/test_unittest/test_case.py
Lib/unittest/_log.py
Lib/unittest/case.py
Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst [new file with mode: 0644]

index dcdda1719bf5938de2901df1169e098618072699..d526e835caa18cc5a34125f754af5b2b91206855 100644 (file)
@@ -1131,7 +1131,7 @@ Test cases
       .. versionchanged:: 3.3
          Added the *msg* keyword argument when used as a context manager.
 
-   .. method:: assertLogs(logger=None, level=None)
+   .. method:: assertLogs(logger=None, level=None, formatter=None)
 
       A context manager to test that at least one message is logged on
       the *logger* or one of its children, with at least the given
@@ -1146,6 +1146,10 @@ Test cases
       its string equivalent (for example either ``"ERROR"`` or
       :const:`logging.ERROR`).  The default is :const:`logging.INFO`.
 
+      If given, *formatter* should be a :class:`logging.Formatter` object.
+      The default is a formatter with format string
+      ``"%(levelname)s:%(name)s:%(message)s"``
+
       The test passes if at least one message emitted inside the ``with``
       block matches the *logger* and *level* conditions, otherwise it fails.
 
@@ -1173,6 +1177,9 @@ Test cases
 
       .. versionadded:: 3.4
 
+      .. versionchanged:: next
+         Now accepts a *formatter* to control how messages are formatted.
+
    .. method:: assertNoLogs(logger=None, level=None)
 
       A context manager to test that no messages are logged on
index f06d4c84ea53d1118d682284a79603a23efdcdcd..706a816f888b301b2fa8a8b13a79bca1a53b4220 100644 (file)
@@ -291,6 +291,15 @@ typing
   (Contributed by Bénédikt Tran in :gh:`133823`.)
 
 
+unittest
+--------
+
+* Lets users specify formatter in TestCase.assertLogs.
+  :func:`unittest.TestCase.assertLogs` will now accept a formatter
+  to control how messages are formatted.
+  (Contributed by Garry Cairns in :gh:`134567`.)
+
+
 wave
 ----
 
index d66cab146af246861e5cb74c68b3871781dd75c3..cf10e956bf2bdc110a392ea2799efebe9de74d58 100644 (file)
@@ -1920,6 +1920,22 @@ test case
             with self.assertLogs():
                 raise ZeroDivisionError("Unexpected")
 
+    def testAssertLogsWithFormatter(self):
+        # Check alternative formats will be respected
+        format = "[No.1: the larch] %(levelname)s:%(name)s:%(message)s"
+        formatter = logging.Formatter(format)
+        with self.assertNoStderr():
+            with self.assertLogs() as cm:
+                log_foo.info("1")
+                log_foobar.debug("2")
+            self.assertEqual(cm.output, ["INFO:foo:1"])
+            self.assertLogRecords(cm.records, [{'name': 'foo'}])
+            with self.assertLogs(formatter=formatter) as cm:
+                log_foo.info("1")
+                log_foobar.debug("2")
+            self.assertEqual(cm.output, ["[No.1: the larch] INFO:foo:1"])
+            self.assertLogRecords(cm.records, [{'name': 'foo'}])
+
     def testAssertNoLogsDefault(self):
         with self.assertRaises(self.failureException) as cm:
             with self.assertNoLogs():
index 94868e5bb95eb35fb17c9bea103f04c7d0fd5433..3d69385ea243e73c71e0fe6742339ed92c8e6ffe 100644 (file)
@@ -30,7 +30,7 @@ class _AssertLogsContext(_BaseTestCaseContext):
 
     LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
 
-    def __init__(self, test_case, logger_name, level, no_logs):
+    def __init__(self, test_case, logger_name, level, no_logs, formatter=None):
         _BaseTestCaseContext.__init__(self, test_case)
         self.logger_name = logger_name
         if level:
@@ -39,13 +39,14 @@ class _AssertLogsContext(_BaseTestCaseContext):
             self.level = logging.INFO
         self.msg = None
         self.no_logs = no_logs
+        self.formatter = formatter
 
     def __enter__(self):
         if isinstance(self.logger_name, logging.Logger):
             logger = self.logger = self.logger_name
         else:
             logger = self.logger = logging.getLogger(self.logger_name)
-        formatter = logging.Formatter(self.LOGGING_FORMAT)
+        formatter = self.formatter or logging.Formatter(self.LOGGING_FORMAT)
         handler = _CapturingHandler()
         handler.setLevel(self.level)
         handler.setFormatter(formatter)
index db10de68e4ac7318362a3378c48aeb2dc126e747..eba50839cd33ae509a364ca7c0b800591c4bb9a6 100644 (file)
@@ -849,7 +849,7 @@ class TestCase(object):
         context = _AssertNotWarnsContext(expected_warning, self)
         return context.handle('_assertNotWarns', args, kwargs)
 
-    def assertLogs(self, logger=None, level=None):
+    def assertLogs(self, logger=None, level=None, formatter=None):
         """Fail unless a log message of level *level* or higher is emitted
         on *logger_name* or its children.  If omitted, *level* defaults to
         INFO and *logger* defaults to the root logger.
@@ -861,6 +861,8 @@ class TestCase(object):
         `records` attribute will be a list of the corresponding LogRecord
         objects.
 
+        Optionally supply `formatter` to control how messages are formatted.
+
         Example::
 
             with self.assertLogs('foo', level='INFO') as cm:
@@ -871,7 +873,7 @@ class TestCase(object):
         """
         # Lazy import to avoid importing logging if it is not needed.
         from ._log import _AssertLogsContext
-        return _AssertLogsContext(self, logger, level, no_logs=False)
+        return _AssertLogsContext(self, logger, level, no_logs=False, formatter=formatter)
 
     def assertNoLogs(self, logger=None, level=None):
         """ Fail unless no log messages of level *level* or higher are emitted
diff --git a/Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst b/Misc/NEWS.d/next/Tests/2025-05-23-09-19-52.gh-issue-134567.hwEIMb.rst
new file mode 100644 (file)
index 0000000..42e4a01
--- /dev/null
@@ -0,0 +1,2 @@
+Expose log formatter to users in TestCase.assertLogs.
+:func:`unittest.TestCase.assertLogs` will now optionally accept a formatter that will be used to format the strings in output if provided.