Skip to content

Commit 152227b

Browse files
pythongh-103606: Improve error message from logging.config.FileConfig (pythonGH-103628)
1 parent c5b670e commit 152227b

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-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:`ValueError` 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+
.. versionadded:: 3.12
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

+16-6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io
3030
import logging
3131
import logging.handlers
32+
import os
3233
import queue
3334
import re
3435
import struct
@@ -60,15 +61,24 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non
6061
"""
6162
import configparser
6263

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

7383
formatters = _create_formatters(cp)
7484

Lib/test/test_logging.py

+36
Original file line numberDiff line numberDiff line change
@@ -1756,6 +1756,42 @@ def test_config_set_handler_names(self):
17561756
self.apply_config(test_config)
17571757
self.assertEqual(logging.getLogger().handlers[0].name, 'hand1')
17581758

1759+
def test_exception_if_confg_file_is_invalid(self):
1760+
test_config = """
1761+
[loggers]
1762+
keys=root
1763+
1764+
[handlers]
1765+
keys=hand1
1766+
1767+
[formatters]
1768+
keys=form1
1769+
1770+
[logger_root]
1771+
handlers=hand1
1772+
1773+
[handler_hand1]
1774+
class=StreamHandler
1775+
formatter=form1
1776+
1777+
[formatter_form1]
1778+
format=%(levelname)s ++ %(message)s
1779+
1780+
prince
1781+
"""
1782+
1783+
file = io.StringIO(textwrap.dedent(test_config))
1784+
self.assertRaises(ValueError, logging.config.fileConfig, file)
1785+
1786+
def test_exception_if_confg_file_is_empty(self):
1787+
fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini')
1788+
os.close(fd)
1789+
self.assertRaises(ValueError, logging.config.fileConfig, fn)
1790+
os.remove(fn)
1791+
1792+
def test_exception_if_config_file_does_not_exist(self):
1793+
self.assertRaises(FileNotFoundError, logging.config.fileConfig, 'filenotfound')
1794+
17591795
def test_defaults_do_no_interpolation(self):
17601796
"""bpo-33802 defaults should not get interpolated"""
17611797
ini = textwrap.dedent("""

0 commit comments

Comments
 (0)