Skip to content

Commit 2ade563

Browse files
[3.11] pythongh-103606: Improve error message from logging.config.FileConfig (pythonGH-103628) (python#104687)
* pythongh-103606: Improve error message from logging.config.FileConfig (pythonGH-103628) (cherry picked from commit 152227b) plus backport the followup exception change fix to that in python#104701
1 parent e033eda commit 2ade563

File tree

3 files changed

+61
-6
lines changed

3 files changed

+61
-6
lines changed

Doc/library/logging.config.rst

+8
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in
8787
provides a mechanism to present the choices and load the chosen
8888
configuration).
8989

90+
It will raise :exc:`FileNotFoundError` if the file
91+
doesn't exist and :exc:`RuntimeError` if the file is invalid or
92+
empty.
93+
9094
:param fname: A filename, or a file-like object, or an instance derived
9195
from :class:`~configparser.RawConfigParser`. If a
9296
``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
126130
.. versionadded:: 3.10
127131
The *encoding* parameter is added.
128132

133+
.. versionchanged:: 3.11.4
134+
An exception will be thrown if the provided file
135+
doesn't exist or is invalid or empty.
136+
129137
.. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)
130138

131139
Starts up a socket server on the specified port, and listens for new

Lib/logging/config.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import io
2929
import logging
3030
import logging.handlers
31+
import os
32+
import queue
3133
import re
3234
import struct
3335
import threading
@@ -58,15 +60,24 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non
5860
"""
5961
import configparser
6062

63+
if isinstance(fname, str):
64+
if not os.path.exists(fname):
65+
raise FileNotFoundError(f"{fname} doesn't exist")
66+
elif not os.path.getsize(fname):
67+
raise RuntimeError(f'{fname} is an empty file')
68+
6169
if isinstance(fname, configparser.RawConfigParser):
6270
cp = fname
6371
else:
64-
cp = configparser.ConfigParser(defaults)
65-
if hasattr(fname, 'readline'):
66-
cp.read_file(fname)
67-
else:
68-
encoding = io.text_encoding(encoding)
69-
cp.read(fname, encoding=encoding)
72+
try:
73+
cp = configparser.ConfigParser(defaults)
74+
if hasattr(fname, 'readline'):
75+
cp.read_file(fname)
76+
else:
77+
encoding = io.text_encoding(encoding)
78+
cp.read(fname, encoding=encoding)
79+
except configparser.ParsingError as e:
80+
raise RuntimeError(f'{fname} is invalid: {e}')
7081

7182
formatters = _create_formatters(cp)
7283

Lib/test/test_logging.py

+36
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,42 @@ def test_config_set_handler_names(self):
16451645
self.apply_config(test_config)
16461646
self.assertEqual(logging.getLogger().handlers[0].name, 'hand1')
16471647

1648+
def test_exception_if_confg_file_is_invalid(self):
1649+
test_config = """
1650+
[loggers]
1651+
keys=root
1652+
1653+
[handlers]
1654+
keys=hand1
1655+
1656+
[formatters]
1657+
keys=form1
1658+
1659+
[logger_root]
1660+
handlers=hand1
1661+
1662+
[handler_hand1]
1663+
class=StreamHandler
1664+
formatter=form1
1665+
1666+
[formatter_form1]
1667+
format=%(levelname)s ++ %(message)s
1668+
1669+
prince
1670+
"""
1671+
1672+
file = io.StringIO(textwrap.dedent(test_config))
1673+
self.assertRaises(RuntimeError, logging.config.fileConfig, file)
1674+
1675+
def test_exception_if_confg_file_is_empty(self):
1676+
fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini')
1677+
os.close(fd)
1678+
self.assertRaises(RuntimeError, logging.config.fileConfig, fn)
1679+
os.remove(fn)
1680+
1681+
def test_exception_if_config_file_does_not_exist(self):
1682+
self.assertRaises(FileNotFoundError, logging.config.fileConfig, 'filenotfound')
1683+
16481684
def test_defaults_do_no_interpolation(self):
16491685
"""bpo-33802 defaults should not get interpolated"""
16501686
ini = textwrap.dedent("""

0 commit comments

Comments
 (0)