mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-133577: Add parameter formatter
to logging.basicConfig
(GH-133578)
This commit is contained in:
parent
9ad0c7b0f1
commit
2eb49d278e
4 changed files with 67 additions and 10 deletions
|
@ -1342,8 +1342,9 @@ functions.
|
|||
|
||||
.. function:: basicConfig(**kwargs)
|
||||
|
||||
Does basic configuration for the logging system by creating a
|
||||
:class:`StreamHandler` with a default :class:`Formatter` and adding it to the
|
||||
Does basic configuration for the logging system by either creating a
|
||||
:class:`StreamHandler` with a default :class:`Formatter`
|
||||
or using the given *formatter* instance, and adding it to the
|
||||
root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
|
||||
:func:`error` and :func:`critical` will call :func:`basicConfig` automatically
|
||||
if no handlers are defined for the root logger.
|
||||
|
@ -1428,6 +1429,19 @@ functions.
|
|||
| | which means that it will be treated the |
|
||||
| | same as passing 'errors'. |
|
||||
+--------------+---------------------------------------------+
|
||||
| *formatter* | If specified, set this formatter instance |
|
||||
| | (see :ref:`formatter-objects`) |
|
||||
| | for all involved handlers. |
|
||||
| | If not specified, the default is to create |
|
||||
| | and use an instance of |
|
||||
| | :class:`logging.Formatter` based on |
|
||||
| | arguments *format*, *datefmt* and *style*. |
|
||||
| | When *formatter* is specified together with |
|
||||
| | any of the three arguments *format*, |
|
||||
| | *datefmt* and *style*, a ``ValueError`` is |
|
||||
| | raised to signal that these arguments would |
|
||||
| | lose meaning otherwise. |
|
||||
+--------------+---------------------------------------------+
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
The *style* argument was added.
|
||||
|
@ -1444,6 +1458,9 @@ functions.
|
|||
.. versionchanged:: 3.9
|
||||
The *encoding* and *errors* arguments were added.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
The *formatter* argument was added.
|
||||
|
||||
.. function:: shutdown()
|
||||
|
||||
Informs the logging system to perform an orderly shutdown by flushing and
|
||||
|
|
|
@ -2057,6 +2057,15 @@ def basicConfig(**kwargs):
|
|||
created FileHandler, causing it to be used when the file is
|
||||
opened in text mode. If not specified, the default value is
|
||||
`backslashreplace`.
|
||||
formatter If specified, set this formatter instance for all involved
|
||||
handlers.
|
||||
If not specified, the default is to create and use an instance of
|
||||
`logging.Formatter` based on arguments 'format', 'datefmt' and
|
||||
'style'.
|
||||
When 'formatter' is specified together with any of the three
|
||||
arguments 'format', 'datefmt' and 'style', a `ValueError`
|
||||
is raised to signal that these arguments would lose meaning
|
||||
otherwise.
|
||||
|
||||
Note that you could specify a stream created using open(filename, mode)
|
||||
rather than passing the filename and mode in. However, it should be
|
||||
|
@ -2079,6 +2088,9 @@ def basicConfig(**kwargs):
|
|||
|
||||
.. versionchanged:: 3.9
|
||||
Added the ``encoding`` and ``errors`` parameters.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
Added the ``formatter`` parameter.
|
||||
"""
|
||||
# Add thread safety in case someone mistakenly calls
|
||||
# basicConfig() from multiple threads
|
||||
|
@ -2114,13 +2126,19 @@ def basicConfig(**kwargs):
|
|||
stream = kwargs.pop("stream", None)
|
||||
h = StreamHandler(stream)
|
||||
handlers = [h]
|
||||
dfs = kwargs.pop("datefmt", None)
|
||||
style = kwargs.pop("style", '%')
|
||||
if style not in _STYLES:
|
||||
raise ValueError('Style must be one of: %s' % ','.join(
|
||||
_STYLES.keys()))
|
||||
fs = kwargs.pop("format", _STYLES[style][1])
|
||||
fmt = Formatter(fs, dfs, style)
|
||||
fmt = kwargs.pop("formatter", None)
|
||||
if fmt is None:
|
||||
dfs = kwargs.pop("datefmt", None)
|
||||
style = kwargs.pop("style", '%')
|
||||
if style not in _STYLES:
|
||||
raise ValueError('Style must be one of: %s' % ','.join(
|
||||
_STYLES.keys()))
|
||||
fs = kwargs.pop("format", _STYLES[style][1])
|
||||
fmt = Formatter(fs, dfs, style)
|
||||
else:
|
||||
for forbidden_key in ("datefmt", "format", "style"):
|
||||
if forbidden_key in kwargs:
|
||||
raise ValueError(f"{forbidden_key!r} should not be specified together with 'formatter'")
|
||||
for h in handlers:
|
||||
if h.formatter is None:
|
||||
h.setFormatter(fmt)
|
||||
|
|
|
@ -61,7 +61,7 @@ import warnings
|
|||
import weakref
|
||||
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import call, Mock, patch
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
|
||||
ThreadingTCPServer, StreamRequestHandler)
|
||||
|
@ -5655,12 +5655,19 @@ class BasicConfigTest(unittest.TestCase):
|
|||
assertRaises = self.assertRaises
|
||||
handlers = [logging.StreamHandler()]
|
||||
stream = sys.stderr
|
||||
formatter = logging.Formatter()
|
||||
assertRaises(ValueError, logging.basicConfig, filename='test.log',
|
||||
stream=stream)
|
||||
assertRaises(ValueError, logging.basicConfig, filename='test.log',
|
||||
handlers=handlers)
|
||||
assertRaises(ValueError, logging.basicConfig, stream=stream,
|
||||
handlers=handlers)
|
||||
assertRaises(ValueError, logging.basicConfig, formatter=formatter,
|
||||
format='%(message)s')
|
||||
assertRaises(ValueError, logging.basicConfig, formatter=formatter,
|
||||
datefmt='%H:%M:%S')
|
||||
assertRaises(ValueError, logging.basicConfig, formatter=formatter,
|
||||
style='%')
|
||||
# Issue 23207: test for invalid kwargs
|
||||
assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
|
||||
# Should pop both filename and filemode even if filename is None
|
||||
|
@ -5795,6 +5802,20 @@ class BasicConfigTest(unittest.TestCase):
|
|||
# didn't write anything due to the encoding error
|
||||
self.assertEqual(data, r'')
|
||||
|
||||
def test_formatter_given(self):
|
||||
mock_formatter = Mock()
|
||||
mock_handler = Mock(formatter=None)
|
||||
with patch("logging.Formatter") as mock_formatter_init:
|
||||
logging.basicConfig(formatter=mock_formatter, handlers=[mock_handler])
|
||||
self.assertEqual(mock_handler.setFormatter.call_args_list, [call(mock_formatter)])
|
||||
self.assertEqual(mock_formatter_init.call_count, 0)
|
||||
|
||||
def test_formatter_not_given(self):
|
||||
mock_handler = Mock(formatter=None)
|
||||
with patch("logging.Formatter") as mock_formatter_init:
|
||||
logging.basicConfig(handlers=[mock_handler])
|
||||
self.assertEqual(mock_formatter_init.call_count, 1)
|
||||
|
||||
@support.requires_working_socket()
|
||||
def test_log_taskName(self):
|
||||
async def log_record():
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add parameter ``formatter`` to :func:`logging.basicConfig`.
|
Loading…
Add table
Add a link
Reference in a new issue