From 94a75f74a13a11b4025c02612c47f61dec0a7398 Mon Sep 17 00:00:00 2001 From: Abdul Mohammad <154353563+abdulm5@users.noreply.github.com> Date: Sat, 15 Aug 2026 23:12:24 -0400 Subject: [PATCH 1/2] gh-155504: Set the interpreter before fallible thread state initialization (#155590) --- .../2026-08-11-13-50-35.gh-issue-155504.PsTqZm.rst | 2 ++ Python/pystate.c | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-08-11-13-50-35.gh-issue-155504.PsTqZm.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-11-13-50-35.gh-issue-155504.PsTqZm.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-11-13-50-35.gh-issue-155504.PsTqZm.rst new file mode 100644 index 000000000000000..e042bf3554e6f05 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-11-13-50-35.gh-issue-155504.PsTqZm.rst @@ -0,0 +1,2 @@ +Fix a crash when thread state creation fails before the thread state is fully +initialized. diff --git a/Python/pystate.c b/Python/pystate.c index 646c157007d4ac1..6b0d6a7a372c926 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1508,6 +1508,8 @@ alloc_threadstate(PyInterpreterState *interp) } reset_threadstate(tstate); } + // Set the interpreter before any later initialization can fail. + tstate->base.interp = interp; return tstate; } From 70b2b0a2dcce71e8b94757b8ed9313b0cbe0fc4f Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Sat, 15 Aug 2026 23:47:16 -0500 Subject: [PATCH 2/2] gh-129382: Match venv API symlink defaults to the CLI (#155759) --- Doc/library/venv.rst | 13 +++++++-- Lib/test/test_venv.py | 29 +++++++++++++++++-- Lib/venv/__init__.py | 13 ++++----- ...-01-31-02-27-53.gh-issue-129382.GI93CM.rst | 3 ++ 4 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-01-31-02-27-53.gh-issue-129382.GI93CM.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 1ad2401fe2f3f31..fd9c9b9a19dd9b3 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -302,7 +302,7 @@ mechanisms for third-party virtual environment creators to customize environment creation according to their needs, the :class:`EnvBuilder` class. .. class:: EnvBuilder(system_site_packages=False, clear=False, \ - symlinks=False, upgrade=False, with_pip=False, \ + symlinks=None, upgrade=False, with_pip=False, \ prompt=None, upgrade_deps=False, \ *, scm_ignore_files=frozenset()) @@ -316,7 +316,8 @@ creation according to their needs, the :class:`EnvBuilder` class. any existing target directory, before creating the environment. * *symlinks* -- a boolean value indicating whether to attempt to symlink the - Python binary rather than copying. + Python binary rather than copying. If ``None``, the default is ``False`` on + Windows and ``True`` on other platforms, matching the :ref:`CLI `. * *upgrade* -- a boolean value which, if true, will upgrade an existing environment with the running Python - for use when that Python has been @@ -351,6 +352,9 @@ creation according to their needs, the :class:`EnvBuilder` class. .. versionchanged:: 3.13 Added the ``scm_ignore_files`` parameter + .. versionchanged:: 3.16 + The default value of *symlinks* is now platform-dependent. + :class:`EnvBuilder` may be used as a base class. .. method:: create(env_dir) @@ -521,7 +525,7 @@ creation according to their needs, the :class:`EnvBuilder` class. There is also a module-level convenience function: .. function:: create(env_dir, system_site_packages=False, clear=False, \ - symlinks=False, with_pip=False, prompt=None, \ + symlinks=None, with_pip=False, prompt=None, \ upgrade_deps=False, *, scm_ignore_files=frozenset()) Create an :class:`EnvBuilder` with the given keyword arguments, and call its @@ -541,6 +545,9 @@ There is also a module-level convenience function: .. versionchanged:: 3.13 Added the *scm_ignore_files* parameter + .. versionchanged:: 3.16 + The default value of *symlinks* is now platform-dependent. + An example of extending ``EnvBuilder`` -------------------------------------- diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index e98e52c2ea20453..b4ad1bf3f412948 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -133,6 +133,31 @@ def test_defaults_with_pathlike(self): self.run_with_capture(venv.create, FakePath(self.env_dir)) self._check_output_of_default_create() + def test_envbuilder_symlinks(self): + for kwargs, expected in ( + ({}, os.name != 'nt'), + ({'symlinks': None}, os.name != 'nt'), + ({'symlinks': True}, True), + ({'symlinks': False}, False), + ): + with self.subTest(kwargs=kwargs): + builder = venv.EnvBuilder(**kwargs) + self.assertIs(builder.symlinks, expected) + + def test_create_symlinks(self): + for kwargs, expected in ( + ({}, os.name != 'nt'), + ({'symlinks': None}, os.name != 'nt'), + ({'symlinks': True}, True), + ({'symlinks': False}, False), + ): + with self.subTest(kwargs=kwargs): + with patch.object(venv.EnvBuilder, 'create', autospec=True) as create: + venv.create(self.env_dir, **kwargs) + builder, env_dir = create.call_args.args + self.assertIs(builder.symlinks, expected) + self.assertEqual(env_dir, self.env_dir) + def _check_output_of_default_create(self): self.isdir(self.bindir) self.isdir(self.include) @@ -146,8 +171,7 @@ def _check_output_of_default_create(self): self.assertIn('home = %s' % path, data) self.assertIn('executable = %s' % os.path.realpath(sys.executable), data) - copies = '' if os.name=='nt' else ' --copies' - cmd = (f'command = {sys.executable} -m venv{copies} --without-pip ' + cmd = (f'command = {sys.executable} -m venv --without-pip ' f'--without-scm-ignore-files {self.env_dir}') self.assertIn(cmd, data) fn = self.get_env_file(self.bindir, self.exe) @@ -156,6 +180,7 @@ def _check_output_of_default_create(self): print('Contents of %r:' % bd) print(' %r' % os.listdir(bd)) self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn) + self.assertEqual(os.path.islink(fn), os.name != 'nt' and can_symlink()) def test_config_file_command_key(self): options = [ diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index bd2762d55ef6961..4c8e4e8efeaa724 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -27,16 +27,15 @@ class EnvBuilder: By default, the builder makes the system (global) site-packages dir *un*available to the created environment. - If invoked using the Python -m option, the default is to use copying - on Windows platforms but symlinks elsewhere. If instantiated some - other way, the default is to *not* use symlinks. + By default, the builder uses copying on Windows platforms but symlinks + elsewhere, matching the behaviour when invoked using the Python -m option. :param system_site_packages: If True, the system (global) site-packages dir is available to created environments. :param clear: If True, delete the contents of the environment directory if it already exists, before environment creation. :param symlinks: If True, attempt to symlink rather than copy files into - virtual environment. + virtual environment. If None, use the platform default. :param upgrade: If True, upgrade an existing virtual environment. :param with_pip: If True, ensure pip is installed in the virtual environment @@ -47,11 +46,11 @@ class EnvBuilder: """ def __init__(self, system_site_packages=False, clear=False, - symlinks=False, upgrade=False, with_pip=False, prompt=None, + symlinks=None, upgrade=False, with_pip=False, prompt=None, upgrade_deps=False, *, scm_ignore_files=frozenset()): self.system_site_packages = system_site_packages self.clear = clear - self.symlinks = symlinks + self.symlinks = os.name != 'nt' if symlinks is None else symlinks self.upgrade = upgrade self.with_pip = with_pip self.orig_prompt = prompt @@ -607,7 +606,7 @@ def upgrade_dependencies(self, context): def create(env_dir, system_site_packages=False, clear=False, - symlinks=False, with_pip=False, prompt=None, upgrade_deps=False, + symlinks=None, with_pip=False, prompt=None, upgrade_deps=False, *, scm_ignore_files=frozenset()): """Create a virtual environment in a directory.""" builder = EnvBuilder(system_site_packages=system_site_packages, diff --git a/Misc/NEWS.d/next/Library/2025-01-31-02-27-53.gh-issue-129382.GI93CM.rst b/Misc/NEWS.d/next/Library/2025-01-31-02-27-53.gh-issue-129382.GI93CM.rst new file mode 100644 index 000000000000000..b1b704cc6f86537 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-01-31-02-27-53.gh-issue-129382.GI93CM.rst @@ -0,0 +1,3 @@ +The :class:`venv.EnvBuilder` and :func:`venv.create` APIs now use the +platform-dependent default for symlinks from :mod:`venv`'s command-line +interface.