summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Lib
diff options
context:
space:
mode:
authorshadchin <[email protected]>2024-12-23 19:39:02 +0300
committershadchin <[email protected]>2024-12-23 19:54:20 +0300
commit65a5bf9d37a3b29eb394f560b9a09318196c40e8 (patch)
treee5cd68fb0682b2388e52d9806bb87adc348e21a8 /contrib/tools/python3/Lib
parenta1dd87a52878ab3e46e5fd2dba5ecbba6113d7e0 (diff)
Update Python 3 to 3.12.8
commit_hash:c20045b8a987d8720e1f3328270357491d5530f3
Diffstat (limited to 'contrib/tools/python3/Lib')
-rw-r--r--contrib/tools/python3/Lib/_collections_abc.py2
-rw-r--r--contrib/tools/python3/Lib/_strptime.py183
-rw-r--r--contrib/tools/python3/Lib/argparse.py132
-rw-r--r--contrib/tools/python3/Lib/asyncio/__main__.py6
-rw-r--r--contrib/tools/python3/Lib/asyncio/base_events.py18
-rw-r--r--contrib/tools/python3/Lib/asyncio/futures.py6
-rw-r--r--contrib/tools/python3/Lib/asyncio/sslproto.py5
-rw-r--r--contrib/tools/python3/Lib/asyncio/staggered.py18
-rw-r--r--contrib/tools/python3/Lib/asyncio/taskgroups.py41
-rw-r--r--contrib/tools/python3/Lib/bdb.py5
-rw-r--r--contrib/tools/python3/Lib/calendar.py16
-rw-r--r--contrib/tools/python3/Lib/concurrent/futures/process.py52
-rw-r--r--contrib/tools/python3/Lib/concurrent/futures/thread.py1
-rw-r--r--contrib/tools/python3/Lib/email/_policybase.py4
-rw-r--r--contrib/tools/python3/Lib/email/policy.py4
-rw-r--r--contrib/tools/python3/Lib/ensurepip/__init__.py2
-rw-r--r--contrib/tools/python3/Lib/enum.py16
-rw-r--r--contrib/tools/python3/Lib/functools.py14
-rw-r--r--contrib/tools/python3/Lib/importlib/__init__.py2
-rw-r--r--contrib/tools/python3/Lib/importlib/_bootstrap_external.py6
-rw-r--r--contrib/tools/python3/Lib/inspect.py14
-rw-r--r--contrib/tools/python3/Lib/json/decoder.py9
-rw-r--r--contrib/tools/python3/Lib/json/scanner.py2
-rw-r--r--contrib/tools/python3/Lib/logging/config.py14
-rw-r--r--contrib/tools/python3/Lib/multiprocessing/connection.py2
-rw-r--r--contrib/tools/python3/Lib/multiprocessing/forkserver.py2
-rw-r--r--contrib/tools/python3/Lib/multiprocessing/managers.py33
-rw-r--r--contrib/tools/python3/Lib/multiprocessing/synchronize.py4
-rw-r--r--contrib/tools/python3/Lib/ntpath.py49
-rw-r--r--contrib/tools/python3/Lib/nturl2path.py54
-rw-r--r--contrib/tools/python3/Lib/pathlib.py4
-rwxr-xr-xcontrib/tools/python3/Lib/pdb.py5
-rw-r--r--contrib/tools/python3/Lib/pickle.py9
-rw-r--r--contrib/tools/python3/Lib/pickletools.py11
-rw-r--r--contrib/tools/python3/Lib/pydoc_data/topics.py824
-rw-r--r--contrib/tools/python3/Lib/re/_compiler.py23
-rw-r--r--contrib/tools/python3/Lib/reprlib.py31
-rw-r--r--contrib/tools/python3/Lib/shutil.py22
-rw-r--r--contrib/tools/python3/Lib/site.py5
-rw-r--r--contrib/tools/python3/Lib/sysconfig.py18
-rw-r--r--contrib/tools/python3/Lib/token.py3
-rw-r--r--contrib/tools/python3/Lib/tokenize.py2
-rw-r--r--contrib/tools/python3/Lib/typing.py3
-rw-r--r--contrib/tools/python3/Lib/unittest/async_case.py1
-rw-r--r--contrib/tools/python3/Lib/unittest/mock.py9
-rw-r--r--contrib/tools/python3/Lib/urllib/request.py19
-rw-r--r--contrib/tools/python3/Lib/venv/__init__.py42
-rw-r--r--contrib/tools/python3/Lib/venv/scripts/common/activate15
-rw-r--r--contrib/tools/python3/Lib/venv/scripts/nt/activate.bat6
-rw-r--r--contrib/tools/python3/Lib/venv/scripts/posix/activate.csh8
-rw-r--r--contrib/tools/python3/Lib/venv/scripts/posix/activate.fish8
-rw-r--r--contrib/tools/python3/Lib/ya.make4
-rw-r--r--contrib/tools/python3/Lib/zipfile/__init__.py6
-rw-r--r--contrib/tools/python3/Lib/zipfile/_path/__init__.py2
54 files changed, 1156 insertions, 640 deletions
diff --git a/contrib/tools/python3/Lib/_collections_abc.py b/contrib/tools/python3/Lib/_collections_abc.py
index 601107d2d86..09745658de1 100644
--- a/contrib/tools/python3/Lib/_collections_abc.py
+++ b/contrib/tools/python3/Lib/_collections_abc.py
@@ -973,7 +973,7 @@ class MutableMapping(Mapping):
def update(self, other=(), /, **kwds):
''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.
- If E present and has a .keys() method, does: for k in E: D[k] = E[k]
+ If E present and has a .keys() method, does: for k in E.keys(): D[k] = E[k]
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
'''
diff --git a/contrib/tools/python3/Lib/_strptime.py b/contrib/tools/python3/Lib/_strptime.py
index 798cf9f9d3f..dfd2bc5d8b4 100644
--- a/contrib/tools/python3/Lib/_strptime.py
+++ b/contrib/tools/python3/Lib/_strptime.py
@@ -14,6 +14,7 @@ import time
import locale
import calendar
from re import compile as re_compile
+from re import sub as re_sub
from re import IGNORECASE
from re import escape as re_escape
from datetime import (date as datetime_date,
@@ -27,6 +28,18 @@ def _getlang():
# Figure out what the current language is set to.
return locale.getlocale(locale.LC_TIME)
+def _findall(haystack, needle):
+ # Find all positions of needle in haystack.
+ if not needle:
+ return
+ i = 0
+ while True:
+ i = haystack.find(needle, i)
+ if i < 0:
+ break
+ yield i
+ i += len(needle)
+
class LocaleTime(object):
"""Stores and handles locale-specific information related to time.
@@ -101,7 +114,8 @@ class LocaleTime(object):
am_pm = []
for hour in (1, 22):
time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0))
- am_pm.append(time.strftime("%p", time_tuple).lower())
+ # br_FR has AM/PM info (' ',' ').
+ am_pm.append(time.strftime("%p", time_tuple).lower().strip())
self.am_pm = am_pm
def __calc_date_time(self):
@@ -113,42 +127,130 @@ class LocaleTime(object):
# values within the format string is very important; it eliminates
# possible ambiguity for what something represents.
time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0))
- date_time = [None, None, None]
- date_time[0] = time.strftime("%c", time_tuple).lower()
- date_time[1] = time.strftime("%x", time_tuple).lower()
- date_time[2] = time.strftime("%X", time_tuple).lower()
- replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'),
- (self.f_month[3], '%B'), (self.a_weekday[2], '%a'),
- (self.a_month[3], '%b'), (self.am_pm[1], '%p'),
- ('1999', '%Y'), ('99', '%y'), ('22', '%H'),
- ('44', '%M'), ('55', '%S'), ('76', '%j'),
- ('17', '%d'), ('03', '%m'), ('3', '%m'),
- # '3' needed for when no leading zero.
- ('2', '%w'), ('10', '%I')]
- replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone
- for tz in tz_values])
- for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')):
- current_format = date_time[offset]
- for old, new in replacement_pairs:
+ time_tuple2 = time.struct_time((1999,1,3,1,1,1,6,3,0))
+ replacement_pairs = [
+ ('1999', '%Y'), ('99', '%y'), ('22', '%H'),
+ ('44', '%M'), ('55', '%S'), ('76', '%j'),
+ ('17', '%d'), ('03', '%m'), ('3', '%m'),
+ # '3' needed for when no leading zero.
+ ('2', '%w'), ('10', '%I'),
+ # Non-ASCII digits
+ ('\u0661\u0669\u0669\u0669', '%Y'),
+ ('\u0669\u0669', '%Oy'),
+ ('\u0662\u0662', '%OH'),
+ ('\u0664\u0664', '%OM'),
+ ('\u0665\u0665', '%OS'),
+ ('\u0661\u0667', '%Od'),
+ ('\u0660\u0663', '%Om'),
+ ('\u0663', '%Om'),
+ ('\u0662', '%Ow'),
+ ('\u0661\u0660', '%OI'),
+ ]
+ date_time = []
+ for directive in ('%c', '%x', '%X'):
+ current_format = time.strftime(directive, time_tuple).lower()
+ current_format = current_format.replace('%', '%%')
+ # The month and the day of the week formats are treated specially
+ # because of a possible ambiguity in some locales where the full
+ # and abbreviated names are equal or names of different types
+ # are equal. See doc of __find_month_format for more details.
+ lst, fmt = self.__find_weekday_format(directive)
+ if lst:
+ current_format = current_format.replace(lst[2], fmt, 1)
+ lst, fmt = self.__find_month_format(directive)
+ if lst:
+ current_format = current_format.replace(lst[3], fmt, 1)
+ if self.am_pm[1]:
# Must deal with possible lack of locale info
# manifesting itself as the empty string (e.g., Swedish's
# lack of AM/PM info) or a platform returning a tuple of empty
# strings (e.g., MacOS 9 having timezone as ('','')).
- if old:
- current_format = current_format.replace(old, new)
+ current_format = current_format.replace(self.am_pm[1], '%p')
+ for tz_values in self.timezone:
+ for tz in tz_values:
+ if tz:
+ current_format = current_format.replace(tz, "%Z")
+ # Transform all non-ASCII digits to digits in range U+0660 to U+0669.
+ current_format = re_sub(r'\d(?<![0-9])',
+ lambda m: chr(0x0660 + int(m[0])),
+ current_format)
+ for old, new in replacement_pairs:
+ current_format = current_format.replace(old, new)
# If %W is used, then Sunday, 2005-01-03 will fall on week 0 since
# 2005-01-03 occurs before the first Monday of the year. Otherwise
# %U is used.
- time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0))
- if '00' in time.strftime(directive, time_tuple):
+ if '00' in time.strftime(directive, time_tuple2):
U_W = '%W'
else:
U_W = '%U'
- date_time[offset] = current_format.replace('11', U_W)
+ current_format = current_format.replace('11', U_W)
+ date_time.append(current_format)
self.LC_date_time = date_time[0]
self.LC_date = date_time[1]
self.LC_time = date_time[2]
+ def __find_month_format(self, directive):
+ """Find the month format appropriate for the current locale.
+
+ In some locales (for example French and Hebrew), the default month
+ used in __calc_date_time has the same name in full and abbreviated
+ form. Also, the month name can by accident match other part of the
+ representation: the day of the week name (for example in Morisyen)
+ or the month number (for example in Japanese). Thus, cycle months
+ of the year and find all positions that match the month name for
+ each month, If no common positions are found, the representation
+ does not use the month name.
+ """
+ full_indices = abbr_indices = None
+ for m in range(1, 13):
+ time_tuple = time.struct_time((1999, m, 17, 22, 44, 55, 2, 76, 0))
+ datetime = time.strftime(directive, time_tuple).lower()
+ indices = set(_findall(datetime, self.f_month[m]))
+ if full_indices is None:
+ full_indices = indices
+ else:
+ full_indices &= indices
+ indices = set(_findall(datetime, self.a_month[m]))
+ if abbr_indices is None:
+ abbr_indices = indices
+ else:
+ abbr_indices &= indices
+ if not full_indices and not abbr_indices:
+ return None, None
+ if full_indices:
+ return self.f_month, '%B'
+ if abbr_indices:
+ return self.a_month, '%b'
+ return None, None
+
+ def __find_weekday_format(self, directive):
+ """Find the day of the week format appropriate for the current locale.
+
+ Similar to __find_month_format().
+ """
+ full_indices = abbr_indices = None
+ for wd in range(7):
+ time_tuple = time.struct_time((1999, 3, 17, 22, 44, 55, wd, 76, 0))
+ datetime = time.strftime(directive, time_tuple).lower()
+ indices = set(_findall(datetime, self.f_weekday[wd]))
+ if full_indices is None:
+ full_indices = indices
+ else:
+ full_indices &= indices
+ if self.f_weekday[wd] != self.a_weekday[wd]:
+ indices = set(_findall(datetime, self.a_weekday[wd]))
+ if abbr_indices is None:
+ abbr_indices = indices
+ else:
+ abbr_indices &= indices
+ if not full_indices and not abbr_indices:
+ return None, None
+ if full_indices:
+ return self.f_weekday, '%A'
+ if abbr_indices:
+ return self.a_weekday, '%a'
+ return None, None
+
def __calc_timezone(self):
# Set self.timezone by using time.tzname.
# Do not worry about possibility of time.tzname[0] == time.tzname[1]
@@ -181,12 +283,12 @@ class TimeRE(dict):
else:
self.locale_time = LocaleTime()
base = super()
- base.__init__({
+ mapping = {
# The " [1-9]" part of the regex is to make %c from ANSI C work
'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
'f': r"(?P<f>[0-9]{1,6})",
'H': r"(?P<H>2[0-3]|[0-1]\d|\d)",
- 'I': r"(?P<I>1[0-2]|0[1-9]|[1-9])",
+ 'I': r"(?P<I>1[0-2]|0[1-9]|[1-9]| [1-9])",
'G': r"(?P<G>\d\d\d\d)",
'j': r"(?P<j>36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])",
'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])",
@@ -210,11 +312,15 @@ class TimeRE(dict):
'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone
for tz in tz_names),
'Z'),
- '%': '%'})
- base.__setitem__('W', base.__getitem__('U').replace('U', 'W'))
- base.__setitem__('c', self.pattern(self.locale_time.LC_date_time))
- base.__setitem__('x', self.pattern(self.locale_time.LC_date))
+ '%': '%'}
+ for d in 'dmyHIMS':
+ mapping['O' + d] = r'(?P<%s>\d\d|\d| \d)' % d
+ mapping['Ow'] = r'(?P<w>\d)'
+ mapping['W'] = mapping['U'].replace('U', 'W')
+ base.__init__(mapping)
base.__setitem__('X', self.pattern(self.locale_time.LC_time))
+ base.__setitem__('x', self.pattern(self.locale_time.LC_date))
+ base.__setitem__('c', self.pattern(self.locale_time.LC_date_time))
def __seqToRE(self, to_convert, directive):
"""Convert a list to a regex string for matching a directive.
@@ -242,21 +348,16 @@ class TimeRE(dict):
regex syntax are escaped.
"""
- processed_format = ''
# The sub() call escapes all characters that might be misconstrued
# as regex syntax. Cannot use re.escape since we have to deal with
# format directives (%m, etc.).
- regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])")
- format = regex_chars.sub(r"\\\1", format)
- whitespace_replacement = re_compile(r'\s+')
- format = whitespace_replacement.sub(r'\\s+', format)
- while '%' in format:
- directive_index = format.index('%')+1
- processed_format = "%s%s%s" % (processed_format,
- format[:directive_index-1],
- self[format[directive_index]])
- format = format[directive_index+1:]
- return "%s%s" % (processed_format, format)
+ format = re_sub(r"([\\.^$*+?\(\){}\[\]|])", r"\\\1", format)
+ format = re_sub(r'\s+', r'\\s+', format)
+ format = re_sub(r"'", "['\u02bc]", format) # needed for br_FR
+ def repl(m):
+ return self[m[1]]
+ format = re_sub(r'%(O?.)', repl, format)
+ return format
def compile(self, format):
"""Return a compiled re object for the format string."""
diff --git a/contrib/tools/python3/Lib/argparse.py b/contrib/tools/python3/Lib/argparse.py
index 3d01415fcf2..2a8b501a44e 100644
--- a/contrib/tools/python3/Lib/argparse.py
+++ b/contrib/tools/python3/Lib/argparse.py
@@ -564,8 +564,7 @@ class HelpFormatter(object):
def _format_action_invocation(self, action):
if not action.option_strings:
default = self._get_default_metavar_for_positional(action)
- metavar, = self._metavar_formatter(action, default)(1)
- return metavar
+ return ' '.join(self._metavar_formatter(action, default)(1))
else:
parts = []
@@ -589,8 +588,7 @@ class HelpFormatter(object):
if action.metavar is not None:
result = action.metavar
elif action.choices is not None:
- choice_strs = [str(choice) for choice in action.choices]
- result = '{%s}' % ','.join(choice_strs)
+ result = '{%s}' % ','.join(map(str, action.choices))
else:
result = default_metavar
@@ -638,8 +636,7 @@ class HelpFormatter(object):
if hasattr(params[name], '__name__'):
params[name] = params[name].__name__
if params.get('choices') is not None:
- choices_str = ', '.join([str(c) for c in params['choices']])
- params['choices'] = choices_str
+ params['choices'] = ', '.join(map(str, params['choices']))
return self._get_help_string(action) % params
def _iter_indented_subactions(self, action):
@@ -752,11 +749,19 @@ def _get_action_name(argument):
elif argument.option_strings:
return '/'.join(argument.option_strings)
elif argument.metavar not in (None, SUPPRESS):
- return argument.metavar
+ metavar = argument.metavar
+ if not isinstance(metavar, tuple):
+ return metavar
+ if argument.nargs == ZERO_OR_MORE and len(metavar) == 2:
+ return '%s[, %s]' % metavar
+ elif argument.nargs == ONE_OR_MORE:
+ return '%s[, %s]' % metavar
+ else:
+ return ', '.join(metavar)
elif argument.dest not in (None, SUPPRESS):
return argument.dest
elif argument.choices:
- return '{' + ','.join(argument.choices) + '}'
+ return '{%s}' % ','.join(map(str, argument.choices))
else:
return None
@@ -1557,7 +1562,11 @@ class _ActionsContainer(object):
# NOTE: if add_mutually_exclusive_group ever gains title= and
# description= then this code will need to be expanded as above
for group in container._mutually_exclusive_groups:
- mutex_group = self.add_mutually_exclusive_group(
+ if group._container is container:
+ cont = self
+ else:
+ cont = title_group_map[group._container.title]
+ mutex_group = cont.add_mutually_exclusive_group(
required=group.required)
# map the actions to their new mutex group
@@ -1902,6 +1911,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
return args
def parse_known_args(self, args=None, namespace=None):
+ return self._parse_known_args2(args, namespace, intermixed=False)
+
+ def _parse_known_args2(self, args, namespace, intermixed):
if args is None:
# args default to the system args
args = _sys.argv[1:]
@@ -1928,18 +1940,18 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
# parse the arguments and exit if there are any errors
if self.exit_on_error:
try:
- namespace, args = self._parse_known_args(args, namespace)
+ namespace, args = self._parse_known_args(args, namespace, intermixed)
except ArgumentError as err:
self.error(str(err))
else:
- namespace, args = self._parse_known_args(args, namespace)
+ namespace, args = self._parse_known_args(args, namespace, intermixed)
if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)
return namespace, args
- def _parse_known_args(self, arg_strings, namespace):
+ def _parse_known_args(self, arg_strings, namespace, intermixed):
# replace arg strings that are file references
if self.fromfile_prefix_chars is not None:
arg_strings = self._read_args_from_files(arg_strings)
@@ -2014,7 +2026,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if len(option_tuples) > 1:
options = ', '.join([option_string
for action, option_string, sep, explicit_arg in option_tuples])
- args = {'option': arg_string, 'matches': options}
+ args = {'option': arg_strings[start_index], 'matches': options}
msg = _('ambiguous option: %(option)s could match %(matches)s')
raise ArgumentError(None, msg % args)
@@ -2029,6 +2041,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
# if we found no optional action, skip it
if action is None:
extras.append(arg_strings[start_index])
+ extras_pattern.append('O')
return start_index + 1
# if there is an explicit argument, try to match the
@@ -2064,6 +2077,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
sep = ''
else:
extras.append(char + explicit_arg)
+ extras_pattern.append('O')
stop = start_index + 1
break
# if the action expect exactly one argument, we've
@@ -2134,6 +2148,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
# consume Positionals and Optionals alternately, until we have
# passed the last option string
extras = []
+ extras_pattern = []
start_index = 0
if option_string_indices:
max_option_string_index = max(option_string_indices)
@@ -2146,7 +2161,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
index
for index in option_string_indices
if index >= start_index])
- if start_index != next_option_string_index:
+ if not intermixed and start_index != next_option_string_index:
positionals_end_index = consume_positionals(start_index)
# only try to parse the next optional if we didn't consume
@@ -2162,16 +2177,35 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if start_index not in option_string_indices:
strings = arg_strings[start_index:next_option_string_index]
extras.extend(strings)
+ extras_pattern.extend(arg_strings_pattern[start_index:next_option_string_index])
start_index = next_option_string_index
# consume the next optional and any arguments for it
start_index = consume_optional(start_index)
- # consume any positionals following the last Optional
- stop_index = consume_positionals(start_index)
+ if not intermixed:
+ # consume any positionals following the last Optional
+ stop_index = consume_positionals(start_index)
- # if we didn't consume all the argument strings, there were extras
- extras.extend(arg_strings[stop_index:])
+ # if we didn't consume all the argument strings, there were extras
+ extras.extend(arg_strings[stop_index:])
+ else:
+ extras.extend(arg_strings[start_index:])
+ extras_pattern.extend(arg_strings_pattern[start_index:])
+ extras_pattern = ''.join(extras_pattern)
+ assert len(extras_pattern) == len(extras)
+ # consume all positionals
+ arg_strings = [s for s, c in zip(extras, extras_pattern) if c != 'O']
+ arg_strings_pattern = extras_pattern.replace('O', '')
+ stop_index = consume_positionals(0)
+ # leave unknown optionals and non-consumed positionals in extras
+ for i, c in enumerate(extras_pattern):
+ if not stop_index:
+ break
+ if c != 'O':
+ stop_index -= 1
+ extras[i] = None
+ extras = [s for s in extras if s is not None]
# make sure all required actions were present and also convert
# action defaults which were not given as arguments
@@ -2437,10 +2471,6 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
# are then parsed. If the parser definition is incompatible with the
# intermixed assumptions (e.g. use of REMAINDER, subparsers) a
# TypeError is raised.
- #
- # positionals are 'deactivated' by setting nargs and default to
- # SUPPRESS. This blocks the addition of that positional to the
- # namespace
positionals = self._get_positional_actions()
a = [action for action in positionals
@@ -2449,59 +2479,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
raise TypeError('parse_intermixed_args: positional arg'
' with nargs=%s'%a[0].nargs)
- if [action.dest for group in self._mutually_exclusive_groups
- for action in group._group_actions if action in positionals]:
- raise TypeError('parse_intermixed_args: positional in'
- ' mutuallyExclusiveGroup')
-
- try:
- save_usage = self.usage
- try:
- if self.usage is None:
- # capture the full usage for use in error messages
- self.usage = self.format_usage()[7:]
- for action in positionals:
- # deactivate positionals
- action.save_nargs = action.nargs
- # action.nargs = 0
- action.nargs = SUPPRESS
- action.save_default = action.default
- action.default = SUPPRESS
- namespace, remaining_args = self.parse_known_args(args,
- namespace)
- for action in positionals:
- # remove the empty positional values from namespace
- if (hasattr(namespace, action.dest)
- and getattr(namespace, action.dest)==[]):
- from warnings import warn
- warn('Do not expect %s in %s' % (action.dest, namespace))
- delattr(namespace, action.dest)
- finally:
- # restore nargs and usage before exiting
- for action in positionals:
- action.nargs = action.save_nargs
- action.default = action.save_default
- optionals = self._get_optional_actions()
- try:
- # parse positionals. optionals aren't normally required, but
- # they could be, so make sure they aren't.
- for action in optionals:
- action.save_required = action.required
- action.required = False
- for group in self._mutually_exclusive_groups:
- group.save_required = group.required
- group.required = False
- namespace, extras = self.parse_known_args(remaining_args,
- namespace)
- finally:
- # restore parser values before exiting
- for action in optionals:
- action.required = action.save_required
- for group in self._mutually_exclusive_groups:
- group.required = group.save_required
- finally:
- self.usage = save_usage
- return namespace, extras
+ return self._parse_known_args2(args, namespace, intermixed=True)
# ========================
# Value conversion methods
@@ -2589,8 +2567,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if isinstance(choices, str):
choices = iter(choices)
if value not in choices:
- args = {'value': value,
- 'choices': ', '.join(map(repr, action.choices))}
+ args = {'value': str(value),
+ 'choices': ', '.join(map(str, action.choices))}
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
raise ArgumentError(action, msg % args)
diff --git a/contrib/tools/python3/Lib/asyncio/__main__.py b/contrib/tools/python3/Lib/asyncio/__main__.py
index 04655801151..29e528aeed7 100644
--- a/contrib/tools/python3/Lib/asyncio/__main__.py
+++ b/contrib/tools/python3/Lib/asyncio/__main__.py
@@ -2,6 +2,7 @@ import ast
import asyncio
import code
import concurrent.futures
+import contextvars
import inspect
import sys
import threading
@@ -17,6 +18,7 @@ class AsyncIOInteractiveConsole(code.InteractiveConsole):
super().__init__(locals)
self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
self.loop = loop
+ self.context = contextvars.copy_context()
def runcode(self, code):
future = concurrent.futures.Future()
@@ -46,12 +48,12 @@ class AsyncIOInteractiveConsole(code.InteractiveConsole):
return
try:
- repl_future = self.loop.create_task(coro)
+ repl_future = self.loop.create_task(coro, context=self.context)
futures._chain_future(repl_future, future)
except BaseException as exc:
future.set_exception(exc)
- loop.call_soon_threadsafe(callback)
+ loop.call_soon_threadsafe(callback, context=self.context)
try:
return future.result()
diff --git a/contrib/tools/python3/Lib/asyncio/base_events.py b/contrib/tools/python3/Lib/asyncio/base_events.py
index cb037fd472c..3146f7f3f65 100644
--- a/contrib/tools/python3/Lib/asyncio/base_events.py
+++ b/contrib/tools/python3/Lib/asyncio/base_events.py
@@ -17,7 +17,6 @@ import collections
import collections.abc
import concurrent.futures
import errno
-import functools
import heapq
import itertools
import os
@@ -1106,11 +1105,18 @@ class BaseEventLoop(events.AbstractEventLoop):
except OSError:
continue
else: # using happy eyeballs
- sock, _, _ = await staggered.staggered_race(
- (functools.partial(self._connect_sock,
- exceptions, addrinfo, laddr_infos)
- for addrinfo in infos),
- happy_eyeballs_delay, loop=self)
+ sock = (await staggered.staggered_race(
+ (
+ # can't use functools.partial as it keeps a reference
+ # to exceptions
+ lambda addrinfo=addrinfo: self._connect_sock(
+ exceptions, addrinfo, laddr_infos
+ )
+ for addrinfo in infos
+ ),
+ happy_eyeballs_delay,
+ loop=self,
+ ))[0] # can't use sock, _, _ as it keeks a reference to exceptions
if sock is None:
exceptions = [exc for sub in exceptions for exc in sub]
diff --git a/contrib/tools/python3/Lib/asyncio/futures.py b/contrib/tools/python3/Lib/asyncio/futures.py
index fd486f02c67..0c530bbdbcf 100644
--- a/contrib/tools/python3/Lib/asyncio/futures.py
+++ b/contrib/tools/python3/Lib/asyncio/futures.py
@@ -194,8 +194,7 @@ class Future:
the future is done and has an exception set, this exception is raised.
"""
if self._state == _CANCELLED:
- exc = self._make_cancelled_error()
- raise exc
+ raise self._make_cancelled_error()
if self._state != _FINISHED:
raise exceptions.InvalidStateError('Result is not ready.')
self.__log_traceback = False
@@ -212,8 +211,7 @@ class Future:
InvalidStateError.
"""
if self._state == _CANCELLED:
- exc = self._make_cancelled_error()
- raise exc
+ raise self._make_cancelled_error()
if self._state != _FINISHED:
raise exceptions.InvalidStateError('Exception is not set.')
self.__log_traceback = False
diff --git a/contrib/tools/python3/Lib/asyncio/sslproto.py b/contrib/tools/python3/Lib/asyncio/sslproto.py
index e51669a2ab2..29e72b1fd9a 100644
--- a/contrib/tools/python3/Lib/asyncio/sslproto.py
+++ b/contrib/tools/python3/Lib/asyncio/sslproto.py
@@ -101,7 +101,7 @@ class _SSLProtocolTransport(transports._FlowControlMixin,
return self._ssl_protocol._app_protocol
def is_closing(self):
- return self._closed
+ return self._closed or self._ssl_protocol._is_transport_closing()
def close(self):
"""Close the transport.
@@ -379,6 +379,9 @@ class SSLProtocol(protocols.BufferedProtocol):
self._app_transport_created = True
return self._app_transport
+ def _is_transport_closing(self):
+ return self._transport is not None and self._transport.is_closing()
+
def connection_made(self, transport):
"""Called when the low-level connection is made.
diff --git a/contrib/tools/python3/Lib/asyncio/staggered.py b/contrib/tools/python3/Lib/asyncio/staggered.py
index c3a7441a7b0..0f4df8855a8 100644
--- a/contrib/tools/python3/Lib/asyncio/staggered.py
+++ b/contrib/tools/python3/Lib/asyncio/staggered.py
@@ -69,7 +69,11 @@ async def staggered_race(coro_fns, delay, *, loop=None):
exceptions = []
running_tasks = []
- async def run_one_coro(previous_failed) -> None:
+ async def run_one_coro(ok_to_start, previous_failed) -> None:
+ # in eager tasks this waits for the calling task to append this task
+ # to running_tasks, in regular tasks this wait is a no-op that does
+ # not yield a future. See gh-124309.
+ await ok_to_start.wait()
# Wait for the previous task to finish, or for delay seconds
if previous_failed is not None:
with contextlib.suppress(exceptions_mod.TimeoutError):
@@ -85,8 +89,12 @@ async def staggered_race(coro_fns, delay, *, loop=None):
return
# Start task that will run the next coroutine
this_failed = locks.Event()
- next_task = loop.create_task(run_one_coro(this_failed))
+ next_ok_to_start = locks.Event()
+ next_task = loop.create_task(run_one_coro(next_ok_to_start, this_failed))
running_tasks.append(next_task)
+ # next_task has been appended to running_tasks so next_task is ok to
+ # start.
+ next_ok_to_start.set()
assert len(running_tasks) == this_index + 2
# Prepare place to put this coroutine's exceptions if not won
exceptions.append(None)
@@ -116,8 +124,11 @@ async def staggered_race(coro_fns, delay, *, loop=None):
if i != this_index:
t.cancel()
- first_task = loop.create_task(run_one_coro(None))
+ ok_to_start = locks.Event()
+ first_task = loop.create_task(run_one_coro(ok_to_start, None))
running_tasks.append(first_task)
+ # first_task has been appended to running_tasks so first_task is ok to start.
+ ok_to_start.set()
try:
# Wait for a growing list of tasks to all finish: poor man's version of
# curio's TaskGroup or trio's nursery
@@ -133,6 +144,7 @@ async def staggered_race(coro_fns, delay, *, loop=None):
raise d.exception()
return winner_result, winner_index, exceptions
finally:
+ del exceptions
# Make sure no tasks are left running if we leave this function
for t in running_tasks:
t.cancel()
diff --git a/contrib/tools/python3/Lib/asyncio/taskgroups.py b/contrib/tools/python3/Lib/asyncio/taskgroups.py
index d264e51f1fd..aada3ffa8e0 100644
--- a/contrib/tools/python3/Lib/asyncio/taskgroups.py
+++ b/contrib/tools/python3/Lib/asyncio/taskgroups.py
@@ -66,6 +66,20 @@ class TaskGroup:
return self
async def __aexit__(self, et, exc, tb):
+ tb = None
+ try:
+ return await self._aexit(et, exc)
+ finally:
+ # Exceptions are heavy objects that can have object
+ # cycles (bad for GC); let's not keep a reference to
+ # a bunch of them. It would be nicer to use a try/finally
+ # in __aexit__ directly but that introduced some diff noise
+ self._parent_task = None
+ self._errors = None
+ self._base_error = None
+ exc = None
+
+ async def _aexit(self, et, exc):
self._exiting = True
if (exc is not None and
@@ -126,25 +140,34 @@ class TaskGroup:
assert not self._tasks
if self._base_error is not None:
- raise self._base_error
+ try:
+ raise self._base_error
+ finally:
+ exc = None
# Propagate CancelledError if there is one, except if there
# are other errors -- those have priority.
- if propagate_cancellation_error and not self._errors:
- raise propagate_cancellation_error
+ try:
+ if propagate_cancellation_error and not self._errors:
+ try:
+ raise propagate_cancellation_error
+ finally:
+ exc = None
+ finally:
+ propagate_cancellation_error = None
if et is not None and et is not exceptions.CancelledError:
self._errors.append(exc)
if self._errors:
- # Exceptions are heavy objects that can have object
- # cycles (bad for GC); let's not keep a reference to
- # a bunch of them.
try:
- me = BaseExceptionGroup('unhandled errors in a TaskGroup', self._errors)
- raise me from None
+ raise BaseExceptionGroup(
+ 'unhandled errors in a TaskGroup',
+ self._errors,
+ ) from None
finally:
- self._errors = None
+ exc = None
+
def create_task(self, coro, *, name=None, context=None):
"""Create a new task in this group and return it.
diff --git a/contrib/tools/python3/Lib/bdb.py b/contrib/tools/python3/Lib/bdb.py
index 564d6c5e532..196e6b178cb 100644
--- a/contrib/tools/python3/Lib/bdb.py
+++ b/contrib/tools/python3/Lib/bdb.py
@@ -295,9 +295,10 @@ class Bdb:
# Issue #13183: pdb skips frames after hitting a breakpoint and running
# step commands.
# Restore the trace function in the caller (that may not have been set
- # for performance reasons) when returning from the current frame.
+ # for performance reasons) when returning from the current frame, unless
+ # the caller is the botframe.
caller_frame = current_frame.f_back
- if caller_frame and not caller_frame.f_trace:
+ if caller_frame and not caller_frame.f_trace and caller_frame is not self.botframe:
caller_frame.f_trace = self.trace_dispatch
# Derived classes and clients can call the following methods
diff --git a/contrib/tools/python3/Lib/calendar.py b/contrib/tools/python3/Lib/calendar.py
index ee3ec838c96..3509648435d 100644
--- a/contrib/tools/python3/Lib/calendar.py
+++ b/contrib/tools/python3/Lib/calendar.py
@@ -28,7 +28,9 @@ __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
error = ValueError
# Exceptions raised for bad input
-class IllegalMonthError(ValueError):
+# This is trick for backward compatibility. Since 3.13, we will raise IllegalMonthError instead of
+# IndexError for bad month number(out of 1-12). But we can't remove IndexError for backward compatibility.
+class IllegalMonthError(ValueError, IndexError):
def __init__(self, month):
self.month = month
def __str__(self):
@@ -158,11 +160,14 @@ def weekday(year, month, day):
return Day(datetime.date(year, month, day).weekday())
+def _validate_month(month):
+ if not 1 <= month <= 12:
+ raise IllegalMonthError(month)
+
def monthrange(year, month):
"""Return weekday of first day of month (0-6 ~ Mon-Sun)
and number of days (28-31) for year, month."""
- if not 1 <= month <= 12:
- raise IllegalMonthError(month)
+ _validate_month(month)
day1 = weekday(year, month, 1)
ndays = mdays[month] + (month == FEBRUARY and isleap(year))
return day1, ndays
@@ -370,6 +375,8 @@ class TextCalendar(Calendar):
"""
Return a formatted month name.
"""
+ _validate_month(themonth)
+
s = month_name[themonth]
if withyear:
s = "%s %r" % (s, theyear)
@@ -500,6 +507,7 @@ class HTMLCalendar(Calendar):
"""
Return a month name as a table row.
"""
+ _validate_month(themonth)
if withyear:
s = '%s %s' % (month_name[themonth], theyear)
else:
@@ -781,6 +789,8 @@ def main(args):
if options.month is None:
optdict["c"] = options.spacing
optdict["m"] = options.months
+ if options.month is not None:
+ _validate_month(options.month)
if options.year is None:
result = cal.formatyear(datetime.date.today().year, **optdict)
elif options.month is None:
diff --git a/contrib/tools/python3/Lib/concurrent/futures/process.py b/contrib/tools/python3/Lib/concurrent/futures/process.py
index 0e452883963..ff7c17efaab 100644
--- a/contrib/tools/python3/Lib/concurrent/futures/process.py
+++ b/contrib/tools/python3/Lib/concurrent/futures/process.py
@@ -68,27 +68,31 @@ _global_shutdown = False
class _ThreadWakeup:
def __init__(self):
self._closed = False
+ self._lock = threading.Lock()
self._reader, self._writer = mp.Pipe(duplex=False)
def close(self):
- # Please note that we do not take the shutdown lock when
+ # Please note that we do not take the self._lock when
# calling clear() (to avoid deadlocking) so this method can
# only be called safely from the same thread as all calls to
- # clear() even if you hold the shutdown lock. Otherwise we
+ # clear() even if you hold the lock. Otherwise we
# might try to read from the closed pipe.
- if not self._closed:
- self._closed = True
- self._writer.close()
- self._reader.close()
+ with self._lock:
+ if not self._closed:
+ self._closed = True
+ self._writer.close()
+ self._reader.close()
def wakeup(self):
- if not self._closed:
- self._writer.send_bytes(b"")
+ with self._lock:
+ if not self._closed:
+ self._writer.send_bytes(b"")
def clear(self):
- if not self._closed:
- while self._reader.poll():
- self._reader.recv_bytes()
+ if self._closed:
+ raise RuntimeError('operation on closed _ThreadWakeup')
+ while self._reader.poll():
+ self._reader.recv_bytes()
def _python_exit():
@@ -167,10 +171,8 @@ class _CallItem(object):
class _SafeQueue(Queue):
"""Safe Queue set exception to the future object linked to a job"""
- def __init__(self, max_size=0, *, ctx, pending_work_items, shutdown_lock,
- thread_wakeup):
+ def __init__(self, max_size=0, *, ctx, pending_work_items, thread_wakeup):
self.pending_work_items = pending_work_items
- self.shutdown_lock = shutdown_lock
self.thread_wakeup = thread_wakeup
super().__init__(max_size, ctx=ctx)
@@ -179,8 +181,7 @@ class _SafeQueue(Queue):
tb = format_exception(type(e), e, e.__traceback__)
e.__cause__ = _RemoteTraceback('\n"""\n{}"""'.format(''.join(tb)))
work_item = self.pending_work_items.pop(obj.work_id, None)
- with self.shutdown_lock:
- self.thread_wakeup.wakeup()
+ self.thread_wakeup.wakeup()
# work_item can be None if another process terminated. In this
# case, the executor_manager_thread fails all work_items
# with BrokenProcessPool
@@ -305,12 +306,10 @@ class _ExecutorManagerThread(threading.Thread):
# will wake up the queue management thread so that it can terminate
# if there is no pending work item.
def weakref_cb(_,
- thread_wakeup=self.thread_wakeup,
- shutdown_lock=self.shutdown_lock):
+ thread_wakeup=self.thread_wakeup):
mp.util.debug('Executor collected: triggering callback for'
' QueueManager wakeup')
- with shutdown_lock:
- thread_wakeup.wakeup()
+ thread_wakeup.wakeup()
self.executor_reference = weakref.ref(executor, weakref_cb)
@@ -438,11 +437,6 @@ class _ExecutorManagerThread(threading.Thread):
elif wakeup_reader in ready:
is_broken = False
- # No need to hold the _shutdown_lock here because:
- # 1. we're the only thread to use the wakeup reader
- # 2. we're also the only thread to call thread_wakeup.close()
- # 3. we want to avoid a possible deadlock when both reader and writer
- # would block (gh-105829)
self.thread_wakeup.clear()
return result_item, is_broken, cause
@@ -740,10 +734,9 @@ class ProcessPoolExecutor(_base.Executor):
# as it could result in a deadlock if a worker process dies with the
# _result_queue write lock still acquired.
#
- # _shutdown_lock must be locked to access _ThreadWakeup.close() and
- # .wakeup(). Care must also be taken to not call clear or close from
- # more than one thread since _ThreadWakeup.clear() is not protected by
- # the _shutdown_lock
+ # Care must be taken to only call clear and close from the
+ # executor_manager_thread, since _ThreadWakeup.clear() is not protected
+ # by a lock.
self._executor_manager_thread_wakeup = _ThreadWakeup()
# Create communication channels for the executor
@@ -754,7 +747,6 @@ class ProcessPoolExecutor(_base.Executor):
self._call_queue = _SafeQueue(
max_size=queue_size, ctx=self._mp_context,
pending_work_items=self._pending_work_items,
- shutdown_lock=self._shutdown_lock,
thread_wakeup=self._executor_manager_thread_wakeup)
# Killed worker processes can produce spurious "broken pipe"
# tracebacks in the queue's own worker thread. But we detect killed
diff --git a/contrib/tools/python3/Lib/concurrent/futures/thread.py b/contrib/tools/python3/Lib/concurrent/futures/thread.py
index 3b3a36a5093..61dbff8a485 100644
--- a/contrib/tools/python3/Lib/concurrent/futures/thread.py
+++ b/contrib/tools/python3/Lib/concurrent/futures/thread.py
@@ -41,6 +41,7 @@ if hasattr(os, 'register_at_fork'):
os.register_at_fork(before=_global_shutdown_lock.acquire,
after_in_child=_global_shutdown_lock._at_fork_reinit,
after_in_parent=_global_shutdown_lock.release)
+ os.register_at_fork(after_in_child=_threads_queues.clear)
class _WorkItem:
diff --git a/contrib/tools/python3/Lib/email/_policybase.py b/contrib/tools/python3/Lib/email/_policybase.py
index 5f9aa9fb091..c9f0d743090 100644
--- a/contrib/tools/python3/Lib/email/_policybase.py
+++ b/contrib/tools/python3/Lib/email/_policybase.py
@@ -302,12 +302,12 @@ class Compat32(Policy):
"""+
The name is parsed as everything up to the ':' and returned unmodified.
The value is determined by stripping leading whitespace off the
- remainder of the first line, joining all subsequent lines together, and
+ remainder of the first line joined with all subsequent lines, and
stripping any trailing carriage return or linefeed characters.
"""
name, value = sourcelines[0].split(':', 1)
- value = value.lstrip(' \t') + ''.join(sourcelines[1:])
+ value = ''.join((value, *sourcelines[1:])).lstrip(' \t\r\n')
return (name, value.rstrip('\r\n'))
def header_store_parse(self, name, value):
diff --git a/contrib/tools/python3/Lib/email/policy.py b/contrib/tools/python3/Lib/email/policy.py
index 46b7de5bb6d..6e109b65011 100644
--- a/contrib/tools/python3/Lib/email/policy.py
+++ b/contrib/tools/python3/Lib/email/policy.py
@@ -119,13 +119,13 @@ class EmailPolicy(Policy):
"""+
The name is parsed as everything up to the ':' and returned unmodified.
The value is determined by stripping leading whitespace off the
- remainder of the first line, joining all subsequent lines together, and
+ remainder of the first line joined with all subsequent lines, and
stripping any trailing carriage return or linefeed characters. (This
is the same as Compat32).
"""
name, value = sourcelines[0].split(':', 1)
- value = value.lstrip(' \t') + ''.join(sourcelines[1:])
+ value = ''.join((value, *sourcelines[1:])).lstrip(' \t\r\n')
return (name, value.rstrip('\r\n'))
def header_store_parse(self, name, value):
diff --git a/contrib/tools/python3/Lib/ensurepip/__init__.py b/contrib/tools/python3/Lib/ensurepip/__init__.py
index a7c84572382..35d04d2f8b8 100644
--- a/contrib/tools/python3/Lib/ensurepip/__init__.py
+++ b/contrib/tools/python3/Lib/ensurepip/__init__.py
@@ -10,7 +10,7 @@ from importlib import resources
__all__ = ["version", "bootstrap"]
_PACKAGE_NAMES = ('pip',)
-_PIP_VERSION = "24.2"
+_PIP_VERSION = "24.3.1"
_PROJECTS = [
("pip", _PIP_VERSION, "py3"),
]
diff --git a/contrib/tools/python3/Lib/enum.py b/contrib/tools/python3/Lib/enum.py
index d9859b3c0a9..eaa517e2fbc 100644
--- a/contrib/tools/python3/Lib/enum.py
+++ b/contrib/tools/python3/Lib/enum.py
@@ -592,19 +592,13 @@ class EnumType(type):
classdict['_all_bits_'] = 0
classdict['_inverted_'] = None
try:
- exc = None
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
except Exception as e:
- # since 3.12 the line "Error calling __set_name__ on '_proto_member' instance ..."
- # is tacked on to the error instead of raising a RuntimeError
- # recreate the exception to discard
- exc = type(e)(str(e))
- exc.__cause__ = e.__cause__
- exc.__context__ = e.__context__
- tb = e.__traceback__
- if exc is not None:
- raise exc.with_traceback(tb)
- #
+ # since 3.12 the note "Error calling __set_name__ on '_proto_member' instance ..."
+ # is tacked on to the error instead of raising a RuntimeError, so discard it
+ if hasattr(e, '__notes__'):
+ del e.__notes__
+ raise
# update classdict with any changes made by __init_subclass__
classdict.update(enum_class.__dict__)
#
diff --git a/contrib/tools/python3/Lib/functools.py b/contrib/tools/python3/Lib/functools.py
index 318efd04fd8..f6849899e75 100644
--- a/contrib/tools/python3/Lib/functools.py
+++ b/contrib/tools/python3/Lib/functools.py
@@ -238,12 +238,14 @@ def reduce(function, sequence, initial=_initial_missing):
"""
reduce(function, iterable[, initial]) -> value
- Apply a function of two arguments cumulatively to the items of a sequence
- or iterable, from left to right, so as to reduce the iterable to a single
- value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
- ((((1+2)+3)+4)+5). If initial is present, it is placed before the items
- of the iterable in the calculation, and serves as a default when the
- iterable is empty.
+ Apply a function of two arguments cumulatively to the items of an iterable, from left to right.
+
+ This effectively reduces the iterable to a single value. If initial is present,
+ it is placed before the items of the iterable in the calculation, and serves as
+ a default when the iterable is empty.
+
+ For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
+ calculates ((((1 + 2) + 3) + 4) + 5).
"""
it = iter(sequence)
diff --git a/contrib/tools/python3/Lib/importlib/__init__.py b/contrib/tools/python3/Lib/importlib/__init__.py
index 707c081cb2c..5b92442fc37 100644
--- a/contrib/tools/python3/Lib/importlib/__init__.py
+++ b/contrib/tools/python3/Lib/importlib/__init__.py
@@ -105,7 +105,7 @@ def reload(module):
try:
name = module.__name__
except AttributeError:
- raise TypeError("reload() argument must be a module")
+ raise TypeError("reload() argument must be a module") from None
if sys.modules.get(name) is not module:
raise ImportError(f"module {name} not in sys.modules", name=name)
diff --git a/contrib/tools/python3/Lib/importlib/_bootstrap_external.py b/contrib/tools/python3/Lib/importlib/_bootstrap_external.py
index 61dafc0f4cb..9b8a8dfc5aa 100644
--- a/contrib/tools/python3/Lib/importlib/_bootstrap_external.py
+++ b/contrib/tools/python3/Lib/importlib/_bootstrap_external.py
@@ -204,7 +204,11 @@ def _write_atomic(path, data, mode=0o666):
# We first write data to a temporary file, and then use os.replace() to
# perform an atomic rename.
with _io.FileIO(fd, 'wb') as file:
- file.write(data)
+ bytes_written = file.write(data)
+ if bytes_written != len(data):
+ # Raise an OSError so the 'except' below cleans up the partially
+ # written file.
+ raise OSError("os.write() didn't write the full pyc file")
_os.replace(path_tmp, path)
except OSError:
try:
diff --git a/contrib/tools/python3/Lib/inspect.py b/contrib/tools/python3/Lib/inspect.py
index c43faa73159..b630cb28359 100644
--- a/contrib/tools/python3/Lib/inspect.py
+++ b/contrib/tools/python3/Lib/inspect.py
@@ -1638,11 +1638,15 @@ def getclosurevars(func):
global_vars = {}
builtin_vars = {}
unbound_names = set()
- for name in code.co_names:
- if name in ("None", "True", "False"):
- # Because these used to be builtins instead of keywords, they
- # may still show up as name references. We ignore them.
- continue
+ global_names = set()
+ for instruction in dis.get_instructions(code):
+ opname = instruction.opname
+ name = instruction.argval
+ if opname == "LOAD_ATTR":
+ unbound_names.add(name)
+ elif opname == "LOAD_GLOBAL":
+ global_names.add(name)
+ for name in global_names:
try:
global_vars[name] = global_ns[name]
except KeyError:
diff --git a/contrib/tools/python3/Lib/json/decoder.py b/contrib/tools/python3/Lib/json/decoder.py
index c5d9ae2d0d5..5e5effeac02 100644
--- a/contrib/tools/python3/Lib/json/decoder.py
+++ b/contrib/tools/python3/Lib/json/decoder.py
@@ -50,17 +50,18 @@ _CONSTANTS = {
}
+HEXDIGITS = re.compile(r'[0-9A-Fa-f]{4}', FLAGS)
STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
BACKSLASH = {
'"': '"', '\\': '\\', '/': '/',
'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t',
}
-def _decode_uXXXX(s, pos):
- esc = s[pos + 1:pos + 5]
- if len(esc) == 4 and esc[1] not in 'xX':
+def _decode_uXXXX(s, pos, _m=HEXDIGITS.match):
+ esc = _m(s, pos + 1)
+ if esc is not None:
try:
- return int(esc, 16)
+ return int(esc.group(), 16)
except ValueError:
pass
msg = "Invalid \\uXXXX escape"
diff --git a/contrib/tools/python3/Lib/json/scanner.py b/contrib/tools/python3/Lib/json/scanner.py
index 7a61cfc2d24..090897515fe 100644
--- a/contrib/tools/python3/Lib/json/scanner.py
+++ b/contrib/tools/python3/Lib/json/scanner.py
@@ -9,7 +9,7 @@ except ImportError:
__all__ = ['make_scanner']
NUMBER_RE = re.compile(
- r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
+ r'(-?(?:0|[1-9][0-9]*))(\.[0-9]+)?([eE][-+]?[0-9]+)?',
(re.VERBOSE | re.MULTILINE | re.DOTALL))
def py_make_scanner(context):
diff --git a/contrib/tools/python3/Lib/logging/config.py b/contrib/tools/python3/Lib/logging/config.py
index ac90b537d8a..c128bc7a61e 100644
--- a/contrib/tools/python3/Lib/logging/config.py
+++ b/contrib/tools/python3/Lib/logging/config.py
@@ -502,7 +502,7 @@ class BaseConfigurator(object):
def _is_queue_like_object(obj):
"""Check that *obj* implements the Queue API."""
- if isinstance(obj, queue.Queue):
+ if isinstance(obj, (queue.Queue, queue.SimpleQueue)):
return True
# defer importing multiprocessing as much as possible
from multiprocessing.queues import Queue as MPQueue
@@ -519,13 +519,13 @@ def _is_queue_like_object(obj):
# Ideally, we would have wanted to simply use strict type checking
# instead of a protocol-based type checking since the latter does
# not check the method signatures.
- queue_interface = [
- 'empty', 'full', 'get', 'get_nowait',
- 'put', 'put_nowait', 'join', 'qsize',
- 'task_done',
- ]
+ #
+ # Note that only 'put_nowait' and 'get' are required by the logging
+ # queue handler and queue listener (see gh-124653) and that other
+ # methods are either optional or unused.
+ minimal_queue_interface = ['put_nowait', 'get']
return all(callable(getattr(obj, method, None))
- for method in queue_interface)
+ for method in minimal_queue_interface)
class DictConfigurator(BaseConfigurator):
"""
diff --git a/contrib/tools/python3/Lib/multiprocessing/connection.py b/contrib/tools/python3/Lib/multiprocessing/connection.py
index d0582e3cd54..fdbc3bda7db 100644
--- a/contrib/tools/python3/Lib/multiprocessing/connection.py
+++ b/contrib/tools/python3/Lib/multiprocessing/connection.py
@@ -956,7 +956,7 @@ def answer_challenge(connection, authkey: bytes):
f'Protocol error, expected challenge: {message=}')
message = message[len(_CHALLENGE):]
if len(message) < _MD5ONLY_MESSAGE_LENGTH:
- raise AuthenticationError('challenge too short: {len(message)} bytes')
+ raise AuthenticationError(f'challenge too short: {len(message)} bytes')
digest = _create_response(authkey, message)
connection.send_bytes(digest)
response = connection.recv_bytes(256) # reject large message
diff --git a/contrib/tools/python3/Lib/multiprocessing/forkserver.py b/contrib/tools/python3/Lib/multiprocessing/forkserver.py
index 4642707dae2..9fb563276e3 100644
--- a/contrib/tools/python3/Lib/multiprocessing/forkserver.py
+++ b/contrib/tools/python3/Lib/multiprocessing/forkserver.py
@@ -167,6 +167,8 @@ class ForkServer(object):
def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
'''Run forkserver.'''
if preload:
+ if sys_path is not None:
+ sys.path[:] = sys_path
if '__main__' in preload and main_path is not None:
process.current_process()._inheriting = True
try:
diff --git a/contrib/tools/python3/Lib/multiprocessing/managers.py b/contrib/tools/python3/Lib/multiprocessing/managers.py
index 75d9c18c201..010d16e1498 100644
--- a/contrib/tools/python3/Lib/multiprocessing/managers.py
+++ b/contrib/tools/python3/Lib/multiprocessing/managers.py
@@ -755,22 +755,29 @@ class BaseProxy(object):
_address_to_local = {}
_mutex = util.ForkAwareThreadLock()
+ # Each instance gets a `_serial` number. Unlike `id(...)`, this number
+ # is never reused.
+ _next_serial = 1
+
def __init__(self, token, serializer, manager=None,
authkey=None, exposed=None, incref=True, manager_owned=False):
with BaseProxy._mutex:
- tls_idset = BaseProxy._address_to_local.get(token.address, None)
- if tls_idset is None:
- tls_idset = util.ForkAwareLocal(), ProcessLocalSet()
- BaseProxy._address_to_local[token.address] = tls_idset
+ tls_serials = BaseProxy._address_to_local.get(token.address, None)
+ if tls_serials is None:
+ tls_serials = util.ForkAwareLocal(), ProcessLocalSet()
+ BaseProxy._address_to_local[token.address] = tls_serials
+
+ self._serial = BaseProxy._next_serial
+ BaseProxy._next_serial += 1
# self._tls is used to record the connection used by this
# thread to communicate with the manager at token.address
- self._tls = tls_idset[0]
+ self._tls = tls_serials[0]
- # self._idset is used to record the identities of all shared
- # objects for which the current process owns references and
+ # self._all_serials is a set used to record the identities of all
+ # shared objects for which the current process owns references and
# which are in the manager at token.address
- self._idset = tls_idset[1]
+ self._all_serials = tls_serials[1]
self._token = token
self._id = self._token.id
@@ -850,20 +857,20 @@ class BaseProxy(object):
dispatch(conn, None, 'incref', (self._id,))
util.debug('INCREF %r', self._token.id)
- self._idset.add(self._id)
+ self._all_serials.add(self._serial)
state = self._manager and self._manager._state
self._close = util.Finalize(
self, BaseProxy._decref,
- args=(self._token, self._authkey, state,
- self._tls, self._idset, self._Client),
+ args=(self._token, self._serial, self._authkey, state,
+ self._tls, self._all_serials, self._Client),
exitpriority=10
)
@staticmethod
- def _decref(token, authkey, state, tls, idset, _Client):
- idset.discard(token.id)
+ def _decref(token, serial, authkey, state, tls, idset, _Client):
+ idset.discard(serial)
# check whether manager is still alive
if state is None or state.value == State.STARTED:
diff --git a/contrib/tools/python3/Lib/multiprocessing/synchronize.py b/contrib/tools/python3/Lib/multiprocessing/synchronize.py
index 3ccbfe311c7..0f682b9a094 100644
--- a/contrib/tools/python3/Lib/multiprocessing/synchronize.py
+++ b/contrib/tools/python3/Lib/multiprocessing/synchronize.py
@@ -174,7 +174,7 @@ class Lock(SemLock):
name = process.current_process().name
if threading.current_thread().name != 'MainThread':
name += '|' + threading.current_thread().name
- elif self._semlock._get_value() == 1:
+ elif not self._semlock._is_zero():
name = 'None'
elif self._semlock._count() > 0:
name = 'SomeOtherThread'
@@ -200,7 +200,7 @@ class RLock(SemLock):
if threading.current_thread().name != 'MainThread':
name += '|' + threading.current_thread().name
count = self._semlock._count()
- elif self._semlock._get_value() == 1:
+ elif not self._semlock._is_zero():
name, count = 'None', 0
elif self._semlock._count() > 0:
name, count = 'SomeOtherThread', 'nonzero'
diff --git a/contrib/tools/python3/Lib/ntpath.py b/contrib/tools/python3/Lib/ntpath.py
index 2e290dcf9de..c05e965fcb9 100644
--- a/contrib/tools/python3/Lib/ntpath.py
+++ b/contrib/tools/python3/Lib/ntpath.py
@@ -561,28 +561,21 @@ except ImportError:
return prefix + sep.join(comps)
-def _abspath_fallback(path):
- """Return the absolute version of a path as a fallback function in case
- `nt._getfullpathname` is not available or raises OSError. See bpo-31047 for
- more.
-
- """
-
- path = os.fspath(path)
- if not isabs(path):
- if isinstance(path, bytes):
- cwd = os.getcwdb()
- else:
- cwd = os.getcwd()
- path = join(cwd, path)
- return normpath(path)
-
# Return an absolute path.
try:
from nt import _getfullpathname
except ImportError: # not running on Windows - mock up something sensible
- abspath = _abspath_fallback
+ def abspath(path):
+ """Return the absolute version of a path."""
+ path = os.fspath(path)
+ if not isabs(path):
+ if isinstance(path, bytes):
+ cwd = os.getcwdb()
+ else:
+ cwd = os.getcwd()
+ path = join(cwd, path)
+ return normpath(path)
else: # use native Windows method on Windows
def abspath(path):
@@ -590,7 +583,27 @@ else: # use native Windows method on Windows
try:
return _getfullpathname(normpath(path))
except (OSError, ValueError):
- return _abspath_fallback(path)
+ # See gh-75230, handle outside for cleaner traceback
+ pass
+ path = os.fspath(path)
+ if not isabs(path):
+ if isinstance(path, bytes):
+ sep = b'\\'
+ getcwd = os.getcwdb
+ else:
+ sep = '\\'
+ getcwd = os.getcwd
+ drive, root, path = splitroot(path)
+ # Either drive or root can be nonempty, but not both.
+ if drive or root:
+ try:
+ path = join(_getfullpathname(drive + root), path)
+ except (OSError, ValueError):
+ # Drive "\0:" cannot exist; use the root directory.
+ path = drive + sep + path
+ else:
+ path = join(getcwd(), path)
+ return normpath(path)
try:
from nt import _getfinalpathname, readlink as _nt_readlink
diff --git a/contrib/tools/python3/Lib/nturl2path.py b/contrib/tools/python3/Lib/nturl2path.py
index 61852aff589..757fd01bec8 100644
--- a/contrib/tools/python3/Lib/nturl2path.py
+++ b/contrib/tools/python3/Lib/nturl2path.py
@@ -15,32 +15,29 @@ def url2pathname(url):
# become
# C:\foo\bar\spam.foo
import string, urllib.parse
+ if url[:3] == '///':
+ # URL has an empty authority section, so the path begins on the third
+ # character.
+ url = url[2:]
+ elif url[:12] == '//localhost/':
+ # Skip past 'localhost' authority.
+ url = url[11:]
+ if url[:3] == '///':
+ # Skip past extra slash before UNC drive in URL path.
+ url = url[1:]
# Windows itself uses ":" even in URLs.
url = url.replace(':', '|')
if not '|' in url:
# No drive specifier, just convert slashes
- if url[:4] == '////':
- # path is something like ////host/path/on/remote/host
- # convert this to \\host\path\on\remote\host
- # (notice halving of slashes at the start of the path)
- url = url[2:]
- components = url.split('/')
# make sure not to convert quoted slashes :-)
- return urllib.parse.unquote('\\'.join(components))
+ return urllib.parse.unquote(url.replace('/', '\\'))
comp = url.split('|')
if len(comp) != 2 or comp[0][-1] not in string.ascii_letters:
error = 'Bad URL: ' + url
raise OSError(error)
drive = comp[0][-1].upper()
- components = comp[1].split('/')
- path = drive + ':'
- for comp in components:
- if comp:
- path = path + '\\' + urllib.parse.unquote(comp)
- # Issue #11474 - handing url such as |c/|
- if path.endswith(':') and url.endswith('/'):
- path += '\\'
- return path
+ tail = urllib.parse.unquote(comp[1].replace('/', '\\'))
+ return drive + ':' + tail
def pathname2url(p):
"""OS-specific conversion from a file system path to a relative URL
@@ -52,30 +49,21 @@ def pathname2url(p):
import urllib.parse
# First, clean up some special forms. We are going to sacrifice
# the additional information anyway
- if p[:4] == '\\\\?\\':
+ p = p.replace('\\', '/')
+ if p[:4] == '//?/':
p = p[4:]
- if p[:4].upper() == 'UNC\\':
- p = '\\' + p[4:]
+ if p[:4].upper() == 'UNC/':
+ p = '//' + p[4:]
elif p[1:2] != ':':
raise OSError('Bad path: ' + p)
if not ':' in p:
- # No drive specifier, just convert slashes and quote the name
- if p[:2] == '\\\\':
- # path is something like \\host\path\on\remote\host
- # convert this to ////host/path/on/remote/host
- # (notice doubling of slashes at the start of the path)
- p = '\\\\' + p
- components = p.split('\\')
- return urllib.parse.quote('/'.join(components))
+ # No DOS drive specified, just quote the pathname
+ return urllib.parse.quote(p)
comp = p.split(':', maxsplit=2)
if len(comp) != 2 or len(comp[0]) > 1:
error = 'Bad path: ' + p
raise OSError(error)
drive = urllib.parse.quote(comp[0].upper())
- components = comp[1].split('\\')
- path = '///' + drive + ':'
- for comp in components:
- if comp:
- path = path + '/' + urllib.parse.quote(comp)
- return path
+ tail = urllib.parse.quote(comp[1])
+ return '///' + drive + ':' + tail
diff --git a/contrib/tools/python3/Lib/pathlib.py b/contrib/tools/python3/Lib/pathlib.py
index 65ff0ee1977..02eb5c25981 100644
--- a/contrib/tools/python3/Lib/pathlib.py
+++ b/contrib/tools/python3/Lib/pathlib.py
@@ -359,9 +359,9 @@ class PurePath(object):
paths = []
for arg in args:
if isinstance(arg, PurePath):
- if arg._flavour is ntpath and self._flavour is posixpath:
+ if arg._flavour is not self._flavour:
# GH-103631: Convert separators for backwards compatibility.
- paths.extend(path.replace('\\', '/') for path in arg._raw_paths)
+ paths.append(arg.as_posix())
else:
paths.extend(arg._raw_paths)
else:
diff --git a/contrib/tools/python3/Lib/pdb.py b/contrib/tools/python3/Lib/pdb.py
index 89cf975164a..1e1b5ea4f0a 100755
--- a/contrib/tools/python3/Lib/pdb.py
+++ b/contrib/tools/python3/Lib/pdb.py
@@ -96,7 +96,7 @@ __all__ = ["run", "pm", "Pdb", "runeval", "runctx", "runcall", "set_trace",
"post_mortem", "help"]
def find_function(funcname, filename):
- cre = re.compile(r'def\s+%s\s*[(]' % re.escape(funcname))
+ cre = re.compile(r'def\s+%s(\s*\[.+\])?\s*[(]' % re.escape(funcname))
try:
fp = tokenize.open(filename)
except OSError:
@@ -321,8 +321,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def user_line(self, frame):
"""This function is called when we stop or break at this line."""
if self._wait_for_mainpyfile:
- if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
- or frame.f_lineno <= 0):
+ if (self.mainpyfile != self.canonic(frame.f_code.co_filename)):
return
self._wait_for_mainpyfile = False
if self.bp_commands(frame):
diff --git a/contrib/tools/python3/Lib/pickle.py b/contrib/tools/python3/Lib/pickle.py
index 01c1a102794..ea5f1c5dc36 100644
--- a/contrib/tools/python3/Lib/pickle.py
+++ b/contrib/tools/python3/Lib/pickle.py
@@ -533,10 +533,11 @@ class _Pickler:
self.framer.commit_frame()
# Check for persistent id (defined by a subclass)
- pid = self.persistent_id(obj)
- if pid is not None and save_persistent_id:
- self.save_pers(pid)
- return
+ if save_persistent_id:
+ pid = self.persistent_id(obj)
+ if pid is not None:
+ self.save_pers(pid)
+ return
# Check the memo
x = self.memo.get(id(obj))
diff --git a/contrib/tools/python3/Lib/pickletools.py b/contrib/tools/python3/Lib/pickletools.py
index 51ee4a7a263..33a51492ea9 100644
--- a/contrib/tools/python3/Lib/pickletools.py
+++ b/contrib/tools/python3/Lib/pickletools.py
@@ -312,7 +312,7 @@ uint8 = ArgumentDescriptor(
doc="Eight-byte unsigned integer, little-endian.")
-def read_stringnl(f, decode=True, stripquotes=True):
+def read_stringnl(f, decode=True, stripquotes=True, *, encoding='latin-1'):
r"""
>>> import io
>>> read_stringnl(io.BytesIO(b"'abcd'\nefg\n"))
@@ -356,7 +356,7 @@ def read_stringnl(f, decode=True, stripquotes=True):
raise ValueError("no string quotes around %r" % data)
if decode:
- data = codecs.escape_decode(data)[0].decode("ascii")
+ data = codecs.escape_decode(data)[0].decode(encoding)
return data
stringnl = ArgumentDescriptor(
@@ -370,7 +370,7 @@ stringnl = ArgumentDescriptor(
""")
def read_stringnl_noescape(f):
- return read_stringnl(f, stripquotes=False)
+ return read_stringnl(f, stripquotes=False, encoding='utf-8')
stringnl_noescape = ArgumentDescriptor(
name='stringnl_noescape',
@@ -2513,7 +2513,10 @@ def dis(pickle, out=None, memo=None, indentlevel=4, annotate=0):
# make a mild effort to align arguments
line += ' ' * (10 - len(opcode.name))
if arg is not None:
- line += ' ' + repr(arg)
+ if opcode.name in ("STRING", "BINSTRING", "SHORT_BINSTRING"):
+ line += ' ' + ascii(arg)
+ else:
+ line += ' ' + repr(arg)
if markmsg:
line += ' ' + markmsg
if annotate:
diff --git a/contrib/tools/python3/Lib/pydoc_data/topics.py b/contrib/tools/python3/Lib/pydoc_data/topics.py
index b5464cb4d04..12523999ca8 100644
--- a/contrib/tools/python3/Lib/pydoc_data/topics.py
+++ b/contrib/tools/python3/Lib/pydoc_data/topics.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Tue Oct 1 04:02:04 2024
+# Autogenerated by Sphinx on Tue Dec 3 19:41:14 2024
# as part of the release process.
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
@@ -29,13 +29,12 @@ topics = {'assert': 'The "assert" statement\n'
'(command\n'
'line option "-O"). The current code generator emits no code for '
'an\n'
- 'assert statement when optimization is requested at compile time. '
- 'Note\n'
- 'that it is unnecessary to include the source code for the '
- 'expression\n'
- 'that failed in the error message; it will be displayed as part of '
- 'the\n'
- 'stack trace.\n'
+ '"assert" statement when optimization is requested at compile '
+ 'time.\n'
+ 'Note that it is unnecessary to include the source code for the\n'
+ 'expression that failed in the error message; it will be displayed '
+ 'as\n'
+ 'part of the stack trace.\n'
'\n'
'Assignments to "__debug__" are illegal. The value for the '
'built-in\n'
@@ -673,7 +672,8 @@ topics = {'assert': 'The "assert" statement\n'
'should either\n'
' return the (computed) attribute value or raise an '
'"AttributeError"\n'
- ' exception.\n'
+ ' exception. The "object" class itself does not provide '
+ 'this method.\n'
'\n'
' Note that if the attribute is found through the '
'normal mechanism,\n'
@@ -856,7 +856,9 @@ topics = {'assert': 'The "assert" statement\n'
'parents). In the\n'
'examples below, “the attribute” refers to the attribute '
'whose name is\n'
- 'the key of the property in the owner class’ "__dict__".\n'
+ 'the key of the property in the owner class’ "__dict__". '
+ 'The "object"\n'
+ 'class itself does not implement any of these protocols.\n'
'\n'
'object.__get__(self, instance, owner=None)\n'
'\n'
@@ -1529,7 +1531,9 @@ topics = {'assert': 'The "assert" statement\n'
' Called when the instance is “called” as a function; if '
'this method\n'
' is defined, "x(arg1, arg2, ...)" roughly translates to\n'
- ' "type(x).__call__(x, arg1, ...)".\n',
+ ' "type(x).__call__(x, arg1, ...)". The "object" class '
+ 'itself does\n'
+ ' not provide this method.\n',
'calls': 'Calls\n'
'*****\n'
'\n'
@@ -1714,6 +1718,9 @@ topics = {'assert': 'The "assert" statement\n'
' Function definitions. When the code block executes a "return"\n'
' statement, this specifies the return value of the function '
'call.\n'
+ ' If execution reaches the end of the code block without executing '
+ 'a\n'
+ ' "return" statement, the return value is "None".\n'
'\n'
'a built-in function or method:\n'
' The result is up to the interpreter; see Built-in Functions for '
@@ -2762,18 +2769,15 @@ topics = {'assert': 'The "assert" statement\n'
' enter = type(manager).__enter__\n'
' exit = type(manager).__exit__\n'
' value = enter(manager)\n'
- ' hit_except = False\n'
'\n'
' try:\n'
' TARGET = value\n'
' SUITE\n'
' except:\n'
- ' hit_except = True\n'
' if not exit(manager, *sys.exc_info()):\n'
' raise\n'
- ' finally:\n'
- ' if not hit_except:\n'
- ' exit(manager, None, None, None)\n'
+ ' else:\n'
+ ' exit(manager, None, None, None)\n'
'\n'
'With more than one item, the context managers are processed as '
'if\n'
@@ -4389,6 +4393,9 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'For more information on context managers, see Context '
'Manager Types.\n'
+ 'The "object" class itself does not provide the context '
+ 'manager\n'
+ 'methods.\n'
'\n'
'object.__enter__(self)\n'
'\n'
@@ -4658,17 +4665,20 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' This is typically used for debugging, so it is important '
'that the\n'
- ' representation is information-rich and unambiguous.\n'
+ ' representation is information-rich and unambiguous. A '
+ 'default\n'
+ ' implementation is provided by the "object" class '
+ 'itself.\n'
'\n'
'object.__str__(self)\n'
'\n'
- ' Called by "str(object)" and the built-in functions '
- '"format()" and\n'
- ' "print()" to compute the “informal” or nicely printable '
- 'string\n'
- ' representation of an object. The return value must be a '
- 'string\n'
- ' object.\n'
+ ' Called by "str(object)", the default "__format__()" '
+ 'implementation,\n'
+ ' and the built-in function "print()", to compute the '
+ '“informal” or\n'
+ ' nicely printable string representation of an object. '
+ 'The return\n'
+ ' value must be a str object.\n'
'\n'
' This method differs from "object.__repr__()" in that '
'there is no\n'
@@ -4684,7 +4694,9 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' Called by bytes to compute a byte-string representation '
'of an\n'
- ' object. This should return a "bytes" object.\n'
+ ' object. This should return a "bytes" object. The '
+ '"object" class\n'
+ ' itself does not provide this method.\n'
'\n'
'object.__format__(self, format_spec)\n'
'\n'
@@ -4712,6 +4724,11 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' The return value must be a string object.\n'
'\n'
+ ' The default implementation by the "object" class should '
+ 'be given an\n'
+ ' empty *format_spec* string. It delegates to '
+ '"__str__()".\n'
+ '\n'
' Changed in version 3.4: The __format__ method of '
'"object" itself\n'
' raises a "TypeError" if passed any non-empty string.\n'
@@ -4769,6 +4786,16 @@ topics = {'assert': 'The "assert" statement\n'
' ordering operations from a single root operation, see\n'
' "functools.total_ordering()".\n'
'\n'
+ ' By default, the "object" class provides implementations '
+ 'consistent\n'
+ ' with Value comparisons: equality compares according to '
+ 'object\n'
+ ' identity, and order comparisons raise "TypeError". Each '
+ 'default\n'
+ ' method may generate these results directly, but may also '
+ 'return\n'
+ ' "NotImplemented".\n'
+ '\n'
' See the paragraph on "__hash__()" for some important '
'notes on\n'
' creating *hashable* objects which support custom '
@@ -4855,12 +4882,13 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' User-defined classes have "__eq__()" and "__hash__()" '
'methods by\n'
- ' default; with them, all objects compare unequal (except '
- 'with\n'
- ' themselves) and "x.__hash__()" returns an appropriate '
- 'value such\n'
- ' that "x == y" implies both that "x is y" and "hash(x) == '
- 'hash(y)".\n'
+ ' default (inherited from the "object" class); with them, '
+ 'all objects\n'
+ ' compare unequal (except with themselves) and '
+ '"x.__hash__()" returns\n'
+ ' an appropriate value such that "x == y" implies both '
+ 'that "x is y"\n'
+ ' and "hash(x) == hash(y)".\n'
'\n'
' A class that overrides "__eq__()" and does not define '
'"__hash__()"\n'
@@ -4931,9 +4959,9 @@ topics = {'assert': 'The "assert" statement\n'
'the object is\n'
' considered true if its result is nonzero. If a class '
'defines\n'
- ' neither "__len__()" nor "__bool__()", all its instances '
- 'are\n'
- ' considered true.\n',
+ ' neither "__len__()" nor "__bool__()" (which is true of '
+ 'the "object"\n'
+ ' class itself), all its instances are considered true.\n',
'debugger': '"pdb" — The Python Debugger\n'
'***************************\n'
'\n'
@@ -6802,10 +6830,12 @@ topics = {'assert': 'The "assert" statement\n'
'printing fields |\n'
'| | in the form ‘+000000120’. This alignment '
'option is only |\n'
- '| | valid for numeric types. It becomes the '
- 'default for |\n'
- '| | numbers when ‘0’ immediately precedes the '
- 'field width. |\n'
+ '| | valid for numeric types, excluding "complex". '
+ 'It becomes |\n'
+ '| | the default for numbers when ‘0’ immediately '
+ 'precedes the |\n'
+ '| | field '
+ 'width. |\n'
'+-----------+------------------------------------------------------------+\n'
'| "\'^\'" | Forces the field to be centered within the '
'available |\n'
@@ -6912,9 +6942,9 @@ topics = {'assert': 'The "assert" statement\n'
'field by a\n'
'zero ("\'0\'") character enables sign-aware zero-padding '
'for numeric\n'
- 'types. This is equivalent to a *fill* character of "\'0\'" '
- 'with an\n'
- '*alignment* type of "\'=\'".\n'
+ 'types, excluding "complex". This is equivalent to a *fill* '
+ 'character\n'
+ 'of "\'0\'" with an *alignment* type of "\'=\'".\n'
'\n'
'Changed in version 3.10: Preceding the *width* field by '
'"\'0\'" no\n'
@@ -7045,12 +7075,10 @@ topics = {'assert': 'The "assert" statement\n'
'of "6" digits |\n'
' | | after the decimal point for "float", and '
'shows all |\n'
- ' | | coefficient digits for "Decimal". If no '
- 'digits follow the |\n'
- ' | | decimal point, the decimal point is also '
- 'removed unless |\n'
- ' | | the "#" option is '
- 'used. |\n'
+ ' | | coefficient digits for "Decimal". If '
+ '"p=0", the decimal |\n'
+ ' | | point is omitted unless the "#" option is '
+ 'used. |\n'
' '
'+-----------+------------------------------------------------------------+\n'
' | "\'E\'" | Scientific notation. Same as "\'e\'" '
@@ -7069,12 +7097,10 @@ topics = {'assert': 'The "assert" statement\n'
'decimal point for |\n'
' | | "float", and uses a precision large enough '
'to show all |\n'
- ' | | coefficient digits for "Decimal". If no '
- 'digits follow the |\n'
- ' | | decimal point, the decimal point is also '
- 'removed unless |\n'
- ' | | the "#" option is '
- 'used. |\n'
+ ' | | coefficient digits for "Decimal". If '
+ '"p=0", the decimal |\n'
+ ' | | point is omitted unless the "#" option is '
+ 'used. |\n'
' '
'+-----------+------------------------------------------------------------+\n'
' | "\'F\'" | Fixed-point notation. Same as "\'f\'", '
@@ -7184,6 +7210,32 @@ topics = {'assert': 'The "assert" statement\n'
' '
'+-----------+------------------------------------------------------------+\n'
'\n'
+ 'The result should be correctly rounded to a given precision '
+ '"p" of\n'
+ 'digits after the decimal point. The rounding mode for '
+ '"float" matches\n'
+ 'that of the "round()" builtin. For "Decimal", the rounding '
+ 'mode of\n'
+ 'the current context will be used.\n'
+ '\n'
+ 'The available presentation types for "complex" are the same '
+ 'as those\n'
+ 'for "float" ("\'%\'" is not allowed). Both the real and '
+ 'imaginary\n'
+ 'components of a complex number are formatted as '
+ 'floating-point\n'
+ 'numbers, according to the specified presentation type. '
+ 'They are\n'
+ 'separated by the mandatory sign of the imaginary part, the '
+ 'latter\n'
+ 'being terminated by a "j" suffix. If the presentation type '
+ 'is\n'
+ 'missing, the result will match the output of "str()" '
+ '(complex numbers\n'
+ 'with a non-zero real part are also surrounded by '
+ 'parentheses),\n'
+ 'possibly altered by other format modifiers.\n'
+ '\n'
'\n'
'Format examples\n'
'===============\n'
@@ -7577,33 +7629,17 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' global_stmt ::= "global" identifier ("," identifier)*\n'
'\n'
- 'The "global" statement is a declaration which holds for the '
- 'entire\n'
- 'current code block. It means that the listed identifiers are to '
- 'be\n'
- 'interpreted as globals. It would be impossible to assign to a '
- 'global\n'
- 'variable without "global", although free variables may refer to\n'
- 'globals without being declared global.\n'
- '\n'
- 'Names listed in a "global" statement must not be used in the same '
- 'code\n'
- 'block textually preceding that "global" statement.\n'
- '\n'
- 'Names listed in a "global" statement must not be defined as '
- 'formal\n'
- 'parameters, or as targets in "with" statements or "except" '
- 'clauses, or\n'
- 'in a "for" target list, "class" definition, function definition,\n'
- '"import" statement, or variable annotation.\n'
+ 'The "global" statement causes the listed identifiers to be '
+ 'interpreted\n'
+ 'as globals. It would be impossible to assign to a global variable\n'
+ 'without "global", although free variables may refer to globals '
+ 'without\n'
+ 'being declared global.\n'
'\n'
- '**CPython implementation detail:** The current implementation does '
- 'not\n'
- 'enforce some of these restrictions, but programs should not abuse '
- 'this\n'
- 'freedom, as future implementations may enforce them or silently '
- 'change\n'
- 'the meaning of the program.\n'
+ 'The "global" statement applies to the entire scope of a function '
+ 'or\n'
+ 'class body. A "SyntaxError" is raised if a variable is used or\n'
+ 'assigned to prior to its global declaration in the scope.\n'
'\n'
'**Programmer’s note:** "global" is a directive to the parser. It\n'
'applies only to code parsed at the same time as the "global"\n'
@@ -7690,19 +7726,16 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'Within the ASCII range (U+0001..U+007F), the valid characters '
'for\n'
- 'identifiers are the same as in Python 2.x: the uppercase and '
- 'lowercase\n'
- 'letters "A" through "Z", the underscore "_" and, except for '
- 'the first\n'
- 'character, the digits "0" through "9".\n'
- '\n'
- 'Python 3.0 introduces additional characters from outside the '
- 'ASCII\n'
- 'range (see **PEP 3131**). For these characters, the '
- 'classification\n'
- 'uses the version of the Unicode Character Database as '
- 'included in the\n'
- '"unicodedata" module.\n'
+ 'identifiers include the uppercase and lowercase letters "A" '
+ 'through\n'
+ '"Z", the underscore "_" and, except for the first character, '
+ 'the\n'
+ 'digits "0" through "9". Python 3.0 introduced additional '
+ 'characters\n'
+ 'from outside the ASCII range (see **PEP 3131**). For these\n'
+ 'characters, the classification uses the version of the '
+ 'Unicode\n'
+ 'Character Database as included in the "unicodedata" module.\n'
'\n'
'Identifiers are unlimited in length. Case is significant.\n'
'\n'
@@ -8666,8 +8699,8 @@ topics = {'assert': 'The "assert" statement\n'
'scope,\n'
'or if there is no nonlocal scope, a "SyntaxError" is raised.\n'
'\n'
- 'The nonlocal statement applies to the entire scope of a function '
- 'or\n'
+ 'The "nonlocal" statement applies to the entire scope of a '
+ 'function or\n'
'class body. A "SyntaxError" is raised if a variable is used or\n'
'assigned to prior to its nonlocal declaration in the scope.\n'
'\n'
@@ -9425,56 +9458,58 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'The following methods can be defined to implement '
'container objects.\n'
- 'Containers usually are *sequences* (such as "lists" or '
- '"tuples") or\n'
- '*mappings* (like "dictionaries"), but can represent other '
- 'containers\n'
- 'as well. The first set of methods is used either to '
- 'emulate a\n'
- 'sequence or to emulate a mapping; the difference is that '
- 'for a\n'
- 'sequence, the allowable keys should be the integers *k* '
- 'for which "0\n'
- '<= k < N" where *N* is the length of the sequence, or '
- '"slice" objects,\n'
- 'which define a range of items. It is also recommended '
- 'that mappings\n'
- 'provide the methods "keys()", "values()", "items()", '
- '"get()",\n'
- '"clear()", "setdefault()", "pop()", "popitem()", "copy()", '
+ 'None of them are provided by the "object" class itself. '
+ 'Containers\n'
+ 'usually are *sequences* (such as "lists" or "tuples") or '
+ '*mappings*\n'
+ '(like *dictionaries*), but can represent other containers '
+ 'as well.\n'
+ 'The first set of methods is used either to emulate a '
+ 'sequence or to\n'
+ 'emulate a mapping; the difference is that for a sequence, '
+ 'the\n'
+ 'allowable keys should be the integers *k* for which "0 <= '
+ 'k < N" where\n'
+ '*N* is the length of the sequence, or "slice" objects, '
+ 'which define a\n'
+ 'range of items. It is also recommended that mappings '
+ 'provide the\n'
+ 'methods "keys()", "values()", "items()", "get()", '
+ '"clear()",\n'
+ '"setdefault()", "pop()", "popitem()", "copy()", and '
+ '"update()"\n'
+ 'behaving similar to those for Python’s standard '
+ '"dictionary" objects.\n'
+ 'The "collections.abc" module provides a "MutableMapping" '
+ '*abstract\n'
+ 'base class* to help create those methods from a base set '
+ 'of\n'
+ '"__getitem__()", "__setitem__()", "__delitem__()", and '
+ '"keys()".\n'
+ 'Mutable sequences should provide methods "append()", '
+ '"count()",\n'
+ '"index()", "extend()", "insert()", "pop()", "remove()", '
+ '"reverse()"\n'
+ 'and "sort()", like Python standard "list" objects. '
+ 'Finally, sequence\n'
+ 'types should implement addition (meaning concatenation) '
'and\n'
- '"update()" behaving similar to those for Python’s '
- 'standard\n'
- '"dictionary" objects. The "collections.abc" module '
- 'provides a\n'
- '"MutableMapping" *abstract base class* to help create '
- 'those methods\n'
- 'from a base set of "__getitem__()", "__setitem__()", '
- '"__delitem__()",\n'
- 'and "keys()". Mutable sequences should provide methods '
- '"append()",\n'
- '"count()", "index()", "extend()", "insert()", "pop()", '
- '"remove()",\n'
- '"reverse()" and "sort()", like Python standard "list" '
- 'objects.\n'
- 'Finally, sequence types should implement addition '
- '(meaning\n'
- 'concatenation) and multiplication (meaning repetition) by '
- 'defining the\n'
- 'methods "__add__()", "__radd__()", "__iadd__()", '
- '"__mul__()",\n'
- '"__rmul__()" and "__imul__()" described below; they should '
- 'not define\n'
- 'other numerical operators. It is recommended that both '
- 'mappings and\n'
- 'sequences implement the "__contains__()" method to allow '
- 'efficient use\n'
- 'of the "in" operator; for mappings, "in" should search the '
- 'mapping’s\n'
- 'keys; for sequences, it should search through the values. '
- 'It is\n'
- 'further recommended that both mappings and sequences '
- 'implement the\n'
+ 'multiplication (meaning repetition) by defining the '
+ 'methods\n'
+ '"__add__()", "__radd__()", "__iadd__()", "__mul__()", '
+ '"__rmul__()" and\n'
+ '"__imul__()" described below; they should not define other '
+ 'numerical\n'
+ 'operators. It is recommended that both mappings and '
+ 'sequences\n'
+ 'implement the "__contains__()" method to allow efficient '
+ 'use of the\n'
+ '"in" operator; for mappings, "in" should search the '
+ 'mapping’s keys;\n'
+ 'for sequences, it should search through the values. It is '
+ 'further\n'
+ 'recommended that both mappings and sequences implement '
+ 'the\n'
'"__iter__()" method to allow efficient iteration through '
'the\n'
'container; for mappings, "__iter__()" should iterate '
@@ -10014,17 +10049,19 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' This is typically used for debugging, so it is important '
'that the\n'
- ' representation is information-rich and unambiguous.\n'
+ ' representation is information-rich and unambiguous. A '
+ 'default\n'
+ ' implementation is provided by the "object" class itself.\n'
'\n'
'object.__str__(self)\n'
'\n'
- ' Called by "str(object)" and the built-in functions '
- '"format()" and\n'
- ' "print()" to compute the “informal” or nicely printable '
- 'string\n'
- ' representation of an object. The return value must be a '
- 'string\n'
- ' object.\n'
+ ' Called by "str(object)", the default "__format__()" '
+ 'implementation,\n'
+ ' and the built-in function "print()", to compute the '
+ '“informal” or\n'
+ ' nicely printable string representation of an object. The '
+ 'return\n'
+ ' value must be a str object.\n'
'\n'
' This method differs from "object.__repr__()" in that '
'there is no\n'
@@ -10040,7 +10077,9 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' Called by bytes to compute a byte-string representation '
'of an\n'
- ' object. This should return a "bytes" object.\n'
+ ' object. This should return a "bytes" object. The "object" '
+ 'class\n'
+ ' itself does not provide this method.\n'
'\n'
'object.__format__(self, format_spec)\n'
'\n'
@@ -10068,6 +10107,10 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' The return value must be a string object.\n'
'\n'
+ ' The default implementation by the "object" class should '
+ 'be given an\n'
+ ' empty *format_spec* string. It delegates to "__str__()".\n'
+ '\n'
' Changed in version 3.4: The __format__ method of "object" '
'itself\n'
' raises a "TypeError" if passed any non-empty string.\n'
@@ -10125,6 +10168,16 @@ topics = {'assert': 'The "assert" statement\n'
' ordering operations from a single root operation, see\n'
' "functools.total_ordering()".\n'
'\n'
+ ' By default, the "object" class provides implementations '
+ 'consistent\n'
+ ' with Value comparisons: equality compares according to '
+ 'object\n'
+ ' identity, and order comparisons raise "TypeError". Each '
+ 'default\n'
+ ' method may generate these results directly, but may also '
+ 'return\n'
+ ' "NotImplemented".\n'
+ '\n'
' See the paragraph on "__hash__()" for some important '
'notes on\n'
' creating *hashable* objects which support custom '
@@ -10210,12 +10263,13 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' User-defined classes have "__eq__()" and "__hash__()" '
'methods by\n'
- ' default; with them, all objects compare unequal (except '
- 'with\n'
- ' themselves) and "x.__hash__()" returns an appropriate '
- 'value such\n'
- ' that "x == y" implies both that "x is y" and "hash(x) == '
- 'hash(y)".\n'
+ ' default (inherited from the "object" class); with them, '
+ 'all objects\n'
+ ' compare unequal (except with themselves) and '
+ '"x.__hash__()" returns\n'
+ ' an appropriate value such that "x == y" implies both that '
+ '"x is y"\n'
+ ' and "hash(x) == hash(y)".\n'
'\n'
' A class that overrides "__eq__()" and does not define '
'"__hash__()"\n'
@@ -10284,9 +10338,9 @@ topics = {'assert': 'The "assert" statement\n'
'object is\n'
' considered true if its result is nonzero. If a class '
'defines\n'
- ' neither "__len__()" nor "__bool__()", all its instances '
- 'are\n'
- ' considered true.\n'
+ ' neither "__len__()" nor "__bool__()" (which is true of '
+ 'the "object"\n'
+ ' class itself), all its instances are considered true.\n'
'\n'
'\n'
'Customizing attribute access\n'
@@ -10310,7 +10364,8 @@ topics = {'assert': 'The "assert" statement\n'
'either\n'
' return the (computed) attribute value or raise an '
'"AttributeError"\n'
- ' exception.\n'
+ ' exception. The "object" class itself does not provide '
+ 'this method.\n'
'\n'
' Note that if the attribute is found through the normal '
'mechanism,\n'
@@ -10490,7 +10545,9 @@ topics = {'assert': 'The "assert" statement\n'
'parents). In the\n'
'examples below, “the attribute” refers to the attribute '
'whose name is\n'
- 'the key of the property in the owner class’ "__dict__".\n'
+ 'the key of the property in the owner class’ "__dict__". The '
+ '"object"\n'
+ 'class itself does not implement any of these protocols.\n'
'\n'
'object.__get__(self, instance, owner=None)\n'
'\n'
@@ -11373,7 +11430,9 @@ topics = {'assert': 'The "assert" statement\n'
' Called when the instance is “called” as a function; if '
'this method\n'
' is defined, "x(arg1, arg2, ...)" roughly translates to\n'
- ' "type(x).__call__(x, arg1, ...)".\n'
+ ' "type(x).__call__(x, arg1, ...)". The "object" class '
+ 'itself does\n'
+ ' not provide this method.\n'
'\n'
'\n'
'Emulating container types\n'
@@ -11381,54 +11440,54 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'The following methods can be defined to implement container '
'objects.\n'
- 'Containers usually are *sequences* (such as "lists" or '
- '"tuples") or\n'
- '*mappings* (like "dictionaries"), but can represent other '
- 'containers\n'
- 'as well. The first set of methods is used either to emulate '
- 'a\n'
- 'sequence or to emulate a mapping; the difference is that for '
- 'a\n'
- 'sequence, the allowable keys should be the integers *k* for '
- 'which "0\n'
- '<= k < N" where *N* is the length of the sequence, or '
- '"slice" objects,\n'
- 'which define a range of items. It is also recommended that '
- 'mappings\n'
- 'provide the methods "keys()", "values()", "items()", '
- '"get()",\n'
- '"clear()", "setdefault()", "pop()", "popitem()", "copy()", '
- 'and\n'
- '"update()" behaving similar to those for Python’s standard\n'
- '"dictionary" objects. The "collections.abc" module provides '
- 'a\n'
- '"MutableMapping" *abstract base class* to help create those '
- 'methods\n'
- 'from a base set of "__getitem__()", "__setitem__()", '
- '"__delitem__()",\n'
- 'and "keys()". Mutable sequences should provide methods '
- '"append()",\n'
- '"count()", "index()", "extend()", "insert()", "pop()", '
- '"remove()",\n'
- '"reverse()" and "sort()", like Python standard "list" '
+ 'None of them are provided by the "object" class itself. '
+ 'Containers\n'
+ 'usually are *sequences* (such as "lists" or "tuples") or '
+ '*mappings*\n'
+ '(like *dictionaries*), but can represent other containers as '
+ 'well.\n'
+ 'The first set of methods is used either to emulate a '
+ 'sequence or to\n'
+ 'emulate a mapping; the difference is that for a sequence, '
+ 'the\n'
+ 'allowable keys should be the integers *k* for which "0 <= k '
+ '< N" where\n'
+ '*N* is the length of the sequence, or "slice" objects, which '
+ 'define a\n'
+ 'range of items. It is also recommended that mappings '
+ 'provide the\n'
+ 'methods "keys()", "values()", "items()", "get()", '
+ '"clear()",\n'
+ '"setdefault()", "pop()", "popitem()", "copy()", and '
+ '"update()"\n'
+ 'behaving similar to those for Python’s standard "dictionary" '
'objects.\n'
- 'Finally, sequence types should implement addition (meaning\n'
- 'concatenation) and multiplication (meaning repetition) by '
- 'defining the\n'
- 'methods "__add__()", "__radd__()", "__iadd__()", '
- '"__mul__()",\n'
- '"__rmul__()" and "__imul__()" described below; they should '
- 'not define\n'
- 'other numerical operators. It is recommended that both '
- 'mappings and\n'
- 'sequences implement the "__contains__()" method to allow '
- 'efficient use\n'
- 'of the "in" operator; for mappings, "in" should search the '
- 'mapping’s\n'
- 'keys; for sequences, it should search through the values. '
- 'It is\n'
- 'further recommended that both mappings and sequences '
- 'implement the\n'
+ 'The "collections.abc" module provides a "MutableMapping" '
+ '*abstract\n'
+ 'base class* to help create those methods from a base set of\n'
+ '"__getitem__()", "__setitem__()", "__delitem__()", and '
+ '"keys()".\n'
+ 'Mutable sequences should provide methods "append()", '
+ '"count()",\n'
+ '"index()", "extend()", "insert()", "pop()", "remove()", '
+ '"reverse()"\n'
+ 'and "sort()", like Python standard "list" objects. Finally, '
+ 'sequence\n'
+ 'types should implement addition (meaning concatenation) and\n'
+ 'multiplication (meaning repetition) by defining the methods\n'
+ '"__add__()", "__radd__()", "__iadd__()", "__mul__()", '
+ '"__rmul__()" and\n'
+ '"__imul__()" described below; they should not define other '
+ 'numerical\n'
+ 'operators. It is recommended that both mappings and '
+ 'sequences\n'
+ 'implement the "__contains__()" method to allow efficient use '
+ 'of the\n'
+ '"in" operator; for mappings, "in" should search the '
+ 'mapping’s keys;\n'
+ 'for sequences, it should search through the values. It is '
+ 'further\n'
+ 'recommended that both mappings and sequences implement the\n'
'"__iter__()" method to allow efficient iteration through '
'the\n'
'container; for mappings, "__iter__()" should iterate through '
@@ -11844,6 +11903,9 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'For more information on context managers, see Context '
'Manager Types.\n'
+ 'The "object" class itself does not provide the context '
+ 'manager\n'
+ 'methods.\n'
'\n'
'object.__enter__(self)\n'
'\n'
@@ -14348,43 +14410,254 @@ topics = {'assert': 'The "assert" statement\n'
'e.g.,\n'
'"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n'
'\n'
- 'Predefined (writable) attributes:\n'
'\n'
- ' "__name__"\n'
- ' The module’s name.\n'
+ 'Import-related attributes on module objects\n'
+ '-------------------------------------------\n'
+ '\n'
+ 'Module objects have the following attributes that relate to the '
+ 'import\n'
+ 'system. When a module is created using the machinery associated '
+ 'with\n'
+ 'the import system, these attributes are filled in based on the\n'
+ 'module’s *spec*, before the *loader* executes and loads the '
+ 'module.\n'
+ '\n'
+ 'To create a module dynamically rather than using the import '
+ 'system,\n'
+ 'it’s recommended to use "importlib.util.module_from_spec()", which\n'
+ 'will set the various import-controlled attributes to appropriate\n'
+ 'values. It’s also possible to use the "types.ModuleType" '
+ 'constructor\n'
+ 'to create modules directly, but this technique is more error-prone, '
+ 'as\n'
+ 'most attributes must be manually set on the module object after it '
+ 'has\n'
+ 'been created when using this approach.\n'
+ '\n'
+ 'Caution:\n'
+ '\n'
+ ' With the exception of "__name__", it is **strongly** recommended\n'
+ ' that you rely on "__spec__" and its attributes instead of any of '
+ 'the\n'
+ ' other individual attributes listed in this subsection. Note that\n'
+ ' updating an attribute on "__spec__" will not update the\n'
+ ' corresponding attribute on the module itself:\n'
+ '\n'
+ ' >>> import typing\n'
+ ' >>> typing.__name__, typing.__spec__.name\n'
+ " ('typing', 'typing')\n"
+ " >>> typing.__spec__.name = 'spelling'\n"
+ ' >>> typing.__name__, typing.__spec__.name\n'
+ " ('typing', 'spelling')\n"
+ " >>> typing.__name__ = 'keyboard_smashing'\n"
+ ' >>> typing.__name__, typing.__spec__.name\n'
+ " ('keyboard_smashing', 'spelling')\n"
+ '\n'
+ 'module.__name__\n'
+ '\n'
+ ' The name used to uniquely identify the module in the import '
+ 'system.\n'
+ ' For a directly executed module, this will be set to '
+ '""__main__"".\n'
+ '\n'
+ ' This attribute must be set to the fully qualified name of the\n'
+ ' module. It is expected to match the value of\n'
+ ' "module.__spec__.name".\n'
+ '\n'
+ 'module.__spec__\n'
+ '\n'
+ ' A record of the module’s import-system-related state.\n'
+ '\n'
+ ' Set to the "module spec" that was used when importing the '
+ 'module.\n'
+ ' See Module specs for more details.\n'
+ '\n'
+ ' Added in version 3.4.\n'
+ '\n'
+ 'module.__package__\n'
+ '\n'
+ ' The *package* a module belongs to.\n'
+ '\n'
+ ' If the module is top-level (that is, not a part of any specific\n'
+ ' package) then the attribute should be set to "\'\'" (the empty\n'
+ ' string). Otherwise, it should be set to the name of the '
+ 'module’s\n'
+ ' package (which can be equal to "module.__name__" if the module\n'
+ ' itself is a package). See **PEP 366** for further details.\n'
+ '\n'
+ ' This attribute is used instead of "__name__" to calculate '
+ 'explicit\n'
+ ' relative imports for main modules. It defaults to "None" for\n'
+ ' modules created dynamically using the "types.ModuleType"\n'
+ ' constructor; use "importlib.util.module_from_spec()" instead to\n'
+ ' ensure the attribute is set to a "str".\n'
+ '\n'
+ ' It is **strongly** recommended that you use\n'
+ ' "module.__spec__.parent" instead of "module.__package__".\n'
+ ' "__package__" is now only used as a fallback if '
+ '"__spec__.parent"\n'
+ ' is not set, and this fallback path is deprecated.\n'
+ '\n'
+ ' Changed in version 3.4: This attribute now defaults to "None" '
+ 'for\n'
+ ' modules created dynamically using the "types.ModuleType"\n'
+ ' constructor. Previously the attribute was optional.\n'
+ '\n'
+ ' Changed in version 3.6: The value of "__package__" is expected '
+ 'to\n'
+ ' be the same as "__spec__.parent". "__package__" is now only used '
+ 'as\n'
+ ' a fallback during import resolution if "__spec__.parent" is not\n'
+ ' defined.\n'
+ '\n'
+ ' Changed in version 3.10: "ImportWarning" is raised if an import\n'
+ ' resolution falls back to "__package__" instead of\n'
+ ' "__spec__.parent".\n'
+ '\n'
+ ' Changed in version 3.12: Raise "DeprecationWarning" instead of\n'
+ ' "ImportWarning" when falling back to "__package__" during '
+ 'import\n'
+ ' resolution.\n'
+ '\n'
+ 'module.__loader__\n'
'\n'
- ' "__doc__"\n'
- ' The module’s documentation string, or "None" if unavailable.\n'
+ ' The *loader* object that the import machinery used to load the\n'
+ ' module.\n'
+ '\n'
+ ' This attribute is mostly useful for introspection, but can be '
+ 'used\n'
+ ' for additional loader-specific functionality, for example '
+ 'getting\n'
+ ' data associated with a loader.\n'
+ '\n'
+ ' "__loader__" defaults to "None" for modules created dynamically\n'
+ ' using the "types.ModuleType" constructor; use\n'
+ ' "importlib.util.module_from_spec()" instead to ensure the '
+ 'attribute\n'
+ ' is set to a *loader* object.\n'
'\n'
- ' "__file__"\n'
- ' The pathname of the file from which the module was loaded, if '
- 'it\n'
- ' was loaded from a file. The "__file__" attribute may be '
- 'missing\n'
- ' for certain types of modules, such as C modules that are\n'
- ' statically linked into the interpreter. For extension '
+ ' It is **strongly** recommended that you use\n'
+ ' "module.__spec__.loader" instead of "module.__loader__".\n'
+ '\n'
+ ' Changed in version 3.4: This attribute now defaults to "None" '
+ 'for\n'
+ ' modules created dynamically using the "types.ModuleType"\n'
+ ' constructor. Previously the attribute was optional.\n'
+ '\n'
+ ' Deprecated since version 3.12, will be removed in version 3.16:\n'
+ ' Setting "__loader__" on a module while failing to set\n'
+ ' "__spec__.loader" is deprecated. In Python 3.16, "__loader__" '
+ 'will\n'
+ ' cease to be set or taken into consideration by the import system '
+ 'or\n'
+ ' the standard library.\n'
+ '\n'
+ 'module.__path__\n'
+ '\n'
+ ' A (possibly empty) *sequence* of strings enumerating the '
+ 'locations\n'
+ ' where the package’s submodules will be found. Non-package '
'modules\n'
- ' loaded dynamically from a shared library, it’s the pathname '
- 'of\n'
- ' the shared library file.\n'
+ ' should not have a "__path__" attribute. See __path__ attributes '
+ 'on\n'
+ ' modules for more details.\n'
+ '\n'
+ ' It is **strongly** recommended that you use\n'
+ ' "module.__spec__.submodule_search_locations" instead of\n'
+ ' "module.__path__".\n'
+ '\n'
+ 'module.__file__\n'
+ '\n'
+ 'module.__cached__\n'
+ '\n'
+ ' "__file__" and "__cached__" are both optional attributes that '
+ 'may\n'
+ ' or may not be set. Both attributes should be a "str" when they '
+ 'are\n'
+ ' available.\n'
+ '\n'
+ ' "__file__" indicates the pathname of the file from which the '
+ 'module\n'
+ ' was loaded (if loaded from a file), or the pathname of the '
+ 'shared\n'
+ ' library file for extension modules loaded dynamically from a '
+ 'shared\n'
+ ' library. It might be missing for certain types of modules, such '
+ 'as\n'
+ ' C modules that are statically linked into the interpreter, and '
+ 'the\n'
+ ' import system may opt to leave it unset if it has no semantic\n'
+ ' meaning (for example, a module loaded from a database).\n'
+ '\n'
+ ' If "__file__" is set then the "__cached__" attribute might also '
+ 'be\n'
+ ' set, which is the path to any compiled version of the code '
+ '(for\n'
+ ' example, a byte-compiled file). The file does not need to exist '
+ 'to\n'
+ ' set this attribute; the path can simply point to where the '
+ 'compiled\n'
+ ' file *would* exist (see **PEP 3147**).\n'
+ '\n'
+ ' Note that "__cached__" may be set even if "__file__" is not '
+ 'set.\n'
+ ' However, that scenario is quite atypical. Ultimately, the '
+ '*loader*\n'
+ ' is what makes use of the module spec provided by the *finder* '
+ '(from\n'
+ ' which "__file__" and "__cached__" are derived). So if a loader '
+ 'can\n'
+ ' load from a cached module but otherwise does not load from a '
+ 'file,\n'
+ ' that atypical scenario may be appropriate.\n'
+ '\n'
+ ' It is **strongly** recommended that you use\n'
+ ' "module.__spec__.cached" instead of "module.__cached__".\n'
+ '\n'
+ '\n'
+ 'Other writable attributes on module objects\n'
+ '-------------------------------------------\n'
+ '\n'
+ 'As well as the import-related attributes listed above, module '
+ 'objects\n'
+ 'also have the following writable attributes:\n'
+ '\n'
+ 'module.__doc__\n'
+ '\n'
+ ' The module’s documentation string, or "None" if unavailable. '
+ 'See\n'
+ ' also: "__doc__ attributes".\n'
'\n'
- ' "__annotations__"\n'
- ' A dictionary containing *variable annotations* collected '
- 'during\n'
- ' module body execution. For best practices on working with\n'
- ' "__annotations__", please see Annotations Best Practices.\n'
+ 'module.__annotations__\n'
'\n'
- 'Special read-only attribute: "__dict__" is the module’s namespace '
- 'as a\n'
- 'dictionary object.\n'
+ ' A dictionary containing *variable annotations* collected during\n'
+ ' module body execution. For best practices on working with\n'
+ ' "__annotations__", please see Annotations Best Practices.\n'
'\n'
- '**CPython implementation detail:** Because of the way CPython '
- 'clears\n'
- 'module dictionaries, the module dictionary will be cleared when '
+ '\n'
+ 'Module dictionaries\n'
+ '-------------------\n'
+ '\n'
+ 'Module objects also have the following special read-only '
+ 'attribute:\n'
+ '\n'
+ 'module.__dict__\n'
+ '\n'
+ ' The module’s namespace as a dictionary object. Uniquely among '
+ 'the\n'
+ ' attributes listed here, "__dict__" cannot be accessed as a '
+ 'global\n'
+ ' variable from within a module; it can only be accessed as an\n'
+ ' attribute on module objects.\n'
+ '\n'
+ ' **CPython implementation detail:** Because of the way CPython\n'
+ ' clears module dictionaries, the module dictionary will be '
+ 'cleared\n'
+ ' when the module falls out of scope even if the dictionary still '
+ 'has\n'
+ ' live references. To avoid this, copy the dictionary or keep '
'the\n'
- 'module falls out of scope even if the dictionary still has live\n'
- 'references. To avoid this, copy the dictionary or keep the module\n'
- 'around while using its dictionary directly.\n'
+ ' module around while using its dictionary directly.\n'
'\n'
'\n'
'Custom classes\n'
@@ -14719,7 +14992,7 @@ topics = {'assert': 'The "assert" statement\n'
'| | version '
'3.12: This attribute of code objects is |\n'
'| | deprecated, '
- 'and may be removed in Python 3.14. |\n'
+ 'and may be removed in Python 3.15. |\n'
'+----------------------------------------------------+----------------------------------------------------+\n'
'| codeobject.co_stacksize | The required '
'stack size of the code object |\n'
@@ -15174,21 +15447,23 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
' If no positional argument is given, an empty dictionary '
'is created.\n'
- ' If a positional argument is given and it is a mapping '
- 'object, a\n'
- ' dictionary is created with the same key-value pairs as '
- 'the mapping\n'
- ' object. Otherwise, the positional argument must be an '
- '*iterable*\n'
- ' object. Each item in the iterable must itself be an '
- 'iterable with\n'
- ' exactly two objects. The first object of each item '
- 'becomes a key\n'
- ' in the new dictionary, and the second object the '
- 'corresponding\n'
- ' value. If a key occurs more than once, the last value '
- 'for that key\n'
- ' becomes the corresponding value in the new dictionary.\n'
+ ' If a positional argument is given and it defines a '
+ '"keys()" method,\n'
+ ' a dictionary is created by calling "__getitem__()" on the '
+ 'argument\n'
+ ' with each returned key from the method. Otherwise, the '
+ 'positional\n'
+ ' argument must be an *iterable* object. Each item in the '
+ 'iterable\n'
+ ' must itself be an iterable with exactly two elements. '
+ 'The first\n'
+ ' element of each item becomes a key in the new dictionary, '
+ 'and the\n'
+ ' second element the corresponding value. If a key occurs '
+ 'more than\n'
+ ' once, the last value for that key becomes the '
+ 'corresponding value\n'
+ ' in the new dictionary.\n'
'\n'
' If keyword arguments are given, the keyword arguments and '
'their\n'
@@ -15383,15 +15658,17 @@ topics = {'assert': 'The "assert" statement\n'
'*other*,\n'
' overwriting existing keys. Return "None".\n'
'\n'
- ' "update()" accepts either another dictionary object or '
- 'an\n'
- ' iterable of key/value pairs (as tuples or other '
- 'iterables of\n'
- ' length two). If keyword arguments are specified, the '
- 'dictionary\n'
- ' is then updated with those key/value pairs: '
- '"d.update(red=1,\n'
- ' blue=2)".\n'
+ ' "update()" accepts either another object with a '
+ '"keys()" method\n'
+ ' (in which case "__getitem__()" is called with every '
+ 'key returned\n'
+ ' from the method) or an iterable of key/value pairs (as '
+ 'tuples or\n'
+ ' other iterables of length two). If keyword arguments '
+ 'are\n'
+ ' specified, the dictionary is then updated with those '
+ 'key/value\n'
+ ' pairs: "d.update(red=1, blue=2)".\n'
'\n'
' values()\n'
'\n'
@@ -16699,18 +16976,15 @@ topics = {'assert': 'The "assert" statement\n'
' enter = type(manager).__enter__\n'
' exit = type(manager).__exit__\n'
' value = enter(manager)\n'
- ' hit_except = False\n'
'\n'
' try:\n'
' TARGET = value\n'
' SUITE\n'
' except:\n'
- ' hit_except = True\n'
' if not exit(manager, *sys.exc_info()):\n'
' raise\n'
- ' finally:\n'
- ' if not hit_except:\n'
- ' exit(manager, None, None, None)\n'
+ ' else:\n'
+ ' exit(manager, None, None, None)\n'
'\n'
'With more than one item, the context managers are processed as if\n'
'multiple "with" statements were nested:\n'
@@ -16751,7 +17025,8 @@ topics = {'assert': 'The "assert" statement\n'
'\n'
'A "yield" statement is semantically equivalent to a yield '
'expression.\n'
- 'The yield statement can be used to omit the parentheses that would\n'
+ 'The "yield" statement can be used to omit the parentheses that '
+ 'would\n'
'otherwise be required in the equivalent yield expression '
'statement.\n'
'For example, the yield statements\n'
@@ -16767,10 +17042,9 @@ topics = {'assert': 'The "assert" statement\n'
'Yield expressions and statements are only used when defining a\n'
'*generator* function, and are only used in the body of the '
'generator\n'
- 'function. Using yield in a function definition is sufficient to '
- 'cause\n'
- 'that definition to create a generator function instead of a normal\n'
- 'function.\n'
+ 'function. Using "yield" in a function definition is sufficient to\n'
+ 'cause that definition to create a generator function instead of a\n'
+ 'normal function.\n'
'\n'
'For full details of "yield" semantics, refer to the Yield '
'expressions\n'
diff --git a/contrib/tools/python3/Lib/re/_compiler.py b/contrib/tools/python3/Lib/re/_compiler.py
index 285c21936f2..bb97f9fdd10 100644
--- a/contrib/tools/python3/Lib/re/_compiler.py
+++ b/contrib/tools/python3/Lib/re/_compiler.py
@@ -250,11 +250,11 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):
while True:
try:
if op is LITERAL:
- if fixup:
- lo = fixup(av)
- charmap[lo] = 1
- if fixes and lo in fixes:
- for k in fixes[lo]:
+ if fixup: # IGNORECASE and not LOCALE
+ av = fixup(av)
+ charmap[av] = 1
+ if fixes and av in fixes:
+ for k in fixes[av]:
charmap[k] = 1
if not hascased and iscased(av):
hascased = True
@@ -262,7 +262,7 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):
charmap[av] = 1
elif op is RANGE:
r = range(av[0], av[1]+1)
- if fixup:
+ if fixup: # IGNORECASE and not LOCALE
if fixes:
for i in map(fixup, r):
charmap[i] = 1
@@ -289,8 +289,7 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):
# Character set contains non-BMP character codes.
# For range, all BMP characters in the range are already
# proceeded.
- if fixup:
- hascased = True
+ if fixup: # IGNORECASE and not LOCALE
# For now, IN_UNI_IGNORE+LITERAL and
# IN_UNI_IGNORE+RANGE_UNI_IGNORE work for all non-BMP
# characters, because two characters (at least one of
@@ -301,7 +300,13 @@ def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):
# Also, both c.lower() and c.lower().upper() are single
# characters for every non-BMP character.
if op is RANGE:
- op = RANGE_UNI_IGNORE
+ if fixes: # not ASCII
+ op = RANGE_UNI_IGNORE
+ hascased = True
+ else:
+ assert op is LITERAL
+ if not hascased and iscased(av):
+ hascased = True
tail.append((op, av))
break
diff --git a/contrib/tools/python3/Lib/reprlib.py b/contrib/tools/python3/Lib/reprlib.py
index a7b37630a4e..85c1b94a0ea 100644
--- a/contrib/tools/python3/Lib/reprlib.py
+++ b/contrib/tools/python3/Lib/reprlib.py
@@ -35,6 +35,17 @@ def recursive_repr(fillvalue='...'):
return decorating_function
class Repr:
+ _lookup = {
+ 'tuple': 'builtins',
+ 'list': 'builtins',
+ 'array': 'array',
+ 'set': 'builtins',
+ 'frozenset': 'builtins',
+ 'deque': 'collections',
+ 'dict': 'builtins',
+ 'str': 'builtins',
+ 'int': 'builtins'
+ }
def __init__(
self, *, maxlevel=6, maxtuple=6, maxlist=6, maxarray=5, maxdict=4,
@@ -59,14 +70,24 @@ class Repr:
return self.repr1(x, self.maxlevel)
def repr1(self, x, level):
- typename = type(x).__name__
+ cls = type(x)
+ typename = cls.__name__
+
if ' ' in typename:
parts = typename.split()
typename = '_'.join(parts)
- if hasattr(self, 'repr_' + typename):
- return getattr(self, 'repr_' + typename)(x, level)
- else:
- return self.repr_instance(x, level)
+
+ method = getattr(self, 'repr_' + typename, None)
+ if method:
+ # not defined in this class
+ if typename not in self._lookup:
+ return method(x, level)
+ module = getattr(cls, '__module__', None)
+ # defined in this class and is the module intended
+ if module == self._lookup[typename]:
+ return method(x, level)
+
+ return self.repr_instance(x, level)
def _join(self, pieces, level):
if self.indent is None:
diff --git a/contrib/tools/python3/Lib/shutil.py b/contrib/tools/python3/Lib/shutil.py
index 20ad1cb5684..2d285691289 100644
--- a/contrib/tools/python3/Lib/shutil.py
+++ b/contrib/tools/python3/Lib/shutil.py
@@ -1534,21 +1534,21 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
if sys.platform == "win32":
# PATHEXT is necessary to check on Windows.
pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT
- pathext = [ext for ext in pathext_source.split(os.pathsep) if ext]
+ pathext = pathext_source.split(os.pathsep)
+ pathext = [ext.rstrip('.') for ext in pathext if ext]
if use_bytes:
pathext = [os.fsencode(ext) for ext in pathext]
- files = ([cmd] + [cmd + ext for ext in pathext])
+ files = [cmd + ext for ext in pathext]
- # gh-109590. If we are looking for an executable, we need to look
- # for a PATHEXT match. The first cmd is the direct match
- # (e.g. python.exe instead of python)
- # Check that direct match first if and only if the extension is in PATHEXT
- # Otherwise check it last
- suffix = os.path.splitext(files[0])[1].upper()
- if mode & os.X_OK and not any(suffix == ext.upper() for ext in pathext):
- files.append(files.pop(0))
+ # If X_OK in mode, simulate the cmd.exe behavior: look at direct
+ # match if and only if the extension is in PATHEXT.
+ # If X_OK not in mode, simulate the first result of where.exe:
+ # always look at direct match before a PATHEXT match.
+ normcmd = cmd.upper()
+ if not (mode & os.X_OK) or any(normcmd.endswith(ext.upper()) for ext in pathext):
+ files.insert(0, cmd)
else:
# On other platforms you don't have things like PATHEXT to tell you
# what file suffixes are executable, so just pass on cmd as-is.
@@ -1557,7 +1557,7 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None):
seen = set()
for dir in path:
normdir = os.path.normcase(dir)
- if not normdir in seen:
+ if normdir not in seen:
seen.add(normdir)
for thefile in files:
name = os.path.join(dir, thefile)
diff --git a/contrib/tools/python3/Lib/site.py b/contrib/tools/python3/Lib/site.py
index a2ef1bbacd0..5eeec5100f2 100644
--- a/contrib/tools/python3/Lib/site.py
+++ b/contrib/tools/python3/Lib/site.py
@@ -426,8 +426,9 @@ def setcopyright():
"""Set 'copyright' and 'credits' in builtins"""
builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
builtins.credits = _sitebuiltins._Printer("credits", """\
- Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
- for supporting Python development. See www.python.org for more information.""")
+ Thanks to CWI, CNRI, BeOpen, Zope Corporation, the Python Software
+ Foundation, and a cast of thousands for supporting Python
+ development. See www.python.org for more information.""")
files, dirs = [], []
# Not all modules are required to have a __file__ attribute. See
# PEP 420 for more details.
diff --git a/contrib/tools/python3/Lib/sysconfig.py b/contrib/tools/python3/Lib/sysconfig.py
index 4fd5fbaab59..9bb81e7842c 100644
--- a/contrib/tools/python3/Lib/sysconfig.py
+++ b/contrib/tools/python3/Lib/sysconfig.py
@@ -169,9 +169,7 @@ _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
_PY_VERSION = sys.version.split()[0]
_PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}'
_PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}'
-_PREFIX = os.path.normpath(sys.prefix)
_BASE_PREFIX = os.path.normpath(sys.base_prefix)
-_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
# Mutex guarding initialization of _CONFIG_VARS.
_CONFIG_VARS_LOCK = threading.RLock()
@@ -642,8 +640,10 @@ def _init_config_vars():
# Normalized versions of prefix and exec_prefix are handy to have;
# in fact, these are the standard versions used most places in the
# Distutils.
- _CONFIG_VARS['prefix'] = _PREFIX
- _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
+ _PREFIX = os.path.normpath(sys.prefix)
+ _EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
+ _CONFIG_VARS['prefix'] = _PREFIX # FIXME: This gets overwriten by _init_posix.
+ _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX # FIXME: This gets overwriten by _init_posix.
_CONFIG_VARS['py_version'] = _PY_VERSION
_CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
_CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
@@ -711,6 +711,7 @@ def get_config_vars(*args):
With arguments, return a list of values that result from looking up
each argument in the configuration variable dictionary.
"""
+ global _CONFIG_VARS_INITIALIZED
# Avoid claiming the lock once initialization is complete.
if not _CONFIG_VARS_INITIALIZED:
@@ -721,6 +722,15 @@ def get_config_vars(*args):
# don't re-enter init_config_vars().
if _CONFIG_VARS is None:
_init_config_vars()
+ else:
+ # If the site module initialization happened after _CONFIG_VARS was
+ # initialized, a virtual environment might have been activated, resulting in
+ # variables like sys.prefix changing their value, so we need to re-init the
+ # config vars (see GH-126789).
+ if _CONFIG_VARS['base'] != os.path.normpath(sys.prefix):
+ with _CONFIG_VARS_LOCK:
+ _CONFIG_VARS_INITIALIZED = False
+ _init_config_vars()
if args:
vals = []
diff --git a/contrib/tools/python3/Lib/token.py b/contrib/tools/python3/Lib/token.py
index 487f6edd3c9..e26d36bd64e 100644
--- a/contrib/tools/python3/Lib/token.py
+++ b/contrib/tools/python3/Lib/token.py
@@ -1,7 +1,8 @@
"""Token constants."""
# Auto-generated by Tools/build/generate_token.py
-__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF']
+__all__ = ['tok_name', 'ISTERMINAL', 'ISNONTERMINAL', 'ISEOF',
+ 'EXACT_TOKEN_TYPES']
ENDMARKER = 0
NAME = 1
diff --git a/contrib/tools/python3/Lib/tokenize.py b/contrib/tools/python3/Lib/tokenize.py
index 7af7a5cc1cd..b2dff8e6967 100644
--- a/contrib/tools/python3/Lib/tokenize.py
+++ b/contrib/tools/python3/Lib/tokenize.py
@@ -202,7 +202,7 @@ class Untokenizer:
characters[-2::-1]
)
)
- if n_backslashes % 2 == 0:
+ if n_backslashes % 2 == 0 or characters[-1] != "N":
characters.append(character)
else:
consume_until_next_bracket = True
diff --git a/contrib/tools/python3/Lib/typing.py b/contrib/tools/python3/Lib/typing.py
index 94c211292ec..a271416d46c 100644
--- a/contrib/tools/python3/Lib/typing.py
+++ b/contrib/tools/python3/Lib/typing.py
@@ -1815,7 +1815,8 @@ def _allow_reckless_class_checks(depth=2):
_PROTO_ALLOWLIST = {
'collections.abc': [
'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
- 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer',
+ 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection',
+ 'Reversible', 'Buffer',
],
'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
}
diff --git a/contrib/tools/python3/Lib/unittest/async_case.py b/contrib/tools/python3/Lib/unittest/async_case.py
index bd2a4711560..2abfb790798 100644
--- a/contrib/tools/python3/Lib/unittest/async_case.py
+++ b/contrib/tools/python3/Lib/unittest/async_case.py
@@ -5,6 +5,7 @@ import warnings
from .case import TestCase
+__unittest = True
class IsolatedAsyncioTestCase(TestCase):
# Names intentionally have a long prefix
diff --git a/contrib/tools/python3/Lib/unittest/mock.py b/contrib/tools/python3/Lib/unittest/mock.py
index 3e9791b22dc..c4ce8f8a3eb 100644
--- a/contrib/tools/python3/Lib/unittest/mock.py
+++ b/contrib/tools/python3/Lib/unittest/mock.py
@@ -1329,6 +1329,7 @@ class _patch(object):
self.autospec = autospec
self.kwargs = kwargs
self.additional_patchers = []
+ self.is_started = False
def copy(self):
@@ -1441,6 +1442,9 @@ class _patch(object):
def __enter__(self):
"""Perform the patch."""
+ if self.is_started:
+ raise RuntimeError("Patch is already started")
+
new, spec, spec_set = self.new, self.spec, self.spec_set
autospec, kwargs = self.autospec, self.kwargs
new_callable = self.new_callable
@@ -1572,6 +1576,7 @@ class _patch(object):
self.temp_original = original
self.is_local = local
self._exit_stack = contextlib.ExitStack()
+ self.is_started = True
try:
setattr(self.target, self.attribute, new_attr)
if self.attribute_name is not None:
@@ -1591,6 +1596,9 @@ class _patch(object):
def __exit__(self, *exc_info):
"""Undo the patch."""
+ if not self.is_started:
+ return
+
if self.is_local and self.temp_original is not DEFAULT:
setattr(self.target, self.attribute, self.temp_original)
else:
@@ -1607,6 +1615,7 @@ class _patch(object):
del self.target
exit_stack = self._exit_stack
del self._exit_stack
+ self.is_started = False
return exit_stack.__exit__(*exc_info)
diff --git a/contrib/tools/python3/Lib/urllib/request.py b/contrib/tools/python3/Lib/urllib/request.py
index 7228a35534b..9a559f44152 100644
--- a/contrib/tools/python3/Lib/urllib/request.py
+++ b/contrib/tools/python3/Lib/urllib/request.py
@@ -1681,12 +1681,27 @@ else:
def url2pathname(pathname):
"""OS-specific conversion from a relative URL of the 'file' scheme
to a file system path; not recommended for general use."""
- return unquote(pathname)
+ if pathname[:3] == '///':
+ # URL has an empty authority section, so the path begins on the
+ # third character.
+ pathname = pathname[2:]
+ elif pathname[:12] == '//localhost/':
+ # Skip past 'localhost' authority.
+ pathname = pathname[11:]
+ encoding = sys.getfilesystemencoding()
+ errors = sys.getfilesystemencodeerrors()
+ return unquote(pathname, encoding=encoding, errors=errors)
def pathname2url(pathname):
"""OS-specific conversion from a file system path to a relative URL
of the 'file' scheme; not recommended for general use."""
- return quote(pathname)
+ if pathname[:2] == '//':
+ # Add explicitly empty authority to avoid interpreting the path
+ # as authority.
+ pathname = '//' + pathname
+ encoding = sys.getfilesystemencoding()
+ errors = sys.getfilesystemencodeerrors()
+ return quote(pathname, encoding=encoding, errors=errors)
ftpcache = {}
diff --git a/contrib/tools/python3/Lib/venv/__init__.py b/contrib/tools/python3/Lib/venv/__init__.py
index d5dec4ab44b..aeb522c3199 100644
--- a/contrib/tools/python3/Lib/venv/__init__.py
+++ b/contrib/tools/python3/Lib/venv/__init__.py
@@ -11,6 +11,7 @@ import subprocess
import sys
import sysconfig
import types
+import shlex
CORE_VENV_DEPS = ('pip',)
@@ -422,11 +423,41 @@ class EnvBuilder:
:param context: The information for the environment creation request
being processed.
"""
- text = text.replace('__VENV_DIR__', context.env_dir)
- text = text.replace('__VENV_NAME__', context.env_name)
- text = text.replace('__VENV_PROMPT__', context.prompt)
- text = text.replace('__VENV_BIN_NAME__', context.bin_name)
- text = text.replace('__VENV_PYTHON__', context.env_exe)
+ replacements = {
+ '__VENV_DIR__': context.env_dir,
+ '__VENV_NAME__': context.env_name,
+ '__VENV_PROMPT__': context.prompt,
+ '__VENV_BIN_NAME__': context.bin_name,
+ '__VENV_PYTHON__': context.env_exe,
+ }
+
+ def quote_ps1(s):
+ """
+ This should satisfy PowerShell quoting rules [1], unless the quoted
+ string is passed directly to Windows native commands [2].
+ [1]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules
+ [2]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#passing-arguments-that-contain-quote-characters
+ """
+ s = s.replace("'", "''")
+ return f"'{s}'"
+
+ def quote_bat(s):
+ return s
+
+ # gh-124651: need to quote the template strings properly
+ quote = shlex.quote
+ script_path = context.script_path
+ if script_path.endswith('.ps1'):
+ quote = quote_ps1
+ elif script_path.endswith('.bat'):
+ quote = quote_bat
+ else:
+ # fallbacks to POSIX shell compliant quote
+ quote = shlex.quote
+
+ replacements = {key: quote(s) for key, s in replacements.items()}
+ for key, quoted in replacements.items():
+ text = text.replace(key, quoted)
return text
def install_scripts(self, context, path):
@@ -466,6 +497,7 @@ class EnvBuilder:
with open(srcfile, 'rb') as f:
data = f.read()
if not srcfile.endswith(('.exe', '.pdb')):
+ context.script_path = srcfile
try:
data = data.decode('utf-8')
data = self.replace_variables(data, context)
diff --git a/contrib/tools/python3/Lib/venv/scripts/common/activate b/contrib/tools/python3/Lib/venv/scripts/common/activate
index d5914e0cbb4..74825877c38 100644
--- a/contrib/tools/python3/Lib/venv/scripts/common/activate
+++ b/contrib/tools/python3/Lib/venv/scripts/common/activate
@@ -14,8 +14,9 @@ deactivate () {
unset _OLD_VIRTUAL_PYTHONHOME
fi
- # Call hash to forget past commands. Without forgetting
- # past commands the $PATH changes we made may not be respected
+ # Call hash to forget past locations. Without forgetting
+ # past locations the $PATH changes we made may not be respected.
+ # See "man bash" for more details. hash is usually a builtin of your shell
hash -r 2> /dev/null
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
@@ -39,14 +40,14 @@ deactivate nondestructive
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
# transform D:\path\to\venv to /d/path/to/venv on MSYS
# and to /cygdrive/d/path/to/venv on Cygwin
- export VIRTUAL_ENV=$(cygpath "__VENV_DIR__")
+ export VIRTUAL_ENV=$(cygpath __VENV_DIR__)
else
# use the path as-is
- export VIRTUAL_ENV="__VENV_DIR__"
+ export VIRTUAL_ENV=__VENV_DIR__
fi
_OLD_VIRTUAL_PATH="$PATH"
-PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH"
+PATH="$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH"
export PATH
# unset PYTHONHOME if set
@@ -59,9 +60,9 @@ fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
- PS1="__VENV_PROMPT__${PS1:-}"
+ PS1=__VENV_PROMPT__"${PS1:-}"
export PS1
- VIRTUAL_ENV_PROMPT="__VENV_PROMPT__"
+ VIRTUAL_ENV_PROMPT=__VENV_PROMPT__
export VIRTUAL_ENV_PROMPT
fi
diff --git a/contrib/tools/python3/Lib/venv/scripts/nt/activate.bat b/contrib/tools/python3/Lib/venv/scripts/nt/activate.bat
index 5daa45afc9f..c2c6dd29fe4 100644
--- a/contrib/tools/python3/Lib/venv/scripts/nt/activate.bat
+++ b/contrib/tools/python3/Lib/venv/scripts/nt/activate.bat
@@ -8,7 +8,7 @@ if defined _OLD_CODEPAGE (
"%SystemRoot%\System32\chcp.com" 65001 > nul
)
-set VIRTUAL_ENV=__VENV_DIR__
+set "VIRTUAL_ENV=__VENV_DIR__"
if not defined PROMPT set PROMPT=$P$G
@@ -24,8 +24,8 @@ set PYTHONHOME=
if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
-set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%
-set VIRTUAL_ENV_PROMPT=__VENV_PROMPT__
+set "PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%"
+set "VIRTUAL_ENV_PROMPT=__VENV_PROMPT__"
:END
if defined _OLD_CODEPAGE (
diff --git a/contrib/tools/python3/Lib/venv/scripts/posix/activate.csh b/contrib/tools/python3/Lib/venv/scripts/posix/activate.csh
index 5e8d66fa9e5..08f79296f59 100644
--- a/contrib/tools/python3/Lib/venv/scripts/posix/activate.csh
+++ b/contrib/tools/python3/Lib/venv/scripts/posix/activate.csh
@@ -9,17 +9,17 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
# Unset irrelevant variables.
deactivate nondestructive
-setenv VIRTUAL_ENV "__VENV_DIR__"
+setenv VIRTUAL_ENV __VENV_DIR__
set _OLD_VIRTUAL_PATH="$PATH"
-setenv PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH"
+setenv PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
- set prompt = "__VENV_PROMPT__$prompt"
- setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__"
+ set prompt = __VENV_PROMPT__"$prompt"
+ setenv VIRTUAL_ENV_PROMPT __VENV_PROMPT__
endif
alias pydoc python -m pydoc
diff --git a/contrib/tools/python3/Lib/venv/scripts/posix/activate.fish b/contrib/tools/python3/Lib/venv/scripts/posix/activate.fish
index 91ad6442e05..508cab0db46 100644
--- a/contrib/tools/python3/Lib/venv/scripts/posix/activate.fish
+++ b/contrib/tools/python3/Lib/venv/scripts/posix/activate.fish
@@ -33,10 +33,10 @@ end
# Unset irrelevant variables.
deactivate nondestructive
-set -gx VIRTUAL_ENV "__VENV_DIR__"
+set -gx VIRTUAL_ENV __VENV_DIR__
set -gx _OLD_VIRTUAL_PATH $PATH
-set -gx PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__" $PATH
+set -gx PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__ $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
@@ -56,7 +56,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
- printf "%s%s%s" (set_color 4B8BBE) "__VENV_PROMPT__" (set_color normal)
+ printf "%s%s%s" (set_color 4B8BBE) __VENV_PROMPT__ (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
@@ -65,5 +65,5 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
- set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__"
+ set -gx VIRTUAL_ENV_PROMPT __VENV_PROMPT__
end
diff --git a/contrib/tools/python3/Lib/ya.make b/contrib/tools/python3/Lib/ya.make
index 30bec984789..ba53fefab39 100644
--- a/contrib/tools/python3/Lib/ya.make
+++ b/contrib/tools/python3/Lib/ya.make
@@ -4,9 +4,9 @@ ENABLE(PYBUILD_NO_PY)
PY3_LIBRARY()
-VERSION(3.12.7)
+VERSION(3.12.8)
-ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.12.7.tar.gz)
+ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.12.8.tar.gz)
LICENSE(Python-2.0)
diff --git a/contrib/tools/python3/Lib/zipfile/__init__.py b/contrib/tools/python3/Lib/zipfile/__init__.py
index 91358156bc1..cf71c6dba2b 100644
--- a/contrib/tools/python3/Lib/zipfile/__init__.py
+++ b/contrib/tools/python3/Lib/zipfile/__init__.py
@@ -295,7 +295,7 @@ def _EndRecData(fpin):
fpin.seek(-sizeEndCentDir, 2)
except OSError:
return None
- data = fpin.read()
+ data = fpin.read(sizeEndCentDir)
if (len(data) == sizeEndCentDir and
data[0:4] == stringEndArchive and
data[-2:] == b"\000\000"):
@@ -315,9 +315,9 @@ def _EndRecData(fpin):
# record signature. The comment is the last item in the ZIP file and may be
# up to 64K long. It is assumed that the "end of central directory" magic
# number does not appear in the comment.
- maxCommentStart = max(filesize - (1 << 16) - sizeEndCentDir, 0)
+ maxCommentStart = max(filesize - ZIP_MAX_COMMENT - sizeEndCentDir, 0)
fpin.seek(maxCommentStart, 0)
- data = fpin.read()
+ data = fpin.read(ZIP_MAX_COMMENT + sizeEndCentDir)
start = data.rfind(stringEndArchive)
if start >= 0:
# found the magic number; attempt to unpack and interpret
diff --git a/contrib/tools/python3/Lib/zipfile/_path/__init__.py b/contrib/tools/python3/Lib/zipfile/_path/__init__.py
index 8db5ef18d7c..645cfafdd62 100644
--- a/contrib/tools/python3/Lib/zipfile/_path/__init__.py
+++ b/contrib/tools/python3/Lib/zipfile/_path/__init__.py
@@ -303,7 +303,7 @@ class Path:
if self.is_dir():
raise IsADirectoryError(self)
zip_mode = mode[0]
- if not self.exists() and zip_mode == 'r':
+ if zip_mode == 'r' and not self.exists():
raise FileNotFoundError(self)
stream = self.root.open(self.at, zip_mode, pwd=pwd)
if 'b' in mode: