diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst
index 36db964a8bbfe4..81949261c563d0 100644
--- a/Doc/library/csv.rst
+++ b/Doc/library/csv.rst
@@ -322,6 +322,12 @@ The :mod:`!csv` module defines the following classes:
in particular if it is a single column,
so there is no delimiter to find.
+ If several combinations fit the sample equally well ---
+ for example if both ``','`` and ``';'`` split every row consistently ---
+ the delimiters ``','``, ``'\t'``, ``';'``, ``' '`` and ``':'``
+ are preferred, in this order,
+ no matter how many times each of them occurs.
+
.. versionchanged:: next
The dialect is now deduced by trial parsing
and the results may differ from those of earlier Python versions.
diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst
index 9063bea96ccb0a..d5f89102d5853b 100644
--- a/Doc/library/warnings.rst
+++ b/Doc/library/warnings.rst
@@ -566,7 +566,7 @@ Available Functions
and calls to :func:`simplefilter`.
-.. decorator:: deprecated(msg, *, category=DeprecationWarning, stacklevel=1)
+.. decorator:: deprecated(message, /, *, category=DeprecationWarning, stacklevel=1)
Decorator to indicate that a class, function or overload is deprecated.
diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst
index 6cf945de5b3f3b..a01dabbf2475aa 100644
--- a/Doc/using/mac.rst
+++ b/Doc/using/mac.rst
@@ -29,8 +29,8 @@ Installation steps
For `current Python versions `_
(other than those in ``security`` status), the release team produces a
**Python for macOS** installer package for each new release.
-A list of available installers
-is available `here `_.
+A list of available installers is provided on the
+`macOS downloads page `__.
We recommend using the most recent supported Python version where possible.
Current installers provide a
`universal2 binary `_ build
@@ -39,14 +39,14 @@ supported by a wide range of macOS versions,
currently typically from at least **macOS 10.15 Catalina** on.
The downloaded file is a standard macOS installer package file (``.pkg``).
-File integrity information (checksum, size, sigstore signature, etc) for each file is included
+File integrity information (such as checksum, size, and Sigstore signature) for each file is included
on the release download page. Installer packages and their contents are signed and notarized
with ``Python Software Foundation`` Apple Developer ID certificates
to meet `macOS Gatekeeper requirements `_.
For a default installation, double-click on the downloaded installer package file.
This should launch the standard macOS Installer app and display the first of several
-installer windows steps.
+installer steps.
.. image:: mac_installer_01_introduction.png
@@ -73,8 +73,8 @@ display. For most uses, the standard set of installation operations is appropria
By pressing the **Customize** button, you can choose to omit or select certain package
components of the installer. Click on each package name to see a description of
what it installs.
-To also install support for the optional free-threaded feature,
-see :ref:`install-freethreaded-macos`.
+For details of the optional free-threaded feature, which is installed
+by default, see :ref:`install-freethreaded-macos`.
.. image:: mac_installer_05_custom_install.png
@@ -98,7 +98,7 @@ for its use.
.. image:: mac_installer_08_install_certificates.png
-If ``Successfully installed certifi`` and ``update complete`` appears
+If ``Successfully installed certifi`` and ``update complete`` appear
in the terminal window, the installation is complete.
Close this terminal window and the installer window.
@@ -171,7 +171,7 @@ be certain of what you are about to run.
.. _alternative_bundles:
-Alternative Distributions
+Alternative distributions
=========================
Besides the standard ``python.org`` for macOS installer, there are third-party
@@ -199,7 +199,7 @@ other libraries, and are not maintained or supported by the core Python team.
.. _mac-package-manager:
-Installing Additional Python Packages
+Installing additional Python packages
=====================================
Refer to the `Python Packaging User Guide`_ for more information.
@@ -211,7 +211,7 @@ Refer to the `Python Packaging User Guide`_ for more information.
.. _gui-programming-on-the-mac:
-GUI Programming
+GUI programming
===============
There are several options for building GUI applications on the Mac with Python.
@@ -241,19 +241,22 @@ A number of alternative macOS GUI toolkits are available including:
supports desktop operating systems.
-Advanced Topics
+Advanced topics
===============
.. _install-freethreaded-macos:
-Installing Free-threaded Binaries
+Installing free-threaded binaries
---------------------------------
.. versionadded:: 3.13
+.. versionchanged:: 3.15
+ Free-threading support is now installed by default.
+
The ``python.org`` :ref:`Python for macOS `
-installer package can optionally install an additional build of
-Python |version| that supports :pep:`703`, the free-threading feature
+installer package installs, by default, an additional build of
+Python |version| that supports :term:`free threading`
(running with the :term:`global interpreter lock` disabled).
Check the release page on ``python.org`` for possible updated information.
@@ -262,14 +265,15 @@ there is some additional overhead in single-threaded workloads compared
to the regular build. Additionally, third-party packages, in particular ones
with an :term:`extension module`, may not be ready for use in a
free-threaded build, and will re-enable the :term:`GIL`.
-Therefore, the support for free-threading
-is not installed by default. It is packaged as a separate install option,
-available by clicking the **Customize** button on the **Installation Type**
+As of Python 3.15, free-threading support is installed by default.
+It is packaged as a separate install option, which can be deselected
+by clicking the **Customize** button on the **Installation Type**
step of the installer as described above.
.. image:: mac_installer_09_custom_install_free_threaded.png
-If the box next to the **Free-threaded Python** package name is checked,
+If the box next to the **Free-threaded Python** package name is checked
+(as it is by default),
a separate :file:`PythonT.framework` will also be installed
alongside the normal :file:`Python.framework` in :file:`/Library/Frameworks`.
This configuration allows a free-threaded Python |version| build to co-exist
@@ -284,7 +288,7 @@ Known cautions and limitations:
the free-threaded interpreter, and |python_x_dot_y_t_literal_config|,
a configuration utility which may be useful for package builders.
Since :file:`/usr/local/bin` is typically included in your shell ``PATH``,
- in most cases no changes to your ``PATH`` environment variables should
+ in most cases no changes to your ``PATH`` environment variable should
be needed to use |python_x_dot_y_t_literal|.
- For this release, the **Shell profile updater** package and the
@@ -367,8 +371,8 @@ the macOS command line :command:`installer` utility lets you select non-default
options, too. If you are not familiar with :command:`installer`, it can be
somewhat cryptic (see :command:`man installer` for more information).
As an example, the following shell snippet shows one way to do it,
-using the |x_dot_y_b2_literal| release and selecting the free-threaded interpreter
-option:
+using the |x_dot_y_b2_literal| release and deselecting the free-threaded
+interpreter option:
.. parsed-literal::
@@ -378,7 +382,7 @@ option:
curl -O \https://www.python.org/ftp/python/\ |version|\ .0/${RELEASE}
# create installer choicechanges to customize the install:
- # enable the PythonTFramework-\ |version|\ package
+ # disable the PythonTFramework-\ |version|\ package
# while accepting the other defaults (install all other packages)
cat > ./choicechanges.plist <
@@ -387,7 +391,7 @@ option:
attributeSetting
- 1
+ 0
choiceAttribute
selected
choiceIdentifier
@@ -400,7 +404,7 @@ option:
sudo installer -pkg ./${RELEASE} -applyChoiceChangesXML ./choicechanges.plist -target /
-You can then test that both installer builds are now available with something like:
+After a default install, you can test that both builds are available with something like:
.. parsed-literal::
@@ -425,7 +429,7 @@ You can then test that both installer builds are now available with something li
.. _distributing-python-applications-on-the-mac:
-Distributing Python Applications
+Distributing Python applications
--------------------------------
A range of tools exist for converting your Python code into a standalone
@@ -442,7 +446,7 @@ distributable application:
* `PyInstaller `_: A cross-platform packaging tool that creates
a single file or folder as a distributable artifact.
-App Store Compliance
+App Store compliance
--------------------
Apps submitted for distribution through the macOS App Store must pass Apple's
@@ -464,7 +468,7 @@ This patch is not normally required to use CPython on a Mac; nor is it required
if you are distributing an app *outside* the macOS App Store. It is *only*
required if you are using the macOS App Store as a distribution channel.
-Other Resources
+Other resources
===============
The `python.org Help page `_ has links to many useful resources.
diff --git a/Doc/using/mac_installer_01_introduction.png b/Doc/using/mac_installer_01_introduction.png
index 1999f3a3759093..81e1f4e5ac5c32 100644
Binary files a/Doc/using/mac_installer_01_introduction.png and b/Doc/using/mac_installer_01_introduction.png differ
diff --git a/Doc/using/mac_installer_02_readme.png b/Doc/using/mac_installer_02_readme.png
index a36efaf7d50fd6..7e4a9b15cf94f6 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_03_license.png b/Doc/using/mac_installer_03_license.png
index 598c22a13d9e62..153daa780efa9e 100644
Binary files a/Doc/using/mac_installer_03_license.png and b/Doc/using/mac_installer_03_license.png differ
diff --git a/Doc/using/mac_installer_04_installation_type.png b/Doc/using/mac_installer_04_installation_type.png
index 9498fd06240a4e..1fc597c2427ab7 100644
Binary files a/Doc/using/mac_installer_04_installation_type.png and b/Doc/using/mac_installer_04_installation_type.png differ
diff --git a/Doc/using/mac_installer_05_custom_install.png b/Doc/using/mac_installer_05_custom_install.png
index 3a201d2f44655a..c70d93bbcee70a 100644
Binary files a/Doc/using/mac_installer_05_custom_install.png and b/Doc/using/mac_installer_05_custom_install.png differ
diff --git a/Doc/using/mac_installer_06_summary.png b/Doc/using/mac_installer_06_summary.png
index 1af6eee2c668cd..f8a67052ef0447 100644
Binary files a/Doc/using/mac_installer_06_summary.png and b/Doc/using/mac_installer_06_summary.png differ
diff --git a/Doc/using/mac_installer_07_applications.png b/Doc/using/mac_installer_07_applications.png
index c8b3aa1099adfc..c39741f33ac807 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_08_install_certificates.png b/Doc/using/mac_installer_08_install_certificates.png
index c125eeb18aa0c1..f476c7f37d245d 100644
Binary files a/Doc/using/mac_installer_08_install_certificates.png and b/Doc/using/mac_installer_08_install_certificates.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..e867e422e42e48 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/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h
index 0623adce693d46..3d577ff717cc6e 100644
--- a/Include/internal/pycore_interp_structs.h
+++ b/Include/internal/pycore_interp_structs.h
@@ -977,6 +977,7 @@ struct _is {
struct _obmalloc_state *obmalloc;
PyObject *audit_hooks;
+ PyMutex audit_hooks_mutex;
PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS];
PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS];
PyContext_WatchCallback context_watchers[CONTEXT_MAX_WATCHERS];
diff --git a/Lib/csv.py b/Lib/csv.py
index 505e9e501e6772..a84234f110dd70 100644
--- a/Lib/csv.py
+++ b/Lib/csv.py
@@ -260,6 +260,10 @@ def sniff(self, sample, delimiters=None):
beginning, then, after eliminating the combinations which are
clearly worse than the leader, a several times larger part,
and so on.
+
+ If several combinations fit the sample equally well, the
+ delimiters listed in the preferred attribute are preferred, in
+ that order, no matter how many times each of them occurs.
"""
import re
from collections import defaultdict
diff --git a/Lib/stat.py b/Lib/stat.py
index 214c7917b5e048..76f02d7aa33d16 100644
--- a/Lib/stat.py
+++ b/Lib/stat.py
@@ -1,7 +1,4 @@
-"""Constants/functions for interpreting results of os.stat() and os.lstat().
-
-Suggested usage: from stat import *
-"""
+"""Constants/functions for interpreting results of os.stat() and os.lstat()."""
# Indices for stat struct members in the tuple returned by os.stat()
diff --git a/Lib/test/test_free_threading/test_sys.py b/Lib/test/test_free_threading/test_sys.py
index 271fdd13c62b66..b8ba933cb01adc 100644
--- a/Lib/test/test_free_threading/test_sys.py
+++ b/Lib/test/test_free_threading/test_sys.py
@@ -44,6 +44,20 @@ def worker(worker_id):
workers = [lambda: worker(i) for i in range(5)]
threading_helper.run_concurrently(workers)
+ def test_sys_audit_hooks(self):
+ def _hook(*args):
+ return None
+
+ def adder():
+ for _ in range(100):
+ sys.addaudithook(_hook)
+
+ def auditor():
+ for _ in range(2000):
+ sys.audit("fusil.tsan.test")
+
+ threading_helper.run_concurrently([adder, auditor])
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst b/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst
new file mode 100644
index 00000000000000..a56c3b3a6f21f3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-22-12-42-53.gh-issue-154431.U2kXXZ.rst
@@ -0,0 +1 @@
+Fixes a data race in free-threading build in :func:`sys.addaudithook`.
diff --git a/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst b/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst
new file mode 100644
index 00000000000000..b0a7058f0519ff
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-22-13-00-00.gh-issue-154460.wCsFtM.rst
@@ -0,0 +1,2 @@
+Fix :func:`time.strftime` and :meth:`datetime.datetime.strftime` returning a
+wrong ISO 8601 week number (``%V``) on OpenBSD.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index d90bf1f2ef90ed..70d7e1b3713687 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -763,6 +763,13 @@ Other codes may be available on your platform. See documentation for\n\
the C library strftime function.\n"
#ifdef HAVE_STRFTIME
+// gh-154460: OpenBSD's wcsftime() computes %V incorrectly: it returns 53
+// whenever the ISO 8601 week belongs to a different year than tm_year.
+// strftime() is not affected.
+#ifdef __OpenBSD__
+# undef HAVE_WCSFTIME
+#endif
+
#ifdef HAVE_WCSFTIME
#define time_char wchar_t
#define format_time wcsftime
diff --git a/Python/pystate.c b/Python/pystate.c
index d10b38def32911..b6c34552e94337 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -578,6 +578,7 @@ init_interpreter(PyInterpreterState *interp,
llist_init(&interp->mem_free_queue.head);
llist_init(&interp->asyncio_tasks_head);
interp->asyncio_tasks_lock = (PyMutex){0};
+ interp->audit_hooks_mutex = (PyMutex){0};
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
interp->monitors.tools[i] = 0;
}
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 9442472b53abbe..207ccbce41d71d 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -236,7 +236,7 @@ should_audit(PyInterpreterState *interp)
return 0;
}
return (interp->runtime->audit_hooks.head
- || interp->audit_hooks
+ || FT_ATOMIC_LOAD_PTR_ACQUIRE(interp->audit_hooks)
|| PyDTrace_AUDIT_ENABLED());
}
@@ -306,13 +306,14 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
}
/* Call interpreter hooks */
- if (is->audit_hooks) {
+ PyObject *audit_hooks = FT_ATOMIC_LOAD_PTR_ACQUIRE(is->audit_hooks);
+ if (audit_hooks) {
eventName = PyUnicode_FromString(event);
if (!eventName) {
goto exit;
}
- hooks = PyObject_GetIter(is->audit_hooks);
+ hooks = PyObject_GetIter(audit_hooks);
if (!hooks) {
goto exit;
}
@@ -536,20 +537,29 @@ sys_addaudithook_impl(PyObject *module, PyObject *hook)
}
PyInterpreterState *interp = tstate->interp;
+ PyMutex mutex = interp->audit_hooks_mutex;
+ PyMutex_Lock(&mutex);
+
if (interp->audit_hooks == NULL) {
- interp->audit_hooks = PyList_New(0);
- if (interp->audit_hooks == NULL) {
- return NULL;
+ PyObject *new_list = PyList_New(0);
+ if (new_list == NULL) {
+ goto error;
}
/* Avoid having our list of hooks show up in the GC module */
- PyObject_GC_UnTrack(interp->audit_hooks);
+ PyObject_GC_UnTrack(new_list);
+ FT_ATOMIC_STORE_PTR_RELEASE(interp->audit_hooks, new_list);
}
if (PyList_Append(interp->audit_hooks, hook) < 0) {
- return NULL;
+ goto error;
}
+ PyMutex_Unlock(&mutex);
Py_RETURN_NONE;
+
+error:
+ PyMutex_Unlock(&mutex);
+ return NULL;
}
/*[clinic input]
diff --git a/configure b/configure
index 58f3dfc119ec13..08b493311a3f92 100755
--- a/configure
+++ b/configure
@@ -1102,6 +1102,7 @@ enable_framework
with_app_store_compliance
enable_wasm_dynamic_linking
enable_wasm_pthreads
+enable_emscripten_syscalls
with_suffix
enable_shared
with_static_libpython
@@ -1843,6 +1844,10 @@ Optional Features:
loader to handle imports
--enable-wasm-pthreads Enable pthread emulation for WebAssembly (default is
no)
+ --disable-emscripten-syscalls
+ Disable the Emscripten syscall overrides in
+ Python/emscripten_syscalls.c (default is enabled for
+ Emscripten)
--enable-shared enable building a shared Python library (default is
no)
--enable-static-libpython-for-interpreter
@@ -7620,6 +7625,30 @@ fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_pthreads" >&5
printf "%s\n" "$enable_wasm_pthreads" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-emscripten-syscalls" >&5
+printf %s "checking for --enable-emscripten-syscalls... " >&6; }
+# Check whether --enable-emscripten-syscalls was given.
+if test ${enable_emscripten_syscalls+y}
+then :
+ enableval=$enable_emscripten_syscalls;
+ case $ac_sys_system in #(
+ Emscripten) :
+ ;; #(
+ *) :
+ as_fn_error $? "--enable-emscripten-syscalls only applies to Emscripten" "$LINENO" 5
+ ;;
+esac
+
+else case e in #(
+ e)
+ enable_emscripten_syscalls=yes
+ ;;
+esac
+fi
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_emscripten_syscalls" >&5
+printf "%s\n" "$enable_emscripten_syscalls" >&6; }
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-suffix" >&5
printf %s "checking for --with-suffix... " >&6; }
@@ -20159,7 +20188,13 @@ PLATFORM_OBJS=
case $ac_sys_system in #(
Emscripten) :
- as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o Python/emscripten_syscalls.o'
+ as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o'
+ if test "x$enable_emscripten_syscalls" = xyes
+then :
+
+ as_fn_append PLATFORM_OBJS ' Python/emscripten_syscalls.o'
+
+fi
as_fn_append PLATFORM_HEADERS ' $(srcdir)/Include/internal/pycore_emscripten_signal.h $(srcdir)/Include/internal/pycore_emscripten_trampoline.h'
;; #(
*) :
diff --git a/configure.ac b/configure.ac
index 273a64814f9a1f..f40db5bc82e24a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1365,6 +1365,20 @@ AC_ARG_ENABLE([wasm-pthreads],
])
AC_MSG_RESULT([$enable_wasm_pthreads])
+AC_MSG_CHECKING([for --enable-emscripten-syscalls])
+AC_ARG_ENABLE([emscripten-syscalls],
+ [AS_HELP_STRING([--disable-emscripten-syscalls],
+ [Disable the Emscripten syscall overrides in Python/emscripten_syscalls.c (default is enabled for Emscripten)])],
+[
+ AS_CASE([$ac_sys_system],
+ [Emscripten], [],
+ [AC_MSG_ERROR([--enable-emscripten-syscalls only applies to Emscripten])]
+ )
+], [
+ enable_emscripten_syscalls=yes
+])
+AC_MSG_RESULT([$enable_emscripten_syscalls])
+
AC_MSG_CHECKING([for --with-suffix])
AC_ARG_WITH([suffix],
[AS_HELP_STRING([--with-suffix=SUFFIX], [set executable suffix to SUFFIX (default is empty, yes is mapped to '.exe')])],
@@ -5380,7 +5394,10 @@ PLATFORM_OBJS=
AS_CASE([$ac_sys_system],
[Emscripten], [
- AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o Python/emscripten_syscalls.o'])
+ AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o'])
+ AS_VAR_IF([enable_emscripten_syscalls], [yes], [
+ AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_syscalls.o'])
+ ])
AS_VAR_APPEND([PLATFORM_HEADERS], [' $(srcdir)/Include/internal/pycore_emscripten_signal.h $(srcdir)/Include/internal/pycore_emscripten_trampoline.h'])
],
)