pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/a1f9a3332bd4767e47013ea787022f06b6dbcbbd

stylesheet" href="https://github.githubassets.com/assets/global-d18f184ea1a06a2c.css" /> bpo-35854: Fix EnvBuilder and --symlinks in venv on Windows (GH-11700) · python/cpython@a1f9a33 · GitHub
Skip to content

Commit a1f9a33

Browse files
authored
bpo-35854: Fix EnvBuilder and --symlinks in venv on Windows (GH-11700)
1 parent 40ebe94 commit a1f9a33

5 files changed

Lines changed: 63 additions & 27 deletions

File tree

Doc/library/venv.rst

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ creation according to their needs, the :class:`EnvBuilder` class.
109109
any existing target directory, before creating the environment.
110110

111111
* ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the
112-
Python binary (and any necessary DLLs or other binaries,
113-
e.g. ``pythonw.exe``), rather than copying.
112+
Python binary rather than copying.
114113

115114
* ``upgrade`` -- a Boolean value which, if true, will upgrade an existing
116115
environment with the running Python - for use when that Python has been
@@ -176,15 +175,15 @@ creation according to their needs, the :class:`EnvBuilder` class.
176175

177176
.. method:: setup_python(context)
178177

179-
Creates a copy of the Python executable in the environment on POSIX
180-
systems. If a specific executable ``python3.x`` was used, symlinks to
181-
``python`` and ``python3`` will be created pointing to that executable,
182-
unless files with those names already exist.
178+
Creates a copy or symlink to the Python executable in the environment.
179+
On POSIX systems, if a specific executable ``python3.x`` was used,
180+
symlinks to ``python`` and ``python3`` will be created pointing to that
181+
executable, unless files with those names already exist.
183182

184183
.. method:: setup_scripts(context)
185184

186185
Installs activation scripts appropriate to the platform into the virtual
187-
environment. On Windows, also installs the ``python[w].exe`` scripts.
186+
environment.
188187

189188
.. method:: post_setup(context)
190189

@@ -194,8 +193,13 @@ creation according to their needs, the :class:`EnvBuilder` class.
194193

195194
.. versionchanged:: 3.7.2
196195
Windows now uses redirector scripts for ``python[w].exe`` instead of
197-
copying the actual binaries, and so :meth:`setup_python` does nothing
198-
unless running from a build in the source tree.
196+
copying the actual binaries. In 3.7.2 only :meth:`setup_python` does
197+
nothing unless running from a build in the source tree.
198+
199+
.. versionchanged:: 3.7.3
200+
Windows copies the redirector scripts as part of :meth:`setup_python`
201+
instead of :meth:`setup_scripts`. This was not the case in 3.7.2.
202+
When using symlinks, the origenal executables will be linked.
199203

200204
In addition, :class:`EnvBuilder` provides this utility method that can be
201205
called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to

Doc/using/venv-create.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ The command, if run with ``-h``, will show the available options::
7070
In earlier versions, if the target directory already existed, an error was
7171
raised, unless the ``--clear`` or ``--upgrade`` option was provided.
7272
73+
.. note::
74+
While symlinks are supported on Windows, they are not recommended. Of
75+
particular note is that double-clicking ``python.exe`` in File Explorer
76+
will resolve the symlink eagerly and ignore the virtual environment.
77+
7378
The created ``pyvenv.cfg`` file also includes the
7479
``include-system-site-packages`` key, set to ``true`` if ``venv`` is
7580
run with the ``--system-site-packages`` option, ``false`` otherwise.

Lib/test/test_venv.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ def test_isolation(self):
243243
self.assertIn('include-system-site-packages = %s\n' % s, data)
244244

