diff options
author | shadchin <shadchin@yandex-team.com> | 2024-08-17 21:51:59 +0300 |
---|---|---|
committer | shadchin <shadchin@yandex-team.com> | 2024-08-17 22:04:51 +0300 |
commit | ee9edbd8878888bafcd0eeb3b528f3ec4311560b (patch) | |
tree | d54d8138e50a446904f10a2092719be86af011b7 /contrib/tools/python3/Lib | |
parent | 72cbe4bad58add0912623ba51351ff1db8587249 (diff) | |
download | ydb-ee9edbd8878888bafcd0eeb3b528f3ec4311560b.tar.gz |
Update Python 3 to 3.12.5
https://docs.python.org/release/3.12.5/whatsnew/changelog.html#python-3-12-5-final
de86cdeacd3a8653b9ec36e87975886fafcf6dc2
Diffstat (limited to 'contrib/tools/python3/Lib')
44 files changed, 589 insertions, 323 deletions
diff --git a/contrib/tools/python3/Lib/_pydatetime.py b/contrib/tools/python3/Lib/_pydatetime.py index cd0ea900bfb..ad6292e1e41 100644 --- a/contrib/tools/python3/Lib/_pydatetime.py +++ b/contrib/tools/python3/Lib/_pydatetime.py @@ -970,6 +970,8 @@ class date: @classmethod def fromtimestamp(cls, t): "Construct a date from a POSIX timestamp (like time.time())." + if t is None: + raise TypeError("'NoneType' object cannot be interpreted as an integer") y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t) return cls(y, m, d) diff --git a/contrib/tools/python3/Lib/_pydecimal.py b/contrib/tools/python3/Lib/_pydecimal.py index 613123ec7b4..75df3db2624 100644 --- a/contrib/tools/python3/Lib/_pydecimal.py +++ b/contrib/tools/python3/Lib/_pydecimal.py @@ -424,7 +424,7 @@ def localcontext(ctx=None, **kwargs): # numbers.py for more detail. class Decimal(object): - """Floating point class for decimal arithmetic.""" + """Floating-point class for decimal arithmetic.""" __slots__ = ('_exp','_int','_sign', '_is_special') # Generally, the value of the Decimal instance is given by diff --git a/contrib/tools/python3/Lib/argparse.py b/contrib/tools/python3/Lib/argparse.py index 120cb6c8458..e4892955e4f 100644 --- a/contrib/tools/python3/Lib/argparse.py +++ b/contrib/tools/python3/Lib/argparse.py @@ -1843,7 +1843,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # ================================== def add_subparsers(self, **kwargs): if self._subparsers is not None: - self.error(_('cannot have multiple subparser arguments')) + raise ArgumentError(None, _('cannot have multiple subparser arguments')) # add the parser class to the arguments if it's not present kwargs.setdefault('parser_class', type(self)) @@ -1895,8 +1895,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def parse_args(self, args=None, namespace=None): args, argv = self.parse_known_args(args, namespace) if argv: - msg = _('unrecognized arguments: %s') - self.error(msg % ' '.join(argv)) + msg = _('unrecognized arguments: %s') % ' '.join(argv) + if self.exit_on_error: + self.error(msg) + else: + raise ArgumentError(None, msg) return args def parse_known_args(self, args=None, namespace=None): @@ -2175,7 +2178,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): self._get_value(action, action.default)) if required_actions: - self.error(_('the following arguments are required: %s') % + raise ArgumentError(None, _('the following arguments are required: %s') % ', '.join(required_actions)) # make sure all required groups had one option present @@ -2191,7 +2194,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): for action in group._group_actions if action.help is not SUPPRESS] msg = _('one of the arguments %s is required') - self.error(msg % ' '.join(names)) + raise ArgumentError(None, msg % ' '.join(names)) # return the updated namespace and the extra arguments return namespace, extras @@ -2218,7 +2221,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): arg_strings = self._read_args_from_files(arg_strings) new_arg_strings.extend(arg_strings) except OSError as err: - self.error(str(err)) + raise ArgumentError(None, str(err)) # return the modified argument list return new_arg_strings @@ -2298,7 +2301,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): for action, option_string, sep, explicit_arg in option_tuples]) args = {'option': arg_string, 'matches': options} msg = _('ambiguous option: %(option)s could match %(matches)s') - self.error(msg % args) + raise ArgumentError(None, msg % args) # if exactly one action matched, this segmentation is good, # so return the parsed action @@ -2358,7 +2361,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # shouldn't ever get here else: - self.error(_('unexpected option string: %s') % option_string) + raise ArgumentError(None, _('unexpected option string: %s') % option_string) # return the collected option tuples return result @@ -2415,8 +2418,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def parse_intermixed_args(self, args=None, namespace=None): args, argv = self.parse_known_intermixed_args(args, namespace) if argv: - msg = _('unrecognized arguments: %s') - self.error(msg % ' '.join(argv)) + msg = _('unrecognized arguments: %s') % ' '.join(argv) + if self.exit_on_error: + self.error(msg) + else: + raise ArgumentError(None, msg) return args def parse_known_intermixed_args(self, args=None, namespace=None): diff --git a/contrib/tools/python3/Lib/asyncio/__main__.py b/contrib/tools/python3/Lib/asyncio/__main__.py index c39a31d7b3d..04655801151 100644 --- a/contrib/tools/python3/Lib/asyncio/__main__.py +++ b/contrib/tools/python3/Lib/asyncio/__main__.py @@ -89,6 +89,8 @@ class REPLThread(threading.Thread): if __name__ == '__main__': + sys.audit("cpython.run_stdin") + loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) diff --git a/contrib/tools/python3/Lib/asyncio/base_events.py b/contrib/tools/python3/Lib/asyncio/base_events.py index 29eff0499cb..cb037fd472c 100644 --- a/contrib/tools/python3/Lib/asyncio/base_events.py +++ b/contrib/tools/python3/Lib/asyncio/base_events.py @@ -994,8 +994,7 @@ class BaseEventLoop(events.AbstractEventLoop): except OSError as exc: msg = ( f'error while attempting to bind on ' - f'address {laddr!r}: ' - f'{exc.strerror.lower()}' + f'address {laddr!r}: {str(exc).lower()}' ) exc = OSError(exc.errno, msg) my_exceptions.append(exc) @@ -1561,7 +1560,7 @@ class BaseEventLoop(events.AbstractEventLoop): except OSError as err: msg = ('error while attempting ' 'to bind on address %r: %s' - % (sa, err.strerror.lower())) + % (sa, str(err).lower())) if err.errno == errno.EADDRNOTAVAIL: # Assume the family is not enabled (bpo-30945) sockets.pop() diff --git a/contrib/tools/python3/Lib/calendar.py b/contrib/tools/python3/Lib/calendar.py index 97d7cab3365..ee3ec838c96 100644 --- a/contrib/tools/python3/Lib/calendar.py +++ b/contrib/tools/python3/Lib/calendar.py @@ -159,8 +159,8 @@ def weekday(year, month, day): def monthrange(year, month): - """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for - 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) day1 = weekday(year, month, 1) diff --git a/contrib/tools/python3/Lib/code.py b/contrib/tools/python3/Lib/code.py index 2bd5fa3e795..b4b1ef3b8b9 100644 --- a/contrib/tools/python3/Lib/code.py +++ b/contrib/tools/python3/Lib/code.py @@ -127,7 +127,7 @@ class InteractiveInterpreter: else: # If someone has set sys.excepthook, we let that take precedence # over self.write - sys.excepthook(type, value, tb) + self._call_excepthook(type, value, tb) def showtraceback(self): """Display the exception that just occurred. @@ -141,16 +141,29 @@ class InteractiveInterpreter: sys.last_traceback = last_tb sys.last_exc = ei[1] try: - lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) if sys.excepthook is sys.__excepthook__: + lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) self.write(''.join(lines)) else: # If someone has set sys.excepthook, we let that take precedence # over self.write - sys.excepthook(ei[0], ei[1], last_tb) + self._call_excepthook(ei[0], ei[1], last_tb) finally: last_tb = ei = None + def _call_excepthook(self, typ, value, tb): + try: + sys.excepthook(typ, value, tb) + except SystemExit: + raise + except BaseException as e: + e.__context__ = None + print('Error in sys.excepthook:', file=sys.stderr) + sys.__excepthook__(type(e), e, e.__traceback__.tb_next) + print(file=sys.stderr) + print('Original exception was:', file=sys.stderr) + sys.__excepthook__(typ, value, tb) + def write(self, data): """Write a string. diff --git a/contrib/tools/python3/Lib/colorsys.py b/contrib/tools/python3/Lib/colorsys.py index bc897bd0f99..e97f91718a3 100644 --- a/contrib/tools/python3/Lib/colorsys.py +++ b/contrib/tools/python3/Lib/colorsys.py @@ -24,7 +24,7 @@ HSV: Hue, Saturation, Value __all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb", "rgb_to_hsv","hsv_to_rgb"] -# Some floating point constants +# Some floating-point constants ONE_THIRD = 1.0/3.0 ONE_SIXTH = 1.0/6.0 diff --git a/contrib/tools/python3/Lib/concurrent/futures/__init__.py b/contrib/tools/python3/Lib/concurrent/futures/__init__.py index 292e886d5a8..72de617a5b6 100644 --- a/contrib/tools/python3/Lib/concurrent/futures/__init__.py +++ b/contrib/tools/python3/Lib/concurrent/futures/__init__.py @@ -23,6 +23,7 @@ __all__ = ( 'ALL_COMPLETED', 'CancelledError', 'TimeoutError', + 'InvalidStateError', 'BrokenExecutor', 'Future', 'Executor', diff --git a/contrib/tools/python3/Lib/decimal.py b/contrib/tools/python3/Lib/decimal.py index d61e374b9f9..4d8e15cb68f 100644 --- a/contrib/tools/python3/Lib/decimal.py +++ b/contrib/tools/python3/Lib/decimal.py @@ -1,6 +1,6 @@ -"""Decimal fixed point and floating point arithmetic. +"""Decimal fixed-point and floating-point arithmetic. -This is an implementation of decimal floating point arithmetic based on +This is an implementation of decimal floating-point arithmetic based on the General Decimal Arithmetic Specification: http://speleotrove.com/decimal/decarith.html diff --git a/contrib/tools/python3/Lib/email/_header_value_parser.py b/contrib/tools/python3/Lib/email/_header_value_parser.py index ab3c3031ef5..ec2215a5e5f 100644 --- a/contrib/tools/python3/Lib/email/_header_value_parser.py +++ b/contrib/tools/python3/Lib/email/_header_value_parser.py @@ -92,6 +92,8 @@ TOKEN_ENDS = TSPECIALS | WSP ASPECIALS = TSPECIALS | set("*'%") ATTRIBUTE_ENDS = ASPECIALS | WSP EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') +NLSET = {'\n', '\r'} +SPECIALSNL = SPECIALS | NLSET def quote_string(value): return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' @@ -2802,9 +2804,13 @@ def _refold_parse_tree(parse_tree, *, policy): wrap_as_ew_blocked -= 1 continue tstr = str(part) - if part.token_type == 'ptext' and set(tstr) & SPECIALS: - # Encode if tstr contains special characters. - want_encoding = True + if not want_encoding: + if part.token_type == 'ptext': + # Encode if tstr contains special characters. + want_encoding = not SPECIALSNL.isdisjoint(tstr) + else: + # Encode if tstr contains newlines. + want_encoding = not NLSET.isdisjoint(tstr) try: tstr.encode(encoding) charset = encoding @@ -2988,6 +2994,7 @@ def _fold_as_ew(to_encode, lines, maxlen, last_ew, ew_combine_allowed, charset, excess = len(encoded_word) - remaining_space lines[-1] += encoded_word to_encode = to_encode[len(to_encode_word):] + leading_whitespace = '' if to_encode: lines.append(' ') diff --git a/contrib/tools/python3/Lib/email/_policybase.py b/contrib/tools/python3/Lib/email/_policybase.py index 2ec54fbabae..5f9aa9fb091 100644 --- a/contrib/tools/python3/Lib/email/_policybase.py +++ b/contrib/tools/python3/Lib/email/_policybase.py @@ -157,6 +157,13 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): message_factory -- the class to use to create new message objects. If the value is None, the default is Message. + verify_generated_headers + -- if true, the generator verifies that each header + they are properly folded, so that a parser won't + treat it as multiple headers, start-of-body, or + part of another header. + This is a check against custom Header & fold() + implementations. """ raise_on_defect = False @@ -165,6 +172,7 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): max_line_length = 78 mangle_from_ = False message_factory = None + verify_generated_headers = True def handle_defect(self, obj, defect): """Based on policy, either raise defect or call register_defect. diff --git a/contrib/tools/python3/Lib/email/errors.py b/contrib/tools/python3/Lib/email/errors.py index 3ad00565549..02aa5eced6a 100644 --- a/contrib/tools/python3/Lib/email/errors.py +++ b/contrib/tools/python3/Lib/email/errors.py @@ -29,6 +29,10 @@ class CharsetError(MessageError): """An illegal charset was given.""" +class HeaderWriteError(MessageError): + """Error while writing headers.""" + + # These are parsing defects which the parser was able to work around. class MessageDefect(ValueError): """Base class for a message defect.""" diff --git a/contrib/tools/python3/Lib/email/generator.py b/contrib/tools/python3/Lib/email/generator.py index c8056ad47ba..47b9df8f4e6 100644 --- a/contrib/tools/python3/Lib/email/generator.py +++ b/contrib/tools/python3/Lib/email/generator.py @@ -14,12 +14,14 @@ import random from copy import deepcopy from io import StringIO, BytesIO from email.utils import _has_surrogates +from email.errors import HeaderWriteError UNDERSCORE = '_' NL = '\n' # XXX: no longer used by the code below. NLCRE = re.compile(r'\r\n|\r|\n') fcre = re.compile(r'^From ', re.MULTILINE) +NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') class Generator: @@ -222,7 +224,16 @@ class Generator: def _write_headers(self, msg): for h, v in msg.raw_items(): - self.write(self.policy.fold(h, v)) + folded = self.policy.fold(h, v) + if self.policy.verify_generated_headers: + linesep = self.policy.linesep + if not folded.endswith(self.policy.linesep): + raise HeaderWriteError( + f'folded header does not end with {linesep!r}: {folded!r}') + if NEWLINE_WITHOUT_FWSP.search(folded.removesuffix(linesep)): + raise HeaderWriteError( + f'folded header contains newline: {folded!r}') + self.write(folded) # A blank line always separates headers from body self.write(self._NL) diff --git a/contrib/tools/python3/Lib/email/utils.py b/contrib/tools/python3/Lib/email/utils.py index aa949aa933a..1de547a0117 100644 --- a/contrib/tools/python3/Lib/email/utils.py +++ b/contrib/tools/python3/Lib/email/utils.py @@ -128,7 +128,7 @@ def formatdate(timeval=None, localtime=False, usegmt=False): Fri, 09 Nov 2001 01:08:47 -0000 - Optional timeval if given is a floating point time value as accepted by + Optional timeval if given is a floating-point time value as accepted by gmtime() and localtime(), otherwise the current time is used. Optional localtime is a flag that when True, interprets timeval, and diff --git a/contrib/tools/python3/Lib/ensurepip/__init__.py b/contrib/tools/python3/Lib/ensurepip/__init__.py index 2ac872c25c8..a7c84572382 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.0" +_PIP_VERSION = "24.2" _PROJECTS = [ ("pip", _PIP_VERSION, "py3"), ] diff --git a/contrib/tools/python3/Lib/filecmp.py b/contrib/tools/python3/Lib/filecmp.py index 30bd900fa80..6fdb48f7a39 100644 --- a/contrib/tools/python3/Lib/filecmp.py +++ b/contrib/tools/python3/Lib/filecmp.py @@ -160,12 +160,14 @@ class dircmp: ok = True try: a_stat = os.stat(a_path) - except OSError: + except (OSError, ValueError): + # See https://github.com/python/cpython/issues/122400 + # for the rationale for protecting against ValueError. # print('Can\'t stat', a_path, ':', why.args[1]) ok = False try: b_stat = os.stat(b_path) - except OSError: + except (OSError, ValueError): # print('Can\'t stat', b_path, ':', why.args[1]) ok = False @@ -280,12 +282,12 @@ def cmpfiles(a, b, common, shallow=True): # Return: # 0 for equal # 1 for different -# 2 for funny cases (can't stat, etc.) +# 2 for funny cases (can't stat, NUL bytes, etc.) # def _cmp(a, b, sh, abs=abs, cmp=cmp): try: return not abs(cmp(a, b, sh)) - except OSError: + except (OSError, ValueError): return 2 diff --git a/contrib/tools/python3/Lib/fractions.py b/contrib/tools/python3/Lib/fractions.py index 88b418fe383..e3a8bbcfb3e 100644 --- a/contrib/tools/python3/Lib/fractions.py +++ b/contrib/tools/python3/Lib/fractions.py @@ -825,8 +825,10 @@ class Fraction(numbers.Rational): # A fractional power will generally produce an # irrational number. return float(a) ** float(b) - else: + elif isinstance(b, (float, complex)): return float(a) ** b + else: + return NotImplemented def __rpow__(b, a): """a ** b""" diff --git a/contrib/tools/python3/Lib/functools.py b/contrib/tools/python3/Lib/functools.py index 1f1ba638866..318efd04fd8 100644 --- a/contrib/tools/python3/Lib/functools.py +++ b/contrib/tools/python3/Lib/functools.py @@ -372,15 +372,13 @@ class partialmethod(object): self.keywords = keywords def __repr__(self): - args = ", ".join(map(repr, self.args)) - keywords = ", ".join("{}={!r}".format(k, v) - for k, v in self.keywords.items()) - format_string = "{module}.{cls}({func}, {args}, {keywords})" - return format_string.format(module=self.__class__.__module__, - cls=self.__class__.__qualname__, - func=self.func, - args=args, - keywords=keywords) + cls = type(self) + module = cls.__module__ + qualname = cls.__qualname__ + args = [repr(self.func)] + args.extend(map(repr, self.args)) + args.extend(f"{k}={v!r}" for k, v in self.keywords.items()) + return f"{module}.{qualname}({', '.join(args)})" def _make_unbound_method(self): def _method(cls_or_self, /, *args, **keywords): diff --git a/contrib/tools/python3/Lib/http/cookies.py b/contrib/tools/python3/Lib/http/cookies.py index 35ac2dc6ae2..351faf428a2 100644 --- a/contrib/tools/python3/Lib/http/cookies.py +++ b/contrib/tools/python3/Lib/http/cookies.py @@ -234,7 +234,7 @@ def _unquote(str): # header. By default, _getdate() returns the current time in the appropriate # "expires" format for a Set-Cookie header. The one optional argument is an # offset from now, in seconds. For example, an offset of -3600 means "one hour -# ago". The offset may be a floating point number. +# ago". The offset may be a floating-point number. # _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] diff --git a/contrib/tools/python3/Lib/importlib/metadata/__init__.py b/contrib/tools/python3/Lib/importlib/metadata/__init__.py index 54156e93afc..e6ca17821d1 100644 --- a/contrib/tools/python3/Lib/importlib/metadata/__init__.py +++ b/contrib/tools/python3/Lib/importlib/metadata/__init__.py @@ -534,7 +534,7 @@ class Distribution(DeprecatedNonAbstract): paths = ( (subdir / name) .resolve() - .relative_to(self.locate_file('').resolve()) + .relative_to(self.locate_file('').resolve(), walk_up=True) .as_posix() for name in text.splitlines() ) diff --git a/contrib/tools/python3/Lib/importlib/util.py b/contrib/tools/python3/Lib/importlib/util.py index 3743e6aa912..4b836f47120 100644 --- a/contrib/tools/python3/Lib/importlib/util.py +++ b/contrib/tools/python3/Lib/importlib/util.py @@ -13,7 +13,6 @@ from ._bootstrap_external import spec_from_file_location import _imp import sys -import threading import types @@ -253,6 +252,9 @@ class LazyLoader(Loader): def exec_module(self, module): """Make the module load lazily.""" + # Threading is only needed for lazy loading, and importlib.util can + # be pulled in at interpreter startup, so defer until needed. + import threading module.__spec__.loader = self.loader module.__loader__ = self.loader # Don't need to worry about deep-copying as trying to set an attribute diff --git a/contrib/tools/python3/Lib/inspect.py b/contrib/tools/python3/Lib/inspect.py index 497169dacb5..c43faa73159 100644 --- a/contrib/tools/python3/Lib/inspect.py +++ b/contrib/tools/python3/Lib/inspect.py @@ -280,7 +280,13 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False): if globals is None: globals = obj_globals if locals is None: - locals = obj_locals + locals = obj_locals or {} + + # "Inject" type parameters into the local namespace + # (unless they are shadowed by assignments *in* the local namespace), + # as a way of emulating annotation scopes when calling `eval()` + if type_params := getattr(obj, "__type_params__", ()): + locals = {param.__name__: param for param in type_params} | locals return_value = {key: value if not isinstance(value, str) else eval(value, globals, locals) @@ -401,13 +407,13 @@ def isgeneratorfunction(obj): return _has_code_flag(obj, CO_GENERATOR) # A marker for markcoroutinefunction and iscoroutinefunction. -_is_coroutine_marker = object() +_is_coroutine_mark = object() def _has_coroutine_mark(f): while ismethod(f): f = f.__func__ f = functools._unwrap_partial(f) - return getattr(f, "_is_coroutine_marker", None) is _is_coroutine_marker + return getattr(f, "_is_coroutine_marker", None) is _is_coroutine_mark def markcoroutinefunction(func): """ @@ -415,7 +421,7 @@ def markcoroutinefunction(func): """ if hasattr(func, '__func__'): func = func.__func__ - func._is_coroutine_marker = _is_coroutine_marker + func._is_coroutine_marker = _is_coroutine_mark return func def iscoroutinefunction(obj): diff --git a/contrib/tools/python3/Lib/ipaddress.py b/contrib/tools/python3/Lib/ipaddress.py index d8f3b5e2e9e..816fbcd2bc4 100644 --- a/contrib/tools/python3/Lib/ipaddress.py +++ b/contrib/tools/python3/Lib/ipaddress.py @@ -310,7 +310,7 @@ def collapse_addresses(addresses): [IPv4Network('192.0.2.0/24')] Args: - addresses: An iterator of IPv4Network or IPv6Network objects. + addresses: An iterable of IPv4Network or IPv6Network objects. Returns: An iterator of the collapsed IPv(4|6)Network objects. diff --git a/contrib/tools/python3/Lib/linecache.py b/contrib/tools/python3/Lib/linecache.py index 5585216d2b5..05eb49d3b05 100644 --- a/contrib/tools/python3/Lib/linecache.py +++ b/contrib/tools/python3/Lib/linecache.py @@ -70,7 +70,7 @@ def checkcache(filename=None): continue # no-op for files loaded via a __loader__ try: stat = os.stat(fullname) - except OSError: + except (OSError, ValueError): cache.pop(filename, None) continue if size != stat.st_size or mtime != stat.st_mtime: @@ -140,10 +140,12 @@ def updatecache(filename, module_globals=None): try: stat = os.stat(fullname) break - except OSError: + except (OSError, ValueError): pass else: return [] + except ValueError: # may be raised by os.stat() + return [] try: with tokenize.open(fullname) as fp: lines = fp.readlines() diff --git a/contrib/tools/python3/Lib/logging/config.py b/contrib/tools/python3/Lib/logging/config.py index 1824d0aa747..ac90b537d8a 100644 --- a/contrib/tools/python3/Lib/logging/config.py +++ b/contrib/tools/python3/Lib/logging/config.py @@ -500,6 +500,33 @@ class BaseConfigurator(object): value = tuple(value) return value +def _is_queue_like_object(obj): + """Check that *obj* implements the Queue API.""" + if isinstance(obj, queue.Queue): + return True + # defer importing multiprocessing as much as possible + from multiprocessing.queues import Queue as MPQueue + if isinstance(obj, MPQueue): + return True + # Depending on the multiprocessing start context, we cannot create + # a multiprocessing.managers.BaseManager instance 'mm' to get the + # runtime type of mm.Queue() or mm.JoinableQueue() (see gh-119819). + # + # Since we only need an object implementing the Queue API, we only + # do a protocol check, but we do not use typing.runtime_checkable() + # and typing.Protocol to reduce import time (see gh-121723). + # + # 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', + ] + return all(callable(getattr(obj, method, None)) + for method in queue_interface) + class DictConfigurator(BaseConfigurator): """ Configure logging using a dictionary-like object to describe the @@ -787,25 +814,20 @@ class DictConfigurator(BaseConfigurator): # if 'handlers' not in config: # raise ValueError('No handlers specified for a QueueHandler') if 'queue' in config: - from multiprocessing.queues import Queue as MPQueue - from multiprocessing import Manager as MM - proxy_queue = MM().Queue() - proxy_joinable_queue = MM().JoinableQueue() qspec = config['queue'] - if not isinstance(qspec, (queue.Queue, MPQueue, - type(proxy_queue), type(proxy_joinable_queue))): - if isinstance(qspec, str): - q = self.resolve(qspec) - if not callable(q): - raise TypeError('Invalid queue specifier %r' % qspec) - q = q() - elif isinstance(qspec, dict): - if '()' not in qspec: - raise TypeError('Invalid queue specifier %r' % qspec) - q = self.configure_custom(dict(qspec)) - else: + + if isinstance(qspec, str): + q = self.resolve(qspec) + if not callable(q): raise TypeError('Invalid queue specifier %r' % qspec) - config['queue'] = q + config['queue'] = q() + elif isinstance(qspec, dict): + if '()' not in qspec: + raise TypeError('Invalid queue specifier %r' % qspec) + config['queue'] = self.configure_custom(dict(qspec)) + elif not _is_queue_like_object(qspec): + raise TypeError('Invalid queue specifier %r' % qspec) + if 'listener' in config: lspec = config['listener'] if isinstance(lspec, type): diff --git a/contrib/tools/python3/Lib/logging/handlers.py b/contrib/tools/python3/Lib/logging/handlers.py index 1ae6bb84434..715bce785c1 100644 --- a/contrib/tools/python3/Lib/logging/handlers.py +++ b/contrib/tools/python3/Lib/logging/handlers.py @@ -187,15 +187,15 @@ class RotatingFileHandler(BaseRotatingHandler): Basically, see if the supplied record would cause the file to exceed the size limit we have. """ - # See bpo-45401: Never rollover anything other than regular files - if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename): - return False if self.stream is None: # delay was set... self.stream = self._open() if self.maxBytes > 0: # are we rolling over? msg = "%s\n" % self.format(record) self.stream.seek(0, 2) #due to non-posix-compliant Windows feature if self.stream.tell() + len(msg) >= self.maxBytes: + # See bpo-45401: Never rollover anything other than regular files + if os.path.exists(self.baseFilename) and not os.path.isfile(self.baseFilename): + return False return True return False diff --git a/contrib/tools/python3/Lib/mimetypes.py b/contrib/tools/python3/Lib/mimetypes.py index 3cc027aa368..10f3ddc5a15 100644 --- a/contrib/tools/python3/Lib/mimetypes.py +++ b/contrib/tools/python3/Lib/mimetypes.py @@ -551,6 +551,8 @@ def _default_mime_types(): '.csv' : 'text/csv', '.html' : 'text/html', '.htm' : 'text/html', + '.md' : 'text/markdown', + '.markdown': 'text/markdown', '.n3' : 'text/n3', '.txt' : 'text/plain', '.bat' : 'text/plain', diff --git a/contrib/tools/python3/Lib/pdb.py b/contrib/tools/python3/Lib/pdb.py index 225c9f253ef..89cf975164a 100755 --- a/contrib/tools/python3/Lib/pdb.py +++ b/contrib/tools/python3/Lib/pdb.py @@ -395,7 +395,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Called before loop, handles display expressions # Set up convenience variable containers - def preloop(self): + def _show_display(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): @@ -419,10 +419,16 @@ class Pdb(bdb.Bdb, cmd.Cmd): else: Pdb._previous_sigint_handler = None self.setup(frame, traceback) - # if we have more commands to process, do not show the stack entry - if not self.cmdqueue: - self.print_stack_entry(self.stack[self.curindex]) + # We should print the stack entry if and only if the user input + # is expected, and we should print it right before the user input. + # We achieve this by appending _pdbcmd_print_frame_status to the + # command queue. If cmdqueue is not exausted, the user input is + # not expected and we will not print the stack entry. + self.cmdqueue.append('_pdbcmd_print_frame_status') self._cmdloop() + # If _pdbcmd_print_frame_status is not used, pop it out + if self.cmdqueue and self.cmdqueue[-1] == '_pdbcmd_print_frame_status': + self.cmdqueue.pop() self.forget() def displayhook(self, obj): @@ -524,6 +530,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): a breakpoint command list definition. """ if not self.commands_defining: + if line.startswith('_pdbcmd'): + command, arg, line = self.parseline(line) + if hasattr(self, command): + return getattr(self, command)(arg) return cmd.Cmd.onecmd(self, line) else: return self.handle_command_def(line) @@ -623,6 +633,12 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Complete a simple name. return [n for n in ns.keys() if n.startswith(text)] + # Pdb meta commands, only intended to be used internally by pdb + + def _pdbcmd_print_frame_status(self, arg): + self.print_stack_entry(self.stack[self.curindex]) + self._show_display() + # Command definitions, called by cmdloop() # The argument is the remaining string on the command line # Return true to exit from the command loop diff --git a/contrib/tools/python3/Lib/pickle.py b/contrib/tools/python3/Lib/pickle.py index 6e3c61fd0b2..c4d6e658216 100644 --- a/contrib/tools/python3/Lib/pickle.py +++ b/contrib/tools/python3/Lib/pickle.py @@ -314,16 +314,17 @@ class _Unframer: # Tools used for pickling. def _getattribute(obj, name): + top = obj for subpath in name.split('.'): if subpath == '<locals>': raise AttributeError("Can't get local attribute {!r} on {!r}" - .format(name, obj)) + .format(name, top)) try: parent = obj obj = getattr(obj, subpath) except AttributeError: raise AttributeError("Can't get attribute {!r} on {!r}" - .format(name, obj)) from None + .format(name, top)) from None return obj, parent def whichmodule(obj, name): @@ -780,14 +781,10 @@ class _Pickler: self.write(FLOAT + repr(obj).encode("ascii") + b'\n') dispatch[float] = save_float - def save_bytes(self, obj): - if self.proto < 3: - if not obj: # bytes object is empty - self.save_reduce(bytes, (), obj=obj) - else: - self.save_reduce(codecs.encode, - (str(obj, 'latin1'), 'latin1'), obj=obj) - return + def _save_bytes_no_memo(self, obj): + # helper for writing bytes objects for protocol >= 3 + # without memoizing them + assert self.proto >= 3 n = len(obj) if n <= 0xff: self.write(SHORT_BINBYTES + pack("<B", n) + obj) @@ -797,9 +794,29 @@ class _Pickler: self._write_large_bytes(BINBYTES + pack("<I", n), obj) else: self.write(BINBYTES + pack("<I", n) + obj) + + def save_bytes(self, obj): + if self.proto < 3: + if not obj: # bytes object is empty + self.save_reduce(bytes, (), obj=obj) + else: + self.save_reduce(codecs.encode, + (str(obj, 'latin1'), 'latin1'), obj=obj) + return + self._save_bytes_no_memo(obj) self.memoize(obj) dispatch[bytes] = save_bytes + def _save_bytearray_no_memo(self, obj): + # helper for writing bytearray objects for protocol >= 5 + # without memoizing them + assert self.proto >= 5 + n = len(obj) + if n >= self.framer._FRAME_SIZE_TARGET: + self._write_large_bytes(BYTEARRAY8 + pack("<Q", n), obj) + else: + self.write(BYTEARRAY8 + pack("<Q", n) + obj) + def save_bytearray(self, obj): if self.proto < 5: if not obj: # bytearray is empty @@ -807,18 +824,14 @@ class _Pickler: else: self.save_reduce(bytearray, (bytes(obj),), obj=obj) return - n = len(obj) - if n >= self.framer._FRAME_SIZE_TARGET: - self._write_large_bytes(BYTEARRAY8 + pack("<Q", n), obj) - else: - self.write(BYTEARRAY8 + pack("<Q", n) + obj) + self._save_bytearray_no_memo(obj) self.memoize(obj) dispatch[bytearray] = save_bytearray if _HAVE_PICKLE_BUFFER: def save_picklebuffer(self, obj): if self.proto < 5: - raise PicklingError("PickleBuffer can only pickled with " + raise PicklingError("PickleBuffer can only be pickled with " "protocol >= 5") with obj.raw() as m: if not m.contiguous: @@ -830,10 +843,18 @@ class _Pickler: if in_band: # Write data in-band # XXX The C implementation avoids a copy here + buf = m.tobytes() + in_memo = id(buf) in self.memo if m.readonly: - self.save_bytes(m.tobytes()) + if in_memo: + self._save_bytes_no_memo(buf) + else: + self.save_bytes(buf) else: - self.save_bytearray(m.tobytes()) + if in_memo: + self._save_bytearray_no_memo(buf) + else: + self.save_bytearray(buf) else: # Write data out-of-band self.write(NEXT_BUFFER) @@ -1088,11 +1109,35 @@ class _Pickler: self.save(module_name) self.save(name) write(STACK_GLOBAL) - elif parent is not module: - self.save_reduce(getattr, (parent, lastname)) - elif self.proto >= 3: - write(GLOBAL + bytes(module_name, "utf-8") + b'\n' + - bytes(name, "utf-8") + b'\n') + elif '.' in name: + # In protocol < 4, objects with multi-part __qualname__ + # are represented as + # getattr(getattr(..., attrname1), attrname2). + dotted_path = name.split('.') + name = dotted_path.pop(0) + save = self.save + for attrname in dotted_path: + save(getattr) + if self.proto < 2: + write(MARK) + self._save_toplevel_by_name(module_name, name) + for attrname in dotted_path: + save(attrname) + if self.proto < 2: + write(TUPLE) + else: + write(TUPLE2) + write(REDUCE) + else: + self._save_toplevel_by_name(module_name, name) + + self.memoize(obj) + + def _save_toplevel_by_name(self, module_name, name): + if self.proto >= 3: + # Non-ASCII identifiers are supported only with protocols >= 3. + self.write(GLOBAL + bytes(module_name, "utf-8") + b'\n' + + bytes(name, "utf-8") + b'\n') else: if self.fix_imports: r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING @@ -1102,14 +1147,12 @@ class _Pickler: elif module_name in r_import_mapping: module_name = r_import_mapping[module_name] try: - write(GLOBAL + bytes(module_name, "ascii") + b'\n' + - bytes(name, "ascii") + b'\n') + self.write(GLOBAL + bytes(module_name, "ascii") + b'\n' + + bytes(name, "ascii") + b'\n') except UnicodeEncodeError: raise PicklingError( "can't pickle global identifier '%s.%s' using " - "pickle protocol %i" % (module, name, self.proto)) from None - - self.memoize(obj) + "pickle protocol %i" % (module_name, name, self.proto)) from None def save_type(self, obj): if obj is type(None): diff --git a/contrib/tools/python3/Lib/pstats.py b/contrib/tools/python3/Lib/pstats.py index 51bcca84188..f3611777dec 100644 --- a/contrib/tools/python3/Lib/pstats.py +++ b/contrib/tools/python3/Lib/pstats.py @@ -83,7 +83,7 @@ class Stats: method now take arbitrarily many file names as arguments. All the print methods now take an argument that indicates how many lines - to print. If the arg is a floating point number between 0 and 1.0, then + to print. If the arg is a floating-point number between 0 and 1.0, then it is taken as a decimal percentage of the available lines to be printed (e.g., .1 means print 10% of all available lines). If it is an integer, it is taken to mean the number of lines of data that you wish to have diff --git a/contrib/tools/python3/Lib/pydoc.py b/contrib/tools/python3/Lib/pydoc.py index 9a8812392af..e3745e5453b 100755 --- a/contrib/tools/python3/Lib/pydoc.py +++ b/contrib/tools/python3/Lib/pydoc.py @@ -2148,7 +2148,7 @@ has the same effect as typing a particular string at the help> prompt. elif request in self.symbols: self.showsymbol(request) elif request in ['True', 'False', 'None']: # special case these keywords since they are objects too - doc(eval(request), 'Help on %s:', is_cli=is_cli) + doc(eval(request), 'Help on %s:', output=self._output, is_cli=is_cli) elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) @@ -2241,7 +2241,11 @@ module "pydoc_data.topics" could not be found. text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n' wrapped_text = textwrap.wrap(text, 72) doc += '\n%s\n' % '\n'.join(wrapped_text) - pager(doc) + + if self._output is None: + pager(doc) + else: + self.output.write(doc) def _gettopic(self, topic, more_xrefs=''): """Return unbuffered tuple of (topic, xrefs). diff --git a/contrib/tools/python3/Lib/pydoc_data/topics.py b/contrib/tools/python3/Lib/pydoc_data/topics.py index e9e6337cbed..33b5834b863 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 Thu Jun 6 20:20:21 2024 +# Autogenerated by Sphinx on Tue Aug 6 21:02:50 2024 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -308,10 +308,10 @@ topics = {'assert': 'The "assert" statement\n' 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal ' - 'effect. In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. ' + 'In the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -362,21 +362,26 @@ topics = {'assert': 'The "assert" statement\n' 'a single\n' 'target is allowed.\n' '\n' - 'For simple names as assignment targets, if in class or module ' - 'scope,\n' - 'the annotations are evaluated and stored in a special class or ' - 'module\n' - 'attribute "__annotations__" that is a dictionary mapping from ' - 'variable\n' - 'names (mangled if private) to evaluated annotations. This ' - 'attribute is\n' - 'writable and is automatically created at the start of class or ' - 'module\n' - 'body execution, if annotations are found statically.\n' - '\n' - 'For expressions as assignment targets, the annotations are ' + 'The assignment target is considered “simple” if it consists of ' + 'a\n' + 'single name that is not enclosed in parentheses. For simple ' + 'assignment\n' + 'targets, if in class or module scope, the annotations are ' 'evaluated\n' - 'if in class or module scope, but not stored.\n' + 'and stored in a special class or module attribute ' + '"__annotations__"\n' + 'that is a dictionary mapping from variable names (mangled if ' + 'private)\n' + 'to evaluated annotations. This attribute is writable and is\n' + 'automatically created at the start of class or module body ' + 'execution,\n' + 'if annotations are found statically.\n' + '\n' + 'If the assignment target is not simple (an attribute, ' + 'subscript node,\n' + 'or parenthesized name), the annotation is evaluated if in ' + 'class or\n' + 'module scope, but not stored.\n' '\n' 'If a name is annotated in a function scope, then this name is ' 'local\n' @@ -555,31 +560,67 @@ topics = {'assert': 'The "assert" statement\n' 'evaluate it\n' 'raises a "NameError" exception.\n' '\n' - '**Private name mangling:** When an identifier that ' - 'textually occurs in\n' - 'a class definition begins with two or more underscore ' - 'characters and\n' - 'does not end in two or more underscores, it is ' - 'considered a *private\n' - 'name* of that class. Private names are transformed to a ' - 'longer form\n' - 'before code is generated for them. The transformation ' - 'inserts the\n' - 'class name, with leading underscores removed and a ' - 'single underscore\n' - 'inserted, in front of the name. For example, the ' - 'identifier "__spam"\n' - 'occurring in a class named "Ham" will be transformed to ' - '"_Ham__spam".\n' - 'This transformation is independent of the syntactical ' + '\n' + 'Private name mangling\n' + '=====================\n' + '\n' + 'When an identifier that textually occurs in a class ' + 'definition begins\n' + 'with two or more underscore characters and does not end ' + 'in two or more\n' + 'underscores, it is considered a *private name* of that ' + 'class.\n' + '\n' + 'See also: The class specifications.\n' + '\n' + 'More precisely, private names are transformed to a ' + 'longer form before\n' + 'code is generated for them. If the transformed name is ' + 'longer than\n' + '255 characters, implementation-defined truncation may ' + 'happen.\n' + '\n' + 'The transformation is independent of the syntactical ' 'context in which\n' - 'the identifier is used. If the transformed name is ' - 'extremely long\n' - '(longer than 255 characters), implementation defined ' - 'truncation may\n' - 'happen. If the class name consists only of underscores, ' - 'no\n' - 'transformation is done.\n', + 'the identifier is used but only the following private ' + 'identifiers are\n' + 'mangled:\n' + '\n' + '* Any name used as the name of a variable that is ' + 'assigned or read or\n' + ' any name of an attribute being accessed.\n' + '\n' + ' The "__name__" attribute of nested functions, classes, ' + 'and type\n' + ' aliases is however not mangled.\n' + '\n' + '* The name of imported modules, e.g., "__spam" in ' + '"import __spam". If\n' + ' the module is part of a package (i.e., its name ' + 'contains a dot), the\n' + ' name is *not* mangled, e.g., the "__foo" in "import ' + '__foo.bar" is\n' + ' not mangled.\n' + '\n' + '* The name of an imported member, e.g., "__f" in "from ' + 'spam import\n' + ' __f".\n' + '\n' + 'The transformation rule is defined as follows:\n' + '\n' + '* The class name, with leading underscores removed and a ' + 'single\n' + ' leading underscore inserted, is inserted in front of ' + 'the identifier,\n' + ' e.g., the identifier "__spam" occurring in a class ' + 'named "Foo",\n' + ' "_Foo" or "__Foo" is transformed to "_Foo__spam".\n' + '\n' + '* If the class name consists only of underscores, the ' + 'transformation\n' + ' is the identity, e.g., the identifier "__spam" ' + 'occurring in a class\n' + ' named "_" or "__" is left as is.\n', 'atom-literals': 'Literals\n' '********\n' '\n' @@ -592,10 +633,10 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'Evaluation of a literal yields an object of the given type ' '(string,\n' - 'bytes, integer, floating point number, complex number) with ' + 'bytes, integer, floating-point number, complex number) with ' 'the given\n' 'value. The value may be approximated in the case of ' - 'floating point\n' + 'floating-point\n' 'and imaginary (complex) literals. See section Literals for ' 'details.\n' '\n' @@ -1163,10 +1204,10 @@ topics = {'assert': 'The "assert" statement\n' 'target.\n' 'The target is only evaluated once.\n' '\n' - 'An augmented assignment expression like "x += 1" can be ' - 'rewritten as\n' - '"x = x + 1" to achieve a similar, but not exactly equal effect. ' - 'In the\n' + 'An augmented assignment statement like "x += 1" can be ' + 'rewritten as "x\n' + '= x + 1" to achieve a similar, but not exactly equal effect. In ' + 'the\n' 'augmented version, "x" is only evaluated once. Also, when ' 'possible,\n' 'the actual operation is performed *in-place*, meaning that ' @@ -1239,6 +1280,10 @@ topics = {'assert': 'The "assert" statement\n' 'The "@" (at) operator is intended to be used for matrix\n' 'multiplication. No builtin Python types implement this operator.\n' '\n' + 'This operation can be customized using the special "__matmul__()" ' + 'and\n' + '"__rmatmul__()" methods.\n' + '\n' 'Added in version 3.5.\n' '\n' 'The "/" (division) and "//" (floor division) operators yield the\n' @@ -1251,17 +1296,19 @@ topics = {'assert': 'The "assert" statement\n' 'result. Division by zero raises the "ZeroDivisionError" ' 'exception.\n' '\n' - 'This operation can be customized using the special "__truediv__()" ' + 'The division operation can be customized using the special\n' + '"__truediv__()" and "__rtruediv__()" methods. The floor division\n' + 'operation can be customized using the special "__floordiv__()" ' 'and\n' - '"__floordiv__()" methods.\n' + '"__rfloordiv__()" methods.\n' '\n' 'The "%" (modulo) operator yields the remainder from the division ' 'of\n' 'the first argument by the second. The numeric arguments are ' 'first\n' 'converted to a common type. A zero right argument raises the\n' - '"ZeroDivisionError" exception. The arguments may be floating ' - 'point\n' + '"ZeroDivisionError" exception. The arguments may be ' + 'floating-point\n' 'numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals ' '"4*0.7 +\n' '0.34".) The modulo operator always yields a result with the same ' @@ -1288,13 +1335,13 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'The *modulo* operation can be customized using the special ' '"__mod__()"\n' - 'method.\n' + 'and "__rmod__()" methods.\n' '\n' 'The floor division operator, the modulo operator, and the ' '"divmod()"\n' 'function are not defined for complex numbers. Instead, convert to ' 'a\n' - 'floating point number using the "abs()" function if appropriate.\n' + 'floating-point number using the "abs()" function if appropriate.\n' '\n' 'The "+" (addition) operator yields the sum of its arguments. The\n' 'arguments must either both be numbers or both be sequences of the ' @@ -1313,7 +1360,8 @@ topics = {'assert': 'The "assert" statement\n' 'The numeric arguments are first converted to a common type.\n' '\n' 'This operation can be customized using the special "__sub__()" ' - 'method.\n', + 'and\n' + '"__rsub__()" methods.\n', 'bitwise': 'Binary bitwise operations\n' '*************************\n' '\n' @@ -2388,18 +2436,16 @@ topics = {'assert': 'The "assert" statement\n' 'An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if ' - 'the\n' - 'resulting object is “compatible” with the exception. An object ' - 'is\n' - 'compatible with an exception if the object is the class or a ' - '*non-\n' - 'virtual base class* of the exception object, or a tuple ' - 'containing an\n' - 'item that is the class or a non-virtual base class of the ' - 'exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. ' + 'The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception ' + 'object, or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -2548,13 +2594,16 @@ topics = {'assert': 'The "assert" statement\n' ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type ' - 'cannot be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and ' - '"return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot ' + 'be\n' + '"except*:". Furthermore, this expression cannot contain ' + 'exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same ' + '"try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -4400,7 +4449,7 @@ topics = {'assert': 'The "assert" statement\n' 'converted to\n' ' complex;\n' '\n' - '* otherwise, if either argument is a floating point number, ' + '* otherwise, if either argument is a floating-point number, ' 'the other\n' ' is converted to floating point;\n' '\n' @@ -4511,6 +4560,10 @@ topics = {'assert': 'The "assert" statement\n' ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -6413,10 +6466,10 @@ topics = {'assert': 'The "assert" statement\n' 'that expression. (To create an empty tuple, use an empty pair ' 'of\n' 'parentheses: "()".)\n', - 'floating': 'Floating point literals\n' + 'floating': 'Floating-point literals\n' '***********************\n' '\n' - 'Floating point literals are described by the following lexical\n' + 'Floating-point literals are described by the following lexical\n' 'definitions:\n' '\n' ' floatnumber ::= pointfloat | exponentfloat\n' @@ -6430,12 +6483,12 @@ topics = {'assert': 'The "assert" statement\n' 'using\n' 'radix 10. For example, "077e010" is legal, and denotes the same ' 'number\n' - 'as "77e10". The allowed range of floating point literals is\n' + 'as "77e10". The allowed range of floating-point literals is\n' 'implementation-dependent. As in integer literals, underscores ' 'are\n' 'supported for digit grouping.\n' '\n' - 'Some examples of floating point literals:\n' + 'Some examples of floating-point literals:\n' '\n' ' 3.14 10. .001 1e100 3.14e-10 0e0 ' '3.14_15_93\n' @@ -6818,7 +6871,7 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'The "\'_\'" option signals the use of an underscore for a ' 'thousands\n' - 'separator for floating point presentation types and for ' + 'separator for floating-point presentation types and for ' 'integer\n' 'presentation type "\'d\'". For integer presentation types ' '"\'b\'", "\'o\'",\n' @@ -6945,11 +6998,11 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'In addition to the above presentation types, integers can ' 'be formatted\n' - 'with the floating point presentation types listed below ' + 'with the floating-point presentation types listed below ' '(except "\'n\'"\n' 'and "None"). When doing so, "float()" is used to convert ' 'the integer\n' - 'to a floating point number before formatting.\n' + 'to a floating-point number before formatting.\n' '\n' 'The available presentation types for "float" and "Decimal" ' 'values are:\n' @@ -7807,11 +7860,11 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'An imaginary literal yields a complex number with a real part ' 'of 0.0.\n' - 'Complex numbers are represented as a pair of floating point ' + 'Complex numbers are represented as a pair of floating-point ' 'numbers\n' 'and have the same restrictions on their range. To create a ' 'complex\n' - 'number with a nonzero real part, add a floating point number to ' + 'number with a nonzero real part, add a floating-point number to ' 'it,\n' 'e.g., "(3+4j)". Some examples of imaginary literals:\n' '\n' @@ -8605,8 +8658,8 @@ topics = {'assert': 'The "assert" statement\n' 'numbers': 'Numeric literals\n' '****************\n' '\n' - 'There are three types of numeric literals: integers, floating ' - 'point\n' + 'There are three types of numeric literals: integers, ' + 'floating-point\n' 'numbers, and imaginary numbers. There are no complex literals\n' '(complex numbers can be formed by adding a real number and an\n' 'imaginary number).\n' @@ -9176,8 +9229,8 @@ topics = {'assert': 'The "assert" statement\n' '"complex"\n' 'number. (In earlier versions it raised a "ValueError".)\n' '\n' - 'This operation can be customized using the special "__pow__()" ' - 'method.\n', + 'This operation can be customized using the special "__pow__()" and\n' + '"__rpow__()" methods.\n', 'raise': 'The "raise" statement\n' '*********************\n' '\n' @@ -9591,9 +9644,12 @@ topics = {'assert': 'The "assert" statement\n' 'the\n' 'second argument.\n' '\n' - 'This operation can be customized using the special ' - '"__lshift__()" and\n' - '"__rshift__()" methods.\n' + 'The left shift operation can be customized using the special\n' + '"__lshift__()" and "__rlshift__()" methods. The right shift ' + 'operation\n' + 'can be customized using the special "__rshift__()" and ' + '"__rrshift__()"\n' + 'methods.\n' '\n' 'A right shift by *n* bits is defined as floor division by ' '"pow(2,n)".\n' @@ -9863,6 +9919,10 @@ topics = {'assert': 'The "assert" statement\n' ' It is not guaranteed that "__del__()" methods are called ' 'for\n' ' objects that still exist when the interpreter exits.\n' + ' "weakref.finalize" provides a straightforward way to ' + 'register a\n' + ' cleanup function to be called when an object is garbage ' + 'collected.\n' '\n' ' Note:\n' '\n' @@ -12657,11 +12717,11 @@ topics = {'assert': 'The "assert" statement\n' ' and are deemed to delimit empty strings (for example,\n' ' "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', ' '\'2\']"). The *sep* argument\n' - ' may consist of multiple characters (for example,\n' - ' "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', ' - '\'3\']"). Splitting an\n' - ' empty string with a specified separator returns ' - '"[\'\']".\n' + ' may consist of multiple characters as a single ' + 'delimiter (to split\n' + ' with multiple delimiters, use "re.split()"). Splitting ' + 'an empty\n' + ' string with a specified separator returns "[\'\']".\n' '\n' ' For example:\n' '\n' @@ -12671,6 +12731,8 @@ topics = {'assert': 'The "assert" statement\n' " ['1', '2,3']\n" " >>> '1,2,,3,'.split(',')\n" " ['1', '2', '', '3', '']\n" + " >>> '1<>2<>3<4'.split('<>')\n" + " ['1', '2', '3<4']\n" '\n' ' If *sep* is not specified or is "None", a different ' 'splitting\n' @@ -13351,14 +13413,15 @@ topics = {'assert': 'The "assert" statement\n' 'clauses in turn until one is found that matches the exception. An\n' 'expression-less "except" clause, if present, must be last; it ' 'matches\n' - 'any exception. For an "except" clause with an expression, that\n' - 'expression is evaluated, and the clause matches the exception if the\n' - 'resulting object is “compatible” with the exception. An object is\n' - 'compatible with an exception if the object is the class or a *non-\n' - 'virtual base class* of the exception object, or a tuple containing ' - 'an\n' - 'item that is the class or a non-virtual base class of the exception\n' - 'object.\n' + 'any exception.\n' + '\n' + 'For an "except" clause with an expression, the expression must\n' + 'evaluate to an exception type or a tuple of exception types. The\n' + 'raised exception matches an "except" clause whose expression ' + 'evaluates\n' + 'to the class or a *non-virtual base class* of the exception object, ' + 'or\n' + 'to a tuple that contains such a class.\n' '\n' 'If no "except" clause matches the exception, the search for an\n' 'exception handler continues in the surrounding code and on the\n' @@ -13487,12 +13550,13 @@ topics = {'assert': 'The "assert" statement\n' ' ...\n' " ExceptionGroup('', (BlockingIOError()))\n" '\n' - 'An "except*" clause must have a matching type, and this type cannot ' - 'be\n' - 'a subclass of "BaseExceptionGroup". It is not possible to mix ' - '"except"\n' - 'and "except*" in the same "try". "break", "continue" and "return"\n' - 'cannot appear in an "except*" clause.\n' + 'An "except*" clause must have a matching expression; it cannot be\n' + '"except*:". Furthermore, this expression cannot contain exception\n' + 'group types, because that would have ambiguous semantics.\n' + '\n' + 'It is not possible to mix "except" and "except*" in the same "try".\n' + '"break", "continue" and "return" cannot appear in an "except*" ' + 'clause.\n' '\n' '\n' '"else" clause\n' @@ -13653,7 +13717,7 @@ topics = {'assert': 'The "assert" statement\n' '\n' '* A sign is shown only when the number is negative.\n' '\n' - 'Python distinguishes between integers, floating point numbers, and\n' + 'Python distinguishes between integers, floating-point numbers, and\n' 'complex numbers:\n' '\n' '\n' @@ -13698,28 +13762,28 @@ topics = {'assert': 'The "assert" statement\n' '"numbers.Real" ("float")\n' '------------------------\n' '\n' - 'These represent machine-level double precision floating point ' + 'These represent machine-level double precision floating-point ' 'numbers.\n' 'You are at the mercy of the underlying machine architecture (and C ' 'or\n' 'Java implementation) for the accepted range and handling of ' 'overflow.\n' - 'Python does not support single-precision floating point numbers; ' + 'Python does not support single-precision floating-point numbers; ' 'the\n' 'savings in processor and memory usage that are usually the reason ' 'for\n' 'using these are dwarfed by the overhead of using objects in Python, ' 'so\n' 'there is no reason to complicate the language with two kinds of\n' - 'floating point numbers.\n' + 'floating-point numbers.\n' '\n' '\n' '"numbers.Complex" ("complex")\n' '-----------------------------\n' '\n' 'These represent complex numbers as a pair of machine-level double\n' - 'precision floating point numbers. The same caveats apply as for\n' - 'floating point numbers. The real and imaginary parts of a complex\n' + 'precision floating-point numbers. The same caveats apply as for\n' + 'floating-point numbers. The real and imaginary parts of a complex\n' 'number "z" can be retrieved through the read-only attributes ' '"z.real"\n' 'and "z.imag".\n' @@ -14134,21 +14198,10 @@ topics = {'assert': 'The "assert" statement\n' 'to\n' 'calling "f(C,1)" where "f" is the underlying function.\n' '\n' - 'Note that the transformation from function object to instance ' - 'method\n' - 'object happens each time the attribute is retrieved from the ' - 'instance.\n' - 'In some cases, a fruitful optimization is to assign the attribute ' - 'to a\n' - 'local variable and call that local variable. Also notice that this\n' - 'transformation only happens for user-defined functions; other ' - 'callable\n' - 'objects (and all non-callable objects) are retrieved without\n' - 'transformation. It is also important to note that user-defined\n' - 'functions which are attributes of a class instance are not ' - 'converted\n' - 'to bound methods; this *only* happens when the function is an\n' - 'attribute of the class.\n' + 'It is important to note that user-defined functions which are\n' + 'attributes of a class instance are not converted to bound methods;\n' + 'this *only* happens when the function is an attribute of the ' + 'class.\n' '\n' '\n' 'Generator functions\n' @@ -15155,7 +15208,7 @@ topics = {'assert': 'The "assert" statement\n' '\n' ' Return a shallow copy of the dictionary.\n' '\n' - ' classmethod fromkeys(iterable, value=None)\n' + ' classmethod fromkeys(iterable, value=None, /)\n' '\n' ' Create a new dictionary with keys from *iterable* and ' 'values set\n' @@ -15923,7 +15976,9 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same length as ' + 'the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that by ' 'default the\n' @@ -16280,7 +16335,7 @@ topics = {'assert': 'The "assert" statement\n' '\n' ' * The linspace recipe shows how to implement a lazy version of ' 'range\n' - ' suitable for floating point applications.\n', + ' suitable for floating-point applications.\n', 'typesseq-mutable': 'Mutable Sequence Types\n' '**********************\n' '\n' @@ -16387,8 +16442,9 @@ topics = {'assert': 'The "assert" statement\n' '\n' 'Notes:\n' '\n' - '1. *t* must have the same length as the slice it is ' - 'replacing.\n' + '1. If *k* is not equal to "1", *t* must have the same ' + 'length as the\n' + ' slice it is replacing.\n' '\n' '2. The optional argument *i* defaults to "-1", so that ' 'by default the\n' diff --git a/contrib/tools/python3/Lib/re/_casefix.py b/contrib/tools/python3/Lib/re/_casefix.py index 06507d08bee..fed2d84fc01 100644 --- a/contrib/tools/python3/Lib/re/_casefix.py +++ b/contrib/tools/python3/Lib/re/_casefix.py @@ -1,4 +1,4 @@ -# Auto-generated by Tools/scripts/generate_re_casefix.py. +# Auto-generated by Tools/build/generate_re_casefix.py. # Maps the code of lowercased character to codes of different lowercased # characters which have the same uppercase. diff --git a/contrib/tools/python3/Lib/sched.py b/contrib/tools/python3/Lib/sched.py index 14613cf2987..fb20639d459 100644 --- a/contrib/tools/python3/Lib/sched.py +++ b/contrib/tools/python3/Lib/sched.py @@ -11,7 +11,7 @@ substituting time and sleep from built-in module time, or you can implement simulated time by writing your own functions. This can also be used to integrate scheduling with STDWIN events; the delay function is allowed to modify the queue. Time can be expressed as -integers or floating point numbers, as long as it is consistent. +integers or floating-point numbers, as long as it is consistent. Events are specified by tuples (time, priority, action, argument, kwargs). As in UNIX, lower priority numbers mean higher priority; in this diff --git a/contrib/tools/python3/Lib/socket.py b/contrib/tools/python3/Lib/socket.py index d796082e054..c1880c4ea51 100644 --- a/contrib/tools/python3/Lib/socket.py +++ b/contrib/tools/python3/Lib/socket.py @@ -592,16 +592,65 @@ if hasattr(_socket.socket, "share"): return socket(0, 0, 0, info) __all__.append("fromshare") -if hasattr(_socket, "socketpair"): +# Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain. +# This is used if _socket doesn't natively provide socketpair. It's +# always defined so that it can be patched in for testing purposes. +def _fallback_socketpair(family=AF_INET, type=SOCK_STREAM, proto=0): + if family == AF_INET: + host = _LOCALHOST + elif family == AF_INET6: + host = _LOCALHOST_V6 + else: + raise ValueError("Only AF_INET and AF_INET6 socket address families " + "are supported") + if type != SOCK_STREAM: + raise ValueError("Only SOCK_STREAM socket type is supported") + if proto != 0: + raise ValueError("Only protocol zero is supported") + + # We create a connected TCP socket. Note the trick with + # setblocking(False) that prevents us from having to create a thread. + lsock = socket(family, type, proto) + try: + lsock.bind((host, 0)) + lsock.listen() + # On IPv6, ignore flow_info and scope_id + addr, port = lsock.getsockname()[:2] + csock = socket(family, type, proto) + try: + csock.setblocking(False) + try: + csock.connect((addr, port)) + except (BlockingIOError, InterruptedError): + pass + csock.setblocking(True) + ssock, _ = lsock.accept() + except: + csock.close() + raise + finally: + lsock.close() - def socketpair(family=None, type=SOCK_STREAM, proto=0): - """socketpair([family[, type[, proto]]]) -> (socket object, socket object) + # Authenticating avoids using a connection from something else + # able to connect to {host}:{port} instead of us. + # We expect only AF_INET and AF_INET6 families. + try: + if ( + ssock.getsockname() != csock.getpeername() + or csock.getsockname() != ssock.getpeername() + ): + raise ConnectionError("Unexpected peer connection") + except: + # getsockname() and getpeername() can fail + # if either socket isn't connected. + ssock.close() + csock.close() + raise - Create a pair of socket objects from the sockets returned by the platform - socketpair() function. - The arguments are the same as for socket() except the default family is - AF_UNIX if defined on the platform; otherwise, the default is AF_INET. - """ + return (ssock, csock) + +if hasattr(_socket, "socketpair"): + def socketpair(family=None, type=SOCK_STREAM, proto=0): if family is None: try: family = AF_UNIX @@ -613,44 +662,7 @@ if hasattr(_socket, "socketpair"): return a, b else: - - # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain. - def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0): - if family == AF_INET: - host = _LOCALHOST - elif family == AF_INET6: - host = _LOCALHOST_V6 - else: - raise ValueError("Only AF_INET and AF_INET6 socket address families " - "are supported") - if type != SOCK_STREAM: - raise ValueError("Only SOCK_STREAM socket type is supported") - if proto != 0: - raise ValueError("Only protocol zero is supported") - - # We create a connected TCP socket. Note the trick with - # setblocking(False) that prevents us from having to create a thread. - lsock = socket(family, type, proto) - try: - lsock.bind((host, 0)) - lsock.listen() - # On IPv6, ignore flow_info and scope_id - addr, port = lsock.getsockname()[:2] - csock = socket(family, type, proto) - try: - csock.setblocking(False) - try: - csock.connect((addr, port)) - except (BlockingIOError, InterruptedError): - pass - csock.setblocking(True) - ssock, _ = lsock.accept() - except: - csock.close() - raise - finally: - lsock.close() - return (ssock, csock) + socketpair = _fallback_socketpair __all__.append("socketpair") socketpair.__doc__ = """socketpair([family[, type[, proto]]]) -> (socket object, socket object) diff --git a/contrib/tools/python3/Lib/statistics.py b/contrib/tools/python3/Lib/statistics.py index 6bd214bbfe2..db108b3e2c8 100644 --- a/contrib/tools/python3/Lib/statistics.py +++ b/contrib/tools/python3/Lib/statistics.py @@ -11,7 +11,7 @@ Calculating averages Function Description ================== ================================================== mean Arithmetic mean (average) of data. -fmean Fast, floating point arithmetic mean. +fmean Fast, floating-point arithmetic mean. geometric_mean Geometric mean of data. harmonic_mean Harmonic mean of data. median Median (middle value) of data. diff --git a/contrib/tools/python3/Lib/symtable.py b/contrib/tools/python3/Lib/symtable.py index 4b0bc6f497a..f95639bee3a 100644 --- a/contrib/tools/python3/Lib/symtable.py +++ b/contrib/tools/python3/Lib/symtable.py @@ -217,8 +217,37 @@ class Class(SymbolTable): """ if self.__methods is None: d = {} + + def is_local_symbol(ident): + flags = self._table.symbols.get(ident, 0) + return ((flags >> SCOPE_OFF) & SCOPE_MASK) == LOCAL + for st in self._table.children: - d[st.name] = 1 + # pick the function-like symbols that are local identifiers + if is_local_symbol(st.name): + match st.type: + case _symtable.TYPE_FUNCTION: + # generators are of type TYPE_FUNCTION with a ".0" + # parameter as a first parameter (which makes them + # distinguishable from a function named 'genexpr') + if st.name == 'genexpr' and '.0' in st.varnames: + continue + d[st.name] = 1 + case _symtable.TYPE_TYPE_PARAM: + # Get the function-def block in the annotation + # scope 'st' with the same identifier, if any. + scope_name = st.name + for c in st.children: + if c.name == scope_name and c.type == _symtable.TYPE_FUNCTION: + # A generic generator of type TYPE_FUNCTION + # cannot be a direct child of 'st' (but it + # can be a descendant), e.g.: + # + # class A: + # type genexpr[genexpr] = (x for x in []) + assert scope_name != 'genexpr' or '.0' not in c.varnames + d[scope_name] = 1 + break self.__methods = tuple(d) return self.__methods diff --git a/contrib/tools/python3/Lib/tabnanny.py b/contrib/tools/python3/Lib/tabnanny.py index e2ac6837f15..d06c4c221e9 100755 --- a/contrib/tools/python3/Lib/tabnanny.py +++ b/contrib/tools/python3/Lib/tabnanny.py @@ -107,14 +107,14 @@ def check(file): errprint("%r: Token Error: %s" % (file, msg)) return - except SyntaxError as msg: - errprint("%r: Token Error: %s" % (file, msg)) - return - except IndentationError as msg: errprint("%r: Indentation Error: %s" % (file, msg)) return + except SyntaxError as msg: + errprint("%r: Syntax Error: %s" % (file, msg)) + return + except NannyNag as nag: badline = nag.get_lineno() line = nag.get_line() diff --git a/contrib/tools/python3/Lib/threading.py b/contrib/tools/python3/Lib/threading.py index 98cb43c6972..0bba85d08a0 100644 --- a/contrib/tools/python3/Lib/threading.py +++ b/contrib/tools/python3/Lib/threading.py @@ -332,7 +332,7 @@ class Condition: awakened or timed out, it re-acquires the lock and returns. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). When the underlying lock is an RLock, it is not released using its @@ -642,7 +642,7 @@ class Event: the optional timeout occurs. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). This method returns the internal flag on exit, so it will always return @@ -685,6 +685,8 @@ class Barrier: default for all subsequent 'wait()' calls. """ + if parties < 1: + raise ValueError("parties must be > 0") self._cond = Condition(Lock()) self._action = action self._timeout = timeout @@ -1120,7 +1122,7 @@ class Thread: or until the optional timeout occurs. When the timeout argument is present and not None, it should be a - floating point number specifying a timeout for the operation in seconds + floating-point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened -- if the thread is still alive, the join() call timed out. diff --git a/contrib/tools/python3/Lib/typing.py b/contrib/tools/python3/Lib/typing.py index 882dc4da58e..94c211292ec 100644 --- a/contrib/tools/python3/Lib/typing.py +++ b/contrib/tools/python3/Lib/typing.py @@ -927,15 +927,24 @@ class ForwardRef(_Final, _root=True): globalns = getattr( sys.modules.get(self.__forward_module__, None), '__dict__', globalns ) + + # type parameters require some special handling, + # as they exist in their own scope + # but `eval()` does not have a dedicated parameter for that scope. + # For classes, names in type parameter scopes should override + # names in the global scope (which here are called `localns`!), + # but should in turn be overridden by names in the class scope + # (which here are called `globalns`!) if type_params: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - locals_to_pass = {param.__name__: param for param in type_params} | localns - else: - locals_to_pass = localns + globalns, localns = dict(globalns), dict(localns) + for param in type_params: + param_name = param.__name__ + if not self.__forward_is_class__ or param_name not in globalns: + globalns[param_name] = param + localns.pop(param_name, None) + type_ = _type_check( - eval(self.__forward_code__, globalns, locals_to_pass), + eval(self.__forward_code__, globalns, localns), "Forward references must evaluate to types.", is_argument=self.__forward_is_argument__, allow_special_forms=self.__forward_is_class__, diff --git a/contrib/tools/python3/Lib/unittest/mock.py b/contrib/tools/python3/Lib/unittest/mock.py index 486e0c634b8..9398f56506b 100644 --- a/contrib/tools/python3/Lib/unittest/mock.py +++ b/contrib/tools/python3/Lib/unittest/mock.py @@ -800,6 +800,9 @@ class NonCallableMock(Base): mock_name = f'{self._extract_mock_name()}.{name}' raise AttributeError(f'Cannot set {mock_name}') + if isinstance(value, PropertyMock): + self.__dict__[name] = value + return return object.__setattr__(self, name, value) @@ -1478,13 +1481,12 @@ class _patch(object): if isinstance(original, type): # If we're patching out a class and there is a spec inherit = True - if spec is None and _is_async_obj(original): - Klass = AsyncMock - else: - Klass = MagicMock - _kwargs = {} + + # Determine the Klass to use if new_callable is not None: Klass = new_callable + elif spec is None and _is_async_obj(original): + Klass = AsyncMock elif spec is not None or spec_set is not None: this_spec = spec if spec_set is not None: @@ -1497,7 +1499,12 @@ class _patch(object): Klass = AsyncMock elif not_callable: Klass = NonCallableMagicMock + else: + Klass = MagicMock + else: + Klass = MagicMock + _kwargs = {} if spec is not None: _kwargs['spec'] = spec if spec_set is not None: @@ -2718,6 +2725,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, if not unsafe: _check_spec_arg_typos(kwargs) + _name = kwargs.pop('name', _name) + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + _kwargs.update(kwargs) Klass = MagicMock @@ -2735,13 +2748,6 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None, elif is_type and instance and not _instance_callable(spec): Klass = NonCallableMagicMock - _name = _kwargs.pop('name', _name) - - _new_name = _name - if _parent is None: - # for a top level object no _new_name should be set - _new_name = '' - mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, name=_name, **_kwargs) diff --git a/contrib/tools/python3/Lib/xml/etree/ElementTree.py b/contrib/tools/python3/Lib/xml/etree/ElementTree.py index fd2cc8704e1..c657b52d12b 100644 --- a/contrib/tools/python3/Lib/xml/etree/ElementTree.py +++ b/contrib/tools/python3/Lib/xml/etree/ElementTree.py @@ -201,7 +201,7 @@ class Element: def __bool__(self): warnings.warn( - "Testing an element's truth value will raise an exception in " + "Testing an element's truth value will always return True in " "future versions. " "Use specific 'len(elem)' or 'elem is not None' test instead.", DeprecationWarning, stacklevel=2 diff --git a/contrib/tools/python3/Lib/ya.make b/contrib/tools/python3/Lib/ya.make index a21fe71ade8..d6607786ff6 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.4) +VERSION(3.12.5) -ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.12.4.tar.gz) +ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.12.5.tar.gz) LICENSE(Python-2.0) |