]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-41906: Accept built filters in dictConfig (GH-30756)
authorMario Corchero <mcorcherojim@bloomberg.net>
Mon, 24 Jan 2022 12:39:50 +0000 (13:39 +0100)
committerGitHub <noreply@github.com>
Mon, 24 Jan 2022 12:39:50 +0000 (04:39 -0800)
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
Doc/library/logging.config.rst
Lib/logging/config.py
Lib/test/test_logging.py
Misc/NEWS.d/next/Library/2022-01-21-18-19-45.bpo-41906.YBaquj.rst [new file with mode: 0644]

index a1b8dc755ba6b0aacffc7b69862d81d500948a39..c979961a221c9a7d75824984598367949b25d5fe 100644 (file)
@@ -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:
 
index 9bc07eddd76b4484316a4ee4c25e040221adbff6..86a1e4eaf4cbc93bf1248b0d4f0596c52421ddcf 100644 (file)
@@ -694,7 +694,11 @@ class DictConfigurator(BaseConfigurator):
         """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
 
index 7c38676012babc391ab1e6ebd1033b40be119f9e..4f3315161cf20fcf056a622bf2a2c5a46a00431d 100644 (file)
@@ -3447,6 +3447,44 @@ class ConfigDictTest(BaseTest):
             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 (file)
index 0000000..be70713
--- /dev/null
@@ -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`.