Skip to content

Commit

Permalink
update to python 3.12.3
Browse files Browse the repository at this point in the history
  • Loading branch information
chcg committed Apr 9, 2024
1 parent 6851859 commit 11774d6
Show file tree
Hide file tree
Showing 122 changed files with 1,654 additions and 1,203 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/CI_build.yml
Expand Up @@ -43,8 +43,8 @@ jobs:
if: matrix.build_configuration == 'Release'
working-directory: installer
run: |
$env:PYTHONBUILDDIR_X64='..\packages\python.3.12.2\tools'
$env:PYTHONBUILDDIR='..\packages\pythonx86.3.12.2\tools'
$env:PYTHONBUILDDIR_X64='..\packages\python.3.12.3\tools'
$env:PYTHONBUILDDIR='..\packages\pythonx86.3.12.3\tools'
Rename-Item -Path ".\buildPaths.bat.orig" -NewName "buildPaths.bat"
$env:WIX_PATH="C:\Program Files (x86)\WiX Toolset v3.11\bin"
$env:PATH = $env:PATH + ';' + $env:WIX_PATH
Expand Down
3 changes: 2 additions & 1 deletion PythonLib/full/_pyio.py
Expand Up @@ -1209,7 +1209,8 @@ def _readinto(self, buf, read1):
return written

def tell(self):
return _BufferedIOMixin.tell(self) - len(self._read_buf) + self._read_pos
# GH-95782: Keep return value non-negative
return max(_BufferedIOMixin.tell(self) - len(self._read_buf) + self._read_pos, 0)

def seek(self, pos, whence=0):
if whence not in valid_seek_flags:
Expand Down
62 changes: 36 additions & 26 deletions PythonLib/full/argparse.py
Expand Up @@ -225,7 +225,8 @@ def format_help(self):
# add the heading if the section was non-empty
if self.heading is not SUPPRESS and self.heading is not None:
current_indent = self.formatter._current_indent
heading = '%*s%s:\n' % (current_indent, '', self.heading)
heading_text = _('%(heading)s:') % dict(heading=self.heading)
heading = '%*s%s\n' % (current_indent, '', heading_text)
else:
heading = ''

Expand Down Expand Up @@ -415,6 +416,8 @@ def _format_actions_usage(self, actions, groups):
suppressed_actions_count += 1

exposed_actions_count = group_action_count - suppressed_actions_count
if not exposed_actions_count:
continue

if not group.required:
if start in inserts:
Expand Down Expand Up @@ -720,7 +723,7 @@ def _get_help_string(self, action):
if action.default is not SUPPRESS:
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
if action.option_strings or action.nargs in defaulting_nargs:
help += ' (default: %(default)s)'
help += _(' (default: %(default)s)')
return help


Expand Down Expand Up @@ -1149,7 +1152,9 @@ def __init__(self,
version=None,
dest=SUPPRESS,
default=SUPPRESS,
help="show program's version number and exit"):
help=None):
if help is None:
help = _("show program's version number and exit")
super(_VersionAction, self).__init__(
option_strings=option_strings,
dest=dest,
Expand Down Expand Up @@ -2004,7 +2009,7 @@ def consume_optional(start_index):

# get the optional identified at this index
option_tuple = option_string_indices[start_index]
action, option_string, explicit_arg = option_tuple
action, option_string, sep, explicit_arg = option_tuple

# identify additional optionals in the same arg string
# (e.g. -xyz is the same as -x -y -z if no args are required)
Expand All @@ -2031,18 +2036,27 @@ def consume_optional(start_index):
and option_string[1] not in chars
and explicit_arg != ''
):
if sep or explicit_arg[0] in chars:
msg = _('ignored explicit argument %r')
raise ArgumentError(action, msg % explicit_arg)
action_tuples.append((action, [], option_string))
char = option_string[0]
option_string = char + explicit_arg[0]
new_explicit_arg = explicit_arg[1:] or None
optionals_map = self._option_string_actions
if option_string in optionals_map:
action = optionals_map[option_string]
explicit_arg = new_explicit_arg
explicit_arg = explicit_arg[1:]
if not explicit_arg:
sep = explicit_arg = None
elif explicit_arg[0] == '=':
sep = '='
explicit_arg = explicit_arg[1:]
else:
sep = ''
else:
msg = _('ignored explicit argument %r')
raise ArgumentError(action, msg % explicit_arg)

extras.append(char + explicit_arg)
stop = start_index + 1
break
# if the action expect exactly one argument, we've
# successfully matched the option; exit the loop
elif arg_count == 1:
Expand Down Expand Up @@ -2262,18 +2276,17 @@ def _parse_optional(self, arg_string):
# if the option string is present in the parser, return the action
if arg_string in self._option_string_actions:
action = self._option_string_actions[arg_string]
return action, arg_string, None
return action, arg_string, None, None

