Skip to content

gh-106045: Fix venv creation from a python executable symlink #115237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mayeut
Copy link

@mayeut mayeut commented Feb 10, 2024

@mayeut mayeut requested a review from vsajip as a code owner February 10, 2024 10:58
@mayeut mayeut force-pushed the venv-home-follow-symlink branch from 91e8d28 to ad36335 Compare May 11, 2024 17:04
@mayeut mayeut marked this pull request as draft September 28, 2024 08:53
@mayeut mayeut force-pushed the venv-home-follow-symlink branch 2 times, most recently from ca424f1 to 340d9c2 Compare September 28, 2024 10:45
@mayeut mayeut marked this pull request as ready for review September 28, 2024 11:15
Copy link
Member

@FFY00 FFY00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR looks good 👍

Comment on lines 169 to 175
executable_ = os.path.abspath(executable)
while os.path.islink(executable_):
link = os.readlink(executable_)
if os.path.isabs(link):
executable_ = link
else:
executable_ = os.path.join(os.path.dirname(executable_), link)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this to a helper function? This way the ensure_directories and symlink resolving logic is clearly separated,

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

subprocess.check_call(cmd)
data = self.get_text_file_contents('pyvenv.cfg')
self.assertIn('home = %s' % tree_symlink, data)
self.assertIn('executable = %s' %
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Since this is so path-operation heavy, it would be nice to use pathlib here instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@vsajip vsajip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur with @FFY00's comments. Also, as another nitpick, why use the name executable_ as a local variable? The trailing underscore is not a common thing to see, in my experience,

Copy link
Contributor

@pelson pelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My view is that this is doing the right thing, but in the wrong place. Instead I think we should not resolve the executable path at all in venv, and instead we should resolve the prefix based on the executable symlink at Python startup (in getpath.py).

Based on what I understand, the issue that this PR is fixing was just fixed by #127974.

# we don't want to overwrite the executable used in context
executable_ = os.path.abspath(executable)
while os.path.islink(executable_):
link = os.readlink(executable_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically we need to watch out for circular links. I think having this in a separate function (as suggested) will make that less painful when implementing.

FWIW, I don't know why there isn't something in the standard library for recursively resolving a symlink (without recursively resolving all child paths as realpath does). Perhaps one for Python ideas?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@mayeut
Copy link
Author

mayeut commented Jan 11, 2025

Based on what I understand, the issue that this PR is fixing was just fixed by #127974.

It appears that the linked PR does not resolve the issue.
Here are the steps I used on macOS on the main branch:

./configure --with-pydebug && make -j
mkdir ../temp-test
ln -s $(pwd)/python.exe ../temp-test/python
../temp-test/python -m venv ../temp-test/temp-test-venv
Error: Command '['.../temp-test/temp-test-venv/bin/python', '-m', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1.

@FFY00
Copy link
Member

FFY00 commented Jan 11, 2025

That PR builds on top of GH-127972, so it only works with --enable-shared.

@mayeut mayeut force-pushed the venv-home-follow-symlink branch from 340d9c2 to f9ef949 Compare January 11, 2025 11:41
- we stop if a candidate does not resolve to the same file
(this can happen with normpath)
"""
result = os.path.abspath(path)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.path.abspath is done first as was used before. It does normalize the path which may end-up with an invalid path in case of symlinks (e.g. "symlink_dir/../segment").

@python-cla-bot
Copy link

The following commit authors need to sign the Contributor License Agreement:

CLA signed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants