Skip to content

Commit 3d316d9

Browse files
authored
Merge branch 'main' into fix-concatenate-docs-142965
2 parents 1e78f7e + c521597 commit 3d316d9

27 files changed

+577
-129
lines changed

Doc/library/concurrent.futures.rst

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ the bytes over a shared :mod:`socket <socket>` or
308308

309309
.. note::
310310
The executor may replace uncaught exceptions from *initializer*
311-
with :class:`~concurrent.futures.interpreter.ExecutionFailed`.
311+
with :class:`~concurrent.interpreters.ExecutionFailed`.
312312

313313
Other caveats from parent :class:`ThreadPoolExecutor` apply here.
314314

@@ -320,11 +320,11 @@ likewise serializes the return value when sending it back.
320320
When a worker's current task raises an uncaught exception, the worker
321321
always tries to preserve the exception as-is. If that is successful
322322
then it also sets the ``__cause__`` to a corresponding
323-
:class:`~concurrent.futures.interpreter.ExecutionFailed`
323+
:class:`~concurrent.interpreters.ExecutionFailed`
324324
instance, which contains a summary of the original exception.
325325
In the uncommon case that the worker is not able to preserve the
326326
original as-is then it directly preserves the corresponding
327-
:class:`~concurrent.futures.interpreter.ExecutionFailed`
327+
:class:`~concurrent.interpreters.ExecutionFailed`
328328
instance instead.
329329

330330

@@ -379,6 +379,11 @@ in a REPL or a lambda should not be expected to work.
379379
default in absence of a *mp_context* parameter. This feature is incompatible
380380
with the "fork" start method.
381381

382+
.. note::
383+
Bugs have been reported when using the *max_tasks_per_child* feature that
384+
can result in the :class:`ProcessPoolExecutor` hanging in some
385+
circumstances. Follow its eventual resolution in :gh:`115634`.
386+
382387
.. versionchanged:: 3.3
383388
When one of the worker processes terminates abruptly, a
384389
:exc:`~concurrent.futures.process.BrokenProcessPool` error is now raised.
@@ -715,15 +720,6 @@ Exception classes
715720

716721
.. versionadded:: 3.14
717722

718-
.. exception:: ExecutionFailed
719-
720-
Raised from :class:`~concurrent.futures.InterpreterPoolExecutor` when
721-
the given initializer fails or from
722-
:meth:`~concurrent.futures.Executor.submit` when there's an uncaught
723-
exception from the submitted task.
724-
725-
.. versionadded:: 3.14
726-
727723
.. currentmodule:: concurrent.futures.process
728724

729725
.. exception:: BrokenProcessPool

Doc/library/socket.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,10 +1072,16 @@ The :mod:`socket` module also offers various network-related services:
10721072
a string representing the canonical name of the *host* if
10731073
:const:`AI_CANONNAME` is part of the *flags* argument; else *canonname*
10741074
will be empty. *sockaddr* is a tuple describing a socket address, whose
1075-
format depends on the returned *family* (a ``(address, port)`` 2-tuple for
1076-
:const:`AF_INET`, a ``(address, port, flowinfo, scope_id)`` 4-tuple for
1077-
:const:`AF_INET6`), and is meant to be passed to the :meth:`socket.connect`
1078-
method.
1075+
format depends on the returned *family* and flags Python was compiled with,
1076+
and is meant to be passed to the :meth:`socket.connect` method.
1077+
1078+
*sockaddr* can be one of the following:
1079+
1080+
* a ``(address, port)`` 2-tuple for :const:`AF_INET`
1081+
* a ``(address, port, flowinfo, scope_id)`` 4-tuple for :const:`AF_INET6` if
1082+
Python was compiled with ``--enable-ipv6`` (the default)
1083+
* a 2-tuple containing raw data for :const:`AF_INET6` if Python was
1084+
compiled with ``--disable-ipv6``
10791085

10801086
.. note::
10811087

Doc/library/textwrap.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ functions should be good enough; otherwise, you should use an instance of
102102
print(repr(s)) # prints ' hello\n world\n '
103103
print(repr(dedent(s))) # prints 'hello\n world\n'
104104

105+
.. versionchanged:: 3.14
106+
The :func:`!dedent` function now correctly normalizes blank lines containing
107+
only whitespace characters. Previously, the implementation only normalized
108+
blank lines containing tabs and spaces.
105109

106110
.. function:: indent(text, prefix, predicate=None)
107111

Doc/reference/import.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,7 @@ entirely with a custom meta path hook.
832832

833833
If it is acceptable to only alter the behaviour of import statements
834834
without affecting other APIs that access the import system, then replacing
835-
the builtin :func:`__import__` function may be sufficient. This technique
836-
may also be employed at the module level to only alter the behaviour of
837-
import statements within that module.
835+
the builtin :func:`__import__` function may be sufficient.
838836

839837
To selectively prevent the import of some modules from a hook early on the
840838
meta path (rather than disabling the standard import system entirely),

