Skip to content

bpo-33897: Add a 'force' keyword argument to logging.basicConfig(). #7873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Doc/library/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ functions.
if no handlers are defined for the root logger.

This function does nothing if the root logger already has handlers
configured for it.
configured, unless the keyword argument *force* is set to ``True``.

.. note:: This function should be called from the main thread
before other threads are started. In versions of Python prior to
Expand Down Expand Up @@ -1183,6 +1183,15 @@ functions.
| | with 'filename' or 'stream' - if both are |
| | present, a ``ValueError`` is raised. |
+--------------+---------------------------------------------+
| ``force`` | If this keyword argument is specified as |
| | true, any existing handlers attached to the |
| | root logger are removed and closed, before |
| | carrying out the configuration as specified |
| | by the other arguments. |
+--------------+---------------------------------------------+

.. versionchanged:: 3.8
The ``force`` argument was added.

.. versionchanged:: 3.2
The ``style`` argument was added.
Expand Down
16 changes: 14 additions & 2 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1793,7 +1793,8 @@ def basicConfig(**kwargs):
Do basic configuration for the logging system.

This function does nothing if the root logger already has handlers
configured. It is a convenience method intended for use by simple scripts
configured, unless the keyword argument *force* is set to ``True``.
It is a convenience method intended for use by simple scripts
to do one-shot configuration of the logging package.

The default behaviour is to create a StreamHandler which writes to
Expand Down Expand Up @@ -1821,13 +1822,19 @@ def basicConfig(**kwargs):
handlers, which will be added to the root handler. Any handler
in the list which does not have a formatter assigned will be
assigned the formatter created in this function.

force If this keyword is specified as true, any existing handlers
attached to the root logger are removed and closed, before
carrying out the configuration as specified by the other
arguments.
Note that you could specify a stream created using open(filename, mode)
rather than passing the filename and mode in. However, it should be
remembered that StreamHandler does not close its stream (since it may be
using sys.stdout or sys.stderr), whereas FileHandler closes its stream
when the handler is closed.

.. versionchanged:: 3.8
Added the ``force`` parameter.

.. versionchanged:: 3.2
Added the ``style`` parameter.

Expand All @@ -1842,6 +1849,11 @@ def basicConfig(**kwargs):
# basicConfig() from multiple threads
_acquireLock()
try:
force = kwargs.pop('force', False)
if force:
for h in root.handlers[:]:
root.removeHandler(h)
h.close()
if len(root.handlers) == 0:
handlers = kwargs.pop("handlers", None)
if handlers is None:
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -3901,6 +3901,27 @@ def test_handlers(self):
self.assertIs(handlers[2].formatter, f)
self.assertIs(handlers[0].formatter, handlers[1].formatter)

def test_force(self):
old_string_io = io.StringIO()
new_string_io = io.StringIO()
old_handlers = [logging.StreamHandler(old_string_io)]
new_handlers = [logging.StreamHandler(new_string_io)]
logging.basicConfig(level=logging.WARNING, handlers=old_handlers)
logging.warning('warn')
logging.info('info')
logging.debug('debug')
self.assertEqual(len(logging.root.handlers), 1)
logging.basicConfig(level=logging.INFO, handlers=new_handlers,
force=True)
logging.warning('warn')
logging.info('info')
logging.debug('debug')
self.assertEqual(len(logging.root.handlers), 1)
self.assertEqual(old_string_io.getvalue().strip(),
'WARNING:root:warn')
self.assertEqual(new_string_io.getvalue().strip(),
'WARNING:root:warn\nINFO:root:info')

def _test_log(self, method, level=None):
# logging.root has no handlers so basicConfig should be called
called = []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a 'force' keyword argument to logging.basicConfig().