From cf9e2f242081e119763f717df5fef5e6fcba8c77 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Tue, 9 Oct 2012 09:06:03 +0100 Subject: [PATCH] Closes #16110: fileConfig now accepts a pre-initialised ConfigParser instance. --- Doc/library/logging.config.rst | 31 ++++++++++++++++++++++++++----- Lib/logging/config.py | 11 +++++++---- Lib/test/test_logging.py | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index d116d0a1d9b..16d3294832f 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -76,11 +76,23 @@ in :mod:`logging` itself) and defining handlers which are declared either in .. function:: fileConfig(fname, defaults=None, disable_existing_loggers=True) - Reads the logging configuration from a :mod:`configparser`\-format file - named *fname*. This function can be called several times from an - application, allowing an end user to select from various pre-canned - configurations (if the developer provides a mechanism to present the choices - and load the chosen configuration). + Reads the logging configuration from a :mod:`configparser`\-format file. + This function can be called several times from an application, allowing an + end user to select from various pre-canned configurations (if the developer + provides a mechanism to present the choices and load the chosen + configuration). + + :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 + is. Otherwise, a :class:`~configparser.Configparser` is + instantiated, and the configuration read by it from the + object passed in ``fname``. If that has a :meth:`readline` + method, it is assumed to be a file-like object and read using + :meth:`~configparser.ConfigParser.read_file`; otherwise, + it is assumed to be a filename and passed to + :meth:`~configparser.ConfigParser.read`. + :param defaults: Defaults to be passed to the ConfigParser can be specified in this argument. @@ -94,6 +106,15 @@ in :mod:`logging` itself) and defining handlers which are declared either in their ancestors are explicitly named in the logging configuration. + .. versionchanged:: 3.4 + An instance of a subclass of :class:`~configparser.RawConfigParser` is + now accepted as a value for ``fname``. This facilitates: + + * Use of a configuration file where logging configuration is just part + of the overall application configuration. + * Use of a configuration read from a file, and then modified by the using + application (e.g. based on command-line parameters or other aspects + of the runtime environment) before being passed to ``fileConfig``. .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 9ba3cca3bcf..0694d21fe05 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -61,11 +61,14 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True): """ import configparser - cp = configparser.ConfigParser(defaults) - if hasattr(fname, 'readline'): - cp.read_file(fname) + if isinstance(fname, configparser.RawConfigParser): + cp = fname else: - cp.read(fname) + cp = configparser.ConfigParser(defaults) + if hasattr(fname, 'readline'): + cp.read_file(fname) + else: + cp.read(fname) formatters = _create_formatters(cp) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index dc49fc16c76..a2a136b0cef 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -26,6 +26,7 @@ import logging.handlers import logging.config import codecs +import configparser import datetime import pickle import io @@ -1279,6 +1280,24 @@ class ConfigFileTest(BaseTest): # Original logger output is empty. self.assert_log_lines([]) + def test_config0_using_cp_ok(self): + # A simple config file which overrides the default settings. + with captured_stdout() as output: + file = io.StringIO(textwrap.dedent(self.config0)) + cp = configparser.ConfigParser() + cp.read_file(file) + logging.config.fileConfig(cp) + logger = logging.getLogger() + # Won't output anything + logger.info(self.next_message()) + # Outputs a message + logger.error(self.next_message()) + self.assert_log_lines([ + ('ERROR', '2'), + ], stream=output) + # Original logger output is empty. + self.assert_log_lines([]) + def test_config1_ok(self, config=config1): # A config file defining a sub-parser as well. with captured_stdout() as output: