@@ -24,55 +24,24 @@ become more portable.
2424Motivation
2525==========
2626
27- There are two main motivations for allowing relative paths in ``pyvenv.cfg ``.
28-
29- First, it is currently prescribed that the ``home `` value in ``pyvenv.cfg `` be
30- an absolute path (`gh-135773 `). The behavior of relative paths is unspecified. While
31- techniques exist to work around this for every other sub-part of a virtual
32- environment, the one remaining part without a tenable solution is how the
33- Python runtime itself finds ``PYTHONHOME ``. This is because, currently, the
34- startup process requires absolute paths be used for the ``home `` key in
35- ``pyvenv.cfg ``. If a relative path is used, behavior is unspecified (the
36- current implementation ends up making it relative to the process's current
37- working directory, making it untenable to use).
38-
39- This requirement is overly proscriptive and restrictive because, given a known
40- anchor point, it's easy to transform a relative path to an absolute path and
41- still retain predictable and reliable behavior. Thus, the absolute path
42- requirement should be relaxed and relative path behavior allowed and defined.
43-
44- Second, such relative paths are a building block to enable portable virtual
45- environments, i.e. copying a virtual environment as-is between hosts of
46- compatible platforms. For example, by pointing to a parent directory, the
47- virtual environment becomes independent of path prefix differences between
48- hosts (e.g. ``/usr/local/ `` in a container vs
49- ``/home/user/.pyenv/versions/3.12.0/bin `` in a user's dev environment).
50-
51- Portable virtual environments are appealing because virtual environments are a
52- popular mechanism for running Python applications. This provides several
53- benefits:
54-
55- * The closer the development environment is to the non-development environment,
56- environment-specific issues are less likely, and the easier it is to
57- reproduce issues.
58- * The simpler the process of re-creating the environment, environment-specific
59- issues are less likely, and the faster the process can be.
60-
61- Making it simpler to copy a virtual environment from one host to another
62- mitigates these categories of problems. Additionally, the development tools to
63- create a virtual environment and install its dependencies aren't needed on the
64- host that intends to run the program.
65-
66- When the virtual environment doesn't require modifications to be usable, it
67- also allows more advanced deployment mechanisms, e.g. remote mounting and
68- caching of artifacts. While this PEP on its own isn't sufficient to enable
69- that, it allows tools like Bazel or venvstacks to more easily prepare
70- constrained environments that allow for such use cases.
71-
72- Rationale
73- =========
74-
75- The reason support for relative virtual environments needs to be
27+ The ``home `` field in :file: `pyvenv.cfg ` is used on interpreter startup to
28+ determine the actual Python interpreter installation that is used to execute
29+ code in that virtual environment. Currently, this path is required to be
30+ absolute for correct virtual environment operation because the original
31+ `PEP 405 <https://peps.python.org/pep-0405/ >`__
32+ specifying virtual environments didn't cover any specific way of processing
33+ relative paths, their behaviour is implementation dependent. CPython releases
34+ up to and including CPython 3.14 resolve them relative to the current process
35+ working directory, making them too unreliable to use in practice.
36+
37+ The reason to support a relative path is to support portable virtual
38+ environments, which rely on using a host-agnostic relative path to point to
39+ ``PYTHONHOME ``.
40+ A portable virtual environment is one that can be moved between
41+ platform-compatible hosts, which is an important feature for some projects (see
42+ "Why portable environments matter").
43+
44+ The reason support for a relative ``home `` path needs to be
7645in the interpreter itself is because locating ``PYTHONHOME `` happens
7746very early in the interpreter startup process, which limits the options for
7847customizing 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
8453(Bazel, omitting the ``home `` key entirely to trigger an implementation
8554dependent fallback to resolving via a symlinked interpreter binary on
8655non-Windows systems, see `gh-135773 `) or by requiring a post-installation script to be executed
87- after the environment is placed in its target location (venvstacks).
56+ after the environment is placed in its target location (
57+ `venvstacks <https://lmstudio.ai/blog/venvstacks#publishing-environment-layer-archives >`__
58+ ).
59+
60+ While this PEP on its own isn't sufficient to enable portable virtual
61+ environments, it allows tools like Bazel or venvstacks to more easily prepare
62+ constrained environments that allow for such use cases.
63+
64+ Why portable virtual environments matter
65+ ----------------------------------------
66+
67+ Portable virtual environments are important for the efficiency and
68+ reproducibility benefits they bring from being created once and reused multiple
69+ times later in different locations. For example, a build farm can build a
70+ virtual environment once, cache it, and then re-use it as-is to CI jobs.
71+
72+
73+ Rationale
74+ =========
75+
76+ Defining semantics for a relative ``home `` path is the chosen design for the
77+ following reasons.
78+
79+ First, it is a small change to interpreter startup, in particular of an
80+ unreliable behavior that isn't specified. Currently, relative paths are
81+ resolved to the process's current working directory, which makes them
82+ unreliable for use in practice.
83+
84+ Second, for portable virtual environments, relative paths allow more
85+ efficient, simple, and correct reproduction of virtual environments between
86+ hosts. This is because they can be copied as-is to different locations. Some
87+ example capabilities this allows are:
88+
89+ * A build farm creating (and caching) a virtual environment, which is then
90+ served to developers (e.g. Bazel).
91+ * Composing virtual environments together (e.g. venvstacks).
92+ * Installing multiple arbitrary virtual environments into a container to
93+ save disk space.
94+ * Layering a virtual environment atop a container image for faster image
95+ building.
96+ * Not needing virtual environment creation tools on the host that uses a
97+ virtual environment.
98+ * Exact reproduction of an application's virtual environment between a
99+ developer's host and a production host.
100+
101+ Third, requiring an absolute path is inherently overly proscriptive. The
102+ interpreter itself doesn't care whether paths are relative or absolute, merely
103+ that they point to valid locations, so users should be given the ability to use
104+ a path of their choosing. Given a known anchor point, it's easy to transform a
105+ relative path to an absolute path and still retain predictable and reliable
106+ behavior that produces correct values.
107+
108+ Fullying designing portable virtual environments
109+ ------------------------------------------------
110+
111+ This PEP purposely only focuses on the interpreter startup behavior to limit
112+ its scope. There are multiple implementations and many design questions for how
113+ to implement portable virtual environments work (e.g. what installers should
114+ do), but they are separate from the Python runtime initialization phase.
115+
88116
89117Specification
90118=============
@@ -162,6 +190,22 @@ relative virtual environment paths will typically be aware of the underlying
162190base runtime Python version, and hence able to update the emitted relative path
163191accordingly.
164192
193+ Security Implications
194+ =====================
195+
196+ A relative path in :file: `pyvenv.cfg ` may resolve differently depending on the
197+ location of the virtual environment. This *could * point to a surprising,
198+ potentially malicious, location.
199+
200+ However, this risk already exists today because a relative path isn't
201+ _rejected_, but resolved relative to the current working directory. This PEP
202+ just changes the anchor point to ``pyvenv.cfg `` itself.
203+
204+ Similarly, the same concern exists for absolute paths. The two are
205+ fundamentally the same because they both rely on trusting whoever created
206+ the ``pyvenv.cfg `` file, which requires having run another tool or downloaded
207+ something from elsewhere.
208+
165209
166210How to Teach This
167211=================
@@ -193,6 +237,11 @@ them. These questions are best addressed separately by tool owners.
193237References
194238==========
195239
240+ portable virtual environment
241+ A portable virtual environment is one that can be copied from
242+ one host to another that is platform compatible (e.g. same OS, CPU
243+ architecture, etc), with little or no modification or post processing.
244+
196245* `rules_python <https://github.com/bazel-contrib/rules_python >`__: implements
197246 host-relocatable virtual environments.
198247* `rules_py <https://github.com/aspect-build/rules_py >`__: implements
@@ -265,6 +314,7 @@ Code generally assumes that any virtual environment will be
265314automatically detected and activated by the presence of ``pyvenv.cfg ``, so
266315things work better when alterations to the environment aren't a concern.
267316
317+
268318Copyright
269319=========
270320
0 commit comments