Skip to content

Commit

Permalink
bpo-41906: Accept built filters in dictConfig (GH-30756)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mariocj89 authored Jan 24, 2022
1 parent 58f3d98 commit d7c6863
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Doc/library/logging.config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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:

Expand Down
6 changes: 5 additions & 1 deletion Lib/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
38 changes: 38 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit d7c6863

Please sign in to comment.