diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 62a87a71b1a3bd..b419a733116a0e 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1397,18 +1397,28 @@ def __init__(self, name, level=NOTSET): """ Filterer.__init__(self) self.name = name - self.level = _checkLevel(level) + self._level = _checkLevel(level) self.parent = None self.propagate = True self.handlers = [] self.disabled = False self._cache = {} + @property + def level(self): + return self._level + + @level.setter + def level(self, level): + warnings.warn("Use the setLevel() method to set the log level", + DeprecationWarning, stacklevel=2) + self.setLevel(level) + def setLevel(self, level): """ Set the logging level of this logger. level must be an int or a str. """ - self.level = _checkLevel(level) + self._level = _checkLevel(level) self.manager._clear_cache() def debug(self, msg, *args, **kwargs): @@ -1671,8 +1681,8 @@ def getEffectiveLevel(self): """ logger = self while logger: - if logger.level: - return logger.level + if logger._level: + return logger._level logger = logger.parent return NOTSET diff --git a/Lib/logging/config.py b/Lib/logging/config.py index cfd93116eeddbd..eb8242be25a927 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -173,9 +173,10 @@ def _handle_existing_loggers(existing, child_loggers, disable_existing): for log in existing: logger = root.manager.loggerDict[log] if log in child_loggers: - logger.level = logging.NOTSET - logger.handlers = [] - logger.propagate = True + if not isinstance(logger, logging.PlaceHolder): + logger.setLevel(logging.NOTSET) + logger.handlers = [] + logger.propagate = True else: logger.disabled = disable_existing diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index dca744c59092f4..1e38f7ecc802f1 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4315,7 +4315,7 @@ def cleanup(self): logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list - logging.root.level = self.original_logging_level + logging.root.setLevel(self.original_logging_level) def test_no_kwargs(self): logging.basicConfig() @@ -4906,6 +4906,15 @@ def test_caching(self): # Ensure logger2 uses parent logger's effective level self.assertFalse(logger2.isEnabledFor(logging.ERROR)) + # Ensure setting level directly still clears cache + self.assertEqual(logger2._cache, {logging.ERROR: False}) + with warnings.catch_warnings(record=True) as w: + logger2.level = logging.ERROR + self.assertEqual(1, len(w)) + self.assertEqual(logger2._cache, {}) + self.assertTrue(logger2.isEnabledFor(logging.ERROR)) + self.assertEqual(logger2._cache, {logging.ERROR: True}) + # Set level to NOTSET and ensure caches are empty logger2.setLevel(logging.NOTSET) self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL) diff --git a/Misc/NEWS.d/next/Library/2019-08-14-16-17-57.bpo-37857.Ganisd.rst b/Misc/NEWS.d/next/Library/2019-08-14-16-17-57.bpo-37857.Ganisd.rst new file mode 100644 index 00000000000000..f7adb956b12ff0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-08-14-16-17-57.bpo-37857.Ganisd.rst @@ -0,0 +1,2 @@ +Setting the ``level`` attribute of a ``logger.Logger`` (instead of calling +``setLevel()``) no longer causes cache inconsistency. diff --git a/Misc/NEWS.d/next/Library/2019-09-20-12-25-33.bpo-37857.s-Emp8.rst b/Misc/NEWS.d/next/Library/2019-09-20-12-25-33.bpo-37857.s-Emp8.rst new file mode 100644 index 00000000000000..c5c54f06d19c59 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-20-12-25-33.bpo-37857.s-Emp8.rst @@ -0,0 +1,2 @@ +Setting the ``level`` attribute of a ``logger.Logger`` is deprecated. The +log level should only ever be set using the ``setLevel()`` method.