diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e0e67e728490a..63cec40a185829 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -91,6 +91,35 @@ repos: args: [--enable=default-role] files: ^Doc/|^Misc/NEWS.d/ + - repo: https://github.com/oxipng/oxipng + rev: v9.1.5 + hooks: + - id: oxipng + args: [ "-o", "2", "--strip", "safe", "--alpha" ] + exclude: | + (?x)^( + PC/icons/*.png| + Android/testbed/app/src/main/res/drawable-xxhdpi/ic_launcher.png| + Objects/object_layout_*.png| + InternalDocs/images/python-cyclic-gc-*-new-page.png| + Doc/howto/logging_flow.png| + Doc/_static/og-image.png| + Doc/library/pathlib-inheritance.png| + Doc/library/tk_msg.png| + Doc/library/hashlib-blake2-tree.png| + Doc/library/turtle-star.png| + Doc/library/kde_example.png| + Doc/using/mac_installer_09_custom_install_free_threaded.png| + Doc/using/win_install_freethreaded.png| + Doc/using/win_installer.png| + Doc/using/mac_installer_*.png| + Tools/msi/bundle/SideBar.png| + Lib/profiling/sampling/_assets/python-logo-only.png| + Lib/test/tkinterdata/python.png| + Lib/test/test_email/data/python.png| + Lib/idlelib/Icons/idle_*.png| + )$ + - repo: local hooks: - id: blurb-no-space-c-api diff --git a/Android/testbed/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/Android/testbed/app/src/main/res/drawable-xxhdpi/ic_launcher.png index 741d6580d60e05..53ce92a3f1e6c7 100644 Binary files a/Android/testbed/app/src/main/res/drawable-xxhdpi/ic_launcher.png and b/Android/testbed/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 4f0199838e151d..b20495e672dd75 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1278,6 +1278,11 @@ PyConfig Default: ``0``. + .. deprecated-removed:: 3.15 3.17 + + The :option:`-b` and :option:`!-bb` options will become no-op in 3.17. + :c:member:`~PyConfig.bytes_warning` member will be removed in 3.17. + .. c:member:: int warn_default_encoding If non-zero, emit a :exc:`EncodingWarning` warning when :class:`io.TextIOWrapper` diff --git a/Doc/faq/python-video-icon.png b/Doc/faq/python-video-icon.png deleted file mode 100644 index 265da50c7b38fc..00000000000000 Binary files a/Doc/faq/python-video-icon.png and /dev/null differ diff --git a/Doc/howto/logging_flow.png b/Doc/howto/logging_flow.png index d60ed7c031585a..dd22541a48880c 100644 Binary files a/Doc/howto/logging_flow.png and b/Doc/howto/logging_flow.png differ diff --git a/Doc/library/hashlib-blake2-tree.png b/Doc/library/hashlib-blake2-tree.png index faef21b55f96b1..38aedb8138bb0c 100644 Binary files a/Doc/library/hashlib-blake2-tree.png and b/Doc/library/hashlib-blake2-tree.png differ diff --git a/Doc/library/kde_example.png b/Doc/library/kde_example.png index 4c26f26292faa5..ace5f6aa0c8efa 100644 Binary files a/Doc/library/kde_example.png and b/Doc/library/kde_example.png differ diff --git a/Doc/library/tk_msg.png b/Doc/library/tk_msg.png index 6495e63e84650d..753d2d73c036ca 100644 Binary files a/Doc/library/tk_msg.png and b/Doc/library/tk_msg.png differ diff --git a/Doc/library/turtle-star.png b/Doc/library/turtle-star.png index 0961e1e2153f72..c42e7176e4aac0 100644 Binary files a/Doc/library/turtle-star.png and b/Doc/library/turtle-star.png differ diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 448f2725e9a3db..3f8b52e2345b25 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -254,6 +254,15 @@ Miscellaneous options .. versionchanged:: 3.5 Affects also comparisons of :class:`bytes` with :class:`int`. + .. deprecated:: 3.15 + + Deprecate :option:`-b` and :option:`!-bb` command line options + and schedule them to become no-op in Python 3.17. + These were primarily helpers for the Python 2 -> 3 transition. + Starting with Python 3.17, no :exc:`BytesWarning` will be raised + for these cases; use a type checker instead. + + .. option:: -B If given, Python won't try to write ``.pyc`` files on the diff --git a/Doc/using/mac_installer_02_readme.png b/Doc/using/mac_installer_02_readme.png index a36efaf7d50fd6..a5fc0e2e541a7c 100644 Binary files a/Doc/using/mac_installer_02_readme.png and b/Doc/using/mac_installer_02_readme.png differ diff --git a/Doc/using/mac_installer_07_applications.png b/Doc/using/mac_installer_07_applications.png index 940219cad6f61c..6e6ca6fc199195 100644 Binary files a/Doc/using/mac_installer_07_applications.png and b/Doc/using/mac_installer_07_applications.png differ diff --git a/Doc/using/mac_installer_09_custom_install_free_threaded.png b/Doc/using/mac_installer_09_custom_install_free_threaded.png index 0f69c55eddb228..3f89d1ffafc7c6 100644 Binary files a/Doc/using/mac_installer_09_custom_install_free_threaded.png and b/Doc/using/mac_installer_09_custom_install_free_threaded.png differ diff --git a/Doc/using/win_install_freethreaded.png b/Doc/using/win_install_freethreaded.png index 0aa01c1df6e051..9e39dbee329ec4 100644 Binary files a/Doc/using/win_install_freethreaded.png and b/Doc/using/win_install_freethreaded.png differ diff --git a/Doc/using/win_installer.png b/Doc/using/win_installer.png index 03bf2d7b16c599..52af9a7387568e 100644 Binary files a/Doc/using/win_installer.png and b/Doc/using/win_installer.png differ diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 1d029e3914baf5..9031301989e396 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -537,6 +537,17 @@ module_name Deprecated ========== +CLI +--- + +* Deprecate :option:`-b` and :option:`!-bb` command line options + and schedule them to become no-op in Python 3.17. + These were primarily helpers for the Python 2 -> 3 transition. + Starting with Python 3.17, no :exc:`BytesWarning` will be raised + for these cases; use a type checker instead. + + (Contributed by Nikita Sobolev in :gh:`136355`.) + hashlib ------- @@ -775,6 +786,10 @@ Deprecated C APIs :c:func:`_Py_c_abs` are :term:`soft deprecated`. (Contributed by Sergey B Kirpichev in :gh:`128813`.) +* :c:member:`~PyConfig.bytes_warning` is deprecated + since 3.15 and will be removed in 3.17. + (Contributed by Nikita Sobolev in :gh:`136355`.) + .. Add C API deprecations above alphabetically, not here at the end. diff --git a/InternalDocs/images/python-cyclic-gc-1-new-page.png b/InternalDocs/images/python-cyclic-gc-1-new-page.png index 2ddac50f4b5575..c3f81e05741500 100644 Binary files a/InternalDocs/images/python-cyclic-gc-1-new-page.png and b/InternalDocs/images/python-cyclic-gc-1-new-page.png differ diff --git a/InternalDocs/images/python-cyclic-gc-2-new-page.png b/InternalDocs/images/python-cyclic-gc-2-new-page.png index 159aeeb05024a3..cc4b8f1ac7ed3f 100644 Binary files a/InternalDocs/images/python-cyclic-gc-2-new-page.png and b/InternalDocs/images/python-cyclic-gc-2-new-page.png differ diff --git a/InternalDocs/images/python-cyclic-gc-3-new-page.png b/InternalDocs/images/python-cyclic-gc-3-new-page.png index 29fab0498e5b10..d16351e8003c5f 100644 Binary files a/InternalDocs/images/python-cyclic-gc-3-new-page.png and b/InternalDocs/images/python-cyclic-gc-3-new-page.png differ diff --git a/InternalDocs/images/python-cyclic-gc-4-new-page.png b/InternalDocs/images/python-cyclic-gc-4-new-page.png index 51a2b1065ea64e..3db7f78f0054cb 100644 Binary files a/InternalDocs/images/python-cyclic-gc-4-new-page.png and b/InternalDocs/images/python-cyclic-gc-4-new-page.png differ diff --git a/InternalDocs/images/python-cyclic-gc-5-new-page.png b/InternalDocs/images/python-cyclic-gc-5-new-page.png index fe67a6896fe4b0..b8cd9980237f24 100644 Binary files a/InternalDocs/images/python-cyclic-gc-5-new-page.png and b/InternalDocs/images/python-cyclic-gc-5-new-page.png differ diff --git a/Lib/idlelib/Icons/idle_16.png b/Lib/idlelib/Icons/idle_16.png index 77d8f711804f95..a18f8f33eb280b 100644 Binary files a/Lib/idlelib/Icons/idle_16.png and b/Lib/idlelib/Icons/idle_16.png differ diff --git a/Lib/idlelib/Icons/idle_256.png b/Lib/idlelib/Icons/idle_256.png index 64f276b40d23b7..6641bf33b7591c 100644 Binary files a/Lib/idlelib/Icons/idle_256.png and b/Lib/idlelib/Icons/idle_256.png differ diff --git a/Lib/idlelib/Icons/idle_32.png b/Lib/idlelib/Icons/idle_32.png index 2aaa55805ed530..9951bea5afbfbe 100644 Binary files a/Lib/idlelib/Icons/idle_32.png and b/Lib/idlelib/Icons/idle_32.png differ diff --git a/Lib/idlelib/Icons/idle_48.png b/Lib/idlelib/Icons/idle_48.png index 705eec42e8a64e..3f06a666ba5618 100644 Binary files a/Lib/idlelib/Icons/idle_48.png and b/Lib/idlelib/Icons/idle_48.png differ diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index cea1a9fe57eedf..bc39a30c6538ce 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -28,7 +28,7 @@ from pathlib._os import ( PathInfo, DirEntryInfo, - magic_open, vfspath, + vfsopen, vfspath, ensure_different_files, ensure_distinct_paths, copyfile2, copyfileobj, copy_info, ) @@ -1129,7 +1129,7 @@ def _copy_from(self, source, follow_symlinks=True, preserve_metadata=False): def _copy_from_file(self, source, preserve_metadata=False): ensure_different_files(source, self) - with magic_open(source, 'rb') as source_f: + with vfsopen(source, 'rb') as source_f: with open(self, 'wb') as target_f: copyfileobj(source_f, target_f) if preserve_metadata: diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index fbcbfb979d1278..6508a9bca0d72b 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -166,48 +166,86 @@ def copyfileobj(source_f, target_f): write_target(buf) -def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, - newline=None): +def _open_reader(obj): + cls = type(obj) + try: + open_reader = cls.__open_reader__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for reading") from None + else: + return open_reader(obj) + + +def _open_writer(obj, mode): + cls = type(obj) + try: + open_writer = cls.__open_writer__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for writing") from None + else: + return open_writer(obj, mode) + + +def _open_updater(obj, mode): + cls = type(obj) + try: + open_updater = cls.__open_updater__ + except AttributeError: + cls_name = cls.__name__ + raise TypeError(f"{cls_name} can't be opened for updating") from None + else: + return open_updater(obj, mode) + + +def vfsopen(obj, mode='r', buffering=-1, encoding=None, errors=None, + newline=None): """ Open the file pointed to by this path and return a file object, as the built-in open() function does. + + Unlike the built-in open() function, this function additionally accepts + 'openable' objects, which are objects with any of these special methods: + + __open_reader__() + __open_writer__(mode) + __open_updater__(mode) + + '__open_reader__' is called for 'r' mode; '__open_writer__' for 'a', 'w' + and 'x' modes; and '__open_updater__' for 'r+' and 'w+' modes. If text + mode is requested, the result is wrapped in an io.TextIOWrapper object. """ + if buffering != -1: + raise ValueError("buffer size can't be customized") text = 'b' not in mode if text: # Call io.text_encoding() here to ensure any warning is raised at an # appropriate stack level. encoding = text_encoding(encoding) try: - return open(path, mode, buffering, encoding, errors, newline) + return open(obj, mode, buffering, encoding, errors, newline) except TypeError: pass - cls = type(path) + if not text: + if encoding is not None: + raise ValueError("binary mode doesn't take an encoding argument") + if errors is not None: + raise ValueError("binary mode doesn't take an errors argument") + if newline is not None: + raise ValueError("binary mode doesn't take a newline argument") mode = ''.join(sorted(c for c in mode if c not in 'bt')) - if text: - try: - attr = getattr(cls, f'__open_{mode}__') - except AttributeError: - pass - else: - return attr(path, buffering, encoding, errors, newline) - elif encoding is not None: - raise ValueError("binary mode doesn't take an encoding argument") - elif errors is not None: - raise ValueError("binary mode doesn't take an errors argument") - elif newline is not None: - raise ValueError("binary mode doesn't take a newline argument") - - try: - attr = getattr(cls, f'__open_{mode}b__') - except AttributeError: - pass + if mode == 'r': + stream = _open_reader(obj) + elif mode in ('a', 'w', 'x'): + stream = _open_writer(obj, mode) + elif mode in ('+r', '+w'): + stream = _open_updater(obj, mode[1]) else: - stream = attr(path, buffering) - if text: - stream = TextIOWrapper(stream, encoding, errors, newline) - return stream - - raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}") + raise ValueError(f'invalid mode: {mode}') + if text: + stream = TextIOWrapper(stream, encoding, errors, newline) + return stream def vfspath(obj): diff --git a/Lib/pathlib/types.py b/Lib/pathlib/types.py index 42b80221608bcc..fea0dd305fe2a3 100644 --- a/Lib/pathlib/types.py +++ b/Lib/pathlib/types.py @@ -13,7 +13,7 @@ from abc import ABC, abstractmethod from glob import _GlobberBase from io import text_encoding -from pathlib._os import (magic_open, vfspath, ensure_distinct_paths, +from pathlib._os import (vfsopen, vfspath, ensure_distinct_paths, ensure_different_files, copyfileobj) from pathlib import PurePath, Path from typing import Optional, Protocol, runtime_checkable @@ -264,10 +264,10 @@ def info(self): raise NotImplementedError @abstractmethod - def __open_rb__(self, buffering=-1): + def __open_reader__(self): """ Open the file pointed to by this path for reading in binary mode and - return a file object, like open(mode='rb'). + return a file object. """ raise NotImplementedError @@ -275,7 +275,7 @@ def read_bytes(self): """ Open the file in bytes mode, read it, and close the file. """ - with magic_open(self, mode='rb', buffering=0) as f: + with vfsopen(self, mode='rb') as f: return f.read() def read_text(self, encoding=None, errors=None, newline=None): @@ -285,7 +285,7 @@ def read_text(self, encoding=None, errors=None, newline=None): # Call io.text_encoding() here to ensure any warning is raised at an # appropriate stack level. encoding = text_encoding(encoding) - with magic_open(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: + with vfsopen(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: return f.read() @abstractmethod @@ -394,10 +394,10 @@ def mkdir(self): raise NotImplementedError @abstractmethod - def __open_wb__(self, buffering=-1): + def __open_writer__(self, mode): """ Open the file pointed to by this path for writing in binary mode and - return a file object, like open(mode='wb'). + return a file object. """ raise NotImplementedError @@ -407,7 +407,7 @@ def write_bytes(self, data): """ # type-check for the buffer interface before truncating the file view = memoryview(data) - with magic_open(self, mode='wb') as f: + with vfsopen(self, mode='wb') as f: return f.write(view) def write_text(self, data, encoding=None, errors=None, newline=None): @@ -420,7 +420,7 @@ def write_text(self, data, encoding=None, errors=None, newline=None): if not isinstance(data, str): raise TypeError('data must be str, not %s' % data.__class__.__name__) - with magic_open(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: + with vfsopen(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: return f.write(data) def _copy_from(self, source, follow_symlinks=True): @@ -439,8 +439,8 @@ def _copy_from(self, source, follow_symlinks=True): stack.append((child, dst.joinpath(child.name))) else: ensure_different_files(src, dst) - with magic_open(src, 'rb') as source_f: - with magic_open(dst, 'wb') as target_f: + with vfsopen(src, 'rb') as source_f: + with vfsopen(dst, 'wb') as target_f: copyfileobj(source_f, target_f) diff --git a/Lib/profiling/sampling/_assets/python-logo-only.png b/Lib/profiling/sampling/_assets/python-logo-only.png index 20f36f4d452149..54e5fcf3608850 100644 Binary files a/Lib/profiling/sampling/_assets/python-logo-only.png and b/Lib/profiling/sampling/_assets/python-logo-only.png differ diff --git a/Lib/shlex.py b/Lib/shlex.py index 5bf6e0d70e0012..5959f52dd12639 100644 --- a/Lib/shlex.py +++ b/Lib/shlex.py @@ -322,6 +322,9 @@ def quote(s): if not s: return "''" + if not isinstance(s, str): + raise TypeError(f"expected string object, got {type(s).__name__!r}") + # Use bytes.translate() for performance safe_chars = (b'%+,-./0123456789:=@' b'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' diff --git a/Lib/test/test_email/data/python.png b/Lib/test/test_email/data/python.png index 1a987f79fcd248..eec919bcfd94b9 100644 Binary files a/Lib/test/test_email/data/python.png and b/Lib/test/test_email/data/python.png differ diff --git a/Lib/test/test_pathlib/support/local_path.py b/Lib/test/test_pathlib/support/local_path.py index c1423c545bfd00..ddfd6fd419533c 100644 --- a/Lib/test/test_pathlib/support/local_path.py +++ b/Lib/test/test_pathlib/support/local_path.py @@ -145,7 +145,7 @@ def __init__(self, *pathsegments): super().__init__(*pathsegments) self.info = LocalPathInfo(self) - def __open_rb__(self, buffering=-1): + def __open_reader__(self): return open(self, 'rb') def iterdir(self): @@ -163,8 +163,8 @@ class WritableLocalPath(_WritablePath, LexicalPath): __slots__ = () __fspath__ = LexicalPath.__vfspath__ - def __open_wb__(self, buffering=-1): - return open(self, 'wb') + def __open_writer__(self, mode): + return open(self, f'{mode}b') def mkdir(self, mode=0o777): os.mkdir(self, mode) diff --git a/Lib/test/test_pathlib/support/zip_path.py b/Lib/test/test_pathlib/support/zip_path.py index 2bfe89b36595b0..90b939b6a59010 100644 --- a/Lib/test/test_pathlib/support/zip_path.py +++ b/Lib/test/test_pathlib/support/zip_path.py @@ -264,13 +264,13 @@ def info(self): tree = self.zip_file.filelist.tree return tree.resolve(vfspath(self), follow_symlinks=False) - def __open_rb__(self, buffering=-1): + def __open_reader__(self): info = self.info.resolve() if not info.exists(): raise FileNotFoundError(errno.ENOENT, "File not found", self) elif info.is_dir(): raise IsADirectoryError(errno.EISDIR, "Is a directory", self) - return self.zip_file.open(info.zip_info, 'r') + return self.zip_file.open(info.zip_info) def iterdir(self): info = self.info.resolve() @@ -320,8 +320,8 @@ def __repr__(self): def with_segments(self, *pathsegments): return type(self)(*pathsegments, zip_file=self.zip_file) - def __open_wb__(self, buffering=-1): - return self.zip_file.open(vfspath(self), 'w') + def __open_writer__(self, mode): + return self.zip_file.open(vfspath(self), mode) def mkdir(self, mode=0o777): zinfo = zipfile.ZipInfo(vfspath(self) + '/') diff --git a/Lib/test/test_pathlib/test_read.py b/Lib/test/test_pathlib/test_read.py index 482203c290a3c4..16fb555b2aee05 100644 --- a/Lib/test/test_pathlib/test_read.py +++ b/Lib/test/test_pathlib/test_read.py @@ -13,10 +13,10 @@ if is_pypi: from pathlib_abc import PathInfo, _ReadablePath - from pathlib_abc._os import magic_open + from pathlib_abc._os import vfsopen else: from pathlib.types import PathInfo, _ReadablePath - from pathlib._os import magic_open + from pathlib._os import vfsopen class ReadTestBase: @@ -32,10 +32,16 @@ def test_is_readable(self): def test_open_r(self): p = self.root / 'fileA' - with magic_open(p, 'r', encoding='utf-8') as f: + with vfsopen(p, 'r', encoding='utf-8') as f: self.assertIsInstance(f, io.TextIOBase) self.assertEqual(f.read(), 'this is file A\n') + def test_open_r_buffering_error(self): + p = self.root / 'fileA' + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=0) + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=1) + self.assertRaises(ValueError, vfsopen, p, 'r', buffering=1024) + @unittest.skipIf( not getattr(sys.flags, 'warn_default_encoding', 0), "Requires warn_default_encoding", @@ -43,17 +49,17 @@ def test_open_r(self): def test_open_r_encoding_warning(self): p = self.root / 'fileA' with self.assertWarns(EncodingWarning) as wc: - with magic_open(p, 'r'): + with vfsopen(p, 'r'): pass self.assertEqual(wc.filename, __file__) def test_open_rb(self): p = self.root / 'fileA' - with magic_open(p, 'rb') as f: + with vfsopen(p, 'rb') as f: self.assertEqual(f.read(), b'this is file A\n') - self.assertRaises(ValueError, magic_open, p, 'rb', encoding='utf8') - self.assertRaises(ValueError, magic_open, p, 'rb', errors='strict') - self.assertRaises(ValueError, magic_open, p, 'rb', newline='') + self.assertRaises(ValueError, vfsopen, p, 'rb', encoding='utf8') + self.assertRaises(ValueError, vfsopen, p, 'rb', errors='strict') + self.assertRaises(ValueError, vfsopen, p, 'rb', newline='') def test_read_bytes(self): p = self.root / 'fileA' diff --git a/Lib/test/test_pathlib/test_write.py b/Lib/test/test_pathlib/test_write.py index b958490d0a834f..c9c1d64656c9be 100644 --- a/Lib/test/test_pathlib/test_write.py +++ b/Lib/test/test_pathlib/test_write.py @@ -13,10 +13,10 @@ if is_pypi: from pathlib_abc import _WritablePath - from pathlib_abc._os import magic_open + from pathlib_abc._os import vfsopen else: from pathlib.types import _WritablePath - from pathlib._os import magic_open + from pathlib._os import vfsopen class WriteTestBase: @@ -31,11 +31,17 @@ def test_is_writable(self): def test_open_w(self): p = self.root / 'fileA' - with magic_open(p, 'w', encoding='utf-8') as f: + with vfsopen(p, 'w', encoding='utf-8') as f: self.assertIsInstance(f, io.TextIOBase) f.write('this is file A\n') self.assertEqual(self.ground.readtext(p), 'this is file A\n') + def test_open_w_buffering_error(self): + p = self.root / 'fileA' + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=0) + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=1) + self.assertRaises(ValueError, vfsopen, p, 'w', buffering=1024) + @unittest.skipIf( not getattr(sys.flags, 'warn_default_encoding', 0), "Requires warn_default_encoding", @@ -43,19 +49,19 @@ def test_open_w(self): def test_open_w_encoding_warning(self): p = self.root / 'fileA' with self.assertWarns(EncodingWarning) as wc: - with magic_open(p, 'w'): + with vfsopen(p, 'w'): pass self.assertEqual(wc.filename, __file__) def test_open_wb(self): p = self.root / 'fileA' - with magic_open(p, 'wb') as f: + with vfsopen(p, 'wb') as f: #self.assertIsInstance(f, io.BufferedWriter) f.write(b'this is file A\n') self.assertEqual(self.ground.readbytes(p), b'this is file A\n') - self.assertRaises(ValueError, magic_open, p, 'wb', encoding='utf8') - self.assertRaises(ValueError, magic_open, p, 'wb', errors='strict') - self.assertRaises(ValueError, magic_open, p, 'wb', newline='') + self.assertRaises(ValueError, vfsopen, p, 'wb', encoding='utf8') + self.assertRaises(ValueError, vfsopen, p, 'wb', errors='strict') + self.assertRaises(ValueError, vfsopen, p, 'wb', newline='') def test_write_bytes(self): p = self.root / 'fileA' diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py index a13ddcb76b7bcb..2a355abdeeb30f 100644 --- a/Lib/test/test_shlex.py +++ b/Lib/test/test_shlex.py @@ -330,6 +330,7 @@ def testQuote(self): unsafe = '"`$\\!' + unicode_sample self.assertEqual(shlex.quote(''), "''") + self.assertEqual(shlex.quote(None), "''") self.assertEqual(shlex.quote(safeunquoted), safeunquoted) self.assertEqual(shlex.quote('test file name'), "'test file name'") for u in unsafe: @@ -338,6 +339,8 @@ def testQuote(self): for u in unsafe: self.assertEqual(shlex.quote("test%s'name'" % u), "'test%s'\"'\"'name'\"'\"''" % u) + self.assertRaises(TypeError, shlex.quote, 42) + self.assertRaises(TypeError, shlex.quote, b"abc") def testJoin(self): for split_command, command in [ diff --git a/Lib/test/tkinterdata/python.png b/Lib/test/tkinterdata/python.png index 1a987f79fcd248..eec919bcfd94b9 100644 Binary files a/Lib/test/tkinterdata/python.png and b/Lib/test/tkinterdata/python.png differ diff --git a/Misc/NEWS.d/next/C_API/2025-09-14-14-44-24.gh-issue-136355.LCaYyC.rst b/Misc/NEWS.d/next/C_API/2025-09-14-14-44-24.gh-issue-136355.LCaYyC.rst new file mode 100644 index 00000000000000..44537729b3f0a3 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-09-14-14-44-24.gh-issue-136355.LCaYyC.rst @@ -0,0 +1,2 @@ +Deprecate :c:member:`PyConfig.bytes_warning` field and schedule its removal +in 3.17. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-12-24-00.gh-issue-136355.MTcA8j.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-12-24-00.gh-issue-136355.MTcA8j.rst new file mode 100644 index 00000000000000..dd6bd28c3ff02b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-07-12-24-00.gh-issue-136355.MTcA8j.rst @@ -0,0 +1,2 @@ +Deprecate :option:`-b` and :option:`!-bb` command line options +and schedule them to become no-op in Python 3.17. diff --git a/Misc/NEWS.d/next/Library/2025-09-12-01-01-05.gh-issue-138804.46ZukT.rst b/Misc/NEWS.d/next/Library/2025-09-12-01-01-05.gh-issue-138804.46ZukT.rst new file mode 100644 index 00000000000000..5d403f8cf034ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-12-01-01-05.gh-issue-138804.46ZukT.rst @@ -0,0 +1,3 @@ +Raise :exc:`TypeError` instead of :exc:`AttributeError` when an argument of +incorrect type is passed to :func:`shlex.quote`. This restores the behavior of +the function prior to 3.14. diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 914172684158a1..ea94f4321d74de 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -669,9 +669,7 @@ _bz2_BZ2Decompressor_impl(PyTypeObject *type) self->bzs_avail_in_real = 0; self->input_buffer = NULL; self->input_buffer_size = 0; - self->unused_data = PyBytes_FromStringAndSize(NULL, 0); - if (self->unused_data == NULL) - goto error; + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); if (catch_bz2_error(bzerror)) diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 17aca2f00a13c0..3fdcf22ffd56d0 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -450,10 +450,7 @@ _dbm_dbm_setdefault_impl(dbmobject *self, PyTypeObject *cls, const char *key, return PyBytes_FromStringAndSize(val.dptr, val.dsize); } if (default_value == NULL) { - default_value = PyBytes_FromStringAndSize(NULL, 0); - if (default_value == NULL) { - return NULL; - } + default_value = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); val.dptr = NULL; val.dsize = 0; } diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 0b0b1bc765bbc9..bac49b1268cc56 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1263,10 +1263,7 @@ _lzma_LZMADecompressor_impl(PyTypeObject *type, int format, self->needs_input = 1; self->input_buffer = NULL; self->input_buffer_size = 0; - Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0)); - if (self->unused_data == NULL) { - goto error; - } + Py_XSETREF(self->unused_data, Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)); switch (format) { case FORMAT_AUTO: @@ -1445,7 +1442,7 @@ _lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter) { lzma_ret lzret; uint32_t encoded_size; - PyObject *result = NULL; + PyBytesWriter *writer = NULL; _lzma_state *state = get_lzma_state(module); assert(state != NULL); @@ -1453,20 +1450,20 @@ _lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter) if (catch_lzma_error(state, lzret)) goto error; - result = PyBytes_FromStringAndSize(NULL, encoded_size); - if (result == NULL) + writer = PyBytesWriter_Create(encoded_size); + if (writer == NULL) { goto error; + } - lzret = lzma_properties_encode( - &filter, (uint8_t *)PyBytes_AS_STRING(result)); + lzret = lzma_properties_encode(&filter, PyBytesWriter_GetData(writer)); if (catch_lzma_error(state, lzret)) { goto error; } - return result; + return PyBytesWriter_Finish(writer); error: - Py_XDECREF(result); + PyBytesWriter_Discard(writer); return NULL; } diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 0774e91039ec41..bfb2830f3893d6 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2612,31 +2612,26 @@ save_picklebuffer(PickleState *st, PicklerObject *self, PyObject *obj) static PyObject * raw_unicode_escape(PyObject *obj) { - char *p; - Py_ssize_t i, size; - const void *data; - int kind; - _PyBytesWriter writer; + Py_ssize_t size = PyUnicode_GET_LENGTH(obj); + const void *data = PyUnicode_DATA(obj); + int kind = PyUnicode_KIND(obj); - _PyBytesWriter_Init(&writer); - - size = PyUnicode_GET_LENGTH(obj); - data = PyUnicode_DATA(obj); - kind = PyUnicode_KIND(obj); - - p = _PyBytesWriter_Alloc(&writer, size); - if (p == NULL) - goto error; - writer.overallocate = 1; + Py_ssize_t alloc = size; + PyBytesWriter *writer = PyBytesWriter_Create(alloc); + if (writer == NULL) { + return NULL; + } + char *p = PyBytesWriter_GetData(writer); - for (i=0; i < size; i++) { + for (Py_ssize_t i=0; i < size; i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); /* Map 32-bit characters to '\Uxxxxxxxx' */ if (ch >= 0x10000) { /* -1: subtract 1 preallocated byte */ - p = _PyBytesWriter_Prepare(&writer, p, 10-1); - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, 10-1, p); + if (p == NULL) { goto error; + } *p++ = '\\'; *p++ = 'U'; @@ -2655,9 +2650,10 @@ raw_unicode_escape(PyObject *obj) ch == 0x1a) { /* -1: subtract 1 preallocated byte */ - p = _PyBytesWriter_Prepare(&writer, p, 6-1); - if (p == NULL) + p = PyBytesWriter_GrowAndUpdatePointer(writer, 6-1, p); + if (p == NULL) { goto error; + } *p++ = '\\'; *p++ = 'u'; @@ -2671,10 +2667,10 @@ raw_unicode_escape(PyObject *obj) *p++ = (char) ch; } - return _PyBytesWriter_Finish(&writer, p); + return PyBytesWriter_FinishWithPointer(writer, p); error: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } diff --git a/Modules/_struct.c b/Modules/_struct.c index 3fad35a8c94ee2..f09252e82c3915 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2189,7 +2189,6 @@ strings."); static PyObject * s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - char *buf; PyStructObject *soself; _structmodulestate *state = get_struct_state_structinst(self); @@ -2205,21 +2204,19 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } /* Allocate a new string */ - _PyBytesWriter writer; - _PyBytesWriter_Init(&writer); - buf = _PyBytesWriter_Alloc(&writer, soself->s_size); - if (buf == NULL) { - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter *writer = PyBytesWriter_Create(soself->s_size); + if (writer == NULL) { return NULL; } + char *buf = PyBytesWriter_GetData(writer); /* Call the guts */ if ( s_pack_internal(soself, args, 0, buf, state) != 0 ) { - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } - return _PyBytesWriter_Finish(&writer, buf + soself->s_size); + return PyBytesWriter_FinishWithSize(writer, soself->s_size); } PyDoc_STRVAR(s_pack_into__doc__, diff --git a/Modules/binascii.c b/Modules/binascii.c index c70f9f88afe14d..13e4bc5be03ebd 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -205,11 +205,9 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=e027f8e0b0598742 input=7cafeaf73df63d1c]*/ { const unsigned char *ascii_data; - unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; - PyObject *rv; Py_ssize_t ascii_len, bin_len; binascii_state *state; @@ -223,9 +221,11 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) ascii_len--; /* Allocate the buffer */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) + PyBytesWriter *writer = PyBytesWriter_Create(bin_len); + if (writer == NULL) { return NULL; - bin_data = (unsigned char *)PyBytes_AS_STRING(rv); + } + unsigned char *bin_data = PyBytesWriter_GetData(writer); for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) { /* XXX is it really best to add NULs if there's no more data */ @@ -245,11 +245,10 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) if ( this_ch < ' ' || this_ch > (' ' + 64)) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Illegal char"); - Py_DECREF(rv); - return NULL; + goto error; } this_ch = (this_ch - ' ') & 077; } @@ -277,14 +276,17 @@ binascii_a2b_uu_impl(PyObject *module, Py_buffer *data) this_ch != '\n' && this_ch != '\r' ) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Trailing garbage"); - Py_DECREF(rv); - return NULL; + goto error; } } - return rv; + return PyBytesWriter_Finish(writer); + +error: + PyBytesWriter_Discard(writer); + return NULL; } /*[clinic input] @@ -302,16 +304,13 @@ static PyObject * binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) /*[clinic end generated code: output=b1b99de62d9bbeb8 input=beb27822241095cd]*/ { - unsigned char *ascii_data; const unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; binascii_state *state; - Py_ssize_t bin_len, out_len; - _PyBytesWriter writer; + Py_ssize_t bin_len; - _PyBytesWriter_Init(&writer); bin_data = data->buf; bin_len = data->len; if ( bin_len > 45 ) { @@ -325,10 +324,12 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) } /* We're lazy and allocate to much (fixed up later) */ - out_len = 2 + (bin_len + 2) / 3 * 4; - ascii_data = _PyBytesWriter_Alloc(&writer, out_len); - if (ascii_data == NULL) + Py_ssize_t out_len = 2 + (bin_len + 2) / 3 * 4; + PyBytesWriter *writer = PyBytesWriter_Create(out_len); + if (writer == NULL) { return NULL; + } + unsigned char *ascii_data = PyBytesWriter_GetData(writer); /* Store the length */ if (backtick && !bin_len) @@ -356,7 +357,7 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) } *ascii_data++ = '\n'; /* Append a courtesy newline */ - return _PyBytesWriter_Finish(&writer, ascii_data); + return PyBytesWriter_FinishWithPointer(writer, ascii_data); } /*[clinic input] @@ -388,12 +389,11 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ - _PyBytesWriter writer; - _PyBytesWriter_Init(&writer); - unsigned char *bin_data = _PyBytesWriter_Alloc(&writer, bin_len); - if (bin_data == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(bin_len); + if (writer == NULL) { return NULL; - unsigned char *bin_data_start = bin_data; + } + unsigned char *bin_data = PyBytesWriter_GetData(writer); if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { state = get_binascii_state(module); @@ -489,12 +489,14 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) state = get_binascii_state(module); if (state == NULL) { /* error already set, from get_binascii_state */ + assert(PyErr_Occurred()); } else if (quad_pos == 1) { /* ** There is exactly one extra valid, non-padding, base64 character. ** This is an invalid length, as there is no possible input that ** could encoded into such a base64 string. */ + unsigned char *bin_data_start = PyBytesWriter_GetData(writer); PyErr_Format(state->Error, "Invalid base64-encoded string: " "number of data characters (%zd) cannot be 1 more " @@ -503,13 +505,15 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) } else { PyErr_SetString(state->Error, "Incorrect padding"); } - error_end: - _PyBytesWriter_Dealloc(&writer); - return NULL; + goto error_end; } done: - return _PyBytesWriter_Finish(&writer, bin_data); + return PyBytesWriter_FinishWithPointer(writer, bin_data); + +error_end: + PyBytesWriter_Discard(writer); + return NULL; } @@ -528,18 +532,15 @@ static PyObject * binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) /*[clinic end generated code: output=4ad62c8e8485d3b3 input=0e20ff59c5f2e3e1]*/ { - unsigned char *ascii_data; const unsigned char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; - Py_ssize_t bin_len, out_len; - _PyBytesWriter writer; + Py_ssize_t bin_len; binascii_state *state; bin_data = data->buf; bin_len = data->len; - _PyBytesWriter_Init(&writer); assert(bin_len >= 0); @@ -555,12 +556,15 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) /* We're lazy and allocate too much (fixed up later). "+2" leaves room for up to two pad characters. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ - out_len = bin_len*2 + 2; - if (newline) + Py_ssize_t out_len = bin_len*2 + 2; + if (newline) { out_len++; - ascii_data = _PyBytesWriter_Alloc(&writer, out_len); - if (ascii_data == NULL) + } + PyBytesWriter *writer = PyBytesWriter_Create(out_len); + if (writer == NULL) { return NULL; + } + unsigned char *ascii_data = PyBytesWriter_GetData(writer); for( ; bin_len > 0 ; bin_len--, bin_data++ ) { /* Shift the data into our buffer */ @@ -585,7 +589,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int newline) if (newline) *ascii_data++ = '\n'; /* Append a courtesy newline */ - return _PyBytesWriter_Finish(&writer, ascii_data); + return PyBytesWriter_FinishWithPointer(writer, ascii_data); } @@ -887,8 +891,6 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) { const char* argbuf; Py_ssize_t arglen; - PyObject *retval; - char* retbuf; Py_ssize_t i, j; binascii_state *state; @@ -910,10 +912,11 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) return NULL; } - retval = PyBytes_FromStringAndSize(NULL, (arglen/2)); - if (!retval) + PyBytesWriter *writer = PyBytesWriter_Create(arglen/2); + if (writer == NULL) { return NULL; - retbuf = PyBytes_AS_STRING(retval); + } + char *retbuf = PyBytesWriter_GetData(writer); for (i=j=0; i < arglen; i += 2) { unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])]; @@ -921,18 +924,18 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr) if (top >= 16 || bot >= 16) { state = get_binascii_state(module); if (state == NULL) { - return NULL; + goto error; } PyErr_SetString(state->Error, "Non-hexadecimal digit found"); - goto finally; + goto error; } retbuf[j++] = (top << 4) + bot; } - return retval; + return PyBytesWriter_Finish(writer); - finally: - Py_DECREF(retval); +error: + PyBytesWriter_Discard(writer); return NULL; } diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8c9d463ad903ec..8caadde8ae211b 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -448,7 +448,8 @@ _safe_PyBytes_ReverseFind(Py_ssize_t *out, mmap_object *self, } PyObject * -_safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) { +_safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) +{ if (num_bytes == 1) { char dest; if (safe_byte_copy(&dest, start) < 0) { @@ -459,14 +460,15 @@ _safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) { } } else { - PyObject *result = PyBytes_FromStringAndSize(NULL, num_bytes); - if (result == NULL) { + PyBytesWriter *writer = PyBytesWriter_Create(num_bytes); + if (writer == NULL) { return NULL; } - if (safe_memcpy(PyBytes_AS_STRING(result), start, num_bytes) < 0) { - Py_CLEAR(result); + if (safe_memcpy(PyBytesWriter_GetData(writer), start, num_bytes) < 0) { + PyBytesWriter_Discard(writer); + return NULL; } - return result; + return PyBytesWriter_Finish(writer); } } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index f229c4e8dd9322..5e735e86bdee9e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -11507,9 +11507,6 @@ static PyObject * os_read_impl(PyObject *module, int fd, Py_ssize_t length) /*[clinic end generated code: output=dafbe9a5cddb987b input=1df2eaa27c0bf1d3]*/ { - Py_ssize_t n; - PyObject *buffer; - if (length < 0) { errno = EINVAL; return posix_error(); @@ -11517,20 +11514,18 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length) length = Py_MIN(length, _PY_READ_MAX); - buffer = PyBytes_FromStringAndSize((char *)NULL, length); - if (buffer == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; + } - n = _Py_read(fd, PyBytes_AS_STRING(buffer), length); + Py_ssize_t n = _Py_read(fd, PyBytesWriter_GetData(writer), length); if (n == -1) { - Py_DECREF(buffer); + PyBytesWriter_Discard(writer); return NULL; } - if (n != length) - _PyBytes_Resize(&buffer, n); - - return buffer; + return PyBytesWriter_FinishWithSize(writer, n); } /*[clinic input] @@ -11708,20 +11703,20 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) { Py_ssize_t n; int async_err = 0; - PyObject *buffer; if (length < 0) { errno = EINVAL; return posix_error(); } - buffer = PyBytes_FromStringAndSize((char *)NULL, length); - if (buffer == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(length); + if (writer == NULL) { return NULL; + } do { Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH - n = pread(fd, PyBytes_AS_STRING(buffer), length, offset); + n = pread(fd, PyBytesWriter_GetData(writer), length, offset); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); @@ -11730,12 +11725,10 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) if (!async_err) { posix_error(); } - Py_DECREF(buffer); + PyBytesWriter_Discard(writer); return NULL; } - if (n != length) - _PyBytes_Resize(&buffer, n); - return buffer; + return PyBytesWriter_FinishWithSize(writer, n); } #endif /* HAVE_PREAD */ @@ -14945,9 +14938,6 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, int follow_symlinks) /*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/ { - Py_ssize_t i; - PyObject *buffer = NULL; - if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks)) return NULL; @@ -14955,8 +14945,7 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, return NULL; } - for (i = 0; ; i++) { - void *ptr; + for (Py_ssize_t i = 0; ; i++) { ssize_t result; static const Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0}; Py_ssize_t buffer_size = buffer_sizes[i]; @@ -14964,10 +14953,11 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, path_error(path); return NULL; } - buffer = PyBytes_FromStringAndSize(NULL, buffer_size); - if (!buffer) + PyBytesWriter *writer = PyBytesWriter_Create(buffer_size); + if (writer == NULL) { return NULL; - ptr = PyBytes_AS_STRING(buffer); + } + void *ptr = PyBytesWriter_GetData(writer); Py_BEGIN_ALLOW_THREADS; if (path->fd >= 0) @@ -14979,23 +14969,16 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, Py_END_ALLOW_THREADS; if (result < 0) { + PyBytesWriter_Discard(writer); if (errno == ERANGE) { - Py_DECREF(buffer); continue; } path_error(path); - Py_DECREF(buffer); return NULL; } - if (result != buffer_size) { - /* Can only shrink. */ - _PyBytes_Resize(&buffer, result); - } - break; + return PyBytesWriter_FinishWithSize(writer, result); } - - return buffer; } @@ -15222,19 +15205,22 @@ static PyObject * os_urandom_impl(PyObject *module, Py_ssize_t size) /*[clinic end generated code: output=42c5cca9d18068e9 input=58a0def87dbc2c22]*/ { - PyObject *bytes; - int result; + if (size < 0) { + return PyErr_Format(PyExc_ValueError, + "negative argument not allowed"); + } - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; + } - result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); + int result = _PyOS_URandom(PyBytesWriter_GetData(writer), size); if (result == -1) { - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } - return bytes; + return PyBytesWriter_Finish(writer); } #ifdef HAVE_MEMFD_CREATE @@ -16704,25 +16690,20 @@ static PyObject * os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) /*[clinic end generated code: output=b3a618196a61409c input=59bafac39c594947]*/ { - PyObject *bytes; - Py_ssize_t n; - if (size < 0) { errno = EINVAL; return posix_error(); } - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) { - PyErr_NoMemory(); + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; } + void *data = PyBytesWriter_GetData(writer); + Py_ssize_t n; while (1) { - n = syscall(SYS_getrandom, - PyBytes_AS_STRING(bytes), - PyBytes_GET_SIZE(bytes), - flags); + n = syscall(SYS_getrandom, data, size, flags); if (n < 0 && errno == EINTR) { if (PyErr_CheckSignals() < 0) { goto error; @@ -16739,14 +16720,10 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) goto error; } - if (n != size) { - _PyBytes_Resize(&bytes, n); - } - - return bytes; + return PyBytesWriter_FinishWithSize(writer, n); error: - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } #endif /* HAVE_GETRANDOM_SYSCALL */ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index dc8e08ac3e522e..f76be53f6de4ef 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3467,7 +3467,6 @@ sock_getsockopt(PyObject *self, PyObject *args) int level; int optname; int res; - PyObject *buf; socklen_t buflen = 0; int flag = 0; socklen_t flagsize; @@ -3512,17 +3511,17 @@ sock_getsockopt(PyObject *self, PyObject *args) "getsockopt buflen out of range"); return NULL; } - buf = PyBytes_FromStringAndSize((char *)NULL, buflen); - if (buf == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(buflen); + if (writer == NULL) { return NULL; + } res = getsockopt(get_sock_fd(s), level, optname, - (void *)PyBytes_AS_STRING(buf), &buflen); + PyBytesWriter_GetData(writer), &buflen); if (res < 0) { - Py_DECREF(buf); + PyBytesWriter_Discard(writer); return s->errorhandler(); } - _PyBytes_Resize(&buf, buflen); - return buf; + return PyBytesWriter_FinishWithSize(writer, buflen); } PyDoc_STRVAR(getsockopt_doc, diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 1ee14e31612860..f1312e687da71c 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -833,22 +833,24 @@ save_unconsumed_input(compobject *self, Py_buffer *data, int err) input data in self->unused_data. */ if (self->zst.avail_in > 0) { Py_ssize_t old_size = PyBytes_GET_SIZE(self->unused_data); - Py_ssize_t new_size, left_size; - PyObject *new_data; + Py_ssize_t left_size; left_size = (Byte *)data->buf + data->len - self->zst.next_in; if (left_size > (PY_SSIZE_T_MAX - old_size)) { PyErr_NoMemory(); return -1; } - new_size = old_size + left_size; - new_data = PyBytes_FromStringAndSize(NULL, new_size); - if (new_data == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(old_size + left_size); + if (writer == NULL) { return -1; - memcpy(PyBytes_AS_STRING(new_data), - PyBytes_AS_STRING(self->unused_data), old_size); - memcpy(PyBytes_AS_STRING(new_data) + old_size, - self->zst.next_in, left_size); - Py_SETREF(self->unused_data, new_data); + } + char *new_data = PyBytesWriter_GetData(writer); + memcpy(new_data, PyBytes_AS_STRING(self->unused_data), old_size); + memcpy(new_data + old_size, self->zst.next_in, left_size); + PyObject *new_unused_data = PyBytesWriter_Finish(writer); + if (new_unused_data == NULL) { + return -1; + } + Py_SETREF(self->unused_data, new_unused_data); self->zst.avail_in = 0; } } @@ -1009,7 +1011,7 @@ zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode) /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in doing any work at all; just return an empty string. */ if (mode == Z_NO_FLUSH) { - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } ENTER_ZLIB(self); @@ -1764,11 +1766,7 @@ zlib__ZlibDecompressor_impl(PyTypeObject *type, int wbits, PyObject *zdict) self->zst.zfree = PyZlib_Free; self->zst.next_in = NULL; self->zst.avail_in = 0; - self->unused_data = PyBytes_FromStringAndSize(NULL, 0); - if (self->unused_data == NULL) { - Py_CLEAR(self); - return NULL; - } + self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); self->lock = PyThread_allocate_lock(); if (self->lock == NULL) { Py_DECREF(self); diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index fc9e1bef80f037..7a59c76941254c 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -36,6 +36,9 @@ class bytes "PyBytesObject *" "&PyBytes_Type" /* Forward declaration */ Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer, char *str); +static void* _PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, + Py_ssize_t size, void *data); +static Py_ssize_t _PyBytesWriter_GetAllocated(PyBytesWriter *writer); #define CHARACTERS _Py_SINGLETON(bytes_characters) @@ -1090,22 +1093,16 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, int *first_invalid_escape_char, const char **first_invalid_escape_ptr) { - int c; - char *p; - const char *end; - _PyBytesWriter writer; - - _PyBytesWriter_Init(&writer); - - p = _PyBytesWriter_Alloc(&writer, len); - if (p == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(len); + if (writer == NULL) { return NULL; - writer.overallocate = 1; + } + char *p = PyBytesWriter_GetData(writer); *first_invalid_escape_char = -1; *first_invalid_escape_ptr = NULL; - end = s + len; + const char *end = s + len; while (s < end) { if (*s != '\\') { *p++ = *s++; @@ -1134,7 +1131,8 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, case 'a': *p++ = '\007'; break; /* BEL, not classic C */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - c = s[-1] - '0'; + { + int c = s[-1] - '0'; if (s < end && '0' <= *s && *s <= '7') { c = (c<<3) + *s++ - '0'; if (s < end && '0' <= *s && *s <= '7') @@ -1149,6 +1147,7 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, } *p++ = c; break; + } case 'x': if (s+1 < end) { int digit1, digit2; @@ -1195,10 +1194,10 @@ PyObject *_PyBytes_DecodeEscape2(const char *s, } } - return _PyBytesWriter_Finish(&writer, p); + return PyBytesWriter_FinishWithPointer(writer, p); failed: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } @@ -2535,17 +2534,13 @@ bytes_fromhex_impl(PyTypeObject *type, PyObject *string) PyObject* _PyBytes_FromHex(PyObject *string, int use_bytearray) { - char *buf; Py_ssize_t hexlen, invalid_char; unsigned int top, bot; const Py_UCS1 *str, *start, *end; - _PyBytesWriter writer; + PyBytesWriter *writer = NULL; Py_buffer view; view.obj = NULL; - _PyBytesWriter_Init(&writer); - writer.use_bytearray = use_bytearray; - if (PyUnicode_Check(string)) { hexlen = PyUnicode_GET_LENGTH(string); @@ -2581,10 +2576,16 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } /* This overestimates if there are spaces */ - buf = _PyBytesWriter_Alloc(&writer, hexlen / 2); - if (buf == NULL) { + if (use_bytearray) { + writer = _PyBytesWriter_CreateByteArray(hexlen / 2); + } + else { + writer = PyBytesWriter_Create(hexlen / 2); + } + if (writer == NULL) { goto release_buffer; } + char *buf = PyBytesWriter_GetData(writer); start = str; end = str + hexlen; @@ -2623,7 +2624,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) if (view.obj != NULL) { PyBuffer_Release(&view); } - return _PyBytesWriter_Finish(&writer, buf); + return PyBytesWriter_FinishWithPointer(writer, buf); error: if (invalid_char == -1) { @@ -2634,7 +2635,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) "non-hexadecimal number found in " "fromhex() arg at position %zd", invalid_char); } - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); release_buffer: if (view.obj != NULL) { @@ -2789,7 +2790,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, "errors without a string argument"); return NULL; } - bytes = PyBytes_FromStringAndSize(NULL, 0); + bytes = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } else if (encoding != NULL) { /* Encode via the codec registry */ @@ -2861,23 +2862,25 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, static PyObject* _PyBytes_FromBuffer(PyObject *x) { - PyObject *new; Py_buffer view; - if (PyObject_GetBuffer(x, &view, PyBUF_FULL_RO) < 0) return NULL; - new = PyBytes_FromStringAndSize(NULL, view.len); - if (!new) + PyBytesWriter *writer = PyBytesWriter_Create(view.len); + if (writer == NULL) { goto fail; - if (PyBuffer_ToContiguous(((PyBytesObject *)new)->ob_sval, - &view, view.len, 'C') < 0) + } + + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + &view, view.len, 'C') < 0) { goto fail; + } + PyBuffer_Release(&view); - return new; + return PyBytesWriter_Finish(writer); fail: - Py_XDECREF(new); + PyBytesWriter_Discard(writer); PyBuffer_Release(&view); return NULL; } @@ -2885,23 +2888,18 @@ _PyBytes_FromBuffer(PyObject *x) static PyObject* _PyBytes_FromList(PyObject *x) { - Py_ssize_t i, size = PyList_GET_SIZE(x); - Py_ssize_t value; - char *str; - PyObject *item; - _PyBytesWriter writer; - - _PyBytesWriter_Init(&writer); - str = _PyBytesWriter_Alloc(&writer, size); - if (str == NULL) + Py_ssize_t size = PyList_GET_SIZE(x); + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - writer.overallocate = 1; - size = writer.allocated; + } + char *str = PyBytesWriter_GetData(writer); + size = _PyBytesWriter_GetAllocated(writer); - for (i = 0; i < PyList_GET_SIZE(x); i++) { - item = PyList_GET_ITEM(x, i); + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(x); i++) { + PyObject *item = PyList_GET_ITEM(x, i); Py_INCREF(item); - value = PyNumber_AsSsize_t(item, NULL); + Py_ssize_t value = PyNumber_AsSsize_t(item, NULL); Py_DECREF(item); if (value == -1 && PyErr_Occurred()) goto error; @@ -2913,33 +2911,33 @@ _PyBytes_FromList(PyObject *x) } if (i >= size) { - str = _PyBytesWriter_Resize(&writer, str, size+1); - if (str == NULL) - return NULL; - size = writer.allocated; + str = _PyBytesWriter_ResizeAndUpdatePointer(writer, size + 1, str); + if (str == NULL) { + goto error; + } + size = _PyBytesWriter_GetAllocated(writer); } *str++ = (char) value; } - return _PyBytesWriter_Finish(&writer, str); + return PyBytesWriter_FinishWithPointer(writer, str); - error: - _PyBytesWriter_Dealloc(&writer); +error: + PyBytesWriter_Discard(writer); return NULL; } static PyObject* _PyBytes_FromTuple(PyObject *x) { - PyObject *bytes; Py_ssize_t i, size = PyTuple_GET_SIZE(x); Py_ssize_t value; - char *str; PyObject *item; - bytes = PyBytes_FromStringAndSize(NULL, size); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - str = ((PyBytesObject *)bytes)->ob_sval; + } + char *str = PyBytesWriter_GetData(writer); for (i = 0; i < size; i++) { item = PyTuple_GET_ITEM(x, i); @@ -2954,31 +2952,29 @@ _PyBytes_FromTuple(PyObject *x) } *str++ = (char) value; } - return bytes; + return PyBytesWriter_Finish(writer); error: - Py_DECREF(bytes); + PyBytesWriter_Discard(writer); return NULL; } static PyObject * _PyBytes_FromIterator(PyObject *it, PyObject *x) { - char *str; Py_ssize_t i, size; - _PyBytesWriter writer; /* For iterator version, create a bytes object and resize as needed */ size = PyObject_LengthHint(x, 64); if (size == -1 && PyErr_Occurred()) return NULL; - _PyBytesWriter_Init(&writer); - str = _PyBytesWriter_Alloc(&writer, size); - if (str == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(size); + if (writer == NULL) { return NULL; - writer.overallocate = 1; - size = writer.allocated; + } + char *str = PyBytesWriter_GetData(writer); + size = _PyBytesWriter_GetAllocated(writer); /* Run the iterator to exhaustion */ for (i = 0; ; i++) { @@ -3008,18 +3004,18 @@ _PyBytes_FromIterator(PyObject *it, PyObject *x) /* Append the byte */ if (i >= size) { - str = _PyBytesWriter_Resize(&writer, str, size+1); - if (str == NULL) - return NULL; - size = writer.allocated; + str = _PyBytesWriter_ResizeAndUpdatePointer(writer, size + 1, str); + if (str == NULL) { + goto error; + } + size = _PyBytesWriter_GetAllocated(writer); } *str++ = (char) value; } - - return _PyBytesWriter_Finish(&writer, str); + return PyBytesWriter_FinishWithPointer(writer, str); error: - _PyBytesWriter_Dealloc(&writer); + PyBytesWriter_Discard(writer); return NULL; } @@ -3684,7 +3680,7 @@ _PyBytesWriter_Finish(_PyBytesWriter *writer, void *str) if (size == 0 && !writer->use_bytearray) { Py_CLEAR(writer->buffer); /* Get the empty byte string singleton */ - result = PyBytes_FromStringAndSize(NULL, 0); + result = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } else if (writer->use_small_buffer) { if (writer->use_bytearray) { @@ -3987,6 +3983,13 @@ PyBytesWriter_GetSize(PyBytesWriter *writer) } +static Py_ssize_t +_PyBytesWriter_GetAllocated(PyBytesWriter *writer) +{ + return byteswriter_allocated(writer); +} + + int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) { @@ -4002,6 +4005,18 @@ PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) } +static void* +_PyBytesWriter_ResizeAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, + void *data) +{ + Py_ssize_t pos = (char*)data - byteswriter_data(writer); + if (PyBytesWriter_Resize(writer, size) < 0) { + return NULL; + } + return byteswriter_data(writer) + pos; +} + + int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size) { diff --git a/Objects/longobject.c b/Objects/longobject.c index 63b48572ff20d3..dba190d840ca42 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1214,8 +1214,14 @@ _PyLong_AsByteArray(PyLongObject* v, just above didn't get to ensure there's a sign bit, and the loop below wouldn't add one either. Make sure a sign bit exists. */ - unsigned char msb = *(p - pincr); - int sign_bit_set = msb >= 0x80; + int sign_bit_set; + if (n > 0) { + unsigned char msb = *(p - pincr); + sign_bit_set = msb >= 0x80; + } + else { + sign_bit_set = 0; + } assert(accumbits == 0); if (sign_bit_set == do_twos_comp) return 0; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 94ff0fe624e61e..f1232f389210ea 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2285,7 +2285,6 @@ memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) { Py_buffer *src = VIEW_ADDR(self); char ord = 'C'; - PyObject *bytes; CHECK_RELEASED(self); @@ -2303,16 +2302,18 @@ memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) } } - bytes = PyBytes_FromStringAndSize(NULL, src->len); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(src->len); + if (writer == NULL) { return NULL; + } - if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, ord) < 0) { - Py_DECREF(bytes); + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + src, src->len, ord) < 0) { + PyBytesWriter_Discard(writer); return NULL; } - return bytes; + return PyBytesWriter_Finish(writer); } /*[clinic input] @@ -2344,8 +2345,6 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, /*[clinic end generated code: output=430ca760f94f3ca7 input=539f6a3a5fb56946]*/ { Py_buffer *src = VIEW_ADDR(self); - PyObject *bytes; - PyObject *ret; CHECK_RELEASED(self); @@ -2353,19 +2352,22 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, return _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep); } - bytes = PyBytes_FromStringAndSize(NULL, src->len); - if (bytes == NULL) + PyBytesWriter *writer = PyBytesWriter_Create(src->len); + if (writer == NULL) { return NULL; + } - if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, 'C') < 0) { - Py_DECREF(bytes); + if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer), + src, src->len, 'C') < 0) { + PyBytesWriter_Discard(writer); return NULL; } - ret = _Py_strhex_with_sep( - PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes), - sep, bytes_per_sep); - Py_DECREF(bytes); + PyObject *ret = _Py_strhex_with_sep( + PyBytesWriter_GetData(writer), + PyBytesWriter_GetSize(writer), + sep, bytes_per_sep); + PyBytesWriter_Discard(writer); return ret; } diff --git a/Objects/object_layout_312.png b/Objects/object_layout_312.png index a63d095ea0b19e..a3e409e2f90f81 100644 Binary files a/Objects/object_layout_312.png and b/Objects/object_layout_312.png differ diff --git a/Objects/object_layout_313.png b/Objects/object_layout_313.png index f7059c286c84e6..3488bf34dadfcd 100644 Binary files a/Objects/object_layout_313.png and b/Objects/object_layout_313.png differ diff --git a/Objects/object_layout_full_312.png b/Objects/object_layout_full_312.png index 4f46ca86091d45..eebf7b2db67d1f 100644 Binary files a/Objects/object_layout_full_312.png and b/Objects/object_layout_full_312.png differ diff --git a/Objects/object_layout_full_313.png b/Objects/object_layout_full_313.png index 7352ec69e5d8db..d8bc3aeb011591 100644 Binary files a/Objects/object_layout_full_313.png and b/Objects/object_layout_full_313.png differ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4c88e4c1fdca2e..c8d2c68615e13e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4913,7 +4913,7 @@ _PyUnicode_EncodeUTF7(PyObject *str, len = PyUnicode_GET_LENGTH(str); if (len == 0) - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); /* It might be possible to tighten this worst case */ if (len > PY_SSIZE_T_MAX / 8) @@ -6914,7 +6914,7 @@ PyUnicode_AsUnicodeEscapeString(PyObject *unicode) len = PyUnicode_GET_LENGTH(unicode); if (len == 0) { - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } kind = PyUnicode_KIND(unicode); @@ -7364,7 +7364,7 @@ unicode_encode_ucs1(PyObject *unicode, /* allocate enough for a simple encoding without replacements, if we need more, we'll resize */ if (size == 0) - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); _PyBytesWriter_Init(&writer); str = _PyBytesWriter_Alloc(&writer, size); @@ -8305,7 +8305,7 @@ encode_code_page(int code_page, } if (len == 0) - return PyBytes_FromStringAndSize(NULL, 0); + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); offset = 0; do diff --git a/PC/icons/idlex150.png b/PC/icons/idlex150.png index 806cb0c8aa219b..81716f38d75d62 100644 Binary files a/PC/icons/idlex150.png and b/PC/icons/idlex150.png differ diff --git a/PC/icons/idlex44.png b/PC/icons/idlex44.png index 3ef66e6c68e6bb..d201d4da84f336 100644 Binary files a/PC/icons/idlex44.png and b/PC/icons/idlex44.png differ diff --git a/PC/icons/logox128.png b/PC/icons/logox128.png index a403de5818cfec..65d7469c91f27f 100644 Binary files a/PC/icons/logox128.png and b/PC/icons/logox128.png differ diff --git a/PC/icons/py.png b/PC/icons/py.png index 629022a70bdc44..6ed7f0dd4cbb9c 100644 Binary files a/PC/icons/py.png and b/PC/icons/py.png differ diff --git a/PC/icons/pythonwx150.png b/PC/icons/pythonwx150.png index 589873aeb100b2..dad3d86462ae5c 100644 Binary files a/PC/icons/pythonwx150.png and b/PC/icons/pythonwx150.png differ diff --git a/PC/icons/pythonwx44.png b/PC/icons/pythonwx44.png index 8cd8dd0286f681..8ad533d6bedd3c 100644 Binary files a/PC/icons/pythonwx44.png and b/PC/icons/pythonwx44.png differ diff --git a/PC/icons/pythonx150.png b/PC/icons/pythonx150.png index e00aa758edcd47..cc685b1a8e0dd5 100644 Binary files a/PC/icons/pythonx150.png and b/PC/icons/pythonx150.png differ diff --git a/PC/icons/pythonx44.png b/PC/icons/pythonx44.png index db0e9b91d40fe5..1321ab4392c6f3 100644 Binary files a/PC/icons/pythonx44.png and b/PC/icons/pythonx44.png differ diff --git a/PC/icons/pythonx50.png b/PC/icons/pythonx50.png index 8eb5ffce221fae..1b33342eb96937 100644 Binary files a/PC/icons/pythonx50.png and b/PC/icons/pythonx50.png differ diff --git a/Python/initconfig.c b/Python/initconfig.c index efb276ac680ed9..5dc68eb4ec2cca 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -258,6 +258,7 @@ static const char usage_help[] = "\ Options (and corresponding environment variables):\n\ -b : issue warnings about converting bytes/bytearray to str and comparing\n\ bytes/bytearray with str or bytes with int. (-bb: issue errors)\n\ + deprecated since 3.15 and will become no-op in 3.17.\n\ -B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\ -c cmd : program passed in as string (terminates option list)\n\ -d : turn on parser debugging output (for experts only, only works on\n\ diff --git a/Tools/msi/bundle/SideBar.png b/Tools/msi/bundle/SideBar.png index 52f15dd46c18fe..f30f56b43dd040 100644 Binary files a/Tools/msi/bundle/SideBar.png and b/Tools/msi/bundle/SideBar.png differ