diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b71c85c0..34341ade 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -131,6 +131,7 @@ jobs: mamba list python -c "import qcelemental as q;print(q.__file__, q.__version__)" python -c "import qcengine as q;print(q.__file__, q.__version__)" + git describe - name: QCEngineRecords run: | diff --git a/qcengine/programs/psi4.py b/qcengine/programs/psi4.py index 5080e9c5..6de947e7 100644 --- a/qcengine/programs/psi4.py +++ b/qcengine/programs/psi4.py @@ -51,31 +51,46 @@ def found(raise_error: bool = False) -> bool: """ psithon = which("psi4", return_bool=True) psiapi = which_import("psi4", return_bool=True) + error_msg = "" + error_which = which if psithon and not psiapi: with popen([which("psi4"), "--module"]) as exc: exc["proc"].wait(timeout=30) if "module does not exist" in exc["stderr"]: - pass # --module argument only in Psi4 DDD branch + psiapi = True # --module argument only in Psi4 DDD branch (or >=1.6) so grandfathered in else: - sys.path.append(exc["stdout"].split()[-1]) + so, se = exc["stdout"], exc["stderr"] + error_msg = f" In particular, psi4 command found but unable to load psi4 module into sys.path. stdout: {so}, stderr: {se}" + error_which = which_import + if (so) and (not se) and (exc["proc"].returncode == 0): + psimod = Path(so.rstrip()) # stdout is string & Path is tolerant, so safe op + if psimod.exists(): + sys.path.append(str(psimod)) + psiapi = which_import("psi4", return_bool=True) if psiapi and not psithon: - psiimport = str(Path(which_import("psi4")).parent.parent) - env = os.environ.copy() - env["PYTHONPATH"] = psiimport - with popen(["python", "-c", "import psi4; print(psi4.executable[:-5])"], popen_kwargs={"env": env}) as exc: + with popen(["python", "-c", "import psi4; print(psi4.executable)"]) as exc: exc["proc"].wait(timeout=30) - os.environ["PATH"] += os.pathsep + exc["stdout"].split()[-1] - - if psithon or psiapi: + so, se = exc["stdout"], exc["stderr"] + error_msg = f" In particular, psi4 module found but unable to load psi4 command into PATH. stdout: {so}, stderr: {se}" + # yes, everthing up to here could be got from `import psi4; psiexe = psi4.executable`. but, we try not to + # load programs/modules in the `def found` fns. + if (so) and (not se) and (exc["proc"].returncode == 0): + psiexe = Path(so.rstrip()) # stdout is string & Path is tolerant, so safe op + if psiexe.exists(): + os.environ["PATH"] += os.pathsep + str(psiexe.parent) + psithon = which("psi4", return_bool=True) + + if psithon and psiapi: return True - return which( + return error_which( "psi4", return_bool=True, raise_error=raise_error, - raise_msg="Please install via `conda install psi4 -c psi4`. Check it's in your PATH with `which psi4`.", + raise_msg="Please install via `conda install psi4 -c conda-forge/label/libint_dev -c conda-forge`. Check it's in your PATH with `which psi4`." + + error_msg, ) def get_version(self) -> str: @@ -85,7 +100,9 @@ def get_version(self) -> str: if which_prog not in self.version_cache: with popen([which_prog, "--version"]) as exc: exc["proc"].wait(timeout=30) - self.version_cache[which_prog] = safe_version(exc["stdout"].split()[-1]) + if (exc["proc"].returncode != 0) or exc["stderr"]: + raise TypeError(f"Error {exc['proc'].returncode} retrieving Psi4 version: " + exc["stderr"]) + self.version_cache[which_prog] = safe_version(exc["stdout"].rstrip()) candidate_version = self.version_cache[which_prog]