aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/compression/bz2.py (renamed from Lib/compression/bz2/__init__.py)0
-rw-r--r--Lib/compression/gzip.py (renamed from Lib/compression/gzip/__init__.py)0
-rw-r--r--Lib/compression/lzma.py (renamed from Lib/compression/lzma/__init__.py)0
-rw-r--r--Lib/compression/zlib.py (renamed from Lib/compression/zlib/__init__.py)0
-rw-r--r--Lib/compression/zstd/__init__.py52
-rw-r--r--Lib/compression/zstd/_zstdfile.py66
-rw-r--r--Lib/getpass.py11
-rw-r--r--Lib/logging/__init__.py32
-rw-r--r--Lib/tarfile.py2
-rw-r--r--Lib/test/support/__init__.py4
-rw-r--r--Lib/test/test_fractions.py208
-rw-r--r--Lib/test/test_free_threading/test_functools.py75
-rw-r--r--Lib/test/test_genericalias.py6
-rw-r--r--Lib/test/test_logging.py23
-rw-r--r--Lib/test/test_typing.py30
-rw-r--r--Lib/test/test_wave.py26
-rw-r--r--Lib/typing.py8
-rw-r--r--Lib/venv/__init__.py7
-rw-r--r--Lib/wave.py29
19 files changed, 332 insertions, 247 deletions
diff --git a/Lib/compression/bz2/__init__.py b/Lib/compression/bz2.py
index 16815d6cd20..16815d6cd20 100644
--- a/Lib/compression/bz2/__init__.py
+++ b/Lib/compression/bz2.py
diff --git a/Lib/compression/gzip/__init__.py b/Lib/compression/gzip.py
index 552f48f948a..552f48f948a 100644
--- a/Lib/compression/gzip/__init__.py
+++ b/Lib/compression/gzip.py
diff --git a/Lib/compression/lzma/__init__.py b/Lib/compression/lzma.py
index b4bc7ccb1db..b4bc7ccb1db 100644
--- a/Lib/compression/lzma/__init__.py
+++ b/Lib/compression/lzma.py
diff --git a/Lib/compression/zlib/__init__.py b/Lib/compression/zlib.py
index 3aa7e2db90e..3aa7e2db90e 100644
--- a/Lib/compression/zlib/__init__.py
+++ b/Lib/compression/zlib.py
diff --git a/Lib/compression/zstd/__init__.py b/Lib/compression/zstd/__init__.py
index e7b2f427164..84b25914b0a 100644
--- a/Lib/compression/zstd/__init__.py
+++ b/Lib/compression/zstd/__init__.py
@@ -2,28 +2,28 @@
__all__ = (
# compression.zstd
- "COMPRESSION_LEVEL_DEFAULT",
- "compress",
- "CompressionParameter",
- "decompress",
- "DecompressionParameter",
- "finalize_dict",
- "get_frame_info",
- "Strategy",
- "train_dict",
+ 'COMPRESSION_LEVEL_DEFAULT',
+ 'compress',
+ 'CompressionParameter',
+ 'decompress',
+ 'DecompressionParameter',
+ 'finalize_dict',
+ 'get_frame_info',
+ 'Strategy',
+ 'train_dict',
# compression.zstd._zstdfile
- "open",
- "ZstdFile",
+ 'open',
+ 'ZstdFile',
# _zstd
- "get_frame_size",
- "zstd_version",
- "zstd_version_info",
- "ZstdCompressor",
- "ZstdDecompressor",
- "ZstdDict",
- "ZstdError",
+ 'get_frame_size',
+ 'zstd_version',
+ 'zstd_version_info',
+ 'ZstdCompressor',
+ 'ZstdDecompressor',
+ 'ZstdDict',
+ 'ZstdError',
)
import _zstd
@@ -43,6 +43,7 @@ COMPRESSION_LEVEL_DEFAULT = _zstd.ZSTD_CLEVEL_DEFAULT
class FrameInfo:
"""Information about a Zstandard frame."""
+
__slots__ = 'decompressed_size', 'dictionary_id'
def __init__(self, decompressed_size, dictionary_id):
@@ -125,13 +126,13 @@ def finalize_dict(zstd_dict, /, samples, dict_size, level):
chunks = b''.join(samples)
chunk_sizes = tuple(_nbytes(sample) for sample in samples)
if not chunks:
- raise ValueError("The samples are empty content, can't finalize the"
+ raise ValueError("The samples are empty content, can't finalize the "
"dictionary.")
- dict_content = _zstd.finalize_dict(zstd_dict.dict_content,
- chunks, chunk_sizes,
- dict_size, level)
+ dict_content = _zstd.finalize_dict(zstd_dict.dict_content, chunks,
+ chunk_sizes, dict_size, level)
return ZstdDict(dict_content)
+
def compress(data, level=None, options=None, zstd_dict=None):
"""Return Zstandard compressed *data* as bytes.
@@ -147,6 +148,7 @@ def compress(data, level=None, options=None, zstd_dict=None):
comp = ZstdCompressor(level=level, options=options, zstd_dict=zstd_dict)
return comp.compress(data, mode=ZstdCompressor.FLUSH_FRAME)
+
def decompress(data, zstd_dict=None, options=None):
"""Decompress one or more frames of Zstandard compressed *data*.
@@ -162,12 +164,12 @@ def decompress(data, zstd_dict=None, options=None):
decomp = ZstdDecompressor(options=options, zstd_dict=zstd_dict)
results.append(decomp.decompress(data))
if not decomp.eof:
- raise ZstdError("Compressed data ended before the "
- "end-of-stream marker was reached")
+ raise ZstdError('Compressed data ended before the '
+ 'end-of-stream marker was reached')
data = decomp.unused_data
if not data:
break
- return b"".join(results)
+ return b''.join(results)
class CompressionParameter(enum.IntEnum):
diff --git a/Lib/compression/zstd/_zstdfile.py b/Lib/compression/zstd/_zstdfile.py
index 0086c13d3c1..8770e576f50 100644
--- a/Lib/compression/zstd/_zstdfile.py
+++ b/Lib/compression/zstd/_zstdfile.py
@@ -4,7 +4,7 @@ from _zstd import (ZstdCompressor, ZstdDecompressor, ZstdError,
ZSTD_DStreamOutSize)
from compression._common import _streams
-__all__ = ("ZstdFile", "open")
+__all__ = ('ZstdFile', 'open')
_MODE_CLOSED = 0
_MODE_READ = 1
@@ -31,15 +31,15 @@ class ZstdFile(_streams.BaseStream):
FLUSH_BLOCK = ZstdCompressor.FLUSH_BLOCK
FLUSH_FRAME = ZstdCompressor.FLUSH_FRAME
- def __init__(self, file, /, mode="r", *,
+ def __init__(self, file, /, mode='r', *,
level=None, options=None, zstd_dict=None):
"""Open a Zstandard compressed file in binary mode.
*file* can be either an file-like object, or a file name to open.
- *mode* can be "r" for reading (default), "w" for (over)writing, "x" for
- creating exclusively, or "a" for appending. These can equivalently be
- given as "rb", "wb", "xb" and "ab" respectively.
+ *mode* can be 'r' for reading (default), 'w' for (over)writing, 'x' for
+ creating exclusively, or 'a' for appending. These can equivalently be
+ given as 'rb', 'wb', 'xb' and 'ab' respectively.
*level* is an optional int specifying the compression level to use,
or COMPRESSION_LEVEL_DEFAULT if not given.
@@ -57,33 +57,33 @@ class ZstdFile(_streams.BaseStream):
self._buffer = None
if not isinstance(mode, str):
- raise ValueError("mode must be a str")
+ raise ValueError('mode must be a str')
if options is not None and not isinstance(options, dict):
- raise TypeError("options must be a dict or None")
- mode = mode.removesuffix("b") # handle rb, wb, xb, ab
- if mode == "r":
+ raise TypeError('options must be a dict or None')
+ mode = mode.removesuffix('b') # handle rb, wb, xb, ab
+ if mode == 'r':
if level is not None:
- raise TypeError("level is illegal in read mode")
+ raise TypeError('level is illegal in read mode')
self._mode = _MODE_READ
- elif mode in {"w", "a", "x"}:
+ elif mode in {'w', 'a', 'x'}:
if level is not None and not isinstance(level, int):
- raise TypeError("level must be int or None")
+ raise TypeError('level must be int or None')
self._mode = _MODE_WRITE
self._compressor = ZstdCompressor(level=level, options=options,
zstd_dict=zstd_dict)
self._pos = 0
else:
- raise ValueError(f"Invalid mode: {mode!r}")
+ raise ValueError(f'Invalid mode: {mode!r}')
if isinstance(file, (str, bytes, PathLike)):
self._fp = io.open(file, f'{mode}b')
self._close_fp = True
- elif ((mode == 'r' and hasattr(file, "read"))
- or (mode != 'r' and hasattr(file, "write"))):
+ elif ((mode == 'r' and hasattr(file, 'read'))
+ or (mode != 'r' and hasattr(file, 'write'))):
self._fp = file
else:
- raise TypeError("file must be a file-like object "
- "or a str, bytes, or PathLike object")
+ raise TypeError('file must be a file-like object '
+ 'or a str, bytes, or PathLike object')
if self._mode == _MODE_READ:
raw = _streams.DecompressReader(
@@ -151,22 +151,22 @@ class ZstdFile(_streams.BaseStream):
return
self._check_not_closed()
if mode not in {self.FLUSH_BLOCK, self.FLUSH_FRAME}:
- raise ValueError("Invalid mode argument, expected either "
- "ZstdFile.FLUSH_FRAME or "
- "ZstdFile.FLUSH_BLOCK")
+ raise ValueError('Invalid mode argument, expected either '
+ 'ZstdFile.FLUSH_FRAME or '
+ 'ZstdFile.FLUSH_BLOCK')
if self._compressor.last_mode == mode:
return
# Flush zstd block/frame, and write.
data = self._compressor.flush(mode)
self._fp.write(data)
- if hasattr(self._fp, "flush"):
+ if hasattr(self._fp, 'flush'):
self._fp.flush()
def read(self, size=-1):
"""Read up to size uncompressed bytes from the file.
If size is negative or omitted, read until EOF is reached.
- Returns b"" if the file is already at EOF.
+ Returns b'' if the file is already at EOF.
"""
if size is None:
size = -1
@@ -178,7 +178,7 @@ class ZstdFile(_streams.BaseStream):
making multiple reads from the underlying stream. Reads up to a
buffer's worth of data if size is negative.
- Returns b"" if the file is at EOF.
+ Returns b'' if the file is at EOF.
"""
self._check_can_read()
if size < 0:
@@ -293,7 +293,7 @@ class ZstdFile(_streams.BaseStream):
return self._mode == _MODE_WRITE
-def open(file, /, mode="rb", *, level=None, options=None, zstd_dict=None,
+def open(file, /, mode='rb', *, level=None, options=None, zstd_dict=None,
encoding=None, errors=None, newline=None):
"""Open a Zstandard compressed file in binary or text mode.
@@ -301,8 +301,8 @@ def open(file, /, mode="rb", *, level=None, options=None, zstd_dict=None,
in which case the named file is opened, or it can be an existing file object
to read from or write to.
- The mode parameter can be "r", "rb" (default), "w", "wb", "x", "xb", "a",
- "ab" for binary mode, or "rt", "wt", "xt", "at" for text mode.
+ The mode parameter can be 'r', 'rb' (default), 'w', 'wb', 'x', 'xb', 'a',
+ 'ab' for binary mode, or 'rt', 'wt', 'xt', 'at' for text mode.
The level, options, and zstd_dict parameters specify the settings the same
as ZstdFile.
@@ -323,19 +323,19 @@ def open(file, /, mode="rb", *, level=None, options=None, zstd_dict=None,
behavior, and line ending(s).
"""
- text_mode = "t" in mode
- mode = mode.replace("t", "")
+ text_mode = 't' in mode
+ mode = mode.replace('t', '')
if text_mode:
- if "b" in mode:
- raise ValueError(f"Invalid mode: {mode!r}")
+ if 'b' in mode:
+ raise ValueError(f'Invalid mode: {mode!r}')
else:
if encoding is not None:
- raise ValueError("Argument 'encoding' not supported in binary mode")
+ raise ValueError('Argument "encoding" not supported in binary mode')
if errors is not None:
- raise ValueError("Argument 'errors' not supported in binary mode")
+ raise ValueError('Argument "errors" not supported in binary mode')
if newline is not None:
- raise ValueError("Argument 'newline' not supported in binary mode")
+ raise ValueError('Argument "newline" not supported in binary mode')
binary_file = ZstdFile(file, mode, level=level, options=options,
zstd_dict=zstd_dict)
diff --git a/Lib/getpass.py b/Lib/getpass.py
index f571425e541..1dd40e25e09 100644
--- a/Lib/getpass.py
+++ b/Lib/getpass.py
@@ -119,9 +119,9 @@ def win_getpass(prompt='Password: ', stream=None, *, echo_char=None):
raise KeyboardInterrupt
if c == '\b':
if echo_char and pw:
- msvcrt.putch('\b')
- msvcrt.putch(' ')
- msvcrt.putch('\b')
+ msvcrt.putwch('\b')
+ msvcrt.putwch(' ')
+ msvcrt.putwch('\b')
pw = pw[:-1]
else:
pw = pw + c
@@ -132,14 +132,15 @@ def win_getpass(prompt='Password: ', stream=None, *, echo_char=None):
return pw
-def fallback_getpass(prompt='Password: ', stream=None):
+def fallback_getpass(prompt='Password: ', stream=None, *, echo_char=None):
+ _check_echo_char(echo_char)
import warnings
warnings.warn("Can not control echo on the terminal.", GetPassWarning,
stacklevel=2)
if not stream:
stream = sys.stderr
print("Warning: Password input may be echoed.", file=stream)
- return _raw_input(prompt, stream)
+ return _raw_input(prompt, stream, echo_char=echo_char)
def _check_echo_char(echo_char):
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 283a1055182..f2d1a02629d 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -2057,6 +2057,15 @@ def basicConfig(**kwargs):
created FileHandler, causing it to be used when the file is
opened in text mode. If not specified, the default value is
`backslashreplace`.
+ formatter If specified, set this formatter instance for all involved
+ handlers.
+ If not specified, the default is to create and use an instance of
+ `logging.Formatter` based on arguments 'format', 'datefmt' and
+ 'style'.
+ When 'formatter' is specified together with any of the three
+ arguments 'format', 'datefmt' and 'style', a `ValueError`
+ is raised to signal that these arguments would lose meaning
+ otherwise.
Note that you could specify a stream created using open(filename, mode)
rather than passing the filename and mode in. However, it should be
@@ -2079,6 +2088,9 @@ def basicConfig(**kwargs):
.. versionchanged:: 3.9
Added the ``encoding`` and ``errors`` parameters.
+
+ .. versionchanged:: 3.15
+ Added the ``formatter`` parameter.
"""
# Add thread safety in case someone mistakenly calls
# basicConfig() from multiple threads
@@ -2114,13 +2126,19 @@ def basicConfig(**kwargs):
stream = kwargs.pop("stream", None)
h = StreamHandler(stream)
handlers = [h]
- dfs = kwargs.pop("datefmt", None)
- style = kwargs.pop("style", '%')
- if style not in _STYLES:
- raise ValueError('Style must be one of: %s' % ','.join(
- _STYLES.keys()))
- fs = kwargs.pop("format", _STYLES[style][1])
- fmt = Formatter(fs, dfs, style)
+ fmt = kwargs.pop("formatter", None)
+ if fmt is None:
+ dfs = kwargs.pop("datefmt", None)
+ style = kwargs.pop("style", '%')
+ if style not in _STYLES:
+ raise ValueError('Style must be one of: %s' % ','.join(
+ _STYLES.keys()))
+ fs = kwargs.pop("format", _STYLES[style][1])
+ fmt = Formatter(fs, dfs, style)
+ else:
+ for forbidden_key in ("datefmt", "format", "style"):
+ if forbidden_key in kwargs:
+ raise ValueError(f"{forbidden_key!r} should not be specified together with 'formatter'")
for h in handlers:
if h.formatter is None:
h.setFormatter(fmt)
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index c0f5a609b9f..13889d76802 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2065,7 +2065,7 @@ class TarFile(object):
"gz": "gzopen", # gzip compressed tar
"bz2": "bz2open", # bzip2 compressed tar
"xz": "xzopen", # lzma compressed tar
- "zst": "zstopen" # zstd compressed tar
+ "zst": "zstopen", # zstd compressed tar
}
#--------------------------------------------------------------------------
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index c74c3a31909..9b6e80fdad9 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -696,9 +696,11 @@ def sortdict(dict):
return "{%s}" % withcommas
-def run_code(code: str) -> dict[str, object]:
+def run_code(code: str, extra_names: dict[str, object] | None = None) -> dict[str, object]:
"""Run a piece of code after dedenting it, and return its global namespace."""
ns = {}
+ if extra_names:
+ ns.update(extra_names)
exec(textwrap.dedent(code), ns)
return ns
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 84faa636064..96b3f305194 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -1,7 +1,7 @@
"""Tests for Lib/fractions.py."""
from decimal import Decimal
-from test.support import requires_IEEE_754
+from test.support import requires_IEEE_754, adjust_int_max_str_digits
import math
import numbers
import operator
@@ -395,12 +395,14 @@ class FractionTest(unittest.TestCase):
def testFromString(self):
self.assertEqual((5, 1), _components(F("5")))
+ self.assertEqual((5, 1), _components(F("005")))
self.assertEqual((3, 2), _components(F("3/2")))
self.assertEqual((3, 2), _components(F("3 / 2")))
self.assertEqual((3, 2), _components(F(" \n +3/2")))
self.assertEqual((-3, 2), _components(F("-3/2 ")))
- self.assertEqual((13, 2), _components(F(" 013/02 \n ")))
+ self.assertEqual((13, 2), _components(F(" 0013/002 \n ")))
self.assertEqual((16, 5), _components(F(" 3.2 ")))
+ self.assertEqual((16, 5), _components(F("003.2")))
self.assertEqual((-16, 5), _components(F(" -3.2 ")))
self.assertEqual((-3, 1), _components(F(" -3. ")))
self.assertEqual((3, 5), _components(F(" .6 ")))
@@ -419,116 +421,102 @@ class FractionTest(unittest.TestCase):
self.assertRaisesMessage(
ZeroDivisionError, "Fraction(3, 0)",
F, "3/0")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '3/'",
- F, "3/")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '/2'",
- F, "/2")
- self.assertRaisesMessage(
- # Denominators don't need a sign.
- ValueError, "Invalid literal for Fraction: '3/+2'",
- F, "3/+2")
- self.assertRaisesMessage(
- # Imitate float's parsing.
- ValueError, "Invalid literal for Fraction: '+ 3/2'",
- F, "+ 3/2")
- self.assertRaisesMessage(
- # Avoid treating '.' as a regex special character.
- ValueError, "Invalid literal for Fraction: '3a2'",
- F, "3a2")
- self.assertRaisesMessage(
- # Don't accept combinations of decimals and rationals.
- ValueError, "Invalid literal for Fraction: '3/7.2'",
- F, "3/7.2")
- self.assertRaisesMessage(
- # Don't accept combinations of decimals and rationals.
- ValueError, "Invalid literal for Fraction: '3.2/7'",
- F, "3.2/7")
- self.assertRaisesMessage(
- # Allow 3. and .3, but not .
- ValueError, "Invalid literal for Fraction: '.'",
- F, ".")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '_'",
- F, "_")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '_1'",
- F, "_1")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1__2'",
- F, "1__2")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '/_'",
- F, "/_")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1_/'",
- F, "1_/")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '_1/'",
- F, "_1/")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1__2/'",
- F, "1__2/")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/_'",
- F, "1/_")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/_1'",
- F, "1/_1")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/1__2'",
- F, "1/1__2")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1._111'",
- F, "1._111")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1.1__1'",
- F, "1.1__1")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1.1e+_1'",
- F, "1.1e+_1")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1.1e+1__1'",
- F, "1.1e+1__1")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '123.dd'",
- F, "123.dd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '123.5_dd'",
- F, "123.5_dd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: 'dd.5'",
- F, "dd.5")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '7_dd'",
- F, "7_dd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/dd'",
- F, "1/dd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/123_dd'",
- F, "1/123_dd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '789edd'",
- F, "789edd")
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '789e2_dd'",
- F, "789e2_dd")
+
+ def check_invalid(s):
+ msg = "Invalid literal for Fraction: " + repr(s)
+ self.assertRaisesMessage(ValueError, msg, F, s)
+
+ check_invalid("3/")
+ check_invalid("/2")
+ # Denominators don't need a sign.
+ check_invalid("3/+2")
+ check_invalid("3/-2")
+ # Imitate float's parsing.
+ check_invalid("+ 3/2")
+ check_invalid("- 3/2")
+ # Avoid treating '.' as a regex special character.
+ check_invalid("3a2")
+ # Don't accept combinations of decimals and rationals.
+ check_invalid("3/7.2")
+ check_invalid("3.2/7")
+ # No space around dot.
+ check_invalid("3 .2")
+ check_invalid("3. 2")
+ # No space around e.
+ check_invalid("3.2 e1")
+ check_invalid("3.2e 1")
+ # Fractional part don't need a sign.
+ check_invalid("3.+2")
+ check_invalid("3.-2")
+ # Only accept base 10.
+ check_invalid("0x10")
+ check_invalid("0x10/1")
+ check_invalid("1/0x10")
+ check_invalid("0x10.")
+ check_invalid("0x10.1")
+ check_invalid("1.0x10")
+ check_invalid("1.0e0x10")
+ # Only accept decimal digits.
+ check_invalid("³")
+ check_invalid("³/2")
+ check_invalid("3/²")
+ check_invalid("³.2")
+ check_invalid("3.²")
+ check_invalid("3.2e²")
+ check_invalid("¼")
+ # Allow 3. and .3, but not .
+ check_invalid(".")
+ check_invalid("_")
+ check_invalid("_1")
+ check_invalid("1__2")
+ check_invalid("/_")
+ check_invalid("1_/")
+ check_invalid("_1/")
+ check_invalid("1__2/")
+ check_invalid("1/_")
+ check_invalid("1/_1")
+ check_invalid("1/1__2")
+ check_invalid("1._111")
+ check_invalid("1.1__1")
+ check_invalid("1.1e+_1")
+ check_invalid("1.1e+1__1")
+ check_invalid("123.dd")
+ check_invalid("123.5_dd")
+ check_invalid("dd.5")
+ check_invalid("7_dd")
+ check_invalid("1/dd")
+ check_invalid("1/123_dd")
+ check_invalid("789edd")
+ check_invalid("789e2_dd")
# Test catastrophic backtracking.
val = "9"*50 + "_"
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '" + val + "'",
- F, val)
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1/" + val + "'",
- F, "1/" + val)
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1." + val + "'",
- F, "1." + val)
- self.assertRaisesMessage(
- ValueError, "Invalid literal for Fraction: '1.1+e" + val + "'",
- F, "1.1+e" + val)
+ check_invalid(val)
+ check_invalid("1/" + val)
+ check_invalid("1." + val)
+ check_invalid("." + val)
+ check_invalid("1.1+e" + val)
+ check_invalid("1.1e" + val)
+
+ def test_limit_int(self):
+ maxdigits = 5000
+ with adjust_int_max_str_digits(maxdigits):
+ msg = 'Exceeds the limit'
+ val = '1' * maxdigits
+ num = (10**maxdigits - 1)//9
+ self.assertEqual((num, 1), _components(F(val)))
+ self.assertRaisesRegex(ValueError, msg, F, val + '1')
+ self.assertEqual((num, 2), _components(F(val + '/2')))
+ self.assertRaisesRegex(ValueError, msg, F, val + '1/2')
+ self.assertEqual((1, num), _components(F('1/' + val)))
+ self.assertRaisesRegex(ValueError, msg, F, '1/1' + val)
+ self.assertEqual(((10**(maxdigits+1) - 1)//9, 10**maxdigits),
+ _components(F('1.' + val)))
+ self.assertRaisesRegex(ValueError, msg, F, '1.1' + val)
+ self.assertEqual((num, 10**maxdigits), _components(F('.' + val)))
+ self.assertRaisesRegex(ValueError, msg, F, '.1' + val)
+ self.assertRaisesRegex(ValueError, msg, F, '1.1e1' + val)
+ self.assertEqual((11, 10), _components(F('1.1e' + '0' * maxdigits)))
+ self.assertRaisesRegex(ValueError, msg, F, '1.1e' + '0' * (maxdigits+1))
def testImmutable(self):
r = F(7, 3)
diff --git a/Lib/test/test_free_threading/test_functools.py b/Lib/test/test_free_threading/test_functools.py
new file mode 100644
index 00000000000..a442fe056ce
--- /dev/null
+++ b/Lib/test/test_free_threading/test_functools.py
@@ -0,0 +1,75 @@
+import random
+import unittest
+
+from functools import lru_cache
+from threading import Barrier, Thread
+
+from test.support import threading_helper
+
+@threading_helper.requires_working_threading()
+class TestLRUCache(unittest.TestCase):
+
+ def _test_concurrent_operations(self, maxsize):
+ num_threads = 10
+ b = Barrier(num_threads)
+ @lru_cache(maxsize=maxsize)
+ def func(arg=0):
+ return object()
+
+
+ def thread_func():
+ b.wait()
+ for i in range(1000):
+ r = random.randint(0, 1000)
+ if i < 800:
+ func(i)
+ elif i < 900:
+ func.cache_info()
+ else:
+ func.cache_clear()
+
+ threads = []
+ for i in range(num_threads):
+ t = Thread(target=thread_func)
+ threads.append(t)
+
+ with threading_helper.start_threads(threads):
+ pass
+
+ def test_concurrent_operations_unbounded(self):
+ self._test_concurrent_operations(maxsize=None)
+
+ def test_concurrent_operations_bounded(self):
+ self._test_concurrent_operations(maxsize=128)
+
+ def _test_reentrant_cache_clear(self, maxsize):
+ num_threads = 10
+ b = Barrier(num_threads)
+ @lru_cache(maxsize=maxsize)
+ def func(arg=0):
+ func.cache_clear()
+ return object()
+
+
+ def thread_func():
+ b.wait()
+ for i in range(1000):
+ func(random.randint(0, 10000))
+
+ threads = []
+ for i in range(num_threads):
+ t = Thread(target=thread_func)
+ threads.append(t)
+
+ with threading_helper.start_threads(threads):
+ pass
+
+ def test_reentrant_cache_clear_unbounded(self):
+ self._test_reentrant_cache_clear(maxsize=None)
+
+ def test_reentrant_cache_clear_bounded(self):
+ self._test_reentrant_cache_clear(maxsize=128)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py
index 8d21ded4501..ea0dc241e39 100644
--- a/Lib/test/test_genericalias.py
+++ b/Lib/test/test_genericalias.py
@@ -61,6 +61,7 @@ try:
from tkinter import Event
except ImportError:
Event = None
+from string.templatelib import Template, Interpolation
from typing import TypeVar
T = TypeVar('T')
@@ -139,7 +140,10 @@ class BaseTest(unittest.TestCase):
DictReader, DictWriter,
array,
staticmethod,
- classmethod]
+ classmethod,
+ Template,
+ Interpolation,
+ ]
if ctypes is not None:
generic_types.extend((ctypes.Array, ctypes.LibraryLoader, ctypes.py_object))
if ValueProxy is not None:
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 1e5adcc8db1..fa5b1e43816 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -61,7 +61,7 @@ import warnings
import weakref
from http.server import HTTPServer, BaseHTTPRequestHandler
-from unittest.mock import patch
+from unittest.mock import call, Mock, patch
from urllib.parse import urlparse, parse_qs
from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
ThreadingTCPServer, StreamRequestHandler)
@@ -5655,12 +5655,19 @@ class BasicConfigTest(unittest.TestCase):
assertRaises = self.assertRaises
handlers = [logging.StreamHandler()]
stream = sys.stderr
+ formatter = logging.Formatter()
assertRaises(ValueError, logging.basicConfig, filename='test.log',
stream=stream)
assertRaises(ValueError, logging.basicConfig, filename='test.log',
handlers=handlers)
assertRaises(ValueError, logging.basicConfig, stream=stream,
handlers=handlers)
+ assertRaises(ValueError, logging.basicConfig, formatter=formatter,
+ format='%(message)s')
+ assertRaises(ValueError, logging.basicConfig, formatter=formatter,
+ datefmt='%H:%M:%S')
+ assertRaises(ValueError, logging.basicConfig, formatter=formatter,
+ style='%')
# Issue 23207: test for invalid kwargs
assertRaises(ValueError, logging.basicConfig, loglevel=logging.INFO)
# Should pop both filename and filemode even if filename is None
@@ -5795,6 +5802,20 @@ class BasicConfigTest(unittest.TestCase):
# didn't write anything due to the encoding error
self.assertEqual(data, r'')
+ def test_formatter_given(self):
+ mock_formatter = Mock()
+ mock_handler = Mock(formatter=None)
+ with patch("logging.Formatter") as mock_formatter_init:
+ logging.basicConfig(formatter=mock_formatter, handlers=[mock_handler])
+ self.assertEqual(mock_handler.setFormatter.call_args_list, [call(mock_formatter)])
+ self.assertEqual(mock_formatter_init.call_count, 0)
+
+ def test_formatter_not_given(self):
+ mock_handler = Mock(formatter=None)
+ with patch("logging.Formatter") as mock_formatter_init:
+ logging.basicConfig(handlers=[mock_handler])
+ self.assertEqual(mock_formatter_init.call_count, 1)
+
@support.requires_working_socket()
def test_log_taskName(self):
async def log_record():
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 6ef633e4545..246be22a0d8 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -8487,6 +8487,36 @@ class TypedDictTests(BaseTestCase):
self.assertEqual(Child.__required_keys__, frozenset(['a']))
self.assertEqual(Child.__optional_keys__, frozenset())
+ def test_inheritance_pep563(self):
+ def _make_td(future, class_name, annos, base, extra_names=None):
+ lines = []
+ if future:
+ lines.append('from __future__ import annotations')
+ lines.append('from typing import TypedDict')
+ lines.append(f'class {class_name}({base}):')
+ for name, anno in annos.items():
+ lines.append(f' {name}: {anno}')
+ code = '\n'.join(lines)
+ ns = run_code(code, extra_names)
+ return ns[class_name]
+
+ for base_future in (True, False):
+ for child_future in (True, False):
+ with self.subTest(base_future=base_future, child_future=child_future):
+ base = _make_td(
+ base_future, "Base", {"base": "int"}, "TypedDict"
+ )
+ self.assertIsNotNone(base.__annotate__)
+ child = _make_td(
+ child_future, "Child", {"child": "int"}, "Base", {"Base": base}
+ )
+ base_anno = ForwardRef("int", module="builtins") if base_future else int
+ child_anno = ForwardRef("int", module="builtins") if child_future else int
+ self.assertEqual(base.__annotations__, {'base': base_anno})
+ self.assertEqual(
+ child.__annotations__, {'child': child_anno, 'base': base_anno}
+ )
+
def test_required_notrequired_keys(self):
self.assertEqual(NontotalMovie.__required_keys__,
frozenset({"title"}))
diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py
index 5e771c8de96..6c3362857fc 100644
--- a/Lib/test/test_wave.py
+++ b/Lib/test/test_wave.py
@@ -136,32 +136,6 @@ class MiscTestCase(unittest.TestCase):
not_exported = {'WAVE_FORMAT_PCM', 'WAVE_FORMAT_EXTENSIBLE', 'KSDATAFORMAT_SUBTYPE_PCM'}
support.check__all__(self, wave, not_exported=not_exported)
- def test_read_deprecations(self):
- filename = support.findfile('pluck-pcm8.wav', subdir='audiodata')
- with wave.open(filename) as reader:
- with self.assertWarns(DeprecationWarning):
- with self.assertRaises(wave.Error):
- reader.getmark('mark')
- with self.assertWarns(DeprecationWarning):
- self.assertIsNone(reader.getmarkers())
-
- def test_write_deprecations(self):
- with io.BytesIO(b'') as tmpfile:
- with wave.open(tmpfile, 'wb') as writer:
- writer.setnchannels(1)
- writer.setsampwidth(1)
- writer.setframerate(1)
- writer.setcomptype('NONE', 'not compressed')
-
- with self.assertWarns(DeprecationWarning):
- with self.assertRaises(wave.Error):
- writer.setmark(0, 0, 'mark')
- with self.assertWarns(DeprecationWarning):
- with self.assertRaises(wave.Error):
- writer.getmark('mark')
- with self.assertWarns(DeprecationWarning):
- self.assertIsNone(writer.getmarkers())
-
class WaveLowLevelTest(unittest.TestCase):
diff --git a/Lib/typing.py b/Lib/typing.py
index 3d64480e143..98af61be8b0 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -3048,14 +3048,16 @@ class _TypedDictMeta(type):
else:
generic_base = ()
+ ns_annotations = ns.pop('__annotations__', None)
+
tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)
if not hasattr(tp_dict, '__orig_bases__'):
tp_dict.__orig_bases__ = bases
- if "__annotations__" in ns:
+ if ns_annotations is not None:
own_annotate = None
- own_annotations = ns["__annotations__"]
+ own_annotations = ns_annotations
elif (own_annotate := _lazy_annotationlib.get_annotate_from_class_namespace(ns)) is not None:
own_annotations = _lazy_annotationlib.call_annotate_function(
own_annotate, _lazy_annotationlib.Format.FORWARDREF, owner=tp_dict
@@ -3126,7 +3128,7 @@ class _TypedDictMeta(type):
if base_annotate is None:
continue
base_annos = _lazy_annotationlib.call_annotate_function(
- base.__annotate__, format, owner=base)
+ base_annotate, format, owner=base)
annos.update(base_annos)
if own_annotate is not None:
own = _lazy_annotationlib.call_annotate_function(
diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py
index 15e15b7a518..dc9c5991df7 100644
--- a/Lib/venv/__init__.py
+++ b/Lib/venv/__init__.py
@@ -313,11 +313,8 @@ class EnvBuilder:
copier(context.executable, path)
if not os.path.islink(path):
os.chmod(path, 0o755)
-
- suffixes = ['python', 'python3', f'python3.{sys.version_info[1]}']
- if sys.version_info[:2] == (3, 14):
- suffixes.append('𝜋thon')
- for suffix in suffixes:
+ for suffix in ('python', 'python3',
+ f'python3.{sys.version_info[1]}'):
path = os.path.join(binpath, suffix)
if not os.path.exists(path):
# Issue 18807: make copies if
diff --git a/Lib/wave.py b/Lib/wave.py
index a34af244c3e..929609fa524 100644
--- a/Lib/wave.py
+++ b/Lib/wave.py
@@ -20,10 +20,6 @@ This returns an instance of a class with the following public methods:
compression type ('not compressed' linear samples)
getparams() -- returns a namedtuple consisting of all of the
above in the above order
- getmarkers() -- returns None (for compatibility with the
- old aifc module)
- getmark(id) -- raises an error since the mark does not
- exist (for compatibility with the old aifc module)
readframes(n) -- returns at most n frames of audio
rewind() -- rewind to the beginning of the audio stream
setpos(pos) -- seek to the specified position
@@ -341,16 +337,6 @@ class Wave_read:
self.getframerate(), self.getnframes(),
self.getcomptype(), self.getcompname())
- def getmarkers(self):
- import warnings
- warnings._deprecated("Wave_read.getmarkers", remove=(3, 15))
- return None
-
- def getmark(self, id):
- import warnings
- warnings._deprecated("Wave_read.getmark", remove=(3, 15))
- raise Error('no marks')
-
def setpos(self, pos):
if pos < 0 or pos > self._nframes:
raise Error('position not in range')
@@ -551,21 +537,6 @@ class Wave_write:
return _wave_params(self._nchannels, self._sampwidth, self._framerate,
self._nframes, self._comptype, self._compname)
- def setmark(self, id, pos, name):
- import warnings
- warnings._deprecated("Wave_write.setmark", remove=(3, 15))
- raise Error('setmark() not supported')
-
- def getmark(self, id):
- import warnings
- warnings._deprecated("Wave_write.getmark", remove=(3, 15))
- raise Error('no marks')
-
- def getmarkers(self):
- import warnings
- warnings._deprecated("Wave_write.getmarkers", remove=(3, 15))
- return None
-
def tell(self):
return self._nframeswritten