mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Update some libs and tests from 3.14.3 to 3.14.4 (#7576)
* Update some libs and tests to 3.14.4 * Update `pydoc_data`
This commit is contained in:
1 parent
f937cde7af
commit
dcae8f0d53
15 files changed
+722
-377
No files matched your search
Vendored
+7
@@ -168,6 +168,13 @@ class Logcat:
|
||||
# message.
|
||||
message = message.replace(b"\x00", b"\xc0\x80")
|
||||
|
||||
# On API level 30 and higher, Logcat will strip any number of leading
|
||||
# newlines. This is visible in all `logcat` modes, even --binary. Work
|
||||
# around this by adding a leading space, which shouldn't make any
|
||||
# difference to the log's usability.
|
||||
if message.startswith(b"\n"):
|
||||
message = b" " + message
|
||||
|
||||
with self._lock:
|
||||
now = time()
|
||||
self._bucket_level += (
|
||||
|
||||
Vendored
+16
-3
@@ -919,7 +919,7 @@ def get_annotations(
|
||||
does not exist, the __annotate__ function is called. The
|
||||
FORWARDREF format uses __annotations__ if it exists and can be
|
||||
evaluated, and otherwise falls back to calling the __annotate__ function.
|
||||
The SOURCE format tries __annotate__ first, and falls back to
|
||||
The STRING format tries __annotate__ first, and falls back to
|
||||
using __annotations__, stringified using annotations_to_string().
|
||||
|
||||
This function handles several details for you:
|
||||
@@ -1037,13 +1037,26 @@ def get_annotations(
|
||||
obj_globals = obj_locals = unwrap = None
|
||||
|
||||
if unwrap is not None:
|
||||
# Use an id-based visited set to detect cycles in the __wrapped__
|
||||
# and functools.partial.func chain (e.g. f.__wrapped__ = f).
|
||||
# On cycle detection we stop and use whatever __globals__ we have
|
||||
# found so far, mirroring the approach of inspect.unwrap().
|
||||
_seen_ids = {id(unwrap)}
|
||||
while True:
|
||||
if hasattr(unwrap, "__wrapped__"):
|
||||
unwrap = unwrap.__wrapped__
|
||||
candidate = unwrap.__wrapped__
|
||||
if id(candidate) in _seen_ids:
|
||||
break
|
||||
_seen_ids.add(id(candidate))
|
||||
unwrap = candidate
|
||||
continue
|
||||
if functools := sys.modules.get("functools"):
|
||||
if isinstance(unwrap, functools.partial):
|
||||
unwrap = unwrap.func
|
||||
candidate = unwrap.func
|
||||
if id(candidate) in _seen_ids:
|
||||
break
|
||||
_seen_ids.add(id(candidate))
|
||||
unwrap = candidate
|
||||
continue
|
||||
break
|
||||
if hasattr(unwrap, "__globals__"):
|
||||
|
||||
Vendored
+6
-4
@@ -149,6 +149,10 @@ def _copy_items(items):
|
||||
return copy.copy(items)
|
||||
|
||||
|
||||
def _identity(value):
|
||||
return value
|
||||
|
||||
|
||||
# ===============
|
||||
# Formatting Help
|
||||
# ===============
|
||||
@@ -200,7 +204,7 @@ class HelpFormatter(object):
|
||||
self._decolor = decolor
|
||||
else:
|
||||
self._theme = get_theme(force_no_color=True).argparse
|
||||
self._decolor = lambda text: text
|
||||
self._decolor = _identity
|
||||
|
||||
# ===============================
|
||||
# Section and indentation methods
|
||||
@@ -1903,9 +1907,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||
self._subparsers = None
|
||||
|
||||
# register types
|
||||
def identity(string):
|
||||
return string
|
||||
self.register('type', None, identity)
|
||||
self.register('type', None, _identity)
|
||||
|
||||
# add help argument if necessary
|
||||
# (using explicit default to override global argument_default)
|
||||
|
||||
Vendored
+24
-3
@@ -15,7 +15,7 @@ __all__ = ["glob", "iglob", "escape", "translate"]
|
||||
|
||||
def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
|
||||
include_hidden=False):
|
||||
"""Return a list of paths matching a pathname pattern.
|
||||
"""Return a list of paths matching a `pathname` pattern.
|
||||
|
||||
The pattern may contain simple shell-style wildcards a la
|
||||
fnmatch. Unlike fnmatch, filenames starting with a
|
||||
@@ -25,6 +25,15 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
|
||||
The order of the returned list is undefined. Sort it if you need a
|
||||
particular order.
|
||||
|
||||
If `root_dir` is not None, it should be a path-like object specifying the
|
||||
root directory for searching. It has the same effect as changing the
|
||||
current directory before calling it (without actually
|
||||
changing it). If pathname is relative, the result will contain
|
||||
paths relative to `root_dir`.
|
||||
|
||||
If `dir_fd` is not None, it should be a file descriptor referring to a
|
||||
directory, and paths will then be relative to that directory.
|
||||
|
||||
If `include_hidden` is true, the patterns '*', '?', '**' will match hidden
|
||||
directories.
|
||||
|
||||
@@ -36,7 +45,7 @@ def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
|
||||
|
||||
def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
|
||||
include_hidden=False):
|
||||
"""Return an iterator which yields the paths matching a pathname pattern.
|
||||
"""Return an iterator which yields the paths matching a `pathname` pattern.
|
||||
|
||||
The pattern may contain simple shell-style wildcards a la
|
||||
fnmatch. However, unlike fnmatch, filenames starting with a
|
||||
@@ -46,7 +55,19 @@ def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False,
|
||||
The order of the returned paths is undefined. Sort them if you need a
|
||||
particular order.
|
||||
|
||||
If recursive is true, the pattern '**' will match any files and
|
||||
If `root_dir` is not None, it should be a path-like object specifying
|
||||
the root directory for searching. It has the same effect as changing
|
||||
the current directory before calling it (without actually
|
||||
changing it). If pathname is relative, the result will contain
|
||||
paths relative to `root_dir`.
|
||||
|
||||
If `dir_fd` is not None, it should be a file descriptor referring to a
|
||||
directory, and paths will then be relative to that directory.
|
||||
|
||||
If `include_hidden` is true, the patterns '*', '?', '**' will match hidden
|
||||
directories.
|
||||
|
||||
If `recursive` is true, the pattern '**' will match any files and
|
||||
zero or more directories and subdirectories.
|
||||
"""
|
||||
sys.audit("glob.glob", pathname, recursive)
|
||||
|
||||
Vendored
+2
-1
@@ -2660,11 +2660,12 @@ class Parameter:
|
||||
The annotation for the parameter if specified. If the
|
||||
parameter has no annotation, this attribute is set to
|
||||
`Parameter.empty`.
|
||||
* kind : str
|
||||
* kind
|
||||
Describes how argument values are bound to the parameter.
|
||||
Possible values: `Parameter.POSITIONAL_ONLY`,
|
||||
`Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
|
||||
`Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
|
||||
Every value has a `description` attribute describing meaning.
|
||||
"""
|
||||
|
||||
__slots__ = ('_name', '_kind', '_default', '_annotation')
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Autogenerated by Sphinx on Tue Feb 3 17:32:13 2026
|
||||
# Autogenerated by Sphinx on Tue Apr 7 16:13:12 2026
|
||||
# as part of the release process.
|
||||
|
||||
module_docs = {
|
||||
|
||||
Vendored
+561
-327
File diff suppressed because it is too large.
Load diff
Vendored
+10
-9
@@ -351,15 +351,16 @@ def _args_from_interpreter_flags():
|
||||
# -X options
|
||||
if dev_mode:
|
||||
args.extend(('-X', 'dev'))
|
||||
for opt in ('faulthandler', 'tracemalloc', 'importtime',
|
||||
'frozen_modules', 'showrefcount', 'utf8', 'gil'):
|
||||
if opt in xoptions:
|
||||
value = xoptions[opt]
|
||||
if value is True:
|
||||
arg = opt
|
||||
else:
|
||||
arg = '%s=%s' % (opt, value)
|
||||
args.extend(('-X', arg))
|
||||
for opt in sorted(xoptions):
|
||||
if opt == 'dev':
|
||||
# handled above via sys.flags.dev_mode
|
||||
continue
|
||||
value = xoptions[opt]
|
||||
if value is True:
|
||||
arg = opt
|
||||
else:
|
||||
arg = '%s=%s' % (opt, value)
|
||||
args.extend(('-X', arg))
|
||||
|
||||
return args
|
||||
|
||||
|
||||
Vendored
+18
-18
@@ -57,10 +57,11 @@ _bin_openflags = _text_openflags
|
||||
if hasattr(_os, 'O_BINARY'):
|
||||
_bin_openflags |= _os.O_BINARY
|
||||
|
||||
if hasattr(_os, 'TMP_MAX'):
|
||||
TMP_MAX = _os.TMP_MAX
|
||||
else:
|
||||
TMP_MAX = 10000
|
||||
# This is more than enough.
|
||||
# Each name contains over 40 random bits. Even with a million temporary
|
||||
# files, the chance of a conflict is less than 1 in a million, and with
|
||||
# 20 attempts, it is less than 1e-120.
|
||||
TMP_MAX = 20
|
||||
|
||||
# This variable _was_ unused for legacy reasons, see issue 10354.
|
||||
# But as of 3.5 we actually use it at runtime so changing it would
|
||||
@@ -196,8 +197,7 @@ def _get_default_tempdir(dirlist=None):
|
||||
for dir in dirlist:
|
||||
if dir != _os.curdir:
|
||||
dir = _os.path.abspath(dir)
|
||||
# Try only a few names per directory.
|
||||
for seq in range(100):
|
||||
for seq in range(TMP_MAX):
|
||||
name = next(namer)
|
||||
filename = _os.path.join(dir, name)
|
||||
try:
|
||||
@@ -213,10 +213,8 @@ def _get_default_tempdir(dirlist=None):
|
||||
except FileExistsError:
|
||||
pass
|
||||
except PermissionError:
|
||||
# This exception is thrown when a directory with the chosen name
|
||||
# already exists on windows.
|
||||
if (_os.name == 'nt' and _os.path.isdir(dir) and
|
||||
_os.access(dir, _os.W_OK)):
|
||||
# See the comment in mkdtemp().
|
||||
if _os.name == 'nt' and _os.path.isdir(dir):
|
||||
continue
|
||||
break # no point trying more names in this directory
|
||||
except OSError:
|
||||
@@ -258,10 +256,8 @@ def _mkstemp_inner(dir, pre, suf, flags, output_type):
|
||||
except FileExistsError:
|
||||
continue # try again
|
||||
except PermissionError:
|
||||
# This exception is thrown when a directory with the chosen name
|
||||
# already exists on windows.
|
||||
if (_os.name == 'nt' and _os.path.isdir(dir) and
|
||||
_os.access(dir, _os.W_OK)):
|
||||
# See the comment in mkdtemp().
|
||||
if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
@@ -386,10 +382,14 @@ def mkdtemp(suffix=None, prefix=None, dir=None):
|
||||
except FileExistsError:
|
||||
continue # try again
|
||||
except PermissionError:
|
||||
# This exception is thrown when a directory with the chosen name
|
||||
# already exists on windows.
|
||||
if (_os.name == 'nt' and _os.path.isdir(dir) and
|
||||
_os.access(dir, _os.W_OK)):
|
||||
# On Posix, this exception is raised when the user has no
|
||||
# write access to the parent directory.
|
||||
# On Windows, it is also raised when a directory with
|
||||
# the chosen name already exists, or if the parent directory
|
||||
# is not a directory.
|
||||
# We cannot distinguish between "directory-exists-error" and
|
||||
# "access-denied-error".
|
||||
if _os.name == 'nt' and _os.path.isdir(dir) and seq < TMP_MAX - 1:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
Vendored
+25
@@ -646,6 +646,31 @@ class TestGetAnnotations(unittest.TestCase):
|
||||
get_annotations(foo, format=Format.FORWARDREF, eval_str=True)
|
||||
get_annotations(foo, format=Format.STRING, eval_str=True)
|
||||
|
||||
def test_eval_str_wrapped_cycle_self(self):
|
||||
# gh-146556: self-referential __wrapped__ cycle must not hang.
|
||||
def f(x: 'int') -> 'str': ...
|
||||
f.__wrapped__ = f
|
||||
# Cycle is detected and broken; globals from f itself are used.
|
||||
result = get_annotations(f, eval_str=True)
|
||||
self.assertEqual(result, {'x': int, 'return': str})
|
||||
|
||||
def test_eval_str_wrapped_cycle_mutual(self):
|
||||
# gh-146556: mutual __wrapped__ cycle (a -> b -> a) must not hang.
|
||||
def a(x: 'int'): ...
|
||||
def b(): ...
|
||||
a.__wrapped__ = b
|
||||
b.__wrapped__ = a
|
||||
result = get_annotations(a, eval_str=True)
|
||||
self.assertEqual(result, {'x': int})
|
||||
|
||||
def test_eval_str_wrapped_chain_no_cycle(self):
|
||||
# gh-146556: a valid (non-cyclic) __wrapped__ chain must still work.
|
||||
def inner(x: 'int'): ...
|
||||
def outer(x: 'int'): ...
|
||||
outer.__wrapped__ = inner
|
||||
result = get_annotations(outer, eval_str=True)
|
||||
self.assertEqual(result, {'x': int})
|
||||
|
||||
def test_stock_annotations(self):
|
||||
def foo(a: int, b: str):
|
||||
pass
|
||||
|
||||
Vendored
+21
@@ -81,6 +81,27 @@ class StdStreamTest(unittest.TestCase):
|
||||
self.assertRegex(mocked_stderr.getvalue(), r'usage:')
|
||||
|
||||
|
||||
class TestArgumentParserPickleable(unittest.TestCase):
|
||||
|
||||
@force_not_colorized
|
||||
def test_pickle_roundtrip(self):
|
||||
import pickle
|
||||
parser = argparse.ArgumentParser(exit_on_error=False)
|
||||
parser.add_argument('--foo', type=int, default=42)
|
||||
parser.add_argument('bar', nargs='?', default='baz')
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
with self.subTest(protocol=proto):
|
||||
# Try to pickle and unpickle the parser
|
||||
parser2 = pickle.loads(pickle.dumps(parser, protocol=proto))
|
||||
# Check that the round-tripped parser still works
|
||||
ns = parser2.parse_args(['--foo', '123', 'quux'])
|
||||
self.assertEqual(ns.foo, 123)
|
||||
self.assertEqual(ns.bar, 'quux')
|
||||
ns2 = parser2.parse_args([])
|
||||
self.assertEqual(ns2.foo, 42)
|
||||
self.assertEqual(ns2.bar, 'baz')
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
+1
-2
@@ -6234,8 +6234,7 @@ class TestSignatureDefinitions(unittest.TestCase):
|
||||
def test_os_module_has_signatures(self):
|
||||
unsupported_signature = {'chmod', 'utime'}
|
||||
unsupported_signature |= {name for name in
|
||||
['get_terminal_size', 'link', 'posix_spawn', 'posix_spawnp',
|
||||
'register_at_fork', 'startfile']
|
||||
['get_terminal_size', 'link', 'register_at_fork', 'startfile']
|
||||
if hasattr(os, name)}
|
||||
self._test_module_has_signatures(os, unsupported_signature=unsupported_signature)
|
||||
|
||||
|
||||
Vendored
+25
-6
@@ -330,17 +330,36 @@ def _mock_candidate_names(*names):
|
||||
class TestBadTempdir:
|
||||
def test_read_only_directory(self):
|
||||
with _inside_empty_temp_dir():
|
||||
oldmode = mode = os.stat(tempfile.tempdir).st_mode
|
||||
mode &= ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
|
||||
os.chmod(tempfile.tempdir, mode)
|
||||
probe = os.path.join(tempfile.tempdir, 'probe')
|
||||
if os.name == 'nt':
|
||||
cmd = ['icacls', tempfile.tempdir, '/deny', 'Everyone:(W)']
|
||||
stdout = None if support.verbose > 1 else subprocess.DEVNULL
|
||||
subprocess.run(cmd, check=True, stdout=stdout)
|
||||
else:
|
||||
oldmode = mode = os.stat(tempfile.tempdir).st_mode
|
||||
mode &= ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
|
||||
mode = stat.S_IREAD
|
||||
os.chmod(tempfile.tempdir, mode)
|
||||
try:
|
||||
if os.access(tempfile.tempdir, os.W_OK):
|
||||
# Check that the directory is read-only.
|
||||
try:
|
||||
os.mkdir(probe)
|
||||
except PermissionError:
|
||||
pass
|
||||
else:
|
||||
os.rmdir(probe)
|
||||
self.skipTest("can't set the directory read-only")
|
||||
# gh-66305: Now it takes a split second, but previously
|
||||
# it took about 10 days on Windows.
|
||||
with self.assertRaises(PermissionError):
|
||||
self.make_temp()
|
||||
self.assertEqual(os.listdir(tempfile.tempdir), [])
|
||||
finally:
|
||||
os.chmod(tempfile.tempdir, oldmode)
|
||||
if os.name == 'nt':
|
||||
cmd = ['icacls', tempfile.tempdir, '/grant:r', 'Everyone:(M)']
|
||||
subprocess.run(cmd, check=True, stdout=stdout)
|
||||
else:
|
||||
os.chmod(tempfile.tempdir, oldmode)
|
||||
self.assertEqual(os.listdir(tempfile.tempdir), [])
|
||||
|
||||
def test_nonexisting_directory(self):
|
||||
with _inside_empty_temp_dir():
|
||||
|
||||
Vendored
+4
-2
@@ -1,6 +1,6 @@
|
||||
"""Parse (absolute and relative) URLs.
|
||||
|
||||
urlparse module is based upon the following RFC specifications.
|
||||
urllib.parse module is based upon the following RFC specifications.
|
||||
|
||||
RFC 3986 (STD66): "Uniform Resource Identifiers" by T. Berners-Lee, R. Fielding
|
||||
and L. Masinter, January 2005.
|
||||
@@ -20,7 +20,7 @@ RFC 1738: "Uniform Resource Locators (URL)" by T. Berners-Lee, L. Masinter, M.
|
||||
McCahill, December 1994
|
||||
|
||||
RFC 3986 is considered the current standard and any future changes to
|
||||
urlparse module should conform with it. The urlparse module is
|
||||
urllib.parse module should conform with it. The urllib.parse module is
|
||||
currently not entirely compliant with this RFC due to defacto
|
||||
scenarios for parsing, and for backward compatibility purposes, some
|
||||
parsing quirks from older RFCs are retained. The testcases in
|
||||
@@ -390,6 +390,8 @@ def urlparse(url, scheme='', allow_fragments=True):
|
||||
path or query.
|
||||
|
||||
Note that % escapes are not expanded.
|
||||
|
||||
urlsplit() should generally be used instead of urlparse().
|
||||
"""
|
||||
url, scheme, _coerce_result = _coerce_args(url, scheme)
|
||||
scheme, netloc, url, params, query, fragment = _urlparse(url, scheme, allow_fragments)
|
||||
|
||||
Vendored
+1
-1
@@ -950,7 +950,7 @@ class ZipExtFile(io.BufferedIOBase):
|
||||
"""
|
||||
|
||||
# Max size supported by decompressor.
|
||||
MAX_N = 1 << 31 - 1
|
||||
MAX_N = (1 << 31) - 1
|
||||
|
||||
# Read from compressed files in 4k blocks.
|
||||
MIN_READ_SIZE = 4096
|
||||
|
||||
Reference in new issue
Block a user