Skip to content

Commit c29d160

Browse files
committed
enhance PythonPackage easyblock to consider EBPYTHONPREFIXES for test installs and path configuration files
1 parent 2e5a227 commit c29d160

File tree

1 file changed

+55
-17
lines changed

1 file changed

+55
-17
lines changed

easybuild/easyblocks/generic/pythonpackage.py

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
from easybuild.framework.extensioneasyblock import ExtensionEasyBlock
5050
from easybuild.tools.build_log import EasyBuildError, print_msg
5151
from easybuild.tools.config import build_option, PYTHONPATH, EBPYTHONPREFIXES
52-
from easybuild.tools.filetools import change_dir, mkdir, read_file, remove_dir, symlink, which, write_file
52+
from easybuild.tools.filetools import change_dir, mkdir, read_file, remove_dir, symlink, which, write_file, \
53+
find_glob_pattern
5354
from easybuild.tools.modules import ModEnvVarType, get_software_root
5455
from easybuild.tools.run import run_shell_cmd
5556
from easybuild.tools.utilities import nub
@@ -617,6 +618,54 @@ def using_local_py_install_scheme(self):
617618
py_install_scheme = det_py_install_scheme(python_cmd=self.python_cmd)
618619
return py_install_scheme == PY_INSTALL_SCHEME_POSIX_LOCAL and self.using_pip_install()
619620

621+
def using_ebpythonprefixes(self) -> bool:
622+
"""
623+
Determine if we should update $EBPYTHONPREFIXES rather than $PYTHONPATH.
624+
If this Python package was installed for multiple Python versions, the package is using
625+
.pth files, or if we prefer it; note: although EasyBuild framework also has logic for
626+
this in EasyBlock.make_module_extra, we retain full control here, since the logic is
627+
slightly different.
628+
"""
629+
630+
use_ebpythonprefixes = False
631+
runtime_deps = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True)]
632+
633+
if 'Python' in runtime_deps:
634+
self.log.info("Found Python runtime dependency, so considering $EBPYTHONPREFIXES...")
635+
if build_option('prefer_python_search_path') == EBPYTHONPREFIXES:
636+
self.log.info("Preferred Python search path is $EBPYTHONPREFIXES, so using that")
637+
use_ebpythonprefixes = True
638+
639+
# Check if the installdir or sources contain any .pth files. For them to work correctly,
640+
# Python needs these files to be in the sitedir path. While this typically works system-wide
641+
# or in a venv, having Python modules in separate directories is unusual, and only having
642+
# $PYTHONPATH will ignore these files.
643+
# Our sitecustomize.py adds paths in $EBPYTHONPREFIXES to the sitedir path though, allowing
644+
# these .pth files to work as expected. See: https://docs.python.org/3/library/site.html#module-site
645+
# .pth files always should be in the site folder, so most of the path is fixed.
646+
try:
647+
glob_pattern = "%s/lib/python*/site-packages/*.pth"
648+
# Try the installation directory first
649+
if find_glob_pattern(glob_pattern % self.installdir,
650+
fail_on_no_match=False):
651+
self.log.info("Found path configuration file in installation directory."
652+
"Enabling $EBPYTHONPREFIXES...")
653+
use_ebpythonprefixes = True
654+
# If we did a test installation, check that one as well
655+
if self.testinstall and find_glob_pattern(glob_pattern % self.pypkg_test_installdir,
656+
fail_on_no_match=False):
657+
self.log.info("Found path configuration file in test installation directory."
658+
"Enabling $EBPYTHONPREFIXES...")
659+
use_ebpythonprefixes = True
660+
except EasyBuildError:
661+
# find_glob_pattern found more than one match. This is still sufficient for us to assume
662+
# that we need $EBPYTHONPREFIXES.
663+
self.log.info("Found more than one match while searchin for path configuration files."
664+
"Enabling $EBPYTHONPREFIXES...")
665+
use_ebpythonprefixes = True
666+
667+
return self.multi_python or use_ebpythonprefixes
668+
620669
def compose_install_command(self, prefix, extrapath=None, installopts=None):
621670
"""Compose full install command."""
622671

@@ -821,7 +870,7 @@ def test_step(self, return_output_ec=False):
821870
out, ec = (None, None)
822871

823872
if self.testinstall:
824-
# install in test directory and export PYTHONPATH
873+
# install in test directory and export PYTHONPATH and / or EBPYTHONPREFIX if we need it
825874

826875
try:
827876
if self.pypkg_test_installdir is None:
@@ -849,7 +898,9 @@ def test_step(self, return_output_ec=False):
849898
# add install location to both $PYTHONPATH and $PATH
850899
abs_pylibdirs = [os.path.join(actual_installdir, pylibdir) for pylibdir in self.all_pylibdirs]
851900
extrapath = "export PYTHONPATH=%s && " % os.pathsep.join(abs_pylibdirs + ['$PYTHONPATH'])
852-
901+
if self.using_ebpythonprefixes():
902+
extrapath += "export EBPYTHONPREFIXES=%s && " % os.pathsep.join(abs_pylibdirs +
903+
['$EBPYTHONPREFIXES'])
853904
extrapath += "export PATH=%s:$PATH && " % os.path.join(actual_installdir, 'bin')
854905

855906
cmd = self.compose_install_command(self.pypkg_test_installdir, extrapath=extrapath)
@@ -1084,20 +1135,7 @@ def make_module_extra(self, *args, **kwargs):
10841135
"""Add install path to PYTHONPATH"""
10851136
txt = ''
10861137

1087-
# update $EBPYTHONPREFIXES rather than $PYTHONPATH
1088-
# if this Python package was installed for multiple Python versions, or if we prefer it;
1089-
# note: although EasyBuild framework also has logic for this in EasyBlock.make_module_extra,
1090-
# we retain full control here, since the logic is slightly different
1091-
use_ebpythonprefixes = False
1092-
runtime_deps = [dep['name'] for dep in self.cfg.dependencies(runtime_only=True)]
1093-
1094-
if 'Python' in runtime_deps:
1095-
self.log.info("Found Python runtime dependency, so considering $EBPYTHONPREFIXES...")
1096-
if build_option('prefer_python_search_path') == EBPYTHONPREFIXES:
1097-
self.log.info("Preferred Python search path is $EBPYTHONPREFIXES, so using that")
1098-
use_ebpythonprefixes = True
1099-
1100-
if self.multi_python or use_ebpythonprefixes:
1138+
if self.using_ebpythonprefixes():
11011139
path = '' # EBPYTHONPREFIXES are relative to the install dir
11021140
txt += self.module_generator.prepend_paths(EBPYTHONPREFIXES, path)
11031141
elif self.require_python:

0 commit comments

Comments
 (0)