Doc/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# won't suddenly cause build failures. Updating the version is fine as long
88
# as no warnings are raised by doing so.
99
# Keep this version in sync with ``Doc/conf.py``.
10-
sphinx~=9.0.0
10+
sphinx<9.0.0
1111

1212
blurb
1313

Doc/tools/extensions/lexers/asdl_lexer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ASDLLexer(RegexLexer):
2222
bygroups(Keyword, Text, Name.Tag),
2323
),
2424
(
25-
r"(\w+)(\*\s|\?\s|\s)(\w+)",
25+
r"(\w+)([\?\*]*\s)(\w+)",
2626
bygroups(Name.Builtin.Pseudo, Operator, Name),
2727
),
2828
# Keep in line with ``builtin_types`` from Parser/asdl.py.

Doc/whatsnew/3.14.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,15 @@ pdb
22652265
(Contributed by Tian Gao in :gh:`124533`.)
22662266

22672267

2268+
textwrap
2269+
--------
2270+
2271+
* Optimize the :func:`~textwrap.dedent` function, improving performance by
2272+
an average of 2.4x, with larger improvements for bigger inputs,
2273+
and fix a bug with incomplete normalization of blank lines with whitespace
2274+
characters other than space and tab.
2275+
2276+
22682277
uuid
22692278
----
22702279

Lib/difflib.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -638,15 +638,15 @@ def quick_ratio(self):
638638
# avail[x] is the number of times x appears in 'b' less the
639639
# number of times we've seen it in 'a' so far ... kinda
640640
avail = {}
641-
availhas, matches = avail.__contains__, 0
641+
matches = 0
642642
for elt in self.a:
643-
if availhas(elt):
643+
if elt in avail:
644644
numb = avail[elt]
645645
else:
646646
numb = fullbcount.get(elt, 0)
647647
avail[elt] = numb - 1
648648
if numb > 0:
649-
matches = matches + 1
649+
matches += 1
650650
return _calculate_ratio(matches, len(self.a) + len(self.b))
651651

652652
def real_quick_ratio(self):
@@ -702,10 +702,12 @@ def get_close_matches(word, possibilities, n=3, cutoff=0.6):
702702
s.set_seq2(word)
703703
for x in possibilities:
704704
s.set_seq1(x)
705-
if s.real_quick_ratio() >= cutoff and \
706-
s.quick_ratio() >= cutoff and \
707-
s.ratio() >= cutoff:
708-
result.append((s.ratio(), x))
705+
if s.real_quick_ratio() < cutoff or s.quick_ratio() < cutoff:
706+
continue
707+
708+
ratio = s.ratio()
709+
if ratio >= cutoff:
710+
result.append((ratio, x))
709711

710712
# Move the best scorers to head of list
711713
result = _nlargest(n, result)

Lib/logging/handlers.py

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,11 @@ def shouldRollover(self, record):
196196
if self.stream is None: # delay was set...
197197
self.stream = self._open()
198198
if self.maxBytes > 0: # are we rolling over?
199-
pos = self.stream.tell()
199+
try:
200+
pos = self.stream.tell()
201+
except io.UnsupportedOperation:
202+
# gh-143237: Never rollover a named pipe.
203+
return False
200204
if not pos:
201205
# gh-116263: Never rollover an empty file
202206
return False
@@ -1125,46 +1129,54 @@ class NTEventLogHandler(logging.Handler):
11251129
"""
11261130
A handler class which sends events to the NT Event Log. Adds a
11271131
registry entry for the specified application name. If no dllname is
1128-
provided, win32service.pyd (which contains some basic message
1132+
provided and pywin32 installed, win32service.pyd (which contains some basic message
11291133
placeholders) is used. Note that use of these placeholders will make
11301134
your event logs big, as the entire message source is held in the log.
11311135
If you want slimmer logs, you have to pass in the name of your own DLL
11321136
which contains the message definitions you want to use in the event log.
11331137
"""
11341138
def __init__(self, appname, dllname=None, logtype="Application"):
11351139
logging.Handler.__init__(self)
1136-
try:
1137-
import win32evtlogutil, win32evtlog
1138-
self.appname = appname
1139-
self._welu = win32evtlogutil
1140-
if not dllname:
1141-
dllname = os.path.split(self._welu.__file__)
1140+
import _winapi
1141+
self._winapi = _winapi
1142+
self.appname = appname
1143+
if not dllname:
1144+
# backward compatibility
1145+
try:
1146+
import win32evtlogutil
1147+
dllname = os.path.split(win32evtlogutil.__file__)
11421148
dllname = os.path.split(dllname[0])
11431149
dllname = os.path.join(dllname[0], r'win32service.pyd')
1144-
self.dllname = dllname
1145-
self.logtype = logtype
1146-
# Administrative privileges are required to add a source to the registry.
1147-
# This may not be available for a user that just wants to add to an
1148-
# existing source - handle this specific case.
1149-
try:
1150-
self._welu.AddSourceToRegistry(appname, dllname, logtype)
1151-
except Exception as e:
1152-
# This will probably be a pywintypes.error. Only raise if it's not
1153-
# an "access denied" error, else let it pass
1154-
if getattr(e, 'winerror', None) != 5: # not access denied
1155-
raise
1156-
self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
1157-
self.typemap = {
1158-
logging.DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE,
1159-
logging.INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE,
1160-
logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
1161-
logging.ERROR : win32evtlog.EVENTLOG_ERROR_TYPE,
1162-
logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
1163-
}
1164-
except ImportError:
1165-
print("The Python Win32 extensions for NT (service, event "\
1166-
"logging) appear not to be available.")
1167-
self._welu = None
1150+
except ImportError:
1151+
pass
1152+
self.dllname = dllname
1153+
self.logtype = logtype
1154+
# Administrative privileges are required to add a source to the registry.
1155+
# This may not be available for a user that just wants to add to an
1156+
# existing source - handle this specific case.
1157+
try:
1158+
self._add_source_to_registry(appname, dllname, logtype)
1159+
except PermissionError:
1160+
pass
1161+
self.deftype = _winapi.EVENTLOG_ERROR_TYPE
1162+
self.typemap = {
1163+
logging.DEBUG: _winapi.EVENTLOG_INFORMATION_TYPE,
1164+
logging.INFO: _winapi.EVENTLOG_INFORMATION_TYPE,
1165+
logging.WARNING: _winapi.EVENTLOG_WARNING_TYPE,
1166+
logging.ERROR: _winapi.EVENTLOG_ERROR_TYPE,
1167+
logging.CRITICAL: _winapi.EVENTLOG_ERROR_TYPE,
1168+
}
1169+
1170+
@staticmethod
1171+
def _add_source_to_registry(appname, dllname, logtype):
1172+
import winreg
1173+
1174+
key_path = f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{logtype}\\{appname}"
1175+
1176+
with winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, key_path) as key:
1177+
if dllname:
1178+
winreg.SetValueEx(key, "EventMessageFile", 0, winreg.REG_EXPAND_SZ, dllname)
1179+
winreg.SetValueEx(key, "TypesSupported", 0, winreg.REG_DWORD, 7) # All types are supported
11681180

