]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-103606: Improve error message from logging.config.FileConfig (GH-103628...
authorPrince Roshan <princekrroshan01@gmail.com>
Sun, 21 May 2023 19:17:18 +0000 (00:47 +0530)
committerGitHub <noreply@github.com>
Sun, 21 May 2023 19:17:18 +0000 (12:17 -0700)
* gh-103606: Improve error message from logging.config.FileConfig (GH-103628)

(cherry picked from commit 152227b569c3a9b87fe0483706f704762ced6d75)

plus backport the followup exception change fix to that in #104701

Doc/library/logging.config.rst
Lib/logging/config.py
Lib/test/test_logging.py

index 45dc975db474e7b17bf5beb1bed5ec2fde87b266..619e0406066809e5f1d993d0e366b0140117630d 100644 (file)
@@ -87,6 +87,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in
    provides a mechanism to present the choices and load the chosen
    configuration).
 
+   It will raise :exc:`FileNotFoundError` if the file
+   doesn't exist and :exc:`RuntimeError` if the file is invalid or
+   empty.
+
    :param fname: A filename, or a file-like object, or an instance derived
                  from :class:`~configparser.RawConfigParser`. If a
                  ``RawConfigParser``-derived instance is passed, it is used as
@@ -126,6 +130,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in
     .. versionadded:: 3.10
        The *encoding* parameter is added.
 
+    .. versionchanged:: 3.11.4
+       An exception will be thrown if the provided file
+       doesn't exist or is invalid or empty.
+
 .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)
 
    Starts up a socket server on the specified port, and listens for new
index f9ef7b53a3d6488d3d90a2a1257afe5e69fb07c0..7e78a64a2f08a6b5f5ef2c9ee98329eb8244f27b 100644 (file)
@@ -28,6 +28,8 @@ import errno
 import io
 import logging
 import logging.handlers
+import os
+import queue
 import re
 import struct
 import threading
@@ -58,15 +60,24 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non
     """
     import configparser
 
+    if isinstance(fname, str):
+        if not os.path.exists(fname):
+            raise FileNotFoundError(f"{fname} doesn't exist")
+        elif not os.path.getsize(fname):
+            raise RuntimeError(f'{fname} is an empty file')
+
     if isinstance(fname, configparser.RawConfigParser):
         cp = fname
     else:
-        cp = configparser.ConfigParser(defaults)
-        if hasattr(fname, 'readline'):
-            cp.read_file(fname)
-        else:
-            encoding = io.text_encoding(encoding)
-            cp.read(fname, encoding=encoding)
+        try:
+            cp = configparser.ConfigParser(defaults)
+            if hasattr(fname, 'readline'):
+                cp.read_file(fname)
+            else:
+                encoding = io.text_encoding(encoding)
+                cp.read(fname, encoding=encoding)
+        except configparser.ParsingError as e:
+            raise RuntimeError(f'{fname} is invalid: {e}')
 
     formatters = _create_formatters(cp)
 
index 350f4a57e2bbeea8550eeca397ba92f50a32c984..76bd8724e29b41618ed17a8ab695dd1ec360f74b 100644 (file)
@@ -1645,6 +1645,42 @@ class ConfigFileTest(BaseTest):
         self.apply_config(test_config)
         self.assertEqual(logging.getLogger().handlers[0].name, 'hand1')
 
+    def test_exception_if_confg_file_is_invalid(self):
+        test_config = """
+            [loggers]
+            keys=root
+
+            [handlers]
+            keys=hand1
+
+            [formatters]
+            keys=form1
+
+            [logger_root]
+            handlers=hand1
+
+            [handler_hand1]
+            class=StreamHandler
+            formatter=form1
+
+            [formatter_form1]
+            format=%(levelname)s ++ %(message)s
+
+            prince
+            """
+
+        file = io.StringIO(textwrap.dedent(test_config))
+        self.assertRaises(RuntimeError, logging.config.fileConfig, file)
+
+    def test_exception_if_confg_file_is_empty(self):
+        fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini')
+        os.close(fd)
+        self.assertRaises(RuntimeError, logging.config.fileConfig, fn)
+        os.remove(fn)
+
+    def test_exception_if_config_file_does_not_exist(self):
+        self.assertRaises(FileNotFoundError, logging.config.fileConfig, 'filenotfound')
+
     def test_defaults_do_no_interpolation(self):
         """bpo-33802 defaults should not get interpolated"""
         ini = textwrap.dedent("""