summaryrefslogtreecommitdiff
path: root/var
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2024-06-04 17:52:21 +0200
committerGitHub <noreply@github.com>2024-06-04 09:52:21 -0600
commit278f5818b7bf67a7544a4d9733fc9c0eb605f6c6 (patch)
tree687e602ed873aafcd87c6e771643bbd0a3b60d70 /var
parentc2e85202c7d2692cd3384bbfde88c6af7499d312 (diff)
downloadspack-278f5818b7bf67a7544a4d9733fc9c0eb605f6c6.tar.gz
spack-278f5818b7bf67a7544a4d9733fc9c0eb605f6c6.tar.bz2
spack-278f5818b7bf67a7544a4d9733fc9c0eb605f6c6.tar.xz
spack-278f5818b7bf67a7544a4d9733fc9c0eb605f6c6.zip
python: make every view a `venv` (#44382)
#40773 introduced python-venv, which improved build isolation and avoids issues with, e.g., `ubuntu`'s system python modifying `sysconfig` to include a (very unwanted) `local` directory within the default install layout. This addresses a few cases where #40773 removed functionality, without harming the default cases where we use `python-venv`. Traditionally, *every* view with `python` in it was essentially a virtual environment, because we would copy the `python` interpreter and `os.py` into every view when linking. We now rely on `python-venv` to do that, but only when it's used (i.e. new builds) and only for packages that have an `extends("python")` directive. This again makes every view with `python` in it a virtual environment, but only if we're not already using a package like `python-venv`. This uses a different mechanism from before -- instead of using the `virtualenv` trick of copying `python` into the prefix, we instead create a `pyvenv.cfg` like `venv` (the more modern way to do it). This fixes two things: 1. If you already had an environment before Spack `v0.22` that worked, it would stop working without a reconcretize and rebuild in `v0.22`, because we no longer copy the python interpreter on link. Adding `pyvenv.cfg` fixes this in a more modern way, so old views will keep working. 2. If you have an env that only includes python packages that use `depends_on("python")` instead of `extends("python")`, those packages will now be importable as before, though they won't have the same level of build isolation you'd get with `extends` and `python-venv`. * views: avoid making client code deal with link functions Users of views and ViewDescriptors shouldn't have to deal with link functions -- they should just say what type of linking they want. - [x] views take a link_type, not a link function - [x] views work out the link function from the link type - [x] view descriptors and commands now just tell the view what they want. * python: simplify logic for avoiding pyvenv.cfg in copy views Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
Diffstat (limited to 'var')
-rw-r--r--var/spack/repos/builtin/packages/python/package.py46
1 files changed, 46 insertions, 0 deletions
diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py
index ce4c19ba58..201582a2ab 100644
--- a/var/spack/repos/builtin/packages/python/package.py
+++ b/var/spack/repos/builtin/packages/python/package.py
@@ -21,6 +21,25 @@ from spack.package import *
from spack.util.prefix import Prefix
+def make_pyvenv_cfg(python_spec: "spack.spec.Spec", venv_prefix: str) -> str:
+ """Make a pyvenv_cfg file for a given (real) python command and venv prefix."""
+ python_cmd = python_spec.command.path
+ lines = [
+ # directory containing python command
+ f"home = {os.path.dirname(python_cmd)}",
+ # venv should not allow site packages from the real python to be loaded
+ "include-system-site-packages = false",
+ # version of the python command
+ f"version = {python_spec.version}",
+ # the path to the python command
+ f"executable = {python_cmd}",
+ # command "used" to create the pyvenv.cfg
+ f"command = {python_cmd} -m venv --without-pip {venv_prefix}",
+ ]
+
+ return "\n".join(lines) + "\n"
+
+
class Python(Package):
"""The Python programming language."""
@@ -1241,6 +1260,33 @@ print(json.dumps(config))
module.python_platlib = join_path(dependent_spec.prefix, self.platlib)
module.python_purelib = join_path(dependent_spec.prefix, self.purelib)
+ def add_files_to_view(self, view, merge_map, skip_if_exists=True):
+ """Make the view a virtual environment if it isn't one already.
+
+ If `python-venv` is linked into the view, it will already be a virtual
+ environment. If not, then this is an older python that doesn't use the
+ python-venv support, or we may be using python packages that
+ use ``depends_on("python")`` but not ``extends("python")``.
+
+ We used to copy the python interpreter in, but we can get the same effect in a
+ simpler way by adding a ``pyvenv.cfg`` to the environment.
+
+ """
+ super().add_files_to_view(view, merge_map, skip_if_exists=skip_if_exists)
+
+ # location of python inside the view, where we will put the venv config
+ projection = view.get_projection_for_spec(self.spec)
+ pyvenv_cfg = os.path.join(projection, "pyvenv.cfg")
+ if os.path.lexists(pyvenv_cfg):
+ return
+
+ # don't put a pyvenv.cfg in a copy view
+ if view.link_type == "copy":
+ return
+
+ with open(pyvenv_cfg, "w") as cfg_file:
+ cfg_file.write(make_pyvenv_cfg(self.spec["python"], projection))
+
def test_hello_world(self):
"""run simple hello world program"""
# do not use self.command because we are also testing the run env