-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PEP 796: Relative Virtual Environments #4476
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
rickeylev
wants to merge
38
commits into
python:main
Choose a base branch
from
rickeylev:relative.venvs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+320
−0
Open
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
ceeaa3b
initial file
rickeylev d0a9289
add some core content
rickeylev 41d2ea8
rename to motivation
rickeylev 65a415c
note it enables more advanced optimizations
rickeylev 4175b20
add foot notes, relocatable term section, links
rickeylev bbc85b7
update discussion, sponsor headers to pending
rickeylev a0c2529
rst fixups
rickeylev 8e6e21e
fixup italics
rickeylev 37202ca
rename to relative-venv
rickeylev b81c50f
clarify advanced deployment options, reflow some text
rickeylev 55a5e28
add specification, rationale section; doc why env vars arent an option
rickeylev e09b00d
also mention curdir syntax handling
rickeylev c7a6a9b
update some todo text
rickeylev bc1ffbd
update codeowners
rickeylev 2301d2a
add initial discussion footnote link
rickeylev e14b01f
add fr footnote
rickeylev 175f378
revert codeowners change
rickeylev 31cb756
remove packaging-related specs
rickeylev cd46f4d
fix lint errors with headers
rickeylev b532f5c
set sponsor
rickeylev 99434fc
set sponsor as codeowner
rickeylev 862142a
clarify title to focus on core pyvenv.cfg home behavior
rickeylev 1c8fb2d
fix typo; remove host-relocatable mention; remove non-germane copying…
rickeylev c542890
fix typos, grammar
rickeylev 3240227
Apply suggestions from code review
rickeylev 557cb71
fix up markdown and text width
rickeylev 0579623
fix title underlines
rickeylev c9388b3
link to relative venv reference implementation
rickeylev b959f24
Apply suggestions from code review
rickeylev 5b259cc
Apply suggestions from code review
rickeylev 560dadb
Merge branch 'main' of https://github.com/python/peps into relative.v…
rickeylev f41ed51
Merge branch 'relative.venvs' of https://github.com/rickeylev/peps in…
rickeylev 5cbc9f5
better answer why/how relvenvs help; wrap some long lines
rickeylev 0af0eea
Apply AA-Turner suggestions
rickeylev 68dd5e0
add refs, remove CWD acronym, fix grammar
rickeylev b50a80c
address review comments: better split and organize rationale/motivation
rickeylev af8f880
Merge branch 'main' into relative.venvs
AA-Turner ae5a67f
Apply markup and simple grammar fixes from code review
ncoghlan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
address review comments: better split and organize rationale/motivation
- Loading branch information
commit b50a80cfe033360f1070669bbf9e42c20a5a435b
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,55 +24,24 @@ become more portable. | |
| Motivation | ||
| ========== | ||
|
|
||
| There are two main motivations for allowing relative paths in ``pyvenv.cfg``. | ||
|
|
||
| First, it is currently prescribed that the ``home`` value in ``pyvenv.cfg`` be | ||
| an absolute path (`gh-135773`). The behavior of relative paths is unspecified. While | ||
| techniques exist to work around this for every other sub-part of a virtual | ||
| environment, the one remaining part without a tenable solution is how the | ||
| Python runtime itself finds ``PYTHONHOME``. This is because, currently, the | ||
| startup process requires absolute paths be used for the ``home`` key in | ||
| ``pyvenv.cfg``. If a relative path is used, behavior is unspecified (the | ||
| current implementation ends up making it relative to the process's current | ||
| working directory, making it untenable to use). | ||
|
|
||
| This requirement is overly proscriptive and restrictive because, given a known | ||
| anchor point, it's easy to transform a relative path to an absolute path and | ||
| still retain predictable and reliable behavior. Thus, the absolute path | ||
| requirement should be relaxed and relative path behavior allowed and defined. | ||
|
|
||
| Second, such relative paths are a building block to enable portable virtual | ||
| environments, i.e. copying a virtual environment as-is between hosts of | ||
| compatible platforms. For example, by pointing to a parent directory, the | ||
| virtual environment becomes independent of path prefix differences between | ||
| hosts (e.g. ``/usr/local/`` in a container vs | ||
| ``/home/user/.pyenv/versions/3.12.0/bin`` in a user's dev environment). | ||
|
|
||
| Portable virtual environments are appealing because virtual environments are a | ||
| popular mechanism for running Python applications. This provides several | ||
| benefits: | ||
|
|
||
| * The closer the development environment is to the non-development environment, | ||
| environment-specific issues are less likely, and the easier it is to | ||
| reproduce issues. | ||
| * The simpler the process of re-creating the environment, environment-specific | ||
| issues are less likely, and the faster the process can be. | ||
|
|
||
| Making it simpler to copy a virtual environment from one host to another | ||
| mitigates these categories of problems. Additionally, the development tools to | ||
| create a virtual environment and install its dependencies aren't needed on the | ||
| host that intends to run the program. | ||
|
|
||
| When the virtual environment doesn't require modifications to be usable, it | ||
| also allows more advanced deployment mechanisms, e.g. remote mounting and | ||
| caching of artifacts. While this PEP on its own isn't sufficient to enable | ||
| that, it allows tools like Bazel or venvstacks to more easily prepare | ||
| constrained environments that allow for such use cases. | ||
|
|
||
| Rationale | ||
| ========= | ||
|
|
||
| The reason support for relative virtual environments needs to be | ||
| The ``home`` field in :file:`pyvenv.cfg` is used on interpreter startup to | ||
| determine the actual Python interpreter installation that is used to execute | ||
| code in that virtual environment. Currently, this path is required to be | ||
| absolute for correct virtual environment operation because the original | ||
| `PEP 405 <https://peps.python.org/pep-0405/>`__ | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| specifying virtual environments didn't cover any specific way of processing | ||
| relative paths, their behaviour is implementation dependent. CPython releases | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| up to and including CPython 3.14 resolve them relative to the current process | ||
| working directory, making them too unreliable to use in practice. | ||
|
|
||
| The reason to support a relative path is to support portable virtual | ||
| environments, which rely on using a host-agnostic relative path to point to | ||
| ``PYTHONHOME``. | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| A portable virtual environment is one that can be moved between | ||
| platform-compatible hosts, which is an important feature for some projects (see | ||
| "Why portable environments matter"). | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The reason support for a relative ``home`` path needs to be | ||
| in the interpreter itself is because locating ``PYTHONHOME`` happens | ||
| very early in the interpreter startup process, which limits the options for | ||
| customizing how it's computed. Without the ability to specify where the | ||
|
|
@@ -84,7 +53,66 @@ machines do so either by relying on undocumented interpreter behaviour | |
| (Bazel, omitting the ``home`` key entirely to trigger an implementation | ||
| dependent fallback to resolving via a symlinked interpreter binary on | ||
| non-Windows systems, see `gh-135773`) or by requiring a post-installation script to be executed | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| after the environment is placed in its target location (venvstacks). | ||
| after the environment is placed in its target location ( | ||
| `venvstacks <https://lmstudio.ai/blog/venvstacks#publishing-environment-layer-archives>`__ | ||
| ). | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| While this PEP on its own isn't sufficient to enable portable virtual | ||
| environments, it allows tools like Bazel or venvstacks to more easily prepare | ||
| constrained environments that allow for such use cases. | ||
|
|
||
| Why portable virtual environments matter | ||
| ---------------------------------------- | ||
|
|
||
| Portable virtual environments are important for the efficiency and | ||
| reproducibility benefits they bring from being created once and reused multiple | ||
| times later in different locations. For example, a build farm can build a | ||
| virtual environment once, cache it, and then re-use it as-is to CI jobs. | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| Rationale | ||
| ========= | ||
|
|
||
| Defining semantics for a relative ``home`` path is the chosen design for the | ||
| following reasons. | ||
|
|
||
| First, it is a small change to interpreter startup, in particular of an | ||
| unreliable behavior that isn't specified. Currently, relative paths are | ||
| resolved to the process's current working directory, which makes them | ||
| unreliable for use in practice. | ||
|
|
||
| Second, for portable virtual environments, relative paths allow more | ||
| efficient, simple, and correct reproduction of virtual environments between | ||
| hosts. This is because they can be copied as-is to different locations. Some | ||
| example capabilities this allows are: | ||
|
|
||
| * A build farm creating (and caching) a virtual environment, which is then | ||
| served to developers (e.g. Bazel). | ||
| * Composing virtual environments together (e.g. venvstacks). | ||
| * Installing multiple arbitrary virtual environments into a container to | ||
| save disk space. | ||
| * Layering a virtual environment atop a container image for faster image | ||
| building. | ||
| * Not needing virtual environment creation tools on the host that uses a | ||
| virtual environment. | ||
| * Exact reproduction of an application's virtual environment between a | ||
| developer's host and a production host. | ||
|
|
||
| Third, requiring an absolute path is inherently overly proscriptive. The | ||
| interpreter itself doesn't care whether paths are relative or absolute, merely | ||
| that they point to valid locations, so users should be given the ability to use | ||
| a path of their choosing. Given a known anchor point, it's easy to transform a | ||
| relative path to an absolute path and still retain predictable and reliable | ||
| behavior that produces correct values. | ||
|
|
||
| Fullying designing portable virtual environments | ||
| ------------------------------------------------ | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| This PEP purposely only focuses on the interpreter startup behavior to limit | ||
| its scope. There are multiple implementations and many design questions for how | ||
| to implement portable virtual environments work (e.g. what installers should | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| do), but they are separate from the Python runtime initialization phase. | ||
|
|
||
|
|
||
| Specification | ||
| ============= | ||
|
|
@@ -162,6 +190,22 @@ relative virtual environment paths will typically be aware of the underlying | |
| base runtime Python version, and hence able to update the emitted relative path | ||
| accordingly. | ||
|
|
||
| Security Implications | ||
| ===================== | ||
|
|
||
| A relative path in :file:`pyvenv.cfg` may resolve differently depending on the | ||
| location of the virtual environment. This *could* point to a surprising, | ||
| potentially malicious, location. | ||
|
|
||
| However, this risk already exists today because a relative path isn't | ||
| _rejected_, but resolved relative to the current working directory. This PEP | ||
ncoghlan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| just changes the anchor point to ``pyvenv.cfg`` itself. | ||
|
|
||
| Similarly, the same concern exists for absolute paths. The two are | ||
| fundamentally the same because they both rely on trusting whoever created | ||
| the ``pyvenv.cfg`` file, which requires having run another tool or downloaded | ||
| something from elsewhere. | ||
|
|
||
|
|
||
| How to Teach This | ||
| ================= | ||
|
|
@@ -193,6 +237,11 @@ them. These questions are best addressed separately by tool owners. | |
| References | ||
| ========== | ||
|
|
||
| portable virtual environment | ||
| A portable virtual environment is one that can be copied from | ||
| one host to another that is platform compatible (e.g. same OS, CPU | ||
| architecture, etc), with little or no modification or post processing. | ||
|
|
||
| * `rules_python <https://github.com/bazel-contrib/rules_python>`__: implements | ||
| host-relocatable virtual environments. | ||
| * `rules_py <https://github.com/aspect-build/rules_py>`__: implements | ||
|
|
@@ -265,6 +314,7 @@ Code generally assumes that any virtual environment will be | |
| automatically detected and activated by the presence of ``pyvenv.cfg``, so | ||
| things work better when alterations to the environment aren't a concern. | ||
|
|
||
|
|
||
| Copyright | ||
| ========= | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.