11691181
def getMessageID(self, record):
11701182
"""
@@ -1205,15 +1217,20 @@ def emit(self, record):
12051217
Determine the message ID, event category and event type. Then
12061218
log the message in the NT event log.
12071219
"""
1208-
if self._welu:
1220+
try:
1221+
id = self.getMessageID(record)
1222+
cat = self.getEventCategory(record)
1223+
type = self.getEventType(record)
1224+
msg = self.format(record)
1225+
1226+
# Get a handle to the event log
1227+
handle = self._winapi.RegisterEventSource(None, self.appname)
12091228
try:
1210-
id = self.getMessageID(record)
1211-
cat = self.getEventCategory(record)
1212-
type = self.getEventType(record)
1213-
msg = self.format(record)
1214-
self._welu.ReportEvent(self.appname, id, cat, type, [msg])
1215-
except Exception:
1216-
self.handleError(record)
1229+
self._winapi.ReportEvent(handle, type, cat, id, msg)
1230+
finally:
1231+
self._winapi.DeregisterEventSource(handle)
1232+
except Exception:
1233+
self.handleError(record)
12171234

12181235
def close(self):
12191236
"""

Lib/test/test_capi/test_opt.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ def iter_opnames(ex):
6060
def get_opnames(ex):
6161
return list(iter_opnames(ex))
6262

63+
def iter_ops(ex):
64+
for item in ex:
65+
yield item
66+
67+
def get_ops(ex):
68+
return list(iter_ops(ex))
69+
6370

6471
@requires_specialization
6572
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
@@ -3003,14 +3010,25 @@ def f():
30033010
# Outer loop warms up later, linking to the inner one.
30043011
# Therefore, we have at least two executors.
30053012
self.assertGreaterEqual(len(all_executors), 2)
3013+
executor_ids = [id(e) for e in all_executors]
30063014
for executor in all_executors:
3007-
opnames = list(get_opnames(executor))
3015+
ops = get_ops(executor)
30083016
# Assert all executors first terminator ends in
30093017
# _EXIT_TRACE or _JUMP_TO_TOP, not _DEOPT
3010-
for idx, op in enumerate(opnames):
3011-
if op == "_EXIT_TRACE" or op == "_JUMP_TO_TOP":
3018+
for idx, op in enumerate(ops):
3019+
opname = op[0]
3020+
if opname == "_EXIT_TRACE":
3021+
# As this is a link outer executor to inner
3022+
# executor problem, all executors exits should point to
3023+
# another valid executor. In this case, none of them
3024+
# should be the cold executor.
3025+
exit = op[3]
3026+
link_to = _testinternalcapi.get_exit_executor(exit)
3027+
self.assertIn(id(link_to), executor_ids)
3028+
break
3029+
elif opname == "_JUMP_TO_TOP":
30123030
break
3013-
elif op == "_DEOPT":
3031+
elif opname == "_DEOPT":
30143032
self.fail(f"_DEOPT encountered first at executor"
30153033
f" {executor} at offset {idx} rather"
30163034
f" than expected _EXIT_TRACE")

0 commit comments

Comments
 (0)