Skip to content

Commit f68adec

Browse files
committed
Keep logging.handlers eager in config.py
Reverts the lazy alias and the nine logging_handlers.* renames that came with it. The alias left "handlers" out of vars(logging), which broke the documented handlers.X spelling in fileConfig() config files, and it was worth only 0.68 ms of the 6.1 ms win on importing logging.config. Also drop the two comments that no longer carry their weight, so the io and ssl hunks disappear from the diff, and trim the new tests.
1 parent c42e9d7 commit f68adec

3 files changed

Lines changed: 33 additions & 55 deletions

File tree

‎Lib/logging/config.py‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import functools
2929
import io
3030
import logging
31+
import logging.handlers
3132
import os
3233
import re
3334
import threading
@@ -39,7 +40,6 @@
3940
lazy import socket
4041
lazy import struct
4142
lazy from bisect import bisect_left
42-
lazy from logging import handlers as logging_handlers
4343
lazy from socketserver import StreamRequestHandler, ThreadingTCPServer
4444

4545

@@ -82,9 +82,6 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non
8282
except configparser.ParsingError as e:
8383
raise RuntimeError(f'{fname} is invalid: {e}')
8484

85-
# the eval()s below resolve "handlers.X" names against vars(logging)
86-
_ = logging_handlers
87-
8885
formatters = _create_formatters(cp)
8986

9087
# critical section
@@ -170,7 +167,7 @@ def _install_handlers(cp, formatters):
170167
h.setLevel(level)
171168
if len(fmt):
172169
h.setFormatter(formatters[fmt])
173-
if issubclass(klass, logging_handlers.MemoryHandler):
170+
if issubclass(klass, logging.handlers.MemoryHandler):
174171
target = section.get("target", "")
175172
if len(target): #the target handler may not be loaded yet, so keep for later...
176173
fixups.append((h, target))
@@ -764,7 +761,7 @@ def _configure_queue_handler(self, klass, **kwargs):
764761
q = queue.Queue() # unbounded
765762

766763
rhl = kwargs.pop('respect_handler_level', False)
767-
lklass = kwargs.pop('listener', logging_handlers.QueueListener)
764+
lklass = kwargs.pop('listener', logging.handlers.QueueListener)
768765
handlers = kwargs.pop('handlers', [])
769766

770767
listener = lklass(q, *handlers, respect_handler_level=rhl)
@@ -795,7 +792,7 @@ def configure_handler(self, config):
795792
klass = cname
796793
else:
797794
klass = self.resolve(cname)
798-
if issubclass(klass, logging_handlers.MemoryHandler):
795+
if issubclass(klass, logging.handlers.MemoryHandler):
799796
if 'flushLevel' in config:
800797
config['flushLevel'] = logging._checkLevel(config['flushLevel'])
801798
if 'target' in config:
@@ -809,7 +806,7 @@ def configure_handler(self, config):
809806
config['target'] = th
810807
except Exception as e:
811808
raise ValueError('Unable to set target handler %r' % tn) from e
812-
elif issubclass(klass, logging_handlers.QueueHandler):
809+
elif issubclass(klass, logging.handlers.QueueHandler):
813810
# Another special case for handler which refers to other handlers
814811
# if 'handlers' not in config:
815812
# raise ValueError('No handlers specified for a QueueHandler')
@@ -831,13 +828,13 @@ def configure_handler(self, config):
831828
if 'listener' in config:
832829
lspec = config['listener']
833830
if isinstance(lspec, type):
834-
if not issubclass(lspec, logging_handlers.QueueListener):
831+
if not issubclass(lspec, logging.handlers.QueueListener):
835832
raise TypeError('Invalid listener specifier %r' % lspec)
836833
else:
837834
if isinstance(lspec, str):
838835
listener = self.resolve(lspec)
839836
if isinstance(listener, type) and\
840-
not issubclass(listener, logging_handlers.QueueListener):
837+
not issubclass(listener, logging.handlers.QueueListener):
841838
raise TypeError('Invalid listener specifier %r' % lspec)
842839
elif isinstance(lspec, dict):
843840
if '()' not in lspec:
@@ -861,13 +858,13 @@ def configure_handler(self, config):
861858
except Exception as e:
862859
raise ValueError('Unable to set required handler %r' % hn) from e
863860
config['handlers'] = hlist
864-
elif issubclass(klass, logging_handlers.SMTPHandler) and\
861+
elif issubclass(klass, logging.handlers.SMTPHandler) and\
865862
'mailhost' in config:
866863
config['mailhost'] = self.as_tuple(config['mailhost'])
867-
elif issubclass(klass, logging_handlers.SysLogHandler) and\
864+
elif issubclass(klass, logging.handlers.SysLogHandler) and\
868865
'address' in config:
869866
config['address'] = self.as_tuple(config['address'])
870-
if issubclass(klass, logging_handlers.QueueHandler):
867+
if issubclass(klass, logging.handlers.QueueHandler):
871868
factory = functools.partial(self._configure_queue_handler, klass)
872869
else:
873870
factory = klass

