diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 4477a82777877d..6c6f3b71562e11 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1580,6 +1580,11 @@ Deprecated or *sequence* as keyword arguments is now deprecated. (Contributed by Kirill Podoprigora in :gh:`121676`.) +* :mod:`logging`: + Support for custom logging handlers with the *strm* argument is deprecated + and scheduled for removal in Python 3.16. Define handlers with the *stream* + argument instead. (Contributed by Mariusz Felisiak in :gh:`115032`.) + * :mod:`!nturl2path`: This module is now deprecated. Call :func:`urllib.request.url2pathname` and :func:`~urllib.request.pathname2url` instead. diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 6a6a7f726f7e0c..c994349fd6eee5 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -865,6 +865,8 @@ def configure_handler(self, config): else: factory = klass kwargs = {k: config[k] for k in config if (k != '.' and valid_ident(k))} + # When deprecation ends for using the 'strm' parameter, remove the + # "except TypeError ..." try: result = factory(**kwargs) except TypeError as te: @@ -876,6 +878,15 @@ def configure_handler(self, config): #(e.g. by Django) kwargs['strm'] = kwargs.pop('stream') result = factory(**kwargs) + + import warnings + warnings.warn( + "Support for custom logging handlers with the 'strm' argument " + "is deprecated and scheduled for removal in Python 3.16. " + "Define handlers with the 'stream' argument instead.", + DeprecationWarning, + stacklevel=2, + ) if formatter: result.setFormatter(formatter) if level is not None: diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 9305844829a500..de9108288a72f5 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3281,6 +3281,37 @@ def format(self, record): } } + # Remove when deprecation ends. + class DeprecatedStrmHandler(logging.StreamHandler): + def __init__(self, strm=None): + super().__init__(stream=strm) + + config_custom_handler_with_deprecated_strm_arg = { + "version": 1, + "formatters": { + "form1": { + "format": "%(levelname)s ++ %(message)s", + }, + }, + "handlers": { + "hand1": { + "class": DeprecatedStrmHandler, + "formatter": "form1", + "level": "NOTSET", + "stream": "ext://sys.stdout", + }, + }, + "loggers": { + "compiler.parser": { + "level": "DEBUG", + "handlers": ["hand1"], + }, + }, + "root": { + "level": "WARNING", + }, + } + def apply_config(self, conf): logging.config.dictConfig(conf) @@ -3370,6 +3401,15 @@ def test_config5_ok(self): self.test_config1_ok(config=self.config5) self.check_handler('hand1', CustomHandler) + def test_deprecation_warning_custom_handler_with_strm_arg(self): + msg = ( + "Support for custom logging handlers with the 'strm' argument " + "is deprecated and scheduled for removal in Python 3.16. " + "Define handlers with the 'stream' argument instead." + ) + with self.assertWarnsRegex(DeprecationWarning, msg): + self.test_config1_ok(config=self.config_custom_handler_with_deprecated_strm_arg) + def test_config6_failure(self): self.assertRaises(Exception, self.apply_config, self.config6) diff --git a/Misc/NEWS.d/next/Library/2025-04-26-12-25-42.gh-issue-115032.jnM2Co.rst b/Misc/NEWS.d/next/Library/2025-04-26-12-25-42.gh-issue-115032.jnM2Co.rst new file mode 100644 index 00000000000000..80c10aef06996d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-26-12-25-42.gh-issue-115032.jnM2Co.rst @@ -0,0 +1,3 @@ +Support for custom logging handlers with the *strm* argument is deprecated +and scheduled for removal in Python 3.16. Define handlers with the *stream* +argument instead. Patch by Mariusz Felisiak.