# if it's just a single character, it was meant to be positional
if len(arg_string) == 1:
return None

# if the option string before the "=" is present, return the action
if '=' in arg_string:
option_string, explicit_arg = arg_string.split('=', 1)
if option_string in self._option_string_actions:
action = self._option_string_actions[option_string]
return action, option_string, explicit_arg
option_string, sep, explicit_arg = arg_string.partition('=')
if sep and option_string in self._option_string_actions:
action = self._option_string_actions[option_string]
return action, option_string, sep, explicit_arg

# search through all possible prefixes of the option string
# and all actions in the parser for possible interpretations
Expand All @@ -2282,7 +2295,7 @@ def _parse_optional(self, arg_string):
# if multiple actions match, the option string was ambiguous
if len(option_tuples) > 1:
options = ', '.join([option_string
for action, option_string, explicit_arg in option_tuples])
for action, option_string, sep, explicit_arg in option_tuples])
args = {'option': arg_string, 'matches': options}
msg = _('ambiguous option: %(option)s could match %(matches)s')
self.error(msg % args)
Expand All @@ -2306,7 +2319,7 @@ def _parse_optional(self, arg_string):

# it was meant to be an optional but there is no such option
# in this parser (though it might be a valid option in a subparser)
return None, arg_string, None
return None, arg_string, None, None

def _get_option_tuples(self, option_string):
result = []
Expand All @@ -2316,34 +2329,31 @@ def _get_option_tuples(self, option_string):
chars = self.prefix_chars
if option_string[0] in chars and option_string[1] in chars:
if self.allow_abbrev:
if '=' in option_string:
option_prefix, explicit_arg = option_string.split('=', 1)
else:
option_prefix = option_string
explicit_arg = None
option_prefix, sep, explicit_arg = option_string.partition('=')
if not sep:
sep = explicit_arg = None
for option_string in self._option_string_actions:
if option_string.startswith(option_prefix):
action = self._option_string_actions[option_string]
tup = action, option_string, explicit_arg
tup = action, option_string, sep, explicit_arg
result.append(tup)

# single character options can be concatenated with their arguments
# but multiple character options always have to have their argument
# separate
elif option_string[0] in chars and option_string[1] not in chars:
option_prefix = option_string
explicit_arg = None
short_option_prefix = option_string[:2]
short_explicit_arg = option_string[2:]

for option_string in self._option_string_actions:
if option_string == short_option_prefix:
action = self._option_string_actions[option_string]
tup = action, option_string, short_explicit_arg
tup = action, option_string, '', short_explicit_arg
result.append(tup)
elif option_string.startswith(option_prefix):
action = self._option_string_actions[option_string]
tup = action, option_string, explicit_arg
tup = action, option_string, None, None
result.append(tup)

# shouldn't ever get here
Expand Down
15 changes: 8 additions & 7 deletions PythonLib/full/ast.py
Expand Up @@ -1268,14 +1268,18 @@ def visit_JoinedStr(self, node):
quote_type = quote_types[0]
self.write(f"{quote_type}{value}{quote_type}")

def _write_fstring_inner(self, node, scape_newlines=False):
def _write_fstring_inner(self, node, is_format_spec=False):
if isinstance(node, JoinedStr):
# for both the f-string itself, and format_spec
for value in node.values:
self._write_fstring_inner(value, scape_newlines=scape_newlines)
self._write_fstring_inner(value, is_format_spec=is_format_spec)
elif isinstance(node, Constant) and isinstance(node.value, str):
value = node.value.replace("{", "{{").replace("}", "}}")
if scape_newlines:

if is_format_spec:
value = value.replace("\\", "\\\\")
value = value.replace("'", "\\'")
value = value.replace('"', '\\"')
value = value.replace("\n", "\\n")
self.write(value)
elif isinstance(node, FormattedValue):
Expand All @@ -1299,10 +1303,7 @@ def unparse_inner(inner):
self.write(f"!{chr(node.conversion)}")
if node.format_spec:
self.write(":")
self._write_fstring_inner(
node.format_spec,
scape_newlines=True
)
self._write_fstring_inner(node.format_spec, is_format_spec=True)

def visit_Name(self, node):
self.write(node.id)
Expand Down
20 changes: 11 additions & 9 deletions PythonLib/full/asyncio/base_events.py
Expand Up @@ -45,6 +45,7 @@
from . import sslproto
from . import staggered
from . import tasks
from . import timeouts
from . import transports
from . import trsock
from .log import logger
Expand Down Expand Up @@ -596,23 +597,24 @@ async def shutdown_default_executor(self, timeout=None):
thread = threading.Thread(target=self._do_shutdown, args=(future,))
thread.start()
try:
await future
finally:
thread.join(timeout)