‎Lib/logging/handlers.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
To use, simply 'import logging.handlers' and log away!
2424
"""
2525

26-
import io # must stay eager to support finalization
26+
import io
2727
import logging
2828
import os
2929
import re
@@ -1133,7 +1133,7 @@ def emit(self, record):
11331133
msg.set_content(self.format(record))
11341134
if self.username:
11351135
if self.secure is not None:
1136-
import ssl # not lazy: breaks getmembers() without _ssl
1136+
import ssl
11371137

11381138
try:
11391139
keyfile = self.secure[0]

‎Lib/test/test_logging.py‎

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,40 +1865,31 @@ def test_defaults_do_no_interpolation(self):
18651865
finally:
18661866
os.unlink(fn)
18671867

1868-
def test_names_from_handlers_module(self):
1869-
# gh-156777: "handlers.X" is evaluated against vars(logging). Use a
1870-
# subprocess: importing this module already imports logging.handlers.
1871-
ini = textwrap.dedent("""
1868+
def test_class_from_handlers_module(self):
1869+
# gh-156777: "class=handlers.X" is evaluated against vars(logging).
1870+
# Use a subprocess: this module already imports logging.handlers.
1871+
ini = textwrap.dedent("""\
18721872
[loggers]
18731873
keys=root
1874-
18751874
[handlers]
18761875
keys=hand1
1877-
18781876
[formatters]
1879-
keys=form1
1880-
1877+
keys=
18811878
[logger_root]
18821879
handlers=hand1
1883-
18841880
[handler_hand1]
18851881
class=handlers.MemoryHandler
1886-
formatter=form1
18871882
args=(10,)
1888-
1889-
[formatter_form1]
1890-
format=%(levelname)s ++ %(message)s ++ %(port)s
1891-
defaults={'port': handlers.DEFAULT_TCP_LOGGING_PORT}
1892-
""").strip()
1883+
""")
18931884
fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini')
18941885
self.addCleanup(os.unlink, fn)
18951886
os.write(fd, ini.encode('ascii'))
18961887
os.close(fd)
18971888
code = textwrap.dedent(f"""
18981889
import logging, logging.config
18991890
logging.config.fileConfig({fn!r}, encoding="utf-8")
1900-
h = logging.getLogger().handlers[0]
1901-
assert isinstance(h, logging.handlers.MemoryHandler), h
1891+
assert isinstance(logging.getLogger().handlers[0],
1892+
logging.handlers.MemoryHandler)
19021893
""")
19031894
assert_python_ok("-c", code)
19041895

@@ -5478,30 +5469,25 @@ def test_socket_handler_at_shutdown(self):
54785469
# gh-156777: SocketHandler pickles the record before sending it, and
54795470
# that must keep working when importing no longer can.
54805471
code = textwrap.dedent("""
5481-
import logging
5482-
import logging.handlers
5483-
import os
5472+
import logging, logging.handlers, os
54845473
54855474
class Handler(logging.handlers.SocketHandler):
5486-
# report what emit() did instead of doing network I/O
54875475
def send(self, s):
5488-
os.write(1, b"sent %d bytes" % len(s))
5489-
5476+
os.write(1, b"sent")
54905477
def handleError(self, record):
5491-
os.write(1, b"record dropped")
5478+
os.write(1, b"dropped")
54925479
5493-
h = Handler('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
5480+
h = Handler('localhost', 9020)
54945481
r = logging.LogRecord('n', logging.INFO, 'p', 1, 'msg', None, None)
54955482
54965483
class A:
5497-
# the module globals are already cleared when __del__ runs
5498-
def __del__(self, h=h, r=r):
5484+
def __del__(self, h=h, r=r): # globals are cleared by now
54995485
h.emit(r)
55005486
55015487
a = A()
55025488
""")
55035489
rc, out, err = assert_python_ok("-c", code)
5504-
self.assertStartsWith(out.decode(), "sent ")
5490+
self.assertEqual(out, b"sent")
55055491

55065492
def test_recursion_error(self):
55075493
# Issue 36272
@@ -7609,8 +7595,8 @@ class LazyImportTest(unittest.TestCase):
76097595
def test_lazy_imports_config(self):
76107596
import_helper.ensure_lazy_imports(
76117597
"logging.config",
7612-
{"configparser", "json", "logging.handlers", "multiprocessing",
7613-
"select", "socket", "socketserver", "struct"},
7598+
{"configparser", "json", "multiprocessing", "select", "socket",
7599+
"socketserver", "struct"},
76147600
additional_code="logging.config.dictConfig({'version': 1})\n",
76157601
)
76167602

@@ -7622,25 +7608,20 @@ def test_lazy_imports_handlers(self):
76227608
)
76237609

76247610
def test_socket_handler_resolves_imports_when_created(self):
7625-
# gh-156777: emit() may run during finalization, when importing no
7626-
# longer works, so the handler resolves what it needs up front.
7611+
# gh-156777: emit() may run when importing no longer works
76277612
code = textwrap.dedent("""
7628-
import sys
7629-
import logging.handlers
7613+
import sys, logging.handlers
76307614
logging.handlers.SocketHandler('localhost', 9020)
7631-
missing = {'pickle', 'socket', 'struct'} - sys.modules.keys()
7632-
assert not missing, missing
7615+
assert {'pickle', 'socket', 'struct'} <= sys.modules.keys()
76337616
""")
76347617
assert_python_ok("-S", "-c", code)
76357618

76367619
def test_getmembers_without_ssl(self):
7637-
# gh-156777: getmembers() and pydoc resolve lazy imports, so a module
7638-
# level "lazy import ssl" would break them on a build without _ssl.
7620+
# gh-156777: getmembers() resolves lazy imports, so ssl must not be one
76397621
code = textwrap.dedent("""
76407622
import sys
76417623
sys.modules['_ssl'] = None
7642-
import inspect
7643-
import logging.handlers
7624+
import inspect, logging.handlers
76447625
inspect.getmembers(logging.handlers)
76457626
""")
76467627
assert_python_ok("-c", code)

0 commit comments

Comments
 (0)