mirror of
https://github.com/python/cpython.git
synced 2025-10-13 10:23:28 +00:00
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
This commit is contained in:
parent
58f3d98098
commit
d7c6863979
4 changed files with 55 additions and 1 deletions
|
@ -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
|
* ``filters`` (optional). A list of ids of the filters for this
|
||||||
handler.
|
handler.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
``filters`` can take filter instances in addition to ids.
|
||||||
|
|
||||||
All *other* keys are passed through as keyword arguments to the
|
All *other* keys are passed through as keyword arguments to the
|
||||||
handler's constructor. For example, given the snippet:
|
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
|
* ``filters`` (optional). A list of ids of the filters for this
|
||||||
logger.
|
logger.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.11
|
||||||
|
``filters`` can take filter instances in addition to ids.
|
||||||
|
|
||||||
* ``handlers`` (optional). A list of ids of the handlers for this
|
* ``handlers`` (optional). A list of ids of the handlers for this
|
||||||
logger.
|
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
|
the keyword arguments used in the call. The ``'()'`` also serves as a
|
||||||
mnemonic that the corresponding value is a callable.
|
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:
|
.. _logging-config-dict-externalobj:
|
||||||
|
|
||||||
|
|
|
@ -694,7 +694,11 @@ class DictConfigurator(BaseConfigurator):
|
||||||
"""Add filters to a filterer from a list of names."""
|
"""Add filters to a filterer from a list of names."""
|
||||||
for f in filters:
|
for f in filters:
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
raise ValueError('Unable to add filter %r' % f) from e
|
raise ValueError('Unable to add filter %r' % f) from e
|
||||||
|
|
||||||
|
|
|
@ -3447,6 +3447,44 @@ class ConfigDictTest(BaseTest):
|
||||||
logging.info('some log')
|
logging.info('some log')
|
||||||
self.assertEqual(stderr.getvalue(), 'some log my_type\n')
|
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):
|
class ManagerTest(BaseTest):
|
||||||
def test_manager_loggerclass(self):
|
def test_manager_loggerclass(self):
|
||||||
logged = []
|
logged = []
|
||||||
|
|
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue