diff --git a/Doc/deprecations/pending-removal-in-3.17.rst b/Doc/deprecations/pending-removal-in-3.17.rst index d6e4e81afbbd639..5ed674951d90cb8 100644 --- a/Doc/deprecations/pending-removal-in-3.17.rst +++ b/Doc/deprecations/pending-removal-in-3.17.rst @@ -37,6 +37,13 @@ Pending removal in Python 3.17 is deprecated and scheduled for removal in Python 3.17. (Contributed by Stan Ulbrych in :gh:`136702`.) +* :mod:`profile`: + + - The :mod:`!profile` module is deprecated and will be removed in + Python 3.17. Use :mod:`profiling.tracing` instead, which provides a + compatible API. See :pep:`799` for details. + (Contributed by Pablo Galindo and László Kiss Kollár in :gh:`138122`.) + * :mod:`webbrowser`: - :class:`!webbrowser.MacOSXOSAScript` is deprecated in favour of diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index daac31fd7f4b17c..5a8ab88a30fcf58 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -85,7 +85,7 @@ Summary -- Release highlights * :pep:`728`: :ref:`TypedDict with typed extra items ` * :pep:`747`: :ref:`Annotating type forms with TypeForm ` -* :pep:`800`: Disjoint bases in the type system +* :pep:`800`: :ref:`Disjoint bases in the type system ` * :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object ` * :pep:`803`, :pep:`820 <820>`, :pep:`793 <793>`: @@ -494,8 +494,8 @@ drive it with :meth:`~site.StartupState.addsitedir`, .. _whatsnew315-abi3t: -:pep:`803` -- Stable ABI for free-threaded builds -------------------------------------------------- +:pep:`803`: Stable ABI for free-threaded builds +----------------------------------------------- C extensions that target the :ref:`Stable ABI ` can now be compiled for the new *Stable ABI for Free-Threaded Builds* (also known @@ -522,7 +522,7 @@ free-threading (``cp315t``) separately. Stable ABI for Free-Threaded Builds should typically be selected in a build tool (such as, for example, Setuptools, meson-python, scikit-build-core, or Maturin). -At the time of writing, these tools did **not** support ``abi3t``. +At the time of writing, these tools do **not** support ``abi3t``. If this is the case for your tool, compile for ``cp315t`` separately. If not using a build tool -- or when writing such a tool -- you can select ``abi3t`` by setting the macro :c:macro:`!Py_TARGET_ABI3T` as discussed @@ -1103,6 +1103,16 @@ contextlib (Contributed by Alex Grönholm & Gregory P. Smith in :gh:`125862`.) +ctypes +------ + +* Change the :py:attr:`~ctypes._SimpleCData._type_` of + :class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and + :class:`~ctypes.c_longdouble_complex` from ``F``, ``D`` and ``G`` to ``Zf``, + ``Zd`` and ``Zg`` for compatibility with NumPy. + (Contributed by Victor Stinner in :gh:`148675`.) + + dataclasses ----------- @@ -1229,7 +1239,7 @@ importlib.metadata ------------------ * Previously, when accessing a distribution metadata directory not - containing a metadata file, ``metadata()`` and ``Distribution.metadata()`` + containing a metadata file, ``metadata()`` and ``Distribution.metadata`` would return an empty ``PackageMetadata`` object as if the file was present but empty. Now, a ``MetadataNotFound`` exception is raised. See `importlib_metadata#493 `_ @@ -1333,6 +1343,14 @@ os.path (Contributed by Petr Viktorin for :cve:`2025-4517`.) +pathlib +------- + +* :meth:`pathlib.Path.mkdir` now has a *parent_mode* parameter that allows + specifying the mode for intermediate directories when ``parents=True``. + (Contributed by Gregory P. Smith in :gh:`86533`.) + + pdb --- @@ -1447,7 +1465,7 @@ ssl supports "External PSKs" in TLSv1.3, as described in :rfc:`9258`. (Contributed by Will Childs-Klein in :gh:`133624`.) -* Added new methods for managing groups used for SSL key agreement +* Added new methods for managing groups used for SSL key agreement: * :meth:`ssl.SSLContext.set_groups` sets the groups allowed for doing key agreement, extending the previous @@ -1726,6 +1744,8 @@ typing as it was incorrectly inferred at runtime before. (Contributed by Nikita Sobolev in :gh:`137191`.) + .. _whatsnew315-disjoint-base: + * :pep:`800`: Add :deco:`typing.disjoint_base`, a new decorator marking a class as a disjoint base. This is an advanced feature primarily intended to allow type checkers to faithfully reflect the runtime semantics of types defined @@ -1854,8 +1874,8 @@ xml whether a string can be used as an element or attribute name in XML. (Contributed by Serhiy Storchaka in :gh:`139489`.) -* Add the :func:`xml.is_valid_text` function, which allows to check - whether a string can be used in the XML document. +* Add the :func:`xml.is_valid_text` function to check + whether a string can be used in an XML document. (Contributed by Serhiy Storchaka in :gh:`139489`.) @@ -1989,8 +2009,8 @@ is now performed. This means when the JIT compiler detects that certain user code results in constants, the code can be simplified by the JIT. (Contributed by Ken Jin and Savannah Ostrowski in :gh:`132732`.) -:term:`Reference count`\ s are avoided whenever it is safe to do so. This generally -reduces the cost of most operations in Python. +:term:`Reference counts ` are avoided whenever it is safe to +do so. This generally reduces the cost of most operations in Python. (Contributed by Ken Jin, Donghee Na, Zheao Li, Hai Zhu, Savannah Ostrowski, Reiden Ong, Noam Cohen, Tomas Roun, PuQing, Cajetan Rodrigues, and Sacul in :gh:`134584`.) @@ -2058,12 +2078,6 @@ ctypes which has been deprecated since Python 3.13. (Contributed by Bénédikt Tran in :gh:`133866`.) -* Change the :py:attr:`~ctypes._SimpleCData._type_` of - :class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and - :class:`~ctypes.c_longdouble_complex` from ``F``, ``D`` and ``G`` to ``Zf``, - ``Zd`` and ``Zg`` for compatibility with numpy. - (Contributed by Victor Stinner in :gh:`148675`.) - datetime -------- @@ -2103,10 +2117,6 @@ importlib.resources pathlib ------- -* :meth:`pathlib.Path.mkdir` now has a *parent_mode* parameter that allows - specifying the mode for intermediate directories when ``parents=True``. - (Contributed by Gregory P. Smith in :gh:`86533`.) - * Removed deprecated :meth:`!pathlib.PurePath.is_reserved`. Use :func:`os.path.isreserved` to detect reserved paths on Windows. (Contributed by Nikita Sobolev in :gh:`133875`.) @@ -2146,8 +2156,8 @@ threading types ----- -* Removed deprecated in :pep:`626` since Python 3.12 - :attr:`!codeobject.co_lnotab` from :class:`types.CodeType`. +* Removed :attr:`!codeobject.co_lnotab` from :class:`types.CodeType`, + deprecated since Python 3.12 by :pep:`626`. (Contributed by Nikita Sobolev in :gh:`134690`.) @@ -2270,6 +2280,14 @@ New deprecations and changing its value does *not* explicitly close the current file. +* :mod:`profile`: + + * The :mod:`!profile` module is deprecated and will be removed in + Python 3.17. Use :mod:`profiling.tracing` instead, which provides a + compatible API. See :pep:`799` for details. + (Contributed by Pablo Galindo and László Kiss Kollár in :gh:`138122`.) + + * :mod:`re`: * :func:`re.match` and :meth:`re.Pattern.match` are now @@ -2299,8 +2317,8 @@ New deprecations (Contributed by Sergey B Kirpichev and Serhiy Storchaka in :gh:`143715`.) - * Using ``'F'`` and ``'D'`` type codes now are :term:`soft deprecated` - in favor of two-letter forms ``'Zf'`` and ``'Zd'``. + * The ``'F'`` and ``'D'`` type codes are now :term:`soft deprecated` + in favor of the two-letter forms ``'Zf'`` and ``'Zd'``. (Contributed by Sergey B Kirpichev in :gh:`121249`.) @@ -2413,7 +2431,7 @@ New features functions as replacements for :c:func:`PySys_GetObject`. (Contributed by Serhiy Storchaka in :gh:`108512`.) -* Add :c:type:`PyUnstable_Unicode_GET_CACHED_HASH` to get the cached hash of +* Add :c:func:`PyUnstable_Unicode_GET_CACHED_HASH` to get the cached hash of a string. See the documentation for caveats. (Contributed by Petr Viktorin in :gh:`131510`.) @@ -2429,14 +2447,14 @@ New features * :c:func:`PyBytesWriter_Create` * :c:func:`PyBytesWriter_Discard` + * :c:func:`PyBytesWriter_Finish` * :c:func:`PyBytesWriter_FinishWithPointer` * :c:func:`PyBytesWriter_FinishWithSize` - * :c:func:`PyBytesWriter_Finish` * :c:func:`PyBytesWriter_Format` * :c:func:`PyBytesWriter_GetData` * :c:func:`PyBytesWriter_GetSize` - * :c:func:`PyBytesWriter_GrowAndUpdatePointer` * :c:func:`PyBytesWriter_Grow` + * :c:func:`PyBytesWriter_GrowAndUpdatePointer` * :c:func:`PyBytesWriter_Resize` * :c:func:`PyBytesWriter_WriteBytes` @@ -2447,7 +2465,7 @@ New features (Contributed in :gh:`149227`.) -* Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating +* Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C API for creating a module from a *spec* and *initfunc*. (Contributed by Itamar Oren in :gh:`116146`.) @@ -2521,7 +2539,7 @@ New features thread state. (Contributed by Victor Stinner in :gh:`139653`.) -* Add :c:func:`PyUnstable_SetImmortal` C-API function to mark objects as :term:`immortal`. +* Add :c:func:`PyUnstable_SetImmortal` C API function to mark objects as :term:`immortal`. (Contributed by Kumar Aditya in :gh:`143300`.) * Restore private provisional ``_Py_InitializeMain()`` function removed in @@ -2714,10 +2732,11 @@ Build changes At runtime, huge pages must be explicitly enabled by setting the :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable to ``1``. -* Annotating anonymous mmap usage is now supported if Linux kernel supports +* Annotating anonymous mmap usage is now supported if the Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME ` (Linux 5.17 or newer). Annotations are visible in ``/proc//maps`` if the kernel supports the feature - and :option:`-X dev <-X>` is passed to the Python or Python is built in :ref:`debug mode `. + and :option:`-X dev <-X>` is passed to Python, + or Python is built in :ref:`debug mode `. (Contributed by Donghee Na in :gh:`141770`.) * CPython is now built with frame pointers enabled by default diff --git a/InternalDocs/parser.md b/InternalDocs/parser.md index 1bb4cdea5439f17..a6de8d456b6f71c 100644 --- a/InternalDocs/parser.md +++ b/InternalDocs/parser.md @@ -545,7 +545,7 @@ by default** except for rules with the special marker `memo` after the rule name (and type, if present): ``` -rule_name[typr] (memo): +rule_name[return_type] (memo): ... ``` @@ -772,7 +772,7 @@ from them or to perform extra processing on the generated tree. > Actions must **never** be used to accept or reject rules. It may be tempting > in some situations to write a very generic rule and then check the generated > AST to decide whether it is valid or not, but this will render the -> (official grammar)[https://docs.python.org/3/reference/grammar.html] partially +> [official grammar](https://docs.python.org/3/reference/grammar.html) partially > incorrect (because it does not include actions) and will make it more difficult > for other Python implementations to adapt the grammar to their own needs. @@ -860,7 +860,7 @@ $ python -d file_to_test.py This will print **a lot** of output to `stderr` so it is probably better to dump it to a file for further analysis. The output consists of trace lines with the -following structure:: +following structure: ``` ('>'|'-'|'+'|'!') []: ... diff --git a/Lib/shutil.py b/Lib/shutil.py index 6a2e2b2ffdae2c0..94617ec296f5087 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -292,8 +292,11 @@ def copyfile(src, dst, *, follow_symlinks=True): if _samefile(src, dst): raise SameFileError("{!r} and {!r} are the same file".format(src, dst)) + copy_symlink = not follow_symlinks and _islink(src) file_size = 0 for i, fn in enumerate([src, dst]): + if copy_symlink and i == 0: + continue try: st = _stat(fn) except OSError: @@ -315,7 +318,7 @@ def copyfile(src, dst, *, follow_symlinks=True): if _WINDOWS and i == 0: file_size = st.st_size - if not follow_symlinks and _islink(src): + if copy_symlink: os.symlink(os.readlink(src), dst) else: with open(src, 'rb') as fsrc: diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py index cf90835ce87cc30..1878cf8adf63a3b 100644 --- a/Lib/test/test_asyncio/test_futures2.py +++ b/Lib/test/test_asyncio/test_futures2.py @@ -28,6 +28,26 @@ async def raise_exc(): else: self.fail('TypeError was not raised') + async def test_future_traceback_preserved_after_suppress(self): + async def raise_exc(): + raise TypeError(42) + + future = self.cls(raise_exc()) + try: + await future + except TypeError: + pass + + try: + await future + except TypeError as e: + tb = ''.join(traceback.format_tb(e.__traceback__)) + self.assertIn('raise_exc', tb, + 'Original raise site lost after first result() call') + else: + self.fail('TypeError was not raised') + + async def test_task_exc_handler_correct_context(self): # see https://github.com/python/cpython/issues/96704 name = contextvars.ContextVar('name', default='foo') diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 6832bea094fc1dc..ed5d15ecc7ddad6 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1574,6 +1574,47 @@ def test_copyfile_socket(self): self.assertRaisesRegex(shutil.SpecialFileError, 'is a socket', shutil.copyfile, __file__, sock_path) + def _check_copyfile_symlink_to_special_file(self, target): + tmp_dir = self.mkdtemp() + src = os.path.join(tmp_dir, 'src') + dst = os.path.join(tmp_dir, 'dst') + os.symlink(target, src) + + shutil.copyfile(src, dst, follow_symlinks=False) + + self.assertTrue(os.path.islink(dst)) + self.assertEqual(os.readlink(dst), target) + + @os_helper.skip_unless_symlink + @unittest.skipUnless(os.path.exists('/dev/null'), 'requires /dev/null') + def test_copyfile_symlink_to_character_device(self): + self._check_copyfile_symlink_to_special_file('/dev/null') + + @os_helper.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()') + @unittest.skipIf(sys.platform == "vxworks", + "fifo requires special path on VxWorks") + def test_copyfile_symlink_to_named_pipe(self): + fifo_path = os.path.join(self.mkdtemp(), 'fifo') + try: + os.mkfifo(fifo_path) + except PermissionError as e: + self.skipTest('os.mkfifo(): %s' % e) + self._check_copyfile_symlink_to_special_file(fifo_path) + + @os_helper.skip_unless_symlink + @socket_helper.skip_unless_bind_unix_socket + def test_copyfile_symlink_to_socket(self): + sock_path = os.path.join(self.mkdtemp(), 'sock') + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.addCleanup(sock.close) + try: + socket_helper.bind_unix_socket(sock, sock_path) + except OSError as e: + self.skipTest(f'cannot bind AF_UNIX socket: {e}') + self.addCleanup(os_helper.unlink, sock_path) + self._check_copyfile_symlink_to_special_file(sock_path) + @unittest.skipUnless(os.path.exists('/dev/null'), 'requires /dev/null') def test_copyfile_character_device(self): self.assertRaisesRegex(shutil.SpecialFileError, 'is a character device', diff --git a/Lib/typing.py b/Lib/typing.py index 809c0ff88607a59..a05d73c29cf95e5 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -19,7 +19,6 @@ """ from abc import abstractmethod, ABCMeta -import atexit import collections from collections import defaultdict import collections.abc @@ -398,11 +397,6 @@ def _clear_caches(): cleanup() -# Release the LRU caches at shutdown, they otherwise redistribute reference -# leaks of one extension to types of unrelated ones. See GH-151728. -atexit.register(_clear_caches) - - def _tp_cache(func=None, /, *, typed=False): """Internal wrapper caching __getitem__ of generic types. diff --git a/Misc/NEWS.d/next/Library/2026-07-26-11-45-34.gh-issue-154726.hLJk5-.rst b/Misc/NEWS.d/next/Library/2026-07-26-11-45-34.gh-issue-154726.hLJk5-.rst new file mode 100644 index 000000000000000..73cf40a72077439 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-26-11-45-34.gh-issue-154726.hLJk5-.rst @@ -0,0 +1,3 @@ +Fix :func:`shutil.copyfile` to copy a symbolic link to a special file when +``follow_symlinks=False`` instead of raising +:exc:`~shutil.SpecialFileError`. diff --git a/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst new file mode 100644 index 000000000000000..35008e35314b907 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst @@ -0,0 +1,5 @@ +Fix :class:`asyncio.Future` (C implementation) losing the initial exception +traceback frames when ``Future.result()`` is called more than once. Previously, +the C implementation cleared the stored traceback after the first call, causing +subsequent raises to omit the original raise site. The pure-Python +implementation was unaffected. diff --git a/Misc/NEWS.d/next/Library/2026-07-29-11-05-00.gh-issue-151728.Kq3vTn.rst b/Misc/NEWS.d/next/Library/2026-07-29-11-05-00.gh-issue-151728.Kq3vTn.rst deleted file mode 100644 index 39c63a1aea3193a..000000000000000 --- a/Misc/NEWS.d/next/Library/2026-07-29-11-05-00.gh-issue-151728.Kq3vTn.rst +++ /dev/null @@ -1,4 +0,0 @@ -Clear the internal :mod:`typing` caches from an exit handler. Previously, an -extension module that leaked a reference to :mod:`typing` would also keep every -subscripted type alive past interpreter shutdown, including types owned by -unrelated extension modules. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 0cd41d0b4c4d0dc..ec6f35f161136c1 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -769,7 +769,6 @@ future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result) return -1; } *result = Py_NewRef(fut->fut_exception); - Py_CLEAR(fut->fut_exception_tb); return 1; }