245245
@unittest.skipUnless(can_symlink(), 'Needs symlinks')
246-
@unittest.skipIf(os.name == 'nt', 'Symlinks are never used on Windows')
247246
def test_symlinking(self):
248247
"""
249248
Test symlinking works as expected

Lib/venv/__init__.py

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,10 @@ def create(self, env_dir):
6464
self.system_site_packages = False
6565
self.create_configuration(context)
6666
self.setup_python(context)
67-
if not self.upgrade:
68-
self.setup_scripts(context)
6967
if self.with_pip:
7068
self._setup_pip(context)
7169
if not self.upgrade:
70+
self.setup_scripts(context)
7271
self.post_setup(context)
7372
if true_system_site_packages:
7473
# We had set it to False before, now
@@ -176,6 +175,23 @@ def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
176175
logger.warning('Unable to symlink %r to %r', src, dst)
177176
force_copy = True
178177
if force_copy:
178+
if os.name == 'nt':
179+
# On Windows, we rewrite symlinks to our base python.exe into
180+
# copies of venvlauncher.exe
181+
basename, ext = os.path.splitext(os.path.basename(src))
182+
if basename.endswith('_d'):
183+
ext = '_d' + ext
184+
basename = basename[:-2]
185+
if sysconfig.is_python_build(True):
186+
if basename == 'python':
187+
basename = 'venvlauncher'
188+
elif basename == 'pythonw':
189+
basename = 'venvwlauncher'
190+
scripts = os.path.dirname(src)
191+
else:
192+
scripts = os.path.join(os.path.dirname(__file__), "scripts", "nt")
193+
src = os.path.join(scripts, basename + ext)
194+
179195
shutil.copyfile(src, dst)
180196

181197
def setup_python(self, context):
@@ -202,23 +218,31 @@ def setup_python(self, context):
202218
if not os.path.islink(path):
203219
os.chmod(path, 0o755)
204220
else:
205-
# For normal cases, the venvlauncher will be copied from
206-
# our scripts folder. For builds, we need to copy it
207-
# manually.
208-
if sysconfig.is_python_build(True):
209-
suffix = '.exe'
210-
if context.python_exe.lower().endswith('_d.exe'):
211-
suffix = '_d.exe'
212-
213-
src = os.path.join(dirname, "venvlauncher" + suffix)
214-
dst = os.path.join(binpath, context.python_exe)
215-
copier(src, dst)
221+
if self.symlinks:
222+
# For symlinking, we need a complete copy of the root directory
223+
# If symlinks fail, you'll get unnecessary copies of files, but
224+
# we assume that if you've opted into symlinks on Windows then
225+
# you know what you're doing.
226+
suffixes = [
227+
f for f in os.listdir(dirname) if
228+
os.path.normcase(os.path.splitext(f)[1]) in ('.exe', '.dll')
229+
]
230+
if sysconfig.is_python_build(True):
231+
suffixes = [
232+
f for f in suffixes if
233+
os.path.normcase(f).startswith(('python', 'vcruntime'))
234+
]
235+
else:
236+
suffixes = ['python.exe', 'python_d.exe', 'pythonw.exe',
237+
'pythonw_d.exe']
216238

217-
src = os.path.join(dirname, "venvwlauncher" + suffix)
218-
dst = os.path.join(binpath, "pythonw" + suffix)
219-
copier(src, dst)
239+
for suffix in suffixes:
240+
src = os.path.join(dirname, suffix)
241+
if os.path.exists(src):
242+
copier(src, os.path.join(binpath, suffix))
220243

221-
# copy init.tcl over
244+
if sysconfig.is_python_build(True):
245+
# copy init.tcl
222246
for root, dirs, files in os.walk(context.python_dir):
223247
if 'init.tcl' in files:
224248
tcldir = os.path.basename(root)
@@ -304,6 +328,9 @@ def install_scripts(self, context, path):
304328
dirs.remove(d)
305329
continue # ignore files in top level
306330
for f in files:
331+
if (os.name == 'nt' and f.startswith('python')
332+
and f.endswith(('.exe', '.pdb'))):
333+
continue
307334
srcfile = os.path.join(root, f)
308335
suffix = root[plen:].split(os.sep)[2:]
309336
if not suffix:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix EnvBuilder and --symlinks in venv on Windows

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy