Skip to content

PEP 796: relative virtual environments, initial draft #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
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ceeaa3b
initial file
rickeylev Jun 27, 2025
d0a9289
add some core content
rickeylev Jun 28, 2025
41d2ea8
rename to motivation
rickeylev Jun 28, 2025
65a415c
note it enables more advanced optimizations
rickeylev Jun 28, 2025
4175b20
add foot notes, relocatable term section, links
rickeylev Jun 29, 2025
bbc85b7
update discussion, sponsor headers to pending
rickeylev Jun 29, 2025
a0c2529
rst fixups
rickeylev Jun 29, 2025
8e6e21e
fixup italics
rickeylev Jun 29, 2025
37202ca
rename to relative-venv
rickeylev Jun 29, 2025
b81c50f
clarify advanced deployment options, reflow some text
rickeylev Jun 30, 2025
55a5e28
add specification, rationale section; doc why env vars arent an option
rickeylev Jun 30, 2025
e09b00d
also mention curdir syntax handling
rickeylev Jun 30, 2025
c7a6a9b
update some todo text
rickeylev Jun 30, 2025
bc1ffbd
update codeowners
rickeylev Jun 30, 2025
2301d2a
add initial discussion footnote link
rickeylev Jun 30, 2025
e14b01f
add fr footnote
rickeylev Jun 30, 2025
175f378
revert codeowners change
rickeylev Jun 30, 2025
31cb756
remove packaging-related specs
rickeylev Jul 2, 2025
cd46f4d
fix lint errors with headers
rickeylev Jul 2, 2025
b532f5c
set sponsor
rickeylev Jul 2, 2025
99434fc
set sponsor as codeowner
rickeylev Jul 2, 2025
862142a
clarify title to focus on core pyvenv.cfg home behavior
rickeylev Jul 2, 2025
1c8fb2d
fix typo; remove host-relocatable mention; remove non-germane copying…
rickeylev Jul 2, 2025
c542890
fix typos, grammar
rickeylev Jul 2, 2025
3240227
Apply suggestions from code review
rickeylev Jul 2, 2025
557cb71
fix up markdown and text width
rickeylev Jul 2, 2025
0579623
fix title underlines
rickeylev Jul 2, 2025
c9388b3
link to relative venv reference implementation
rickeylev Jul 2, 2025
b959f24
Apply suggestions from code review
rickeylev Jul 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ peps/pep-0791.rst @vstinner
peps/pep-0792.rst @dstufft
peps/pep-0793.rst @encukou
peps/pep-0794.rst @brettcannon
peps/pep-0796.rst @rickeylev
# ...
peps/pep-0801.rst @warsaw
# ...
Expand Down
287 changes: 287 additions & 0 deletions peps/pep-0796.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
PEP: 796
Title: Relative Virtual Environments
Author: Richard Levasseur <richardlev@gmail.com>
Discussions-To: Pending
Status: Draft
Type: Standards Track
Topic: Packaging
Created: 06-26-2025
Python-Version: 3.15
Sponsor: Pending
Post-History: `DD-MM-YYYY <https://url-to-pep-discussion>`__

.. highlight:: rst

Comment on lines +11 to +12
Copy link
Member

Choose a reason for hiding this comment

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

Let's remove this, it's the syntax highlighter used for code blocks (default Python) and there aren't any code blocks here.

Suggested change
.. highlight:: rst


Abstract
========

This PEP describes how a Python virtual environment can be configured
to allow copying it as-is to different hosts and still have a functioning
virtual environment. Making this work consists of two main pieces:

* Using a relative path for ``home`` in ``pyvenv.cfg``, which Python canonicalizes
at runtime.
* Having package installers recognize a relative venv and generate
appropriate outputs, e.g. script wrappers.


Motivation
==========

There are two main motivations for allowing relative paths in ``pyvenv.cfg``
and thus enabling host-relocatable virtual environments.

