From 20438866aefc2e63949d8bb85d8f8e55633fd977 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 15 May 2026 14:34:48 +0300 Subject: [PATCH 01/12] gh-149801: Add IANA registered names and aliases with leading zeros (GH-149804) Like IBM00858, CP00858, IBM01140, CP01140. --- Doc/library/codecs.rst | 4 ++-- Lib/encodings/aliases.py | 8 ++++++++ .../2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 9259ab10d5850b5..059ed2c03acfa38 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1155,7 +1155,7 @@ particular, the following variants typically exist: +-----------------+--------------------------------+--------------------------------+ | cp857 | 857, IBM857 | Turkish | +-----------------+--------------------------------+--------------------------------+ -| cp858 | 858, IBM858 | Western Europe | +| cp858 | 858, IBM00858 | Western Europe | +-----------------+--------------------------------+--------------------------------+ | cp860 | 860, IBM860 | Portuguese | +-----------------+--------------------------------+--------------------------------+ @@ -1192,7 +1192,7 @@ particular, the following variants typically exist: | | | | | | | .. versionadded:: 3.4 | +-----------------+--------------------------------+--------------------------------+ -| cp1140 | ibm1140 | Western Europe | +| cp1140 | IBM01140 | Western Europe | +-----------------+--------------------------------+--------------------------------+ | cp1250 | windows-1250 | Central and Eastern Europe | +-----------------+--------------------------------+--------------------------------+ diff --git a/Lib/encodings/aliases.py b/Lib/encodings/aliases.py index f4b1b8dd43f9205..e5e50630f33d14d 100644 --- a/Lib/encodings/aliases.py +++ b/Lib/encodings/aliases.py @@ -71,6 +71,10 @@ # cp1140 codec '1140' : 'cp1140', + 'cp01140' : 'cp1140', + 'csibm01140' : 'cp1140', + 'ebcdic_us_37_euro' : 'cp1140', + 'ibm01140' : 'cp1140', 'ibm1140' : 'cp1140', # cp1250 codec @@ -159,8 +163,12 @@ # cp858 codec '858' : 'cp858', + 'cp00858' : 'cp858', + 'csibm00858' : 'cp858', 'csibm858' : 'cp858', + 'ibm00858' : 'cp858', 'ibm858' : 'cp858', + 'pc_multilingual_850_euro' : 'cp858', # cp860 codec '860' : 'cp860', diff --git a/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst b/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst new file mode 100644 index 000000000000000..f9e8538527d204e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-13-23-18-39.gh-issue-149801.S_FfGr.rst @@ -0,0 +1,2 @@ +Add IANA registered names and aliases with leading zeros before number (like +IBM00858, CP00858, IBM01140, CP01140) for corresponding codecs. From 1fdf0337742762cc47837042747cc607f024a202 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 15 May 2026 15:38:51 +0300 Subject: [PATCH 02/12] gh-149816: Fix race condition in `memoryview` with free-threading (#149858) --- ...-05-15-11-31-57.gh-issue-149816.ugN2rx.rst | 1 + Objects/memoryobject.c | 20 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst new file mode 100644 index 000000000000000..016c17dd66b19ea --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst @@ -0,0 +1 @@ +Fix a race condition in :class:`memoryview` with free-threading. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index c0fd0b8b2f0f538..ebb3ed7360de682 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1629,11 +1629,7 @@ memory_getbuf(PyObject *_self, Py_buffer *view, int flags) view->obj = Py_NewRef(self); -#ifdef Py_GIL_DISABLED - _Py_atomic_add_ssize(&self->exports, 1); -#else - self->exports++; -#endif + FT_ATOMIC_ADD_SSIZE(self->exports, 1); return 0; } @@ -1642,11 +1638,7 @@ static void memory_releasebuf(PyObject *_self, Py_buffer *view) { PyMemoryViewObject *self = (PyMemoryViewObject *)_self; -#ifdef Py_GIL_DISABLED - _Py_atomic_add_ssize(&self->exports, -1); -#else - self->exports--; -#endif + FT_ATOMIC_ADD_SSIZE(self->exports, -1); return; /* PyBuffer_Release() decrements view->obj after this function returns. */ } @@ -2434,9 +2426,9 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, // Prevent 'self' from being freed if computing len(sep) mutates 'self' // in _Py_strhex_with_sep(). // See: https://github.com/python/cpython/issues/143195. - self->exports++; + FT_ATOMIC_ADD_SSIZE(self->exports, 1); PyObject *ret = _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep); - self->exports--; + FT_ATOMIC_ADD_SSIZE(self->exports, -1); return ret; } @@ -3363,9 +3355,9 @@ memory_hash(PyObject *_self) if (view->obj != NULL) { // Prevent 'self' from being freed when computing the item's hash. // See https://github.com/python/cpython/issues/142664. - self->exports++; + FT_ATOMIC_ADD_SSIZE(self->exports, 1); Py_hash_t h = PyObject_Hash(view->obj); - self->exports--; + FT_ATOMIC_ADD_SSIZE(self->exports, -1); if (h == -1) { /* Keep the original error message */ return -1; From a0551b1a12a32a20839b59511912e608b8231a67 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 May 2026 14:42:30 +0200 Subject: [PATCH 03/12] gh-148200: Update Modules/_hacl/ for Cygwin (#149802) This pulls an updated version of HACL* that fixes Lib_Memzero0.c on Cygwin, via an upstream fix. --- Misc/sbom.spdx.json | 16 ++++++++-------- Modules/_hacl/Lib_Memzero0.c | 4 ++-- Modules/_hacl/libintvector.h | 12 ++++++++++++ Modules/_hacl/refresh.sh | 2 +- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index 28a8b59f17cf63d..5791592dc77a84f 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -608,11 +608,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "0a0b7f3714167ad45ddf5a6a48d76f525a119c9c" + "checksumValue": "67a029736da5efe96f1b2d41b92f00934b955253" }, { "algorithm": "SHA256", - "checksumValue": "135d4afb4812468885c963c9c87a55ba5fae9181df4431af5fbad08588dda229" + "checksumValue": "0d80c2e3f5ff3b31ef0d435fc3196660df89ccf95bdcbb6545dc2f9df07bec9f" } ], "fileName": "Modules/_hacl/Lib_Memzero0.c" @@ -916,11 +916,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "63e47cc290c4ec887dca708000876ac37ee75ba0" + "checksumValue": "8d6a23f4e932cace0c67896bdda46cb24bf5e0ea" }, { "algorithm": "SHA256", - "checksumValue": "d09a6196d65c2645974100eb922002bd387d3ae13f2653780f82ed97a79af635" + "checksumValue": "25decbcadf1fef51f473daa4975a3754480fc903b03068bf95f149fb5349456e" } ], "fileName": "Modules/_hacl/libintvector.h" @@ -1024,14 +1024,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "61e48893f37cb2280d106cefacf6fb5afe84edf625fec39572d0ee94e1018f26" + "checksumValue": "d6db56a5d061dcc0890eabdbb5f58a9fa6c606d9f2fbbe9d626925b870ffadfb" } ], - "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/8ba599b2f6c9701b3dc961db895b0856a2210f76.zip", + "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/504c2987452f87fe44bce9b9f12e19d6e051761f.zip", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:8ba599b2f6c9701b3dc961db895b0856a2210f76:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:504c2987452f87fe44bce9b9f12e19d6e051761f:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1039,7 +1039,7 @@ "name": "hacl-star", "originator": "Organization: HACL* Developers", "primaryPackagePurpose": "SOURCE", - "versionInfo": "8ba599b2f6c9701b3dc961db895b0856a2210f76" + "versionInfo": "504c2987452f87fe44bce9b9f12e19d6e051761f" }, { "SPDXID": "SPDXRef-PACKAGE-macholib", diff --git a/Modules/_hacl/Lib_Memzero0.c b/Modules/_hacl/Lib_Memzero0.c index f94e0e2254a9128..7ab722e737c2ef7 100644 --- a/Modules/_hacl/Lib_Memzero0.c +++ b/Modules/_hacl/Lib_Memzero0.c @@ -31,7 +31,7 @@ #include #endif -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__NetBSD__) #include #endif @@ -57,7 +57,7 @@ void Lib_Memzero0_memzero0(void *dst, uint64_t len) { SecureZeroMemory(dst, len_); #elif defined(__APPLE__) && defined(__MACH__) && defined(APPLE_HAS_MEMSET_S) memset_s(dst, len_, 0, len_); - #elif (defined(__linux__) && !defined(LINUX_NO_EXPLICIT_BZERO)) || defined(__FreeBSD__) || defined(__OpenBSD__) + #elif (defined(__linux__) && !defined(LINUX_NO_EXPLICIT_BZERO)) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__OpenBSD__) explicit_bzero(dst, len_); #elif defined(__NetBSD__) explicit_memset(dst, 0, len_); diff --git a/Modules/_hacl/libintvector.h b/Modules/_hacl/libintvector.h index 6db5253eee4f24c..75ec2e0589830b1 100644 --- a/Modules/_hacl/libintvector.h +++ b/Modules/_hacl/libintvector.h @@ -802,6 +802,18 @@ vector128 Lib_IntVector_Intrinsics_vec128_xor(vector128 x0, vector128 x1) { #if defined(HACL_CAN_COMPILE_VEC128) #include + +/* GCC's AltiVec extension hijacks 'bool' as '__vector __bool int'. + Restore C99/C11 scalar bool for HACL* code. */ +#if defined(__GNUC__) && !defined(__clang__) +#undef bool +#define bool _Bool +#undef true +#define true 1 +#undef false +#define false 0 +#endif + #include // for memcpy #include diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index 72ceb27b7f70e8e..c73bd4ee90f4c55 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=8ba599b2f6c9701b3dc961db895b0856a2210f76 +expected_hacl_star_rev=504c2987452f87fe44bce9b9f12e19d6e051761f hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" From 4aa296f9c4a85a7badc09bf7ca6ede36cd8cd14c Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 15 May 2026 13:51:27 +0100 Subject: [PATCH 04/12] gh-138489: Add build-details.json generation to PC/layout (GH-149153) --- ...-04-29-14-44-51.gh-issue-138489.234aj6.rst | 4 + PC/layout/main.py | 4 + PC/layout/support/builddetails.py | 119 ++++++++++++++++++ PC/layout/support/constants.py | 9 ++ PC/layout/support/options.py | 6 + 5 files changed, 142 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst create mode 100644 PC/layout/support/builddetails.py diff --git a/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst b/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst new file mode 100644 index 000000000000000..4afb8f737b692e8 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-04-29-14-44-51.gh-issue-138489.234aj6.rst @@ -0,0 +1,4 @@ +Windows distributions now include a :file:`build-details.json` file (see +:pep:`739`). The legacy installer does not install it, but all other +distributions from python.org and all preset configurations in the +``PC\layout`` script will include one. diff --git a/PC/layout/main.py b/PC/layout/main.py index 3a62ea91420c9e2..f70a26b2b296591 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -22,6 +22,7 @@ __path__ = [str(Path(__file__).resolve().parent)] from .support.appxmanifest import * +from .support.builddetails import * from .support.catalog import * from .support.constants import * from .support.filesets import * @@ -317,6 +318,9 @@ def _c(d): for dest, src in get_appx_layout(ns): yield dest, src + for dest, src in get_builddetails(ns): + yield dest, src + if ns.include_cat: if ns.flat_dlls: yield ns.include_cat.name, ns.include_cat diff --git a/PC/layout/support/builddetails.py b/PC/layout/support/builddetails.py new file mode 100644 index 000000000000000..6ef860eeb043545 --- /dev/null +++ b/PC/layout/support/builddetails.py @@ -0,0 +1,119 @@ +import io +import json +from . import constants + +_LEVELS = { + 0xA0: "alpha", + 0xB0: "beta", + 0xC0: "candidate", + 0xF0: "final", +} + + +_TEMPLATE = { + "schema_version": "1.0", + "base_prefix": ".", + "base_interpreter": "python.exe", + "platform": None, # Set later + "language": { + "version": f"{constants.VER_MAJOR}.{constants.VER_MINOR}", + "version_info": { + "major": constants.VER_MAJOR, + "minor": constants.VER_MINOR, + "micro": constants.VER_MICRO, + "releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"), + "serial": constants.VER_FIELD4 & 0x0F, + }, + }, + "implementation": { + "name": "cpython", + "cache_tag": f"cpython-{constants.VER_MAJOR}{constants.VER_MINOR}", + "version": { + "major": constants.VER_MAJOR, + "minor": constants.VER_MINOR, + "micro": constants.VER_MICRO, + "releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"), + "serial": constants.VER_FIELD4 & 0x0F, + }, + "hexversion": constants.VER_HEXVERSION, + }, + "abi": { + "flags": [], + "extension_suffix": ".pyd", + "stable_abi_suffix": ".pyd", + }, + "suffixes": { + "source": [".py", ".pyw"], + "bytecode": [".pyc"], + "extensions": [".pyd"], + }, + "libpython": { + "dynamic": constants.PYTHON_DLL_NAME, + "dynamic_stableabi": constants.PYTHON_STABLE_DLL_NAME, + "link_extensions": True, + }, + "c_api": { + }, +} + + +def _with_d(path): + pre, sep, post = path.partition(".") + return pre + "_d" + sep + post + + +def _add_d(data, *args): + for a in args[:-1]: + data = data[a] + a = args[-1] + v = data[a] + if isinstance(v, list): + data[a] = [_with_d(i) for i in data[a]] + else: + data[a] = _with_d(data[a]) + + +def get_builddetails(ns): + if not ns.include_builddetails_json: + return + + details = dict(_TEMPLATE) + + plat = { + "win32": "win32", + "amd64": "win-amd64", + "arm64": "win-arm64", + }.get(ns.arch, ns.arch) + + pyd_abi_flags = "" + if ns.include_freethreaded: + details["abi"]["flags"].append("t") + pyd_abi_flags += "t" + if ns.debug: + details["abi"]["flags"].append("d") + + norm_plat = plat.replace("-", "_") + ext_suffix = f".cp{constants.VER_MAJOR}{constants.VER_MINOR}{pyd_abi_flags}-{norm_plat}.pyd" + details["abi"]["extension_suffix"] = ext_suffix + details["suffixes"]["extensions"].insert(0, ext_suffix) + + details["platform"] = plat + + if ns.include_dev: + details["c_api"]["headers"] = "Include" + + if ns.include_freethreaded: + details["libpython"]["dynamic"] = constants.FREETHREADED_PYTHON_DLL_NAME + details["libpython"]["dynamic_stableabi"] = constants.FREETHREADED_PYTHON_STABLE_DLL_NAME + + if ns.debug: + _add_d(details, "base_interpreter") + _add_d(details, "abi", "stable_abi_suffix") + _add_d(details, "abi", "extension_suffix") + _add_d(details, "suffixes", "extensions") + _add_d(details, "libpython", "dynamic") + _add_d(details, "libpython", "dynamic_stableabi") + + buffer = io.StringIO() + json.dump(details, buffer, indent=2) + yield "build-details.json", ("build-details.json", buffer.getvalue().encode()) diff --git a/PC/layout/support/constants.py b/PC/layout/support/constants.py index 6b8c915e519743f..cb16f534685c8f8 100644 --- a/PC/layout/support/constants.py +++ b/PC/layout/support/constants.py @@ -23,6 +23,14 @@ def _unpack_hexversion(): return _read_patchlevel_version(pathlib.Path(os.getenv("PYTHONINCLUDE"))) except OSError: pass + # Manual search for a '-s ` arument + try: + src = sys.argv[sys.argv.index("-s") + 1] + return _read_patchlevel_version(pathlib.Path(src) / "Include") + except (IndexError, ValueError): + pass + except OSError: + pass return struct.pack(">i", sys.hexversion) @@ -68,6 +76,7 @@ def check_patchlevel_version(sources): VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4 = _unpack_hexversion() +VER_HEXVERSION = (VER_MAJOR << 24) | (VER_MINOR << 16) | (VER_MICRO << 8) | (VER_FIELD4) VER_SUFFIX = _get_suffix(VER_FIELD4) VER_FIELD3 = VER_MICRO << 8 | VER_FIELD4 VER_DOT = "{}.{}".format(VER_MAJOR, VER_MINOR) diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py index e8c393385425e72..3a6e00f720f01ff 100644 --- a/PC/layout/support/options.py +++ b/PC/layout/support/options.py @@ -39,6 +39,7 @@ def public(f): "install-json": {"help": "a PyManager __install__.json file"}, "install-embed-json": {"help": "a PyManager __install__.json file for embeddable distro"}, "install-test-json": {"help": "a PyManager __install__.json for the test distro"}, + "builddetails-json": {"help": "a PEP 739 build-details.json"}, } @@ -69,6 +70,7 @@ def public(f): "props", "nuspec", "alias", + "builddetails-json", ], }, "iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]}, @@ -85,6 +87,7 @@ def public(f): "symbols", "html-doc", "alias", + "builddetails-json", ], }, "embed": { @@ -96,6 +99,7 @@ def public(f): "flat-dlls", "underpth", "precompile", + "builddetails-json", ], }, "pymanager": { @@ -109,6 +113,7 @@ def public(f): "dev", "html-doc", "install-json", + "builddetails-json", ], }, "pymanager-test": { @@ -124,6 +129,7 @@ def public(f): "symbols", "tests", "install-test-json", + "builddetails-json", ], }, } From 1c5fe21eb2a65190c04bb3f4c0931d76f5ccf415 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 15 May 2026 14:43:41 +0100 Subject: [PATCH 05/12] gh-149786: Fixes venvlauncher builds on Windows free-threaded (GH-149847) --- Lib/test/test_venv.py | 12 ++++++------ .../2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst | 1 + PC/layout/support/options.py | 2 ++ PC/layout/support/pymanager.py | 5 +++-- PCbuild/python.vcxproj | 8 ++++++++ PCbuild/pythonw.vcxproj | 8 ++++++++ PCbuild/venvlauncher.vcxproj | 7 +++++-- PCbuild/venvwlauncher.vcxproj | 7 +++++-- 8 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index a42787f261bfe89..9d2960664abfad5 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -301,9 +301,9 @@ def test_sysconfig(self): self.assertEqual(out.strip(), expected, err) for attr, expected in ( ('executable', self.envpy()), - # Usually compare to sys.executable, but if we're running in our own - # venv then we really need to compare to our base executable - ('_base_executable', sys._base_executable), + # Usually compare to sys.prefix, but if we're running in our own + # venv then we really need to compare to our base prefix + ('base_prefix', sys.base_prefix), ): with self.subTest(attr): cmd[2] = f'import sys; print(sys.{attr})' @@ -916,10 +916,10 @@ def test_venvwlauncher(self): exename = exename.replace("python", "pythonw") envpyw = os.path.join(self.env_dir, self.bindir, exename) try: - subprocess.check_call([envpyw, "-c", "import sys; " - "assert sys._base_executable.endswith('%s')" % exename]) + subprocess.check_call([envpyw, "-c", "import fnmatch, sys; " + "assert fnmatch.fnmatch(sys._base_executable, '**/pythonw*.exe')"]) except subprocess.CalledProcessError: - self.fail("venvwlauncher.exe did not run %s" % exename) + self.fail("venvwlauncher.exe did not run pythonw.exe") @requireVenvCreate diff --git a/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst new file mode 100644 index 000000000000000..64ca91a01f41afc --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst @@ -0,0 +1 @@ +Fixes virtual environment launchers on Windows free-threaded builds. diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py index 3a6e00f720f01ff..f67d8ba04d90703 100644 --- a/PC/layout/support/options.py +++ b/PC/layout/support/options.py @@ -112,6 +112,7 @@ def public(f): "venv", "dev", "html-doc", + "alias", "install-json", "builddetails-json", ], @@ -128,6 +129,7 @@ def public(f): "html-doc", "symbols", "tests", + "alias", "install-test-json", "builddetails-json", ], diff --git a/PC/layout/support/pymanager.py b/PC/layout/support/pymanager.py index 831d49ea3f9b46f..f6316e0295c74af 100644 --- a/PC/layout/support/pymanager.py +++ b/PC/layout/support/pymanager.py @@ -66,8 +66,9 @@ def calculate_install_json(ns, *, for_embed=False, for_test=False): if ns.include_freethreaded: # Free-threaded distro comes with a tag suffix TAG_SUFFIX = "t" - TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe" - TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe" + if not ns.include_alias: + TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe" + TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe" DISPLAY_TAGS.append("free-threaded") FILE_SUFFIX = f"t-{ns.arch}" diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index 70dabaa3c8bc027..417ede34c54af3a 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -135,6 +135,14 @@ set PYTHONPATH=$(PySourcePath)Lib "$(OutDir)$(PyExeName)$(PyDebugExt).exe" "$(PySourcePath)PC\validate_ucrtbase.py" $(UcrtName)' ContinueOnError="true" /> + + + + <_Content>@rem This script invokes the most recently built Python with all arguments diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index c6a5b8ce90a0d9b..244cdf622ad915c 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -115,4 +115,12 @@ + + + + \ No newline at end of file diff --git a/PCbuild/venvlauncher.vcxproj b/PCbuild/venvlauncher.vcxproj index abaf3a979af2681..a2e8ffa82b10eb7 100644 --- a/PCbuild/venvlauncher.vcxproj +++ b/PCbuild/venvlauncher.vcxproj @@ -89,10 +89,13 @@ - + + $(PyExeName)$(PyDebugExt).exe + $(PyExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe + - EXENAME=L"$(PyExeName)$(PyDebugExt).exe";_CONSOLE;%(PreprocessorDefinitions) + EXENAME=L"$(ExeName)";_CONSOLE;%(PreprocessorDefinitions) MultiThreaded diff --git a/PCbuild/venvwlauncher.vcxproj b/PCbuild/venvwlauncher.vcxproj index c58280deb8abeb3..f2aaf83fe2b3785 100644 --- a/PCbuild/venvwlauncher.vcxproj +++ b/PCbuild/venvwlauncher.vcxproj @@ -89,10 +89,13 @@ - + + $(PyWExeName)$(PyDebugExt).exe + $(PyWExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe + - EXENAME=L"$(PyWExeName)$(PyDebugExt).exe";_WINDOWS;%(PreprocessorDefinitions) + EXENAME=L"$(ExeName)";_WINDOWS;%(PreprocessorDefinitions) MultiThreaded From 3fafbc8e56538f0e5985826ab724b99be48cbf3b Mon Sep 17 00:00:00 2001 From: Carlo Bramini Date: Fri, 15 May 2026 15:54:08 +0200 Subject: [PATCH 06/12] gh-149833: Change DLL prefix to "cygpython" on Cygwin (#149834) Co-authored-by: Victor Stinner --- configure | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 4453237b06b5b75..e09baf6ac96c126 100755 --- a/configure +++ b/configure @@ -7783,7 +7783,7 @@ printf "%s\n" "#define Py_ENABLE_SHARED 1" >>confdefs.h CYGWIN*) LDLIBRARY='libpython$(LDVERSION).dll.a' BLDLIBRARY='-L. -lpython$(LDVERSION)' - DLLLIBRARY='libpython$(LDVERSION).dll' + DLLLIBRARY='cygpython$(LDVERSION).dll' ;; SunOS*) LDLIBRARY='libpython$(LDVERSION).so' diff --git a/configure.ac b/configure.ac index 87e8abdf3852d63..d720d322453ee76 100644 --- a/configure.ac +++ b/configure.ac @@ -1591,7 +1591,7 @@ if test $enable_shared = "yes"; then CYGWIN*) LDLIBRARY='libpython$(LDVERSION).dll.a' BLDLIBRARY='-L. -lpython$(LDVERSION)' - DLLLIBRARY='libpython$(LDVERSION).dll' + DLLLIBRARY='cygpython$(LDVERSION).dll' ;; SunOS*) LDLIBRARY='libpython$(LDVERSION).so' From a318a9d8d7788fff31f05dba6d58aec676e98eb6 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Fri, 15 May 2026 17:03:46 +0300 Subject: [PATCH 07/12] CI: Move Homebrew dependencies into Brewfile (#148335) Co-authored-by: Brett Cannon --- .github/workflows/reusable-macos.yml | 5 ++--- Misc/Brewfile | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 Misc/Brewfile diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml index f10503055b2259a..93b419159fa8177 100644 --- a/.github/workflows/reusable-macos.yml +++ b/.github/workflows/reusable-macos.yml @@ -38,9 +38,8 @@ jobs: run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: Install Homebrew dependencies run: | - brew install pkg-config openssl@3.5 xz gdbm tcl-tk@9 make - # Because alternate versions are not symlinked into place by default: - brew link --overwrite tcl-tk@9 + brew bundle --file=Misc/Brewfile + brew install make - name: Configure CPython run: | MACOSX_DEPLOYMENT_TARGET=10.15 \ diff --git a/Misc/Brewfile b/Misc/Brewfile new file mode 100644 index 000000000000000..b62c6e943989a0e --- /dev/null +++ b/Misc/Brewfile @@ -0,0 +1,15 @@ +brew "gdbm" +brew "mpdecimal" +brew "openssl@3.5" +brew "pkg-config" +brew "tcl-tk@9" +brew "xz" +brew "zstd" + +brew "bzip2" if OS.linux? +brew "expat" if OS.linux? +brew "libedit" if OS.linux? +brew "libffi" if OS.linux? +brew "ncurses" if OS.linux? +brew "unzip" if OS.linux? +brew "zlib-ng-compat" if OS.linux? From 50aff5fc5ccc5b7c64ad5dcbf2a2d125436b85a0 Mon Sep 17 00:00:00 2001 From: Carlo Bramini Date: Fri, 15 May 2026 16:29:26 +0200 Subject: [PATCH 08/12] gh-149831: Fix ctypes DLL library name on Cygwin (#149832) Co-authored-by: Victor Stinner --- Lib/ctypes/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index 0b84a27f8c6d613..890168cc9809fd6 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -549,9 +549,11 @@ def LoadLibrary(self, name): if _os.name == "nt": pythonapi = PyDLL("python dll", None, _sys.dllhandle) -elif _sys.platform in ["android", "cygwin"]: +elif _sys.platform == "android": # These are Unix-like platforms which use a dynamically-linked libpython. pythonapi = PyDLL(_sysconfig.get_config_var("LDLIBRARY")) +elif _sys.platform == "cygwin": + pythonapi = PyDLL(_sysconfig.get_config_var("DLLLIBRARY")) else: pythonapi = PyDLL(None) From c575172425fa792845dd686a1b2f114982accd23 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 May 2026 17:55:34 +0200 Subject: [PATCH 09/12] gh-149879: Fix sys.orig_argv[0] on Cygwin: add ".exe" suffix (#149885) --- Python/initconfig.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Python/initconfig.c b/Python/initconfig.c index a996fb117aab9d2..e0bdadf491bad32 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -3688,6 +3688,44 @@ PyConfig_SetWideStringList(PyConfig *config, PyWideStringList *list, } +#ifdef __CYGWIN__ +// Cygwin strips ".exe" suffix from argv[0]. +// Add again the ".exe" suffix. +static PyStatus +config_argv0_add_exe(PyConfig *config) +{ + if (config->argv.length < 1) { + return _PyStatus_OK(); + } + const wchar_t *argv0 = config->argv.items[0]; + size_t len = wcslen(argv0); + if (len >= 5 && wcscmp(argv0 + len - 4, L".exe") == 0) { + return _PyStatus_OK(); + } + + wchar_t *exe = PyMem_RawMalloc((len + 4 + 1) * sizeof(wchar_t)); + if (exe == NULL) { + return _PyStatus_NO_MEMORY(); + } + wcscpy(exe, argv0); + wcscat(exe, L".exe"); + + FILE *fp = _Py_wfopen(exe, L"rb"); + if (fp != NULL) { + fclose(fp); + + PyMem_RawFree(config->argv.items[0]); + config->argv.items[0] = exe; + } + else { + PyMem_RawFree(exe); + } + + return _PyStatus_OK(); +} +#endif + + /* Read the configuration into PyConfig from: * Command line arguments @@ -3707,6 +3745,13 @@ _PyConfig_Read(PyConfig *config, int compute_path_config) config_get_global_vars(config); +#ifdef __CYGWIN__ + status = config_argv0_add_exe(config); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +#endif + if (config->orig_argv.length == 0 && !(config->argv.length == 1 && wcscmp(config->argv.items[0], L"") == 0)) From 8be3fb1b50ce6b01bf0924f0a0362a5e04af83b4 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 15 May 2026 19:30:40 +0300 Subject: [PATCH 10/12] gh-142349: Add `help("lazy")` support (#149886) --- Doc/tools/extensions/pydoc_topics.py | 1 + Lib/pydoc.py | 1 + Lib/test/test_pydoc/test_pydoc.py | 2 +- .../next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst diff --git a/Doc/tools/extensions/pydoc_topics.py b/Doc/tools/extensions/pydoc_topics.py index a65d77433b255bc..35878e2d1e43e9b 100644 --- a/Doc/tools/extensions/pydoc_topics.py +++ b/Doc/tools/extensions/pydoc_topics.py @@ -68,6 +68,7 @@ "in", "integers", "lambda", + "lazy", "lists", "naming", "nonlocal", diff --git a/Lib/pydoc.py b/Lib/pydoc.py index a1a6aad434ddf4d..497cc7d90a42456 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1845,6 +1845,7 @@ class Helper: 'in': ('in', 'SEQUENCEMETHODS'), 'is': 'COMPARISON', 'lambda': ('lambda', 'FUNCTIONS'), + 'lazy': ('lazy', 'MODULES'), 'nonlocal': ('nonlocal', 'global NAMESPACES'), 'not': 'BOOLEAN', 'or': 'BOOLEAN', diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 2e190d1b81be8ec..5cd26923f75c311 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -2172,7 +2172,7 @@ def mock_getline(prompt): def test_keywords(self): self.assertEqual(sorted(pydoc.Helper.keywords), - sorted(keyword.kwlist)) + sorted(keyword.kwlist + ['lazy'])) def test_interact_empty_line_continues(self): # gh-138568: test pressing Enter without input should continue in help session diff --git a/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst b/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst new file mode 100644 index 000000000000000..fa667c4110941e9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-15-18-44-20.gh-issue-142349.fHK3v1.rst @@ -0,0 +1 @@ +Add :keyword:`lazy` to the list of support topic by :func:`help`. From c92588efd3676685688b947ed9abe5c0cc9e7b81 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 May 2026 18:33:46 +0200 Subject: [PATCH 11/12] gh-149879: Fix test_pwd on Cygwin (#149880) On Cygwin, pwd.getpwuid(-1) returns an user ('Unknown+User'). --- Lib/test/test_pwd.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py index aa090b464a72222..d0ef30ec4930843 100644 --- a/Lib/test/test_pwd.py +++ b/Lib/test/test_pwd.py @@ -103,9 +103,11 @@ def test_errors(self): self.assertNotIn(fakeuid, byuids) self.assertRaises(KeyError, pwd.getpwuid, fakeuid) - # -1 shouldn't be a valid uid because it has a special meaning in many - # uid-related functions - self.assertRaises(KeyError, pwd.getpwuid, -1) + # On Cygwin, getpwuid(-1) returns 'Unknown+User' user + if sys.platform != 'cygwin': + # -1 shouldn't be a valid uid because it has a special meaning in many + # uid-related functions + self.assertRaises(KeyError, pwd.getpwuid, -1) # should be out of uid_t range self.assertRaises(KeyError, pwd.getpwuid, 2**128) self.assertRaises(KeyError, pwd.getpwuid, -2**128) From 9778db13f799b1e3d6287767ac461d4cd299ec2d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 May 2026 18:57:05 +0200 Subject: [PATCH 12/12] gh-149879: Set thread name max length on Cygwin (#149890) This change fix test_threading on Cygwin. --- configure | 1 + configure.ac | 1 + 2 files changed, 2 insertions(+) diff --git a/configure b/configure index e09baf6ac96c126..63b41117957cab5 100755 --- a/configure +++ b/configure @@ -31754,6 +31754,7 @@ case "$ac_sys_system" in iOS) _PYTHREAD_NAME_MAXLEN=63;; FreeBSD*) _PYTHREAD_NAME_MAXLEN=19;; # gh-131268 OpenBSD*) _PYTHREAD_NAME_MAXLEN=23;; # gh-131268 + CYGWIN*) _PYTHREAD_NAME_MAXLEN=16;; *) _PYTHREAD_NAME_MAXLEN=;; esac if test -n "$_PYTHREAD_NAME_MAXLEN"; then diff --git a/configure.ac b/configure.ac index d720d322453ee76..6df5d1bee31c677 100644 --- a/configure.ac +++ b/configure.ac @@ -7850,6 +7850,7 @@ case "$ac_sys_system" in iOS) _PYTHREAD_NAME_MAXLEN=63;; FreeBSD*) _PYTHREAD_NAME_MAXLEN=19;; # gh-131268 OpenBSD*) _PYTHREAD_NAME_MAXLEN=23;; # gh-131268 + CYGWIN*) _PYTHREAD_NAME_MAXLEN=16;; *) _PYTHREAD_NAME_MAXLEN=;; esac if test -n "$_PYTHREAD_NAME_MAXLEN"; then