if thread.is_alive():
async with timeouts.timeout(timeout):
await future
except TimeoutError:
warnings.warn("The executor did not finishing joining "
f"its threads within {timeout} seconds.",
RuntimeWarning, stacklevel=2)
f"its threads within {timeout} seconds.",
RuntimeWarning, stacklevel=2)
self._default_executor.shutdown(wait=False)
else:
thread.join()

def _do_shutdown(self, future):
try:
self._default_executor.shutdown(wait=True)
if not self.is_closed():
self.call_soon_threadsafe(future.set_result, None)
self.call_soon_threadsafe(futures._set_result_unless_cancelled,
future, None)
except Exception as ex:
if not self.is_closed():
if not self.is_closed() and not future.cancelled():
self.call_soon_threadsafe(future.set_exception, ex)

def _check_running(self):
Expand Down
2 changes: 1 addition & 1 deletion PythonLib/full/asyncio/tasks.py
Expand Up @@ -480,7 +480,7 @@ async def wait_for(fut, timeout):
If the wait is cancelled, the task is also cancelled.
If the task supresses the cancellation and returns a value instead,
If the task suppresses the cancellation and returns a value instead,
that value is returned.
This function is a coroutine.
Expand Down
43 changes: 24 additions & 19 deletions PythonLib/full/asyncio/windows_events.py
Expand Up @@ -8,6 +8,7 @@
import _overlapped
import _winapi
import errno
from functools import partial
import math
import msvcrt
import socket
Expand Down Expand Up @@ -323,13 +324,13 @@ def run_forever(self):
if self._self_reading_future is not None:
ov = self._self_reading_future._ov
self._self_reading_future.cancel()
# self_reading_future was just cancelled so if it hasn't been
# finished yet, it never will be (it's possible that it has
# already finished and its callback is waiting in the queue,
# where it could still happen if the event loop is restarted).
# Unregister it otherwise IocpProactor.close will wait for it
# forever
if ov is not None:
# self_reading_future always uses IOCP, so even though it's
# been cancelled, we need to make sure that the IOCP message
# is received so that the kernel is not holding on to the
# memory, possibly causing memory corruption later. Only
# unregister it if IO is complete in all respects. Otherwise
# we need another _poll() later to complete the IO.
if ov is not None and not ov.pending:
self._proactor._unregister(ov)
self._self_reading_future = None

Expand Down Expand Up @@ -466,6 +467,18 @@ def finish_socket_func(trans, key, ov):
else:
raise

@classmethod
def _finish_recvfrom(cls, trans, key, ov, *, empty_result):
try:
return cls.finish_socket_func(trans, key, ov)
except OSError as exc:
# WSARecvFrom will report ERROR_PORT_UNREACHABLE when the same
# socket is used to send to an address that is not listening.
if exc.winerror == _overlapped.ERROR_PORT_UNREACHABLE:
return empty_result, None
else:
raise

def recv(self, conn, nbytes, flags=0):
self._register_with_iocp(conn)
ov = _overlapped.Overlapped(NULL)
Expand Down Expand Up @@ -500,7 +513,8 @@ def recvfrom(self, conn, nbytes, flags=0):
except BrokenPipeError:
return self._result((b'', None))

return self._register(ov, conn, self.finish_socket_func)
return self._register(ov, conn, partial(self._finish_recvfrom,
empty_result=b''))

def recvfrom_into(self, conn, buf, flags=0):
self._register_with_iocp(conn)
Expand All @@ -510,17 +524,8 @@ def recvfrom_into(self, conn, buf, flags=0):
except BrokenPipeError:
return self._result((0, None))

def finish_recv(trans, key, ov):
try:
return ov.getresult()
except OSError as exc:
if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED,
_overlapped.ERROR_OPERATION_ABORTED):
raise ConnectionResetError(*exc.args)
else:
raise

return self._register(ov, conn, finish_recv)
return self._register(ov, conn, partial(self._finish_recvfrom,
empty_result=0))

def sendto(self, conn, buf, flags=0, addr=None):
self._register_with_iocp(conn)
Expand Down
5 changes: 3 additions & 2 deletions PythonLib/full/collections/__init__.py
Expand Up @@ -638,7 +638,8 @@ def elements(self):
>>> sorted(c.elements())
['A', 'A', 'B', 'B', 'C', 'C']
# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
>>> import math
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
>>> math.prod(prime_factors.elements())
Expand Down Expand Up @@ -679,7 +680,7 @@ def update(self, iterable=None, /, **kwds):
'''
# The regular dict.update() operation makes no sense here because the
# replace behavior results in the some of original untouched counts
# replace behavior results in some of the original untouched counts
# being mixed-in with all of the other counts for a mismash that
# doesn't have a straight-forward interpretation in most counting
# contexts. Instead, we implement straight-addition. Both the inputs
Expand Down

0 comments on commit 11774d6

Please sign in to comment.