First, it is currently proscribed that the ``home`` value in ``pyvenv.cfg`` be
an absolute path. 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 teneable 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 (currently,
it is 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 tranform 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, virtual environments are the standard way for running Python
applications. This means ...

* The closer the dev environment is to the non-dev environment, the more
reliable software one can get.
* The closer the dev and non-dev envs are, the easier it is to reproduce
issues.
* The simpler the process is to re-create the environment, the more reliable
software one can get.
* The simpler the process is to re-create the environment, the faster the
process can be.

By making it trivial to copy a virtual environment from one host to another, it
avoids 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.

Because the virtual environment doesn't require modifications to be usable, it
also allows more advanced deployment mechansisms, e.g. remote mounting and
caching of artifacts.

Rationale
=========

The reason support for relative virtual environments 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
supporting Python runtime files are, the interpreter can't finish startup,
so other hook points (e.g. ``site`` initialization) never trigger.

Specification
=============

The ``home`` value in ``pyvenv.cfg`` is permitted to use a relative path value.
These may contain up-references outside of the virtual environnment root
directory. Examples:

* ``subdir/whatever/bin`` (a directory within the virtual environment).
* ``./subdir/whatever/bin`` (same as above)
* ``../../../../../elsewhere/runtime/bin`` (a directory outside the virtual
environment).
Comment on lines +90 to +93
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* ``subdir/whatever/bin`` (a directory within the virtual environment).
* ``./subdir/whatever/bin`` (same as above)
* ``../../../../../elsewhere/runtime/bin`` (a directory outside the virtual
environment).
* ``subdir/whatever/bin`` (a directory within the virtual environment)
* ``./subdir/whatever/bin`` (same as above)
* ``../../../../../elsewhere/runtime/bin`` (a directory outside the virtual
environment)


Relative paths are relative to the directory containing ``pyvenv.cfg``. During
interpreter startup (i.e. ``getpath.py``), the relative path is joined to the
directory to form an absolute path. Up-references (``../``) and current
directory references (``./``) are resolved syntactically (i.e. not resolving
symlinks). Symlinks are *not* resolved prior to construction of the absolute
path to ensure semantics between a relative path and absolute path remain the
same.

For example, given
``/home/user/venv/bin/pyvenv.cfg`` with
``home = ../../runtime/./bin``, the result is ``home = /home/user/runtime/bin``,
i.e. it's equivalent to using that value verbatim in ``pyvenv.cfg``.


Python Runtime Changes
======================

The Python runtime itself *almost* already supports host-relocating virtual
environment and the only change needed is to define how it resolves relative
paths for ``home`` in ``pyvenv.cfg``.

Today, relative paths resolve relative to the process's current working
directory. Because CWD isn't knowable in advance, it makes relative paths today
effective impossible.

Instead, the paths should be relative to the location of the ``pyvenv.cfg``
file. This file is chosen as the anchor point because the tool that creates the
file also has to know where the Python runtime is, so can easily calculate the
correct relative path. For tools that read the ``pyvenv.cfg``, it is also easy
to simple join the directory name of where ``pyvenv.cfg`` was found with the
path in the config file. When a person reads the config file, they can do
similar, which is a lower cognitive burden and helps avoids the question of
"relative to what?"

This change is only a couple of lines in the start up code. Specifically, when
parsing the ``pyvenv.cfg`` file and finding the ``home`` value, it just needs
to be checked if it's already absolute. If not, then join to the directory name
of the ``pyvenv.cfg`` file. The code alredy knows the directory and has helpers
already present for checking if a path is absolute and joining two paths.

A proof-of-concept of this is implemented in
`rickeylev/feat.relative.pyvenv.home <https://github.com/python/cpython/compare/main...rickeylev:cpython:feat.relative.pyvenv.home>`__
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
`rickeylev/feat.relative.pyvenv.home <https://github.com/python/cpython/compare/main...rickeylev:cpython:feat.relative.pyvenv.home>`__
`rickeylev/feat.relative.pyvenv.home <https://github.com/python/cpython/compare/main...rickeylev:cpython:feat.relative.pyvenv.home>`__.


Virtual Environment Tool Changes
================================

Virtual environment management tools should support a mechanism to generate a
``pyvenv.cfg`` file with a ``home`` key that is a relative path to the relevant
Python installation.

For the standard library's ``venv`` module, the flag ``--relative`` will be
added to trigger this behavior.

Package Installer Changes
=========================

Package installers must be aware of when a relative virtual environment has
been defined so they can avoid using absolute paths. The two main places
absolute paths occur today are:

1. ``bin/`` scripts, where shebangs are rewritten.
2. ``site-packages`` symlinks.

For symlinks, they should create relative symlinks pointing to the actual
installation directory for packages.

For ``bin/`` scripts, installers should generate executables that are able to
locate the venv's interpreter at runtime. How to do this is implementation
defined. Typically it means having shell code use ``$0`` to locate the
appropriate ``bin/python3`` executable, but installers are free to use whatever
mechanism they want (e.g. a native polyglot executable).

Copying a Venv to Another Host
=================================

Copying the venv to another host is simple: copy the venv directory itself, and
any directories outside the venv it needs, while preserving the relative
directory structures.

How to do this, exactly, is implementation-defined.

In practice, this typically means copying a parent directory of the virtual
environment, which contains the runtime, one or more venvs, installations
of dependencies, and any other supporting files.

Backwards Compatibility
=======================

Because relative paths for ``home`` aren't usable in practice, and their
behavior undocumented and unspecified, there shouldn't be any backward
compatibility concerns.


How to Teach This
=================

Teaching this should be simple: if you use a relative path in ``pyvenv.cfg``,
then it's relative to the directory containing the ``pyvenv.cfg`` file. This
is simple to explain and understand.


Reference Implementation
========================

A reference implementation is available by using the combination of:

* Python runtime from `rickeylev/feat.relative.pyvenv.home <https://github.com/python/cpython/compare/main...rickeylev:cpython:feat.relative.pyvenv.home>`__
* rules_python with (todo: link to branch that uses above)

Open Issues
===========

(todo: placeholder section to be updated after discussions)

Footnotes
=========

* `rules_python <https://github.com/bazel-contrib/rules_python>`__: implements
host-relocatable virtual environments.
* `rules_py <https://github.com/aspect-build/rules_py>`__: implements
host-relocatable virtual environments.
* `uv venv
relocatable
<https://docs.astral.sh/uv/reference/cli/#uv-venv--relocatable>`__:
implements same-host relocatable virtual environments.
* `python-build-standalone <https://github.com/astral-sh/python-build-standalone>`__:
Copy link
Member

Choose a reason for hiding this comment

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

Put something after the colon? Or delete the colon?

Suggested change
* `python-build-standalone <https://github.com/astral-sh/python-build-standalone>`__:
* `python-build-standalone <https://github.com/astral-sh/python-build-standalone>`__

A relocatable Python runtime.
* `PoC for relative home in Python startup <https://github.com/python/cpython/compare/main...rickeylev:cpython:feat.relative.pyvenv.home>`__
* `Python Ideas "Making venvs relocatable friendly" discussion <https://discuss.python.org/t/making-venvs-relocatable-friendly/96177>`__
* `GH-136051: relative pyvenv.cfg home <https://github.com/python/cpython/issues/136051>`__
Copy link
Member

Choose a reason for hiding this comment

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

Convention is lowercase for issue, uppercase for PR:

Suggested change
* `GH-136051: relative pyvenv.cfg home <https://github.com/python/cpython/issues/136051>`__
* `gh-136051: relative pyvenv.cfg home <https://github.com/python/cpython/issues/136051>`__


Rejected Ideas
=====================

Relative to virtual env root
----------------------------

Having the ``home`` value in ``pyvenv.cfg`` relative to the virtual environments
root directory would work just as well, but this idea is rejected because it
requires additional effort to compute the virtual env root.

Unspecified home means to dynamically compute home
----------------------------------------------------

Today, if a ``pyvenv.cfg`` file doesn't set ``home``, the runtime will try to
dynamically compute it by checking if the current executable (which is typicall
the venv's ``bin/python3`` symlink) is a symlink and, if so, use where that
points as ``PYTHONHOME``.

This behavior is undesirable for a couple reasons:

1. It presents platform-specific issues, namely with Windows. Windows does
support symlinks, but not by default, and it can require special
permissions to do so.
2. It *requires* that a symlink be used, which precludes using otherwise
equivalent mechanisms for creating an executable (e.g. a wrapper script,
hard links, etc).

In general, symlinks work best when they aren't special cased by consumers.

Using the term "relocatable"
----------------------------

Discussions pointed out the the term "relocatable" is somewhat ambigious and
misleading for a couple reasons.

First, absolute paths makes a venv arbitrarily relocatable *within* a host, but
not between hosts, so "relocatable" requires *some* qualification for
clarity.

Second, when using relative paths that point outside the venv, the venv is only
relocatable insofar as those external artifacts are also relocated. This is an
additional nuance that requires qualification of the term.

To better avoid this confusion, "relative" is chosen, which more naturally
invites the question *"Relative to what?"*.


Using PYTHONHOME at runtime to specify home
-------------------------------------------

Using the ``PYTHONHOME`` environment variable (or any environment variable) is
problematic because it's difficult to know and control when an environment
variable should or shouldn't be inherited by subprocesses. In some cases, it's
not feasible because of how layers of programs calling programs interact.

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 environemtn aren't a concern.

Copyright
=========

This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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