Source code for scine_puffin.programs.program

# -*- coding: utf-8 -*-
__copyright__ = """ This code is licensed under the 3-clause BSD license.
Copyright ETH Zurich, Department of Chemistry and Applied Biosciences, Reiher Group.
See LICENSE.txt for details.
"""

from pkgutil import iter_modules
from typing import List
from warnings import warn
import git
import os
import subprocess
import sys

from scine_puffin.config import Configuration


[docs]class Program: """ A common interface for all programs and their setups Parameters ---------- settings : dict The settings for the particular program. This dictionary should be the given program's block in the ``Configuration``. """ def __init__(self, settings: dict) -> None: self.version = settings["version"] self.root = settings["root"] self.source = settings["source"] self.settings = settings
[docs] def install(self, repo_dir: str, install_dir: str, ncores: int): """ Installs or loads the given program. After the install, the ``check_install`` function should run through with out exceptions. The choice of installation/compilation or loading of the program is based on the settings given in the constructor. Parameters ---------- repo_dir : str The folder for all repositories, if a clone or download is required for the installation, this folder will be used. install_dir : str If the program is actually installed and not just loaded, this folder will be used as target directory for the install process. ncores : int The number of cores/threads to be used when compiling/installing the program. """ raise NotImplementedError
[docs] @staticmethod def initialize(): """ Executed at Puffin start, run once for each available program """
[docs] def check_install(self): """ A small function checking if the program was installed/located correctly and does provide the expected features. """ raise NotImplementedError
[docs] def setup_environment(self, config: Configuration, env_paths: dict, env_vars: dict): """ Appends the program specific environment variables to the given dictionaries. Parameters ---------- config : scine_puffin.config.Configuration The current global configuration. env_paths : dict A dictionary for all the environment paths, such as ``PATH`` and ``LD_LIBRARY_PATH``. The added settings will be appended to the existing paths, using ``export PATH=$PATH:...``. env_vars : dict A dictionary for all fixed environment variables. All settings will replace existing variables such as ``export OMP_NUM_THREADS=1`` """ raise NotImplementedError
[docs] def available_models(self) -> List[str]: """ A small function returning the single point models available now with the given program loaded/installed. Returns ------- models : List[str] A list of names of models that are available if the program is available. """ raise NotImplementedError
[docs] def scine_module_install(self, repo_dir: str, install_dir: str, ncores: int, add_lib: bool = False, add_bin: bool = False): initial_dir = os.getcwd() # Handle repository if os.path.exists(repo_dir): repository = git.Repo(repo_dir) try: repository.remotes.origin.pull() repository.git.submodule("update", "--init") except BaseException: try: repository.git.checkout("master") except git.exc.GitCommandError: # type: ignore[misc] repository.git.checkout("main") repository.git.submodule("update", "--init") repository.remotes.origin.pull() repository.git.submodule("update", "--init") finally: repository.git.checkout(self.version) repository.remotes.origin.pull() repository.git.submodule("update", "--init") else: repository = git.Repo.clone_from(self.source, repo_dir) repository.git.checkout(self.version) repository.git.submodule("update", "--init") # Build from sources into <repo>/build and install build_dir = os.path.join(repo_dir, "build") if build_dir and not os.path.exists(build_dir): os.makedirs(build_dir) os.chdir(build_dir) env = os.environ.copy() if add_bin: env["PATH"] = env["PATH"] + ":" + os.path.join(install_dir, "bin") if add_lib: if "LD_LIBRARY_PATH" in env.keys(): env["LD_LIBRARY_PATH"] = ( env["LD_LIBRARY_PATH"] + ":" + os.path.join(install_dir, "lib") ) else: env["LD_LIBRARY_PATH"] = os.path.join(install_dir, "lib") env["LD_LIBRARY_PATH"] = ( env["LD_LIBRARY_PATH"] + ":" + os.path.join(install_dir, "lib64") ) args = ["cmake"] args.append("-DCMAKE_BUILD_TYPE=Release") args.append("-DSCINE_BUILD_TESTS=OFF") args.append("-DSCINE_BUILD_PYTHON_BINDINGS=ON") args.append("-DSCINE_MARCH=" + self.settings["march"]) if self.settings["cxx_compiler_flags"]: args.append("-DCMAKE_CXX_FLAGS=" + self.settings["cxx_compiler_flags"]) args.append("-DCMAKE_INSTALL_PREFIX=" + install_dir) args.append("-DPYTHON_EXECUTABLE=" + sys.executable) if self.settings["cmake_flags"]: args += self.settings["cmake_flags"].split(" ") if "sphinx" not in (name for loader, name, ispkg in iter_modules()): warn("Sphinx is not installed, skipping Scine documentation build") args.append("-DSCINE_BUILD_DOCS=OFF") args.append("..") subprocess.run(args, env=env, check=True) subprocess.run(["make", "-j" + str(ncores), "install"], env=env, check=True) os.chdir(initial_dir)
[docs] def pip_module_source_install(self, repo_dir: str, install_dir: str): initial_dir = os.getcwd() # Handle repository if os.path.exists(repo_dir): repository = git.Repo(repo_dir) try: repository.remotes.origin.pull() repository.git.submodule("update", "--init") except BaseException: try: repository.git.checkout("master") except git.exc.GitCommandError: # type: ignore[misc] repository.git.checkout("main") repository.git.submodule("update", "--init") repository.remotes.origin.pull() repository.git.submodule("update", "--init") finally: repository.git.checkout(self.version) repository.remotes.origin.pull() repository.git.submodule("update", "--init") else: repository = git.Repo.clone_from(self.source, repo_dir) repository.git.checkout(self.version) repository.git.submodule("update", "--init") build_dir = os.path.join(repo_dir, "build") if build_dir and not os.path.exists(build_dir): os.makedirs(build_dir) os.chdir(build_dir) self.pip_package_install('../.', install_dir) os.chdir(initial_dir)
[docs] @staticmethod def pip_package_install(package: str, install_dir: str): env = os.environ.copy() suffix = ( 'python' + str(sys.version_info.major) + '.' + str(sys.version_info.minor) + '/site-packages' ) if "PYTHONPATH" in env.keys(): env["PYTHONPATH"] = ( os.path.join(install_dir, 'lib', suffix) + ":" + os.path.join(install_dir, 'lib64', suffix) + ":" + env["PYTHONPATH"] ) else: env["PYTHONPATH"] = ( os.path.join(install_dir, 'lib', suffix) + ":" + os.path.join(install_dir, 'lib64', suffix) ) subprocess.run( [ sys.executable, '-m' + 'pip', 'install', package, '--no-cache', '--prefix', install_dir ], env=env, check=True )