[Python-checkins] bpo-41906: Accept built filters in dictConfig (GH-30756)
miss-islington
webhook-mailer at python.org
Mon Jan 24 07:40:02 EST 2022
https://github.com/python/cpython/commit/d7c68639795a576ff58b6479c8bb34c113df3618
commit: d7c68639795a576ff58b6479c8bb34c113df3618
branch: main
author: Mario Corchero <mcorcherojim at bloomberg.net>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-01-24T04:39:50-08:00
summary:
bpo-41906: Accept built filters in dictConfig (GH-30756)
When configuring the logging stack, accept already built filters (or
just callables) in the filters array of loggers and handlers.
This facilitates passing quick callables as filters.
Automerge-Triggered-By: GH:vsajip
files:
A Misc/NEWS.d/next/Library/2022-01-21-18-19-45.bpo-41906.YBaquj.rst
M Doc/library/logging.config.rst
M Lib/logging/config.py
M Lib/test/test_logging.py
diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst
index a1b8dc755ba6b..c979961a221c9 100644
--- a/Doc/library/logging.config.rst
+++ b/Doc/library/logging.config.rst
@@ -288,6 +288,9 @@ otherwise, the context is used to determine what to instantiate.
* ``filters`` (optional). A list of ids of the filters for this
handler.
+ .. versionchanged:: 3.11
+ ``filters`` can take filter instances in addition to ids.
+
All *other* keys are passed through as keyword arguments to the
handler's constructor. For example, given the snippet:
@@ -326,6 +329,9 @@ otherwise, the context is used to determine what to instantiate.
* ``filters`` (optional). A list of ids of the filters for this
logger.
+ .. versionchanged:: 3.11
+ ``filters`` can take filter instances in addition to ids.
+
* ``handlers`` (optional). A list of ids of the handlers for this
logger.
@@ -524,6 +530,10 @@ valid keyword parameter name, and so will not clash with the names of
the keyword arguments used in the call. The ``'()'`` also serves as a
mnemonic that the corresponding value is a callable.
+ .. versionchanged:: 3.11
+ The ``filters`` member of ``handlers`` and ``loggers`` can take
+ filter instances in addition to ids.
+
.. _logging-config-dict-externalobj:
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 9bc07eddd76b4..86a1e4eaf4cbc 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -694,7 +694,11 @@ def add_filters(self, filterer, filters):
"""Add filters to a filterer from a list of names."""
for f in filters:
try:
- filterer.addFilter(self.config['filters'][f])
+ if callable(f) or callable(getattr(f, 'filter', None)):
+ filter_ = f
+ else:
+ filter_ = self.config['filters'][f]
+ filterer.addFilter(filter_)
except Exception as e:
raise ValueError('Unable to add filter %r' % f) from e
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 7c38676012bab..4f3315161cf20 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -3447,6 +3447,44 @@ def emit(self, record):
logging.info('some log')
self.assertEqual(stderr.getvalue(), 'some log my_type\n')
+ def test_config_callable_filter_works(self):
+ def filter_(_):
+ return 1
+ self.apply_config({
+ "version": 1, "root": {"level": "DEBUG", "filters": [filter_]}
+ })
+ assert logging.getLogger().filters[0] is filter_
+ logging.getLogger().filters = []
+
+ def test_config_filter_works(self):
+ filter_ = logging.Filter("spam.eggs")
+ self.apply_config({
+ "version": 1, "root": {"level": "DEBUG", "filters": [filter_]}
+ })
+ assert logging.getLogger().filters[0] is filter_
+ logging.getLogger().filters = []
+
+ def test_config_filter_method_works(self):
+ class FakeFilter:
+ def filter(self, _):
+ return 1
+ filter_ = FakeFilter()
+ self.apply_config({
+ "version": 1, "root": {"level": "DEBUG", "filters": [filter_]}
+ })
+ assert logging.getLogger().filters[0] is filter_
+ logging.getLogger().filters = []
+
+ def test_invalid_type_raises(self):
+ class NotAFilter: pass
+ for filter_ in [None, 1, NotAFilter()]:
+ self.assertRaises(
+ ValueError,
+ self.apply_config,
+ {"version": 1, "root": {"level": "DEBUG", "filters": [filter_]}}
+ )
+
+
class ManagerTest(BaseTest):
def test_manager_loggerclass(self):
logged = []
diff --git a/Misc/NEWS.d/next/Library/2022-01-21-18-19-45.bpo-41906.YBaquj.rst b/Misc/NEWS.d/next/Library/2022-01-21-18-19-45.bpo-41906.YBaquj.rst
new file mode 100644
index 0000000000000..be707130875f2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-01-21-18-19-45.bpo-41906.YBaquj.rst
@@ -0,0 +1,2 @@
+Support passing filter instances in the ``filters`` values of ``handlers`` and
+``loggers`` in the dictionary passed to :func:`logging.config.dictConfig`.
More information about the Python-checkins
mailing list