mirror of https://github.com/python/cpython.git
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
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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…
Reference in New Issue