public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/psi4] rawhide: Update to 1.11.
@ 2026-07-29 13:28 Susi Lehtola
0 siblings, 0 replies; only message in thread
From: Susi Lehtola @ 2026-07-29 13:28 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/psi4
Branch : rawhide
Commit : a5de9f3f7b20b7d218c79691591adfa738eed1da
Author : Susi Lehtola <jussilehtola@fedoraproject.org>
Date : 2026-07-29T13:28:06+00:00
Stats : +1580/-917 in 5 file(s)
URL : https://src.fedoraproject.org/rpms/psi4/c/a5de9f3f7b20b7d218c79691591adfa738eed1da?branch=rawhide
Log:
Update to 1.11.
---
diff --git a/3389.patch b/3389.patch
deleted file mode 100644
index 642c60e..0000000
--- a/3389.patch
+++ /dev/null
@@ -1,842 +0,0 @@
-From d8c29bf947146f6af8be1131e5ca3d42852e8b47 Mon Sep 17 00:00:00 2001
-From: "Lori A. Burns" <lori.burns7@gmail.com>
-Date: Thu, 7 May 2026 00:03:15 -0400
-Subject: [PATCH] make qcmanybody optional
-
----
- CMakeLists.txt | 1 +
- codedeps.yaml | 4 +-
- doc/sphinxman/source/build_planning.rst | 4 +-
- doc/sphinxman/source/external.rst | 1 +
- doc/sphinxman/source/nbody.rst | 3 +-
- external/upstream/qcmanybody/CMakeLists.txt | 72 ++++++++++---------
- psi4/__init__.py | 2 +
- psi4/driver/driver_nbody.py | 33 ++++++++-
- psi4/extras.py | 1 +
- pytest.ini | 4 +-
- tests/cbs-xtpl-nbody/test_input.py | 4 +-
- tests/ddd-function-kwargs/test_input.py | 4 +-
- tests/dfmp2-1/test_input.py | 4 +-
- tests/dfmp2-ecp/test_input.py | 3 +-
- tests/dfmp2-fc/test_input.py | 4 +-
- tests/dft-custom-dhdf/test_input.py | 4 +-
- tests/dftd3/nbody-cp-gradient/test_input.py | 3 +-
- tests/mp2-def2/test_input.py | 4 +-
- tests/nbody-convergence/test_input.py | 4 +-
- tests/nbody-cp-gradient/test_input.py | 4 +-
- tests/nbody-freq/test_input.py | 4 +-
- tests/nbody-he-4b/test_input.py | 4 +-
- tests/nbody-he-cluster/test_input.py | 4 +-
- tests/nbody-hessian/test_input.py | 4 +-
- tests/nbody-intermediates/test_input.py | 4 +-
- tests/nbody-multi-level-2/test_input.py | 4 +-
- tests/nbody-multi-level/test_input.py | 4 +-
- tests/nbody-nocp-gradient/test_input.py | 4 +-
- tests/nbody-vmfc-gradient/test_input.py | 4 +-
- tests/nbody-vmfc-hessian/test_input.py | 4 +-
- tests/pytests/addons.py | 6 +-
- tests/pytests/test_addons.py | 3 +-
- tests/pytests/test_addons_qcschema.py | 3 +-
- tests/pytests/test_compositejk.py | 4 +-
- tests/pytests/test_dft_benchmarks.py | 4 +-
- tests/pytests/test_dftd3.py | 3 +-
- tests/pytests/test_nbody.py | 5 +-
- .../test_nbody_multi_level_qcschema.py | 5 +-
- tests/pytests/test_psi4.py | 3 +-
- tests/pytests/test_psi4_qcschema.py | 3 +-
- tests/tu6-cp-ne2/test_input.py | 4 +-
- 41 files changed, 145 insertions(+), 101 deletions(-)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 8ea2f9f0b64..1e04c3e4f14 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -127,6 +127,7 @@ option(ENABLE_gdma "Enables Stone's GDMA multipole code (requires Fortran; can a
- option(ENABLE_IntegratorXX "Enables use of IntegratorXX density functional grids library" OFF)
- option(ENABLE_OpenOrbitalOptimizer "Enables the OpenOrbitalOptimizer library (requires Armadillo)" OFF)
- option(ENABLE_PCMSolver "Enables PCMSolver library (requires Fortran)" OFF)
-+option(ENABLE_qcmanybody "Enables qcmanybody for n-body/BSSE workflows (can also be added at runtime)" OFF)
- option(ENABLE_snsmp2 "Enables SNSMP2 plugin (can also be added at runtime)" OFF)
- option(ENABLE_v2rdm_casscf "Enables V2RDM_CASSCF plugin (requires Fortran; can also be added at runtime)" OFF)
- option(ENABLE_psi4fockci "Enables Psi4FockCI plugin (can also be added at runtime)" OFF)
-diff --git a/codedeps.yaml b/codedeps.yaml
-index 124c74c4492..316780b00d3 100644
---- a/codedeps.yaml
-+++ b/codedeps.yaml
-@@ -1490,8 +1490,8 @@ data:
- - project: qcmanybody
- use:
- added: "1.10"
-- required: true
-- required_note: "Allows BSSE treatments and MBE analyses. Prior to v1.10, internal code was used."
-+ required: false
-+ required_note: "Allows BSSE treatments and MBE analyses. Required for v1.10. Prior to v1.10, internal code was used."
- buildable: true
- buildtime: true
- buildtime_note: "buildtime for cmake checks; otherwise, runtime."
-diff --git a/doc/sphinxman/source/build_planning.rst b/doc/sphinxman/source/build_planning.rst
-index ef913ecc7be..73dd6c3dd9b 100644
---- a/doc/sphinxman/source/build_planning.rst
-+++ b/doc/sphinxman/source/build_planning.rst
-@@ -241,8 +241,6 @@ build system will automatically download and build.
-
- * optking |w---w| `[what is optking] <https://optking.readthedocs.io/en/latest/>`_ (runtime dependency, required at build-time)
-
--* QCManyBody |w---w| `[what is QCManyBody?] <https://molssi.github.io/QCManyBody/>`_ (August 2025; added by v1.10; runtime dependency, required at build-time)
--
- Additionally, there are runtime-only dependencies:
-
- * msgpack-python for MessagePack https://msgpack.org/ (transitive dependency of QCElemental; optional for QCElemental but required for |PSIfour|)
-@@ -374,6 +372,8 @@ Additionally, there are runtime-loaded capabilities:
-
- * :ref:`ddx <sec:ddx>` |w---w| https://github.com/ddsolvation/ddx
-
-+* QCManyBody |w---w| `[what is QCManyBody?] <https://molssi.github.io/QCManyBody/>`_ (May 2025; optional by v1.11; * August 2025; added required by v1.10; runtime dependency, optional at build-time)
-+
-
- .. _`faq:condapsi4dev`:
-
-diff --git a/doc/sphinxman/source/external.rst b/doc/sphinxman/source/external.rst
-index 14fd2758e0c..54f8c3a4711 100644
---- a/doc/sphinxman/source/external.rst
-+++ b/doc/sphinxman/source/external.rst
-@@ -723,4 +723,5 @@ These environment variables will influence |PSIfours| behavior.
- .. envvar:: QCMANYBODY_EMBEDDING_CHARGES
-
- Set to allow embedding charges with many-body/counterpoise computations.
-+ Relevant when QCManyBody addon is present.
-
-diff --git a/doc/sphinxman/source/nbody.rst b/doc/sphinxman/source/nbody.rst
-index cd51c98142b..13778efd450 100644
---- a/doc/sphinxman/source/nbody.rst
-+++ b/doc/sphinxman/source/nbody.rst
-@@ -50,7 +50,8 @@ Basis Set Superposition Corrections
-
- The nbody function computes counterpoise-corrected (CP), non-CP (noCP), and Valiron-Mayer Function Counterpoise (VMFC) interaction energies for complexes composed of arbitrary numbers of monomers.
-
--.. caution:: August 2025, v1.10 many-body computations are no longer
-+.. caution:: May 2026, v1.11 QCManyBody is no longer required but may need to be
-+ separately installed. August 2025, v1.10 many-body computations are no longer
- using internal driver code but have been offloaded to QCManyBody
- software.
-
-diff --git a/external/upstream/qcmanybody/CMakeLists.txt b/external/upstream/qcmanybody/CMakeLists.txt
-index cb510f0f67c..ef1aefbb53a 100644
---- a/external/upstream/qcmanybody/CMakeLists.txt
-+++ b/external/upstream/qcmanybody/CMakeLists.txt
-@@ -1,41 +1,45 @@
--if(NOT (${CMAKE_DISABLE_FIND_PACKAGE_qcmanybody}))
-- include(FindPythonModule)
-- find_python_module(qcmanybody ATLEAST 0.5.1 QUIET)
--endif()
-+if(${ENABLE_qcmanybody})
-+ if(NOT (${CMAKE_DISABLE_FIND_PACKAGE_qcmanybody}))
-+ include(FindPythonModule)
-+ find_python_module(qcmanybody ATLEAST 0.5.1 QUIET)
-+ endif()
-
--if(${qcmanybody_FOUND})
-- message(STATUS "${Cyan}Found qcmanybody${ColourReset}: ${PY_qcmanybody} (found version ${qcmanybody_VERSION})")
-- add_library(qcmanybody_external INTERFACE) # dummy
-+ if(${qcmanybody_FOUND})
-+ message(STATUS "${Cyan}Found qcmanybody${ColourReset}: ${PY_qcmanybody} (found version ${qcmanybody_VERSION})")
-+ add_library(qcmanybody_external INTERFACE) # dummy
-
-- if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
-- message(VERBOSE "Suitable qcmanybody located externally as user insists")
-- endif()
-+ if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
-+ message(VERBOSE "Suitable qcmanybody located externally as user insists")
-+ endif()
-
--else()
-- if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
-- message(FATAL_ERROR "Suitable qcmanybody could not be externally located as user insists")
-- endif()
-+ else()
-+ if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
-+ message(FATAL_ERROR "Suitable qcmanybody could not be externally located as user insists")
-+ endif()
-
-- include(ExternalProject)
-- message(STATUS "Suitable qcmanybody could not be located, ${Magenta}Building qcmanybody${ColourReset} instead.")
-+ include(ExternalProject)
-+ message(STATUS "Suitable qcmanybody could not be located, ${Magenta}Building qcmanybody${ColourReset} instead.")
-
-- file(TO_NATIVE_PATH "${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${PYMOD_INSTALL_LIBDIR}" _install_lib)
-+ file(TO_NATIVE_PATH "${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${PYMOD_INSTALL_LIBDIR}" _install_lib)
-
-- # Must have specialty egg to compute version correctly, so the URL is only grabbing a dummy file. It's
-- # the pip command that's really selecting the source.
-- ExternalProject_Add(qcmanybody_external
-- DEPENDS qcelemental_external
-- qcengine_external
-- BUILD_ALWAYS 1
-- DOWNLOAD_COMMAND ""
-- CONFIGURE_COMMAND ""
-- UPDATE_COMMAND ""
-- BUILD_COMMAND ""
-- BUILD_IN_SOURCE 1
-- # master: INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/ QCManyBody.git#egg=proj
-- INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/QCManyBody.git@v0.5.1#egg=proj # edit in codedeps
-- --target=${_install_lib}
-- --no-deps
-- #-v
-- )
-+ # Must have specialty egg to compute version correctly, so the URL is only grabbing a dummy file. It's
-+ # the pip command that's really selecting the source.
-+ ExternalProject_Add(qcmanybody_external
-+ DEPENDS qcelemental_external
-+ qcengine_external
-+ BUILD_ALWAYS 1
-+ DOWNLOAD_COMMAND ""
-+ CONFIGURE_COMMAND ""
-+ UPDATE_COMMAND ""
-+ BUILD_COMMAND ""
-+ BUILD_IN_SOURCE 1
-+ # master: INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/ QCManyBody.git#egg=proj
-+ INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/QCManyBody.git@v0.5.1#egg=proj # edit in codedeps
-+ --target=${_install_lib}
-+ --no-deps
-+ #-v
-+ )
-+ endif()
-+else()
-+ add_library(qcmanybody_external INTERFACE) # dummy
- endif()
-diff --git a/psi4/__init__.py b/psi4/__init__.py
-index 22332ee30ec..418a8646d62 100644
---- a/psi4/__init__.py
-+++ b/psi4/__init__.py
-@@ -120,6 +120,8 @@
- sys.path.insert(1, r"@gdma_PYMOD@")
- if "@ENABLE_bse@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # bse
- sys.path.insert(1, r"@bse_PYMOD@")
-+if "@ENABLE_qcmanybody@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # qcmanybody
-+ sys.path.insert(1, r"@qcmanybody_PYMOD@")
-
- # Create a custom logger
- import logging
-diff --git a/psi4/driver/driver_nbody.py b/psi4/driver/driver_nbody.py
-index a554b9b4118..02eef5a899b 100644
---- a/psi4/driver/driver_nbody.py
-+++ b/psi4/driver/driver_nbody.py
-@@ -119,9 +119,30 @@
- from pydantic.v1 import validator
-
- from qcelemental.models import Molecule
--from qcmanybody.models.v1 import AtomicSpecification, ManyBodyInput, ManyBodyResult, BsseEnum
--from qcmanybody import ManyBodyCore, ManyBodyComputer as ManyBodyComputerQCNG
--from qcmanybody.utils import delabeler, labeler, translate_qcvariables, modelchem_labels
-+
-+_QCMANYBODY_IMPORT_ERROR = None
-+try:
-+ from qcmanybody.models.v1 import AtomicSpecification, ManyBodyInput, ManyBodyResult, BsseEnum
-+ from qcmanybody import ManyBodyCore, ManyBodyComputer as ManyBodyComputerQCNG
-+ from qcmanybody.utils import delabeler, labeler, translate_qcvariables, modelchem_labels
-+except ModuleNotFoundError as err:
-+ _QCMANYBODY_IMPORT_ERROR = err
-+ AtomicSpecification = Any
-+ ManyBodyInput = Any
-+ ManyBodyResult = Any
-+ BsseEnum = Any
-+ ManyBodyCore = Any
-+ ManyBodyComputerQCNG = object
-+
-+
-+def _ensure_qcmanybody() -> None:
-+ if _QCMANYBODY_IMPORT_ERROR is None:
-+ return
-+
-+ raise ModuleNotFoundError(
-+ "Python module qcmanybody not found that is required for many-body/counterpoise (`bsse_type`) computations. "
-+ "Solve by installing it: `conda install -c conda-forge qcmanybody` or `pip install qcmanybody`"
-+ ) from _QCMANYBODY_IMPORT_ERROR
-
- if TYPE_CHECKING:
- import qcportal
-@@ -410,6 +431,8 @@ def set_molecule(cls, v: Any) -> Molecule:
- @classmethod
- def from_psi4_task_planner(cls, *, molecule, method, basis, driver, keywords, **mbkwargs):
-
-+ _ensure_qcmanybody()
-+
- atomic_spec = AtomicSpecification(
- model={"method": method, "basis": basis},
- program="psi4",
-@@ -506,6 +529,8 @@ def build_tasks(
- Number of new tasks planned by this call including any supersystem.
-
- """
-+ _ensure_qcmanybody()
-+
- # TODO method not coming from levels right
-
- # Get the n-body orders for this level. e.g., [1] or [2, 3] or ["supersystem"]
-@@ -575,6 +600,8 @@ def get_results(
- All MBE results collected into a QCSchema model.
-
- """
-+ _ensure_qcmanybody()
-+
- component_results = {k: v.get_results(client=client) for k, v in self.task_list.items()}
- component_properties = {}
- props = {"energy", "gradient", "hessian"}
-diff --git a/psi4/extras.py b/psi4/extras.py
-index 794c4dae547..c3b5a6011d9 100644
---- a/psi4/extras.py
-+++ b/psi4/extras.py
-@@ -180,6 +180,7 @@ def psi4_which(command, *, return_bool: bool = False, raise_error: bool = False,
- "gauxc": _CMake_to_Py_boolean("@ENABLE_gauxc@"),
- "integratorxx": _CMake_to_Py_boolean("@ENABLE_IntegratorXX@"),
- "ooo": _CMake_to_Py_boolean("@ENABLE_OpenOrbitalOptimizer@"),
-+ "qcmanybody": which_import("qcmanybody", return_bool=True),
- }
-
-
-diff --git a/pytest.ini b/pytest.ini
-index 45057bbb9ad..66f90ad870d 100644
---- a/pytest.ini
-+++ b/pytest.ini
-@@ -93,7 +93,7 @@ markers =
- mints
- mom
- mp2
-- nbody: "tests that use the nbody aka manybody wrapper"
-+ nbody: "tests that use the nbody aka manybody wrapper; alias to qcmanybody marker"
- noc1
- numint: "tests that use NumIntHelper"
- numpy
-@@ -180,6 +180,7 @@ markers =
- qcfractal: "tests using QCFractal software; skip if unavailable"
- qcfractal_next: "tests using QCFractal software, next branch; skip if unavailable"
- qcportal: "tests using QCPortal software; skip if unavailable"
-+ qcmanybody: "tests using QCManyBody software; skip if unavailable; alias to nbody marker"
- psi4
-
-
-@@ -187,4 +188,3 @@ markers =
- # filterwarnings =
- # error
- # ignore:unclosed file:ResourceWarning
--
-diff --git a/tests/cbs-xtpl-nbody/test_input.py b/tests/cbs-xtpl-nbody/test_input.py
-index 27584e7d16f..c34e747f100 100644
---- a/tests/cbs-xtpl-nbody/test_input.py
-+++ b/tests/cbs-xtpl-nbody/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("cbs;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("cbs")
- def test_cbs_xtpl_nbody():
- ctest_runner(__file__)
--
-diff --git a/tests/ddd-function-kwargs/test_input.py b/tests/ddd-function-kwargs/test_input.py
-index d56b322c643..37216a71829 100644
---- a/tests/ddd-function-kwargs/test_input.py
-+++ b/tests/ddd-function-kwargs/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("findif;nbody;gradient")
-+@uusing("qcmanybody")
-+@ctest_labeler("findif;gradient")
- def test_ddd_function_kwargs():
- ctest_runner(__file__)
--
-diff --git a/tests/dfmp2-1/test_input.py b/tests/dfmp2-1/test_input.py
-index 4f8f3b89542..199f1da3d4f 100644
---- a/tests/dfmp2-1/test_input.py
-+++ b/tests/dfmp2-1/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("quick;smoke;df;dfmp2;cart;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("quick;smoke;df;dfmp2;cart")
- def test_dfmp2_1():
- ctest_runner(__file__)
--
-diff --git a/tests/dfmp2-ecp/test_input.py b/tests/dfmp2-ecp/test_input.py
-index 8a21eda1c89..2441b0fd5e9 100644
---- a/tests/dfmp2-ecp/test_input.py
-+++ b/tests/dfmp2-ecp/test_input.py
-@@ -2,7 +2,8 @@
- from addons import *
-
- @uusing("ecpint")
--@ctest_labeler("quick;df;dfmp2;ecp;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("quick;df;dfmp2;ecp")
- @pytest.mark.parametrize("oopkg", [
- pytest.param(False, id="internal"),
- pytest.param(True, id="openorbitaloptimizer", marks=using("ooo")),
-diff --git a/tests/dfmp2-fc/test_input.py b/tests/dfmp2-fc/test_input.py
-index 5141f0227b2..eda3ee25477 100644
---- a/tests/dfmp2-fc/test_input.py
-+++ b/tests/dfmp2-fc/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("quick;df;dfmp2;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("quick;df;dfmp2")
- def test_dfmp2_fc():
- ctest_runner(__file__)
--
-diff --git a/tests/dft-custom-dhdf/test_input.py b/tests/dft-custom-dhdf/test_input.py
-index 7d649f38da6..eb136c2210b 100644
---- a/tests/dft-custom-dhdf/test_input.py
-+++ b/tests/dft-custom-dhdf/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("dft;scf;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("dft;scf")
- def test_dft_custom_dhdf():
- ctest_runner(__file__)
--
-diff --git a/tests/dftd3/nbody-cp-gradient/test_input.py b/tests/dftd3/nbody-cp-gradient/test_input.py
-index 07746f35f27..1d26cb042b3 100644
---- a/tests/dftd3/nbody-cp-gradient/test_input.py
-+++ b/tests/dftd3/nbody-cp-gradient/test_input.py
-@@ -1,6 +1,7 @@
- from addons import *
-
- @uusing("dftd3")
--@ctest_labeler("cart;nbody;gradient")
-+@uusing("qcmanybody")
-+@ctest_labeler("cart;gradient")
- def test_dftd3_nbody_cp_gradient():
- ctest_runner(__file__)
-diff --git a/tests/mp2-def2/test_input.py b/tests/mp2-def2/test_input.py
-index b3d6ab9a736..c9f7e562bac 100644
---- a/tests/mp2-def2/test_input.py
-+++ b/tests/mp2-def2/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("mp2;cart;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("mp2;cart")
- def test_mp2_def2():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-convergence/test_input.py b/tests/nbody-convergence/test_input.py
-index ca79137c733..85818e08324 100644
---- a/tests/nbody-convergence/test_input.py
-+++ b/tests/nbody-convergence/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;gradient")
-+@uusing("qcmanybody")
-+@ctest_labeler("gradient")
- def test_nbody_convergence():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-cp-gradient/test_input.py b/tests/nbody-cp-gradient/test_input.py
-index c12444621b6..aa7e6cee22b 100644
---- a/tests/nbody-cp-gradient/test_input.py
-+++ b/tests/nbody-cp-gradient/test_input.py
-@@ -1,12 +1,12 @@
- import pytest
- from addons import *
-
-+@uusing("qcmanybody")
- @pytest.mark.parametrize("distributed", [
- pytest.param(False, id="internal"),
- pytest.param(True, id="snowflake", marks=using("qcfractal_next")),
- ])
--@ctest_labeler("nbody;gradient")
-+@ctest_labeler("gradient")
- def test_nbody_cp_gradient(distributed):
- setenv = ["_PSI4_USE_QCF"] if distributed else None
- ctest_runner(__file__, setenv=setenv)
--
-diff --git a/tests/nbody-freq/test_input.py b/tests/nbody-freq/test_input.py
-index 4179468c85f..a00baa262df 100644
---- a/tests/nbody-freq/test_input.py
-+++ b/tests/nbody-freq/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;freq;hessian;gradient;opt")
-+@uusing("qcmanybody")
-+@ctest_labeler("freq;hessian;gradient;opt")
- def test_nbody_freq():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-he-4b/test_input.py b/tests/nbody-he-4b/test_input.py
-index 02fd908076f..f9bf44c7f85 100644
---- a/tests/nbody-he-4b/test_input.py
-+++ b/tests/nbody-he-4b/test_input.py
-@@ -1,12 +1,12 @@
- import pytest
- from addons import *
-
-+@uusing("qcmanybody")
- @pytest.mark.parametrize("distributed", [
- pytest.param(False, id="internal"),
- pytest.param(True, id="snowflake", marks=using("qcfractal_next")),
- ])
--@ctest_labeler("nbody;cart")
-+@ctest_labeler("cart")
- def test_nbody_he_4b(distributed):
- setenv = ["_PSI4_USE_QCF"] if distributed else None
- ctest_runner(__file__, setenv=setenv)
--
-diff --git a/tests/nbody-he-cluster/test_input.py b/tests/nbody-he-cluster/test_input.py
-index b2df4668d78..ca40affec67 100644
---- a/tests/nbody-he-cluster/test_input.py
-+++ b/tests/nbody-he-cluster/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;cart")
-+@uusing("qcmanybody")
-+@ctest_labeler("cart")
- def test_nbody_he_cluster():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-hessian/test_input.py b/tests/nbody-hessian/test_input.py
-index fb54e2c8fbe..906c029cbe2 100644
---- a/tests/nbody-hessian/test_input.py
-+++ b/tests/nbody-hessian/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;hessian")
-+@uusing("qcmanybody")
-+@ctest_labeler("hessian")
- def test_nbody_hessian():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-intermediates/test_input.py b/tests/nbody-intermediates/test_input.py
-index 3daeb7079fc..625cd8729e8 100644
---- a/tests/nbody-intermediates/test_input.py
-+++ b/tests/nbody-intermediates/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("")
- def test_nbody_intermediates():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-multi-level-2/test_input.py b/tests/nbody-multi-level-2/test_input.py
-index 75aac98456a..6e7da06eb9b 100644
---- a/tests/nbody-multi-level-2/test_input.py
-+++ b/tests/nbody-multi-level-2/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("")
- def test_nbody_multi_level_2():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-multi-level/test_input.py b/tests/nbody-multi-level/test_input.py
-index 99c0c9faca0..0afe1a1bc9e 100644
---- a/tests/nbody-multi-level/test_input.py
-+++ b/tests/nbody-multi-level/test_input.py
-@@ -1,7 +1,8 @@
- import pytest
- from addons import *
-
--@ctest_labeler("nbody;extern")
-+@uusing("qcmanybody")
-+@ctest_labeler("extern")
- @pytest.mark.parametrize("distributed", [
- pytest.param(False, id="internal"),
- pytest.param(True, id="snowflake", marks=[*using("qcfractal_next"), pytest.mark.medlong]),
-@@ -10,4 +11,3 @@ def test_nbody_multi_level(distributed, monkeypatch):
- setenv = ["_PSI4_USE_QCF"] if distributed else None
- monkeypatch.setenv("QCMANYBODY_EMBEDDING_CHARGES", "1")
- ctest_runner(__file__, setenv=setenv)
--
-diff --git a/tests/nbody-nocp-gradient/test_input.py b/tests/nbody-nocp-gradient/test_input.py
-index cc75771ad37..55a9bef4dc1 100644
---- a/tests/nbody-nocp-gradient/test_input.py
-+++ b/tests/nbody-nocp-gradient/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;gradient")
-+@uusing("qcmanybody")
-+@ctest_labeler("gradient")
- def test_nbody_nocp_gradient():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-vmfc-gradient/test_input.py b/tests/nbody-vmfc-gradient/test_input.py
-index fa2ec7d45c2..0027999bc7c 100644
---- a/tests/nbody-vmfc-gradient/test_input.py
-+++ b/tests/nbody-vmfc-gradient/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("nbody;gradient")
-+@uusing("qcmanybody")
-+@ctest_labeler("gradient")
- def test_nbody_vmfc_gradient():
- ctest_runner(__file__)
--
-diff --git a/tests/nbody-vmfc-hessian/test_input.py b/tests/nbody-vmfc-hessian/test_input.py
-index 6b3872fc592..7cc3d08be9a 100644
---- a/tests/nbody-vmfc-hessian/test_input.py
-+++ b/tests/nbody-vmfc-hessian/test_input.py
-@@ -1,7 +1,8 @@
- import pytest
- from addons import *
-
--@ctest_labeler("nbody;hessian;d2ints")
-+@uusing("qcmanybody")
-+@ctest_labeler("hessian;d2ints")
-
- @pytest.mark.parametrize("distributed", [
- pytest.param(False, id="internal"),
-@@ -10,4 +11,3 @@
- def test_nbody_vmfc_hessian(distributed):
- setenv = ["_PSI4_USE_QCF"] if distributed else None
- ctest_runner(__file__, setenv=setenv)
--
-diff --git a/tests/pytests/addons.py b/tests/pytests/addons.py
-index c6518356819..644f1a42a4e 100644
---- a/tests/pytests/addons.py
-+++ b/tests/pytests/addons.py
-@@ -90,6 +90,7 @@ def is_nvidia_gpu_present():
- "qcfractal": which_import("qcfractal", return_bool=True),
- "qcfractal_next": is_qcfractal_new_enough("0.49"),
- "qcportal": which_import("qcportal", return_bool=True),
-+ "qcmanybody": which_import("qcmanybody", return_bool=True),
- "bse": which_import("basis_set_exchange", return_bool=True),
- "einsums": psi4.addons("einsums"),
- "pyeinsums": which_import("einsums", return_bool=True),
-@@ -126,7 +127,10 @@ def _using(program: str) -> None:
- general = pytest.mark.addon
- particular = getattr(pytest.mark, program)
-
-- all_marks = (skip, general, particular)
-+ if program == "qcmanybody":
-+ all_marks = (skip, general, particular, getattr(pytest.mark, "nbody"))
-+ else:
-+ all_marks = (skip, general, particular)
- _using_cache[program] = [_compose_decos(all_marks), all_marks]
-
-
-diff --git a/tests/pytests/test_addons.py b/tests/pytests/test_addons.py
-index 60f809eef17..36eaf76f83b 100644
---- a/tests/pytests/test_addons.py
-+++ b/tests/pytests/test_addons.py
-@@ -907,7 +907,7 @@ def test_gpu_dfcc():
-
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- @uusing("dftd3")
- @uusing("gcp")
- def test_grimme_3c():
-@@ -1617,4 +1617,3 @@ def test_pyeinsums_gemm(a, b, c, dtype, array):
- for i in range(a):
- for j in range(c):
- assert C[i, j] == pytest.approx(C_actual[i, j])
--
-diff --git a/tests/pytests/test_addons_qcschema.py b/tests/pytests/test_addons_qcschema.py
-index 3daa45977ca..afd2c832785 100644
---- a/tests/pytests/test_addons_qcschema.py
-+++ b/tests/pytests/test_addons_qcschema.py
-@@ -562,7 +562,7 @@ def test_v2rdm_casscf():
- # assert psi4.compare_values(en_gpu_dfcc, en_dfcc, 8, "CCSD total energy")
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- @uusing("dftd3")
- @uusing("gcp")
- def test_grimme_3c():
-@@ -829,4 +829,3 @@ def test_ddx_tdscf_gaussian():
- for i in range(5):
- e_calc.append(atres.extras["qcvars"][f'TD-HF ROOT 0 -> ROOT {i+1} EXCITATION ENERGY - A TRANSITION'])
- psi4.compare_values(exc_energies[:5], e_calc, 4, 'PCM EXCITATION ENERGY ')
--
-diff --git a/tests/pytests/test_compositejk.py b/tests/pytests/test_compositejk.py
-index b0030c87f7e..dc2bc36428a 100644
---- a/tests/pytests/test_compositejk.py
-+++ b/tests/pytests/test_compositejk.py
-@@ -111,7 +111,7 @@ def test_composite_call(j_algo, k_algo, mols, request):
- "molecule" : "h2o_nap1",
- "bsse_type" : "CP",
- },
-- marks=pytest.mark.nbody,
-+ marks=using("qcmanybody"),
- id="h2o/na+ (rhf ie)"),
- ],
- )
-@@ -216,7 +216,7 @@ def test_seminum(inp, scf, mols, request):
- "molecule" : "h2o_nap1",
- "bsse_type" : "CP",
- },
-- marks=pytest.mark.nbody,
-+ marks=using("qcmanybody"),
- id="h2o/na+ (rhf ie)"),
- ],
- )
-diff --git a/tests/pytests/test_dft_benchmarks.py b/tests/pytests/test_dft_benchmarks.py
-index 975e3cc39b0..106ac5d48d3 100644
---- a/tests/pytests/test_dft_benchmarks.py
-+++ b/tests/pytests/test_dft_benchmarks.py
-@@ -2,7 +2,7 @@
-
- import pytest
- from utils import *
--from addons import using
-+from addons import using, uusing
-
- import psi4
-
-@@ -178,7 +178,7 @@ def test_dft_bench_ionization(func, expected, basis, dft_bench_systems, request)
-
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- @pytest.mark.scf
- @pytest.mark.dft
- @pytest.mark.long
-diff --git a/tests/pytests/test_dftd3.py b/tests/pytests/test_dftd3.py
-index 552a167cb4e..7e0461ed2bf 100644
---- a/tests/pytests/test_dftd3.py
-+++ b/tests/pytests/test_dftd3.py
-@@ -113,7 +113,7 @@ def test_dftd3_dft_grad_lr3():
- s16_r2scan50_psi4 = np.array([-155.6575747, -78.4586347, -77.1962996])
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- @pytest.mark.parametrize("mode", [
- pytest.param("abs", marks=pytest.mark.long),
- pytest.param("ie", marks=pytest.mark.quick),
-@@ -191,4 +191,3 @@ def test_grimme_3c(mtdbas, ref, mode):
-
- ene = psi4.energy(mtdbas, bsse_type='nocp')
- assert psi4.compare_values(kcal * (ref[0] - ref[1] - ref[2]), kcal * ene, 1.1e-3, mtdbas)
--
-diff --git a/tests/pytests/test_nbody.py b/tests/pytests/test_nbody.py
-index 5741f5046b4..24b9dacaf97 100644
---- a/tests/pytests/test_nbody.py
-+++ b/tests/pytests/test_nbody.py
-@@ -2,9 +2,10 @@
- import pytest
- import numpy as np
- from qcelemental.testing import compare, compare_values
-+from addons import uusing
- import psi4
-
--pytestmark = [pytest.mark.psi, pytest.mark.api, pytest.mark.nbody]
-+pytestmark = [pytest.mark.psi, pytest.mark.api]
-
- _tot_cp_ene = -155.40761029
- _ie_cp_ene = -0.00172611
-@@ -121,6 +122,7 @@
- ("gradient", ["nocp", "cp"], None , 5, _tot_uncp_grad, "uncpcp"), # return tot G 5
- ("gradient", ["nocp", "ssfc"], None , 5, _tot_uncp_grad, "uncpcp"), # return tot G 5
- ])
-+@uusing("qcmanybody")
- def test_nbody_number(driver, bsse_type, return_total_data, nbody_number, return_result, stdoutkey):
-
- eneyne = psi4.geometry("""
-@@ -160,4 +162,3 @@ def test_nbody_number(driver, bsse_type, return_total_data, nbody_number, return
- assert compare_values(return_result, ret.return_result, atol=1.e-6, label="manybody")
- assert compare(nbody_number, ret.extras["qcvars"]["NBODY NUMBER"], label="nbody number")
- assert re.search(_stdouts[stdoutkey], ret.stdout, re.MULTILINE), f"N-Body pattern not found: {_stdouts[stdoutkey]}"
--
-diff --git a/tests/pytests/test_nbody_multi_level_qcschema.py b/tests/pytests/test_nbody_multi_level_qcschema.py
-index be576046cf6..7b79e3d6c0c 100644
---- a/tests/pytests/test_nbody_multi_level_qcschema.py
-+++ b/tests/pytests/test_nbody_multi_level_qcschema.py
-@@ -3,10 +3,11 @@
- import pprint
-
- import pytest
-+from addons import uusing
-
- import psi4
-
--pytestmark = [pytest.mark.psi, pytest.mark.api, pytest.mark.nbody]
-+pytestmark = [pytest.mark.psi, pytest.mark.api]
-
- @pytest.fixture
- def base_schema():
-@@ -65,6 +66,7 @@ def base_schema():
- 'VMFC-CORRECTED TOTAL ENERGY THROUGH 2-BODY': -224.943882712817},
- id='nbody-embedded', marks=pytest.mark.extern),
- ])
-+@uusing("qcmanybody")
- def test_nbody_levels(inp, expected, base_schema, monkeypatch):
- monkeypatch.setenv("QCMANYBODY_EMBEDDING_CHARGES", "1")
- # reference for nbody-multilevel generated with this larger fitting basis for sto-3g. fails otherwise by 3.e-5
-@@ -85,4 +87,3 @@ def test_nbody_levels(inp, expected, base_schema, monkeypatch):
-
- for b, v in expected.items():
- assert psi4.compare_values(v, otp.extras["qcvars"][b], 6, b)
--
-diff --git a/tests/pytests/test_psi4.py b/tests/pytests/test_psi4.py
-index d7df6249f2e..8eacacc12b7 100644
---- a/tests/pytests/test_psi4.py
-+++ b/tests/pytests/test_psi4.py
-@@ -1,5 +1,6 @@
- import numpy as np
- import pytest
-+from addons import uusing
-
- import psi4
-
-@@ -85,7 +86,7 @@ def test_psi4_cas():
- assert psi4.compare_values(-76.073865006902, casscf_energy, 6, 'CASSCF Energy')
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- @pytest.mark.smoke
- def test_psi4_dfmp2():
- """dfmp2-1"""
-diff --git a/tests/pytests/test_psi4_qcschema.py b/tests/pytests/test_psi4_qcschema.py
-index 295d44f572d..0576d989b02 100644
---- a/tests/pytests/test_psi4_qcschema.py
-+++ b/tests/pytests/test_psi4_qcschema.py
-@@ -4,6 +4,7 @@
- import pprint
- import os
- from shutil import copytree
-+from addons import uusing
-
- import psi4
-
-@@ -95,7 +96,7 @@ def test_psi4_cas(datadir):
- assert psi4.compare_values(-76.073865006902, atres.return_result, 6, 'CASSCF Energy')
-
-
--@pytest.mark.nbody
-+@uusing("qcmanybody")
- def test_psi4_dfmp2(datadir):
- """dfmp2-1"""
- #! Density fitted MP2 cc-PVDZ/cc-pVDZ-RI computation of formic acid dimer binding energy
-diff --git a/tests/tu6-cp-ne2/test_input.py b/tests/tu6-cp-ne2/test_input.py
-index d4086c15ee3..138e8e005ca 100644
---- a/tests/tu6-cp-ne2/test_input.py
-+++ b/tests/tu6-cp-ne2/test_input.py
-@@ -1,6 +1,6 @@
- from addons import *
-
--@ctest_labeler("tutorial;nbody")
-+@uusing("qcmanybody")
-+@ctest_labeler("tutorial")
- def test_tu6_cp_ne2():
- ctest_runner(__file__)
--
diff --git a/3389_new.patch b/3389_new.patch
new file mode 100644
index 0000000..1db70eb
--- /dev/null
+++ b/3389_new.patch
@@ -0,0 +1,1570 @@
+diff -up psi4-1.11/CMakeLists.txt.noqcmb psi4-1.11/CMakeLists.txt
+--- psi4-1.11/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/CMakeLists.txt 2026-07-23 10:43:03.925378404 +0000
+@@ -134,6 +134,7 @@ option(ENABLE_gdma "Enables Stone's GDMA
+ option(ENABLE_IntegratorXX "Enables use of IntegratorXX density functional grids library" OFF)
+ option(ENABLE_OpenOrbitalOptimizer "Enables the OpenOrbitalOptimizer library (requires Armadillo)" OFF)
+ option(ENABLE_PCMSolver "Enables PCMSolver library (requires Fortran)" OFF)
++option(ENABLE_qcmanybody "Enables qcmanybody for n-body/BSSE workflows (can also be added at runtime)" OFF)
+ option(ENABLE_snsmp2 "Enables SNSMP2 plugin (can also be added at runtime)" OFF)
+ option(ENABLE_v2rdm_casscf "Enables V2RDM_CASSCF plugin (requires Fortran; can also be added at runtime)" OFF)
+ option(ENABLE_psi4fockci "Enables Psi4FockCI plugin (can also be added at runtime)" OFF)
+@@ -323,7 +324,6 @@ ExternalProject_Add(psi4-core
+ -DPSI4_ROOT=${CMAKE_CURRENT_SOURCE_DIR}
+ -DENABLE_ambit=${ENABLE_ambit}
+ -DENABLE_CheMPS2=${ENABLE_CheMPS2}
+- -DENABLE_cppe=${ENABLE_cppe}
+ -DENABLE_dkh=${ENABLE_dkh}
+ -DENABLE_IntegratorXX=${ENABLE_IntegratorXX}
+ -DENABLE_gauxc=${ENABLE_gauxc}
+@@ -333,7 +333,6 @@ ExternalProject_Add(psi4-core
+ -DENABLE_simint=${ENABLE_simint}
+ -DENABLE_gdma=${ENABLE_gdma}
+ -DENABLE_PCMSolver=${ENABLE_PCMSolver}
+- -DENABLE_ddx=${ENABLE_ddx}
+ -DENABLE_mdi=${ENABLE_mdi}
+ -DENABLE_BrianQC=${ENABLE_BrianQC}
+ -DENABLE_OpenOrbitalOptimizer=${ENABLE_OpenOrbitalOptimizer}
+diff -up psi4-1.11/codedeps.yaml.noqcmb psi4-1.11/codedeps.yaml
+--- psi4-1.11/codedeps.yaml.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/codedeps.yaml 2026-07-23 10:43:03.927243876 +0000
+@@ -675,9 +675,11 @@ data:
+ - qcportal
+ - "setuptools<82.0.0"
+ - sphobjinv
++ - qcmanybody
+ aux_build_names_note:
+ qcportal: "Required for docs to resolve objects in pydantic classes."
+ sphobjinv: "Required for easy debugging in CI, not needed for local docs build."
++ qcmanybody: "Required for docs to resolve objects in pydantic classes."
+ cmake:
+ SPHINX_ROOT: ${CONDA_PREFIX}
+ //SPHINXMAN_STRICT: OFF
+@@ -1517,10 +1519,10 @@ data:
+ - project: qcmanybody
+ use:
+ added: "1.10"
+- required: true
+- required_note: "Allows BSSE treatments and MBE analyses. Prior to v1.10, internal code was used."
++ required: false
++ required_note: "Allows BSSE treatments and MBE analyses. Optional for v1.12. Required for v1.10 & 1.11. Prior to v1.10, internal code was used."
+ buildable: true
+- buildtime: true
++ buildtime: false
+ buildtime_note: "buildtime for cmake checks; otherwise, runtime."
+ cms: true
+ repository:
+@@ -1532,16 +1534,18 @@ data:
+ cmake:
+ name: qcmanybody
+ constraint: "ATLEAST 0.7.1"
++ enable: "ENABLE_qcmanybody"
+ target: null
+ conda:
+ channel: conda-forge
+ name: qcmanybody
+ constraint: ">=0.7.1"
+ cmake:
++ ENABLE_qcmanybody: true
+ //CMAKE_INSIST_FIND_PACKAGE_qcmanybody: true
+ //CMAKE_DISABLE_FIND_PACKAGE_qcmanybody: true
+- cmake_note: "Primarily OTF runtime detected."
+-
++ cmake_note: "Primarily OTF runtime detected. With package present, CMake enabling only relevant for CTest."
++
+ - project: openorbitaloptimizer
+ use:
+ added: "1.10"
+diff -up psi4-1.11/doc/sphinxman/source/build_planning.rst.noqcmb psi4-1.11/doc/sphinxman/source/build_planning.rst
+--- psi4-1.11/doc/sphinxman/source/build_planning.rst.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/doc/sphinxman/source/build_planning.rst 2026-07-23 10:43:03.919628662 +0000
+@@ -244,8 +244,6 @@ build system will automatically download
+
+ * optking |w---w| `[what is optking] <https://optking.readthedocs.io/en/latest/>`_ (runtime dependency, required at build-time)
+
+-* QCManyBody |w---w| `[what is QCManyBody?] <https://molssi.github.io/QCManyBody/>`_ (August 2025; added by v1.10; runtime dependency, required at build-time)
+-
+ Additionally, there are runtime-only dependencies:
+
+ * msgpack-python for MessagePack https://msgpack.org/ (transitive dependency of QCElemental; optional for QCElemental but required for |PSIfour|)
+@@ -377,6 +375,8 @@ Additionally, there are runtime-loaded c
+
+ * :ref:`ddx <sec:ddx>` |w---w| https://github.com/ddsolvation/ddx
+
++* QCManyBody |w---w| `[what is QCManyBody?] <https://molssi.github.io/QCManyBody/>`_ (July 2026 - optional by v1.12; August 2025 - added required by v1.10; runtime dependency, optional at build-time)
++
+
+ .. _`faq:condapsi4dev`:
+
+diff -up psi4-1.11/doc/sphinxman/source/external.rst.noqcmb psi4-1.11/doc/sphinxman/source/external.rst
+--- psi4-1.11/doc/sphinxman/source/external.rst.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/doc/sphinxman/source/external.rst 2026-07-23 10:43:03.828436082 +0000
+@@ -728,4 +728,5 @@ These environment variables will influen
+ .. envvar:: QCMANYBODY_EMBEDDING_CHARGES
+
+ Set to allow embedding charges with many-body/counterpoise computations.
++ Relevant when QCManyBody addon is present.
+
+diff -up psi4-1.11/doc/sphinxman/source/nbody.rst.noqcmb psi4-1.11/doc/sphinxman/source/nbody.rst
+--- psi4-1.11/doc/sphinxman/source/nbody.rst.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/doc/sphinxman/source/nbody.rst 2026-07-23 10:43:03.920071300 +0000
+@@ -50,7 +50,8 @@ Basis Set Superposition Corrections
+
+ The nbody function computes counterpoise-corrected (CP), non-CP (noCP), and Valiron-Mayer Function Counterpoise (VMFC) interaction energies for complexes composed of arbitrary numbers of monomers.
+
+-.. caution:: August 2025, v1.10 many-body computations are no longer
++.. caution:: July 2026, v1.12 QCManyBody is no longer required but may need to be
++ separately installed. August 2025, v1.10 many-body computations are no longer
+ using internal driver code but have been offloaded to QCManyBody
+ software.
+
+diff -up psi4-1.11/external/upstream/ambit/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/ambit/CMakeLists.txt
+--- psi4-1.11/external/upstream/ambit/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/ambit/CMakeLists.txt 2026-07-23 10:43:03.920659066 +0000
+@@ -76,5 +76,6 @@ if(${ENABLE_ambit})
+ set(ambit_DIR ${STAGED_INSTALL_PREFIX}/${_ambit_dir} CACHE PATH "path to internally built ambitConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: ambit${ColourReset}")
+ add_library(ambit_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/bse/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/bse/CMakeLists.txt
+--- psi4-1.11/external/upstream/bse/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/bse/CMakeLists.txt 2026-07-23 10:43:03.920848412 +0000
+@@ -38,6 +38,7 @@ if(${ENABLE_bse})
+ )
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: bse${ColourReset} (basis_set_exchange; deferrable to runtime)")
+ add_library(bse_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/chemps2/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/chemps2/CMakeLists.txt
+--- psi4-1.11/external/upstream/chemps2/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/chemps2/CMakeLists.txt 2026-07-23 10:43:03.920997972 +0000
+@@ -70,6 +70,7 @@ if(${ENABLE_CheMPS2})
+ set(CheMPS2_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/CheMPS2 CACHE PATH "path to internally built CheMPS2Config.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: CheMPS2${ColourReset}")
+ add_library(chemps2_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/cppe/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/cppe/CMakeLists.txt
+--- psi4-1.11/external/upstream/cppe/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/cppe/CMakeLists.txt 2026-07-23 10:43:03.921151833 +0000
+@@ -55,5 +55,6 @@ if(${ENABLE_cppe})
+
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: cppe${ColourReset} (deferrable to runtime)")
+ add_library(cppe_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/ddx/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/ddx/CMakeLists.txt
+--- psi4-1.11/external/upstream/ddx/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/ddx/CMakeLists.txt 2026-07-23 10:43:03.921307007 +0000
+@@ -37,5 +37,6 @@ if(${ENABLE_ddx})
+ )
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: ddx${ColourReset} (deferrable to runtime)")
+ add_library(ddx_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/dkh/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/dkh/CMakeLists.txt
+--- psi4-1.11/external/upstream/dkh/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/dkh/CMakeLists.txt 2026-07-23 10:43:03.921470214 +0000
+@@ -49,6 +49,7 @@ if(${ENABLE_dkh})
+ set(dkh_DIR ${STAGED_INSTALL_PREFIX}/${_dkh_dir} CACHE PATH "path to internally built dkhConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: dkh${ColourReset}")
+ add_library(dkh_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/ecpint/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/ecpint/CMakeLists.txt
+--- psi4-1.11/external/upstream/ecpint/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/ecpint/CMakeLists.txt 2026-07-23 10:43:03.921623394 +0000
+@@ -43,6 +43,7 @@ if(${ENABLE_ecpint})
+ set(ecpint_DIR ${STAGED_INSTALL_PREFIX}/lib/cmake/ecpint CACHE PATH "path to internally built ecpint-config.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: ecpint${ColourReset}")
+ add_library(ecpint_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/einsums/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/einsums/CMakeLists.txt
+--- psi4-1.11/external/upstream/einsums/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/einsums/CMakeLists.txt 2026-07-23 10:43:03.921797895 +0000
+@@ -66,5 +66,6 @@ if(${ENABLE_Einsums})
+ set(Einsums_DIR ${STAGED_INSTALL_PREFIX}/${_einsums_dir} CACHE PATH "path to internally built EinsumsConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: einsums${ColourReset}")
+ add_library(einsums_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/gauxc/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/gauxc/CMakeLists.txt
+--- psi4-1.11/external/upstream/gauxc/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/gauxc/CMakeLists.txt 2026-07-23 10:43:03.921956259 +0000
+@@ -99,5 +99,6 @@ if(${ENABLE_gauxc})
+ set(gauxc_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/gauxc CACHE PATH "path to internally built gauxcConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: gauxc${ColourReset}")
+ add_library(gauxc_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/gdma/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/gdma/CMakeLists.txt
+--- psi4-1.11/external/upstream/gdma/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/gdma/CMakeLists.txt 2026-07-23 10:43:03.922119034 +0000
+@@ -55,6 +55,7 @@ if(${ENABLE_gdma})
+ set(gdma_DIR ${STAGED_INSTALL_PREFIX}/${_gdma_dir} CACHE PATH "path to internally built gdmaConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: gdma${ColourReset} (deferrable to runtime)")
+ add_library(gdma_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/integratorxx/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/integratorxx/CMakeLists.txt
+--- psi4-1.11/external/upstream/integratorxx/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/integratorxx/CMakeLists.txt 2026-07-23 10:43:03.922273925 +0000
+@@ -32,6 +32,7 @@ if(${ENABLE_IntegratorXX})
+ set(IntegratorXX_DIR ${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/IntegratorXX CACHE PATH "path to internally built IntegratorXXConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: IntegratorXX${ColourReset}")
+ add_library(integratorxx_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/libefp/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/libefp/CMakeLists.txt
+--- psi4-1.11/external/upstream/libefp/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/libefp/CMakeLists.txt 2026-07-23 10:43:03.922427202 +0000
+@@ -49,5 +49,6 @@ if(${ENABLE_libefp})
+ set(libefp_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/libefp CACHE PATH "path to internally built libefpConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: libefp${ColourReset} (deferrable to runtime)")
+ add_library(libefp_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/mdi/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/mdi/CMakeLists.txt
+--- psi4-1.11/external/upstream/mdi/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/mdi/CMakeLists.txt 2026-07-23 10:43:03.922576764 +0000
+@@ -45,5 +45,6 @@ if(${ENABLE_mdi})
+ set(mdi_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/mdi CACHE PATH "path to internally built mdiConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: mdi${ColourReset} (deferrable to runtime)")
+ add_library(mdi_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/openorbitaloptimizer/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/openorbitaloptimizer/CMakeLists.txt
+--- psi4-1.11/external/upstream/openorbitaloptimizer/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/openorbitaloptimizer/CMakeLists.txt 2026-07-23 10:43:03.922772670 +0000
+@@ -40,5 +40,6 @@ if(${ENABLE_OpenOrbitalOptimizer})
+ set(OpenOrbitalOptimizer_DIR ${STAGED_INSTALL_PREFIX}/${_ooo_dir} CACHE PATH "path to internally built OpenOrbitalOptimizerConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: OpenOrbitalOptimizer${ColourReset}")
+ add_library(openorbitaloptimizer_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/pcmsolver/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/pcmsolver/CMakeLists.txt
+--- psi4-1.11/external/upstream/pcmsolver/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/pcmsolver/CMakeLists.txt 2026-07-23 10:43:03.922932629 +0000
+@@ -68,5 +68,6 @@
+ set(PCMSolver_DIR ${STAGED_INSTALL_PREFIX}/${_pcmsolver_dir} CACHE PATH "path to internally built PCMSolverConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: PCMSolver${ColourReset}")
+ add_library(pcmsolver_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/pylibefp/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/pylibefp/CMakeLists.txt
+--- psi4-1.11/external/upstream/pylibefp/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/pylibefp/CMakeLists.txt 2026-07-23 10:43:03.923084534 +0000
+@@ -60,6 +60,7 @@ if(${ENABLE_libefp})
+ set(pylibefp_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/pylibefp CACHE PATH "path to internally built pylibefpConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: libefp${ColourReset} (deferrable to runtime)")
+ add_library(pylibefp_external INTERFACE) # dummy
+ endif()
+
+diff -up psi4-1.11/external/upstream/qcmanybody/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/qcmanybody/CMakeLists.txt
+--- psi4-1.11/external/upstream/qcmanybody/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/qcmanybody/CMakeLists.txt 2026-07-23 10:43:03.923229960 +0000
+@@ -1,41 +1,46 @@
+-if(NOT (${CMAKE_DISABLE_FIND_PACKAGE_qcmanybody}))
+- include(FindPythonModule)
+- find_python_module(qcmanybody ATLEAST 0.7.1 QUIET)
+-endif()
+-
+-if(${qcmanybody_FOUND})
+- message(STATUS "${Cyan}Found qcmanybody${ColourReset}: ${PY_qcmanybody} (found version ${qcmanybody_VERSION})")
+- add_library(qcmanybody_external INTERFACE) # dummy
+-
+- if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
+- message(VERBOSE "Suitable qcmanybody located externally as user insists")
++if(${ENABLE_qcmanybody})
++ if(NOT (${CMAKE_DISABLE_FIND_PACKAGE_qcmanybody}))
++ include(FindPythonModule)
++ find_python_module(qcmanybody ATLEAST 0.7.1 QUIET)
+ endif()
+
+-else()
+- if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
+- message(FATAL_ERROR "Suitable qcmanybody could not be externally located as user insists")
++ if(${qcmanybody_FOUND})
++ message(STATUS "${Cyan}Found qcmanybody${ColourReset}: ${PY_qcmanybody} (found version ${qcmanybody_VERSION})")
++ add_library(qcmanybody_external INTERFACE) # dummy
++
++ if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
++ message(VERBOSE "Suitable qcmanybody located externally as user insists")
++ endif()
++
++ else()
++ if(${CMAKE_INSIST_FIND_PACKAGE_qcmanybody})
++ message(FATAL_ERROR "Suitable qcmanybody could not be externally located as user insists")
++ endif()
++
++ include(ExternalProject)
++ message(STATUS "Suitable qcmanybody could not be located, ${Magenta}Building qcmanybody${ColourReset} instead.")
++
++ file(TO_NATIVE_PATH "${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${PYMOD_INSTALL_LIBDIR}" _install_lib)
++
++ # Must have specialty egg to compute version correctly, so the URL is only grabbing a dummy file. It's
++ # the pip command that's really selecting the source.
++ ExternalProject_Add(qcmanybody_external
++ DEPENDS qcelemental_external
++ qcengine_external
++ BUILD_ALWAYS 1
++ DOWNLOAD_COMMAND ""
++ CONFIGURE_COMMAND ""
++ UPDATE_COMMAND ""
++ BUILD_COMMAND ""
++ BUILD_IN_SOURCE 1
++ # master: INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/ QCManyBody.git#egg=proj
++ INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/QCManyBody.git@v0.7.1#egg=proj # edit in codedeps
++ --target=${_install_lib}
++ --no-deps
++ #-v
++ )
+ endif()
+-
+- include(ExternalProject)
+- message(STATUS "Suitable qcmanybody could not be located, ${Magenta}Building qcmanybody${ColourReset} instead.")
+-
+- file(TO_NATIVE_PATH "${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${PYMOD_INSTALL_LIBDIR}" _install_lib)
+-
+- # Must have specialty egg to compute version correctly, so the URL is only grabbing a dummy file. It's
+- # the pip command that's really selecting the source.
+- ExternalProject_Add(qcmanybody_external
+- DEPENDS qcelemental_external
+- qcengine_external
+- BUILD_ALWAYS 1
+- DOWNLOAD_COMMAND ""
+- CONFIGURE_COMMAND ""
+- UPDATE_COMMAND ""
+- BUILD_COMMAND ""
+- BUILD_IN_SOURCE 1
+- # master: INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/ QCManyBody.git#egg=proj
+- INSTALL_COMMAND ${Python_EXECUTABLE} -m pip install git+https://github.com/MolSSI/QCManyBody.git@v0.7.1#egg=proj # edit in codedeps
+- --target=${_install_lib}
+- --no-deps
+- #-v
+- )
++else()
++ message(STATUS "Optional addon ${Blue}unsought: qcmanybody${ColourReset} (deferrable to runtime)")
++ add_library(qcmanybody_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/external/upstream/simint/CMakeLists.txt.noqcmb psi4-1.11/external/upstream/simint/CMakeLists.txt
+--- psi4-1.11/external/upstream/simint/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/external/upstream/simint/CMakeLists.txt 2026-07-23 10:43:03.923383733 +0000
+@@ -54,5 +54,6 @@ if(${ENABLE_simint})
+ set(simint_DIR ${STAGED_INSTALL_PREFIX}/share/cmake/simint CACHE PATH "path to internally built simintConfig.cmake" FORCE)
+ endif()
+ else()
++ message(STATUS "Optional addon ${Blue}unsought: simint${ColourReset}")
+ add_library(simint_external INTERFACE) # dummy
+ endif()
+diff -up psi4-1.11/.github/workflows/docs-pr.yml.noqcmb psi4-1.11/.github/workflows/docs-pr.yml
+--- psi4-1.11/.github/workflows/docs-pr.yml.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/.github/workflows/docs-pr.yml 2026-07-23 10:43:03.917956046 +0000
+@@ -23,14 +23,14 @@ jobs:
+ # fetch-depth: 0 gets git history so Psi4 version computable
+ - name: Checkout
+ if: ${{ github.repository == 'psi4/psi4' }}
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ path: code
+
+ - name: Checkout psi4/psi4docs Repo
+ if: ${{ github.repository == 'psi4/psi4' }}
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ repository: psi4/psi4docs
+ path: docs
+diff -up psi4-1.11/.github/workflows/docs.yml.noqcmb psi4-1.11/.github/workflows/docs.yml
+--- psi4-1.11/.github/workflows/docs.yml.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/.github/workflows/docs.yml 2026-07-23 10:43:03.918128518 +0000
+@@ -33,14 +33,14 @@ jobs:
+ # fetch-depth: 0 gets git history so Psi4 version computable
+ - name: Checkout
+ if: ${{ github.repository == 'psi4/psi4' }}
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ path: code
+
+ - name: Checkout website repo
+ if: ${{ github.repository == 'psi4/psi4' }}
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ repository: psi4/psi4docs
+ path: docs
+diff -up psi4-1.11/.github/workflows/ecosystem.yml.noqcmb psi4-1.11/.github/workflows/ecosystem.yml
+--- psi4-1.11/.github/workflows/ecosystem.yml.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/.github/workflows/ecosystem.yml 2026-07-23 10:43:03.928705523 +0000
+@@ -151,7 +151,7 @@ jobs:
+
+ # fetch-depth: 0 gets git history so Psi4 version is computable
+ - name: Checkout Psi4
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+
+@@ -340,7 +340,7 @@ jobs:
+
+ - name: Special Config - Download MolSSI/QCFractal Repo
+ if: runner.os == 'Linux'
+- uses: actions/checkout@v4
++ uses: actions/checkout@v6
+ with:
+ repository: MolSSI/QCFractal
+ path: qca
+@@ -456,6 +456,26 @@ jobs:
+ conda install conda-tree -c conda-forge
+ conda-tree deptree
+
++ - name: dlopen -- Remove Addons
++ if: matrix.cfg.python-version == '3.14' && runner.os != 'Windows'
++ run: conda remove qcmanybody --force -y
++
++ - name: dlopen -- Runtime Conda environment
++ if: matrix.cfg.python-version == '3.14' && runner.os != 'Windows'
++ working-directory: ./objdir
++ run: |
++ conda info
++ conda list
++ PYTHONPATH=stage/lib python -c "import psi4; print(psi4.__file__)"
++
++ - name: dlopen -- Test Addons with Pytest
++ if: matrix.cfg.python-version == '3.14' && runner.os != 'Windows'
++ working-directory: ./objdir
++ run: |
++ export PYTHONPATH=stage/lib
++ pytest --cache-clear -v -rws --color yes -n auto -m qcmanybody stage/lib/psi4/tests/
++ pytest --cache-clear -v -rws --color yes -n auto -k missing stage/lib/psi4/tests/
++
+ # Notes
+ # -----
+
+diff -up psi4-1.11/psi4/CMakeLists.txt.noqcmb psi4-1.11/psi4/CMakeLists.txt
+--- psi4-1.11/psi4/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/psi4/CMakeLists.txt 2026-07-23 10:43:03.923562916 +0000
+@@ -140,7 +140,7 @@ if(${ENABLE_libefp})
+ #list(APPEND _addons ${_loc})
+ message(STATUS "${Cyan}Using pylibefp${ColourReset}: ${_loc} (version ${pylibefp_VERSION})")
+ else()
+- message(STATUS "Disabled libefp ${libefp_DIR} ${pylibefp_DIR}")
++ message(STATUS "Disabled libefp ${libefp_DIR} ${pylibefp_DIR} (deferrable to runtime)")
+ endif()
+
+ if(${ENABLE_Einsums})
+@@ -183,7 +183,7 @@ if(${ENABLE_gdma})
+ get_property(_loc TARGET gdma::pygdma PROPERTY LOCATION)
+ message(STATUS "${Cyan}Found gdma${ColourReset}: ${_loc} (version ${gdma_VERSION})")
+ else()
+- message(STATUS "Disabled gdma ${gdma_DIR}")
++ message(STATUS "Disabled gdma ${gdma_DIR} (deferrable to runtime)")
+ endif()
+
+ find_package(Libint2 2.8.1 CONFIG REQUIRED # edit in codedeps
+@@ -209,7 +209,7 @@ if(${ENABLE_mdi})
+ list(APPEND _addons ${_loc})
+ message(STATUS "${Cyan}Using mdi${ColourReset}: ${_loc} (version ${mdi_VERSION})")
+ else()
+- message(STATUS "Disabled MDI ${mdi_DIR}")
++ message(STATUS "Disabled MDI ${mdi_DIR} (deferrable to runtime)")
+ endif ()
+
+ if(${ENABLE_OpenOrbitalOptimizer})
+diff -up psi4-1.11/psi4/driver/driver_nbody.py.noqcmb psi4-1.11/psi4/driver/driver_nbody.py
+--- psi4-1.11/psi4/driver/driver_nbody.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/psi4/driver/driver_nbody.py 2026-07-23 10:43:03.928197256 +0000
+@@ -118,10 +118,32 @@ from .task_base import AtomicComputer, E
+ from pydantic import field_validator
+
+ from qcelemental.models.v2 import Molecule, AtomicSpecification
+-from qcmanybody.models.v2 import ManyBodyInput, ManyBodyResult, BsseEnum
+-from qcmanybody import ManyBodyCore
+-from qcmanybody.v2 import ManyBodyComputer as ManyBodyComputerQCNG
+-from qcmanybody.utils import delabeler, labeler, translate_qcvariables, modelchem_labels
++
++_QCMANYBODY_IMPORT_ERROR = None
++try:
++ from qcmanybody.models.v2 import ManyBodyInput, ManyBodyResult, BsseEnum
++ from qcmanybody import ManyBodyCore
++ from qcmanybody.v2 import ManyBodyComputer as ManyBodyComputerQCNG
++ from qcmanybody.utils import delabeler, labeler, translate_qcvariables, modelchem_labels
++except ImportError as err:
++ _QCMANYBODY_IMPORT_ERROR = err
++ ManyBodyInput = Any
++ ManyBodyResult = Any
++ BsseEnum = Any
++ ManyBodyCore = Any
++ ManyBodyComputerQCNG = object
++
++
++def _ensure_qcmanybody() -> None:
++ if _QCMANYBODY_IMPORT_ERROR is None:
++ return
++
++ raise ModuleNotFoundError(
++ "Python module qcmanybody not found (or incompatible) that is required for many-body/counterpoise "
++ "(`bsse_type`) computations. Install/upgrade to `qcmanybody>=0.7.1` with "
++ "`conda install -c conda-forge qcmanybody` or `pip install -U qcmanybody`. "
++ f"Original import error: {_QCMANYBODY_IMPORT_ERROR}"
++ ) from _QCMANYBODY_IMPORT_ERROR
+
+ if TYPE_CHECKING:
+ import qcportal
+@@ -411,6 +433,8 @@ class ManyBodyComputer(ManyBodyComputerQ
+ @classmethod
+ def from_psi4_task_planner(cls, *, molecule, method, basis, driver, keywords, **mbkwargs):
+
++ _ensure_qcmanybody()
++
+ atomic_spec = AtomicSpecification(
+ model={"method": method, "basis": basis},
+ program="psi4",
+@@ -505,6 +529,8 @@ class ManyBodyComputer(ManyBodyComputerQ
+ Number of new tasks planned by this call including any supersystem.
+
+ """
++ _ensure_qcmanybody()
++
+ # TODO method not coming from levels right
+
+ # Get the n-body orders for this level. e.g., [1] or [2, 3] or ["supersystem"]
+@@ -574,6 +600,8 @@ class ManyBodyComputer(ManyBodyComputerQ
+ All MBE results collected into a QCSchema model.
+
+ """
++ _ensure_qcmanybody()
++
+ component_results = {k: v.get_results(client=client).convert_v(2) for k, v in self.task_list.items()}
+ component_properties = {}
+ props = {"energy", "gradient", "hessian"}
+diff -up psi4-1.11/psi4/extras.py.noqcmb psi4-1.11/psi4/extras.py
+--- psi4-1.11/psi4/extras.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/psi4/extras.py 2026-07-23 10:43:03.829627156 +0000
+@@ -180,6 +180,7 @@ _addons_ = {
+ "gauxc": _CMake_to_Py_boolean("@ENABLE_gauxc@"),
+ "integratorxx": _CMake_to_Py_boolean("@ENABLE_IntegratorXX@"),
+ "ooo": _CMake_to_Py_boolean("@ENABLE_OpenOrbitalOptimizer@"),
++ "qcmanybody": which_import("qcmanybody", return_bool=True),
+ }
+
+
+diff -up psi4-1.11/psi4/__init__.py.noqcmb psi4-1.11/psi4/__init__.py
+--- psi4-1.11/psi4/__init__.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/psi4/__init__.py 2026-07-23 10:43:03.925174398 +0000
+@@ -109,18 +109,14 @@ from .driver.schema_wrapper import run_q
+ # * Note that this is a "battening down the hatches" for the many
+ # rather than letting PYTHONPATH rule for the few.
+ import sys
+-if "@ENABLE_PCMSolver@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # PCMSolver
++_enabled_choice = ("1", "ON", "YES", "TRUE", "Y")
++if "@ENABLE_PCMSolver@".upper() in _enabled_choice: # PCMSolver
+ sys.path.insert(1, r"@PCMSolver_PYMOD@")
+-if "@ENABLE_cppe@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # cppe
+- sys.path.insert(1, r"@cppe_PYMOD@")
+-if "@ENABLE_ddx@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # pyddx
+- sys.path.insert(1, r"@pyddx_PYMOD@")
+-if "@ENABLE_libefp@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # pylibefp
+- sys.path.insert(1, r"@pylibefp_PYMOD@")
+-if "@ENABLE_gdma@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # gdma
++if "@ENABLE_libefp@".upper() in _enabled_choice: # pylibefp
++ sys.path.insert(1, str(Path(r"@PY_pylibefp@").resolve().parent))
++if "@ENABLE_gdma@".upper() in _enabled_choice: # gdma
+ sys.path.insert(1, r"@gdma_PYMOD@")
+-if "@ENABLE_bse@".upper() in ["1", "ON", "YES", "TRUE", "Y"]: # bse
+- sys.path.insert(1, r"@bse_PYMOD@")
++del _enabled_choice
+
+ # Create a custom logger
+ import logging
+diff -up psi4-1.11/pytest.ini.noqcmb psi4-1.11/pytest.ini
+--- psi4-1.11/pytest.ini.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/pytest.ini 2026-07-23 10:43:03.829833903 +0000
+@@ -93,7 +93,7 @@ markers =
+ mints
+ mom
+ mp2
+- nbody: "tests that use the nbody aka manybody wrapper"
++ nbody: "tests that use the nbody aka manybody wrapper; alias to qcmanybody marker"
+ noc1
+ numint: "tests that use NumIntHelper"
+ numpy
+@@ -181,6 +181,7 @@ markers =
+ qcfractal: "tests using QCFractal software; skip if unavailable"
+ qcfractal_next: "tests using QCFractal software, next branch; skip if unavailable"
+ qcportal: "tests using QCPortal software; skip if unavailable"
++ qcmanybody: "tests using QCManyBody software; skip if unavailable; alias to nbody marker"
+ psi4
+
+
+@@ -188,4 +189,3 @@ markers =
+ # filterwarnings =
+ # error
+ # ignore:unclosed file:ResourceWarning
+-
+diff -up psi4-1.11/tests/cbs-xtpl-nbody/test_input.py.noqcmb psi4-1.11/tests/cbs-xtpl-nbody/test_input.py
+--- psi4-1.11/tests/cbs-xtpl-nbody/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/cbs-xtpl-nbody/test_input.py 2026-07-23 10:43:03.829993598 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("cbs;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("cbs")
+ def test_cbs_xtpl_nbody():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/cfour/CMakeLists.txt.noqcmb psi4-1.11/tests/cfour/CMakeLists.txt
+--- psi4-1.11/tests/cfour/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/cfour/CMakeLists.txt 2026-07-23 10:43:03.906575105 +0000
+@@ -20,7 +20,9 @@ add_subdirectory(scf4)
+ add_subdirectory(mp2-1)
+ add_subdirectory(pywrap-db1)
+ add_subdirectory(pywrap-basis)
+-add_subdirectory(dfmp2-1)
++if(ENABLE_qcmanybody)
++ add_subdirectory(dfmp2-1)
++endif()
+ add_subdirectory(sp-rhf-scf)
+ add_subdirectory(sp-rhf-mp2)
+ add_subdirectory(sp-rhf-ccsd)
+diff -up psi4-1.11/tests/CMakeLists.txt.noqcmb psi4-1.11/tests/CMakeLists.txt
+--- psi4-1.11/tests/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/CMakeLists.txt 2026-07-23 10:43:03.906233614 +0000
+@@ -32,7 +32,7 @@
+ foreach(test_name aediis-1
+ casscf-fzc-sp casscf-semi casscf-sa-sp ao-casscf-sp casscf-sp castup1
+ castup2 castup3 cbs-delta-energy cbs-parser cbs-xtpl-alpha cbs-xtpl-energy
+- cbs-xtpl-freq cbs-xtpl-gradient cbs-xtpl-opt cbs-xtpl-func cbs-xtpl-nbody
++ cbs-xtpl-freq cbs-xtpl-gradient cbs-xtpl-opt cbs-xtpl-func
+ cbs-xtpl-wrapper cbs-xtpl-dict cc1 cc10 cc11 cc12 cc13 cc13a cc13b cc13c
+ cc13d cc14 cc15 cc16 cc17 cc18 cc19 cc2 cc21 cc22 cc23 cc24 cc25 cc26 cc27 cc28
+ cc29 cc3 cc30 cc31 cc32 cc33 cc34 cc35 cc36 cc37 cc38 cc39
+@@ -46,7 +46,7 @@ foreach(test_name aediis-1
+ dct10 dct11 dct12 ao-dfcasscf-sp density-screen-1 density-screen-2 dfcasscf-sa-sp
+ dfcasscf-fzc-sp dfcasscf-sp dfccd1 dfccdl1 dfccd-grad1 dfccsd1 dfccsdl1 dfccsd-grad1
+ dfccsd-t-grad1
+- dfccsdt1 dfccsdat1 dfmp2-1 dfmp2-2 dfmp2-3 dfmp2-4 dfmp2-5 dfmp2-fc dfmp2-freq1 dfmp2-freq2
++ dfccsdt1 dfccsdat1 dfmp2-2 dfmp2-3 dfmp2-4 dfmp2-5 dfmp2-freq1 dfmp2-freq2
+ dfccsd-grad2 dfccsd-t-grad2 dfccsdat2 dfccsdt2
+ dfmp2-grad1 dfmp2-grad2 dfmp2-grad3 dfmp2-grad4 dfmp2-grad5 dfomp2-1 dfomp2-2 dfomp2-3
+ dfomp2-4 dfomp2-grad1 dfomp2-grad2 dfomp2-grad3 dfomp3-1 dfomp3-2
+@@ -70,10 +70,8 @@ foreach(test_name aediis-1
+ mbis-1 mbis-2 mbis-3 mbis-4 mbis-5 mbis-6 mbis-7 mcscf1 mcscf2 mcscf3
+ mints1 mints2 mints3 mints4 mints5 mints6 mints8 mints-benchmark mints-helper
+ mints9 mints10 mints15 molden1 molden2 mom mom-h2o-3 mom-h2o-4
+- mp2-1 mp2-def2 mp2-grad1 mp2-grad2 mp2-grad3 mp2-h mp2p5-grad1 mp2p5-grad2 mp3-grad1 mp3-grad2
+- mp2-property mp2f12-1 mpn-bh nbody-he-cluster nbody-intermediates nbody-nocp-gradient
+- nbo nbody-cp-gradient nbody-vmfc-gradient nbody-vmfc-hessian nbody-hessian nbody-convergence
+- nbody-freq nbody-multi-level nbody-multi-level-2 numint1 numpy-array-interface
++ mp2-1 mp2-grad1 mp2-grad2 mp2-grad3 mp2-h mp2p5-grad1 mp2p5-grad2 mp3-grad1 mp3-grad2
++ mp2-property mp2f12-1 mpn-bh nbo numint1 numpy-array-interface
+ olccd-freq1 olccd-grad1 olccd-grad2 olccd1 olccd2 olccd3
+ omp2-1 omp2-2 omp2-3 omp2-4 omp2-5 omp2-grad1 omp2-grad2
+ omp2p5-1 omp2p5-2 omp2p5-grad1 omp2p5-grad2 omp3-1 omp3-2
+@@ -101,14 +99,14 @@ foreach(test_name aediis-1
+ soscf-dft stability1 dfep2-1 dfep2-2 sapt-dft1 sapt-dft2 sapt-compare sapt-sf1 dft-custom dft-reference
+ stability2 stability3 tu1-h2o-energy tu2-ch2-energy tu3-h2o-opt scf-response1 scf-response2 scf-response3
+ scf-cholesky-basis scf-auto-cholesky
+- tu4-h2o-freq tu5-sapt tu6-cp-ne2 x2c1 x2c2 x2c3 x2c-perturb-h zaptn-nh2 zora
++ tu4-h2o-freq tu5-sapt x2c1 x2c2 x2c3 x2c-perturb-h zaptn-nh2 zora
+ options1 cubeprop-esp dft-smoke scf-hess1 scf-hess2 scf-hess3 scf-hess4 scf-hess5 scf-freq1 dft-jk scf-coverage
+- dft-custom-dhdf dft-custom-hybrid dft-custom-mgga dft-custom-gga
++ dft-custom-hybrid dft-custom-mgga dft-custom-gga
+ pywrap-bfs pywrap-align pywrap-align-chiral mints12 cc-module
+ tdscf-1 tdscf-2 tdscf-3 tdscf-4 tdscf-5 tdscf-6 tdscf-7
+ dft-pruning freq-masses sapt9 sapt10 sapt11 scf-uhf-grad-nobeta
+ linK-1 linK-2 linK-3
+- cbs-xtpl-energy-conv ddd-deriv nbody-he-4b ddd-function-kwargs dfmp2f12-1
++ cbs-xtpl-energy-conv ddd-deriv dfmp2f12-1
+ )
+ add_subdirectory(${test_name})
+ endforeach()
+@@ -280,7 +278,9 @@ endif()
+ if(ENABLE_ecpint)
+ add_subdirectory(aediis-2)
+ add_subdirectory(basis-ecp)
+- add_subdirectory(dfmp2-ecp)
++ if(ENABLE_qcmanybody)
++ add_subdirectory(dfmp2-ecp)
++ endif()
+ add_subdirectory(sapt-ecp)
+ add_subdirectory(scf-ecp)
+ add_subdirectory(scf-ecp2)
+@@ -289,6 +289,32 @@ if(ENABLE_ecpint)
+ message(STATUS "Adding test cases: Psi4 + ecpint")
+ endif()
+
++# <<< QCManyBody >>>
++
++if(ENABLE_qcmanybody)
++ add_subdirectory(cbs-xtpl-nbody)
++ add_subdirectory(ddd-function-kwargs)
++ add_subdirectory(dfmp2-1)
++ add_subdirectory(dfmp2-fc)
++ add_subdirectory(dft-custom-dhdf)
++ add_subdirectory(dlpnocc-3)
++ add_subdirectory(mp2-def2)
++ add_subdirectory(nbody-convergence)
++ add_subdirectory(nbody-cp-gradient)
++ add_subdirectory(nbody-freq)
++ add_subdirectory(nbody-he-4b)
++ add_subdirectory(nbody-he-cluster)
++ add_subdirectory(nbody-hessian)
++ add_subdirectory(nbody-intermediates)
++ add_subdirectory(nbody-multi-level)
++ add_subdirectory(nbody-multi-level-2)
++ add_subdirectory(nbody-nocp-gradient)
++ add_subdirectory(nbody-vmfc-gradient)
++ add_subdirectory(nbody-vmfc-hessian)
++ add_subdirectory(tu6-cp-ne2)
++ message(STATUS "Adding test cases: Psi4 + qcmanybody")
++endif()
++
+ # plugin regime
+ if(ENABLE_PLUGIN_TESTING)
+ add_subdirectory(plugins)
+diff -up psi4-1.11/tests/ddd-function-kwargs/test_input.py.noqcmb psi4-1.11/tests/ddd-function-kwargs/test_input.py
+--- psi4-1.11/tests/ddd-function-kwargs/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/ddd-function-kwargs/test_input.py 2026-07-23 10:43:03.830118208 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("findif;nbody;gradient")
++@uusing("qcmanybody")
++@ctest_labeler("findif;gradient")
+ def test_ddd_function_kwargs():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/dfmp2-1/test_input.py.noqcmb psi4-1.11/tests/dfmp2-1/test_input.py
+--- psi4-1.11/tests/dfmp2-1/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dfmp2-1/test_input.py 2026-07-23 10:43:03.830241091 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("quick;smoke;df;dfmp2;cart;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("quick;smoke;df;dfmp2;cart")
+ def test_dfmp2_1():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/dfmp2-ecp/test_input.py.noqcmb psi4-1.11/tests/dfmp2-ecp/test_input.py
+--- psi4-1.11/tests/dfmp2-ecp/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dfmp2-ecp/test_input.py 2026-07-23 10:43:03.830365941 +0000
+@@ -2,7 +2,8 @@ import pytest
+ from addons import *
+
+ @uusing("ecpint")
+-@ctest_labeler("quick;df;dfmp2;ecp;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("quick;df;dfmp2;ecp")
+ @pytest.mark.parametrize("oopkg", [
+ pytest.param(False, id="internal"),
+ pytest.param(True, id="openorbitaloptimizer", marks=using("ooo")),
+diff -up psi4-1.11/tests/dfmp2-fc/test_input.py.noqcmb psi4-1.11/tests/dfmp2-fc/test_input.py
+--- psi4-1.11/tests/dfmp2-fc/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dfmp2-fc/test_input.py 2026-07-23 10:43:03.830490551 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("quick;df;dfmp2;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("quick;df;dfmp2")
+ def test_dfmp2_fc():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/dft-custom-dhdf/test_input.py.noqcmb psi4-1.11/tests/dft-custom-dhdf/test_input.py
+--- psi4-1.11/tests/dft-custom-dhdf/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dft-custom-dhdf/test_input.py 2026-07-23 10:43:03.830618553 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("dft;scf;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("dft;scf")
+ def test_dft_custom_dhdf():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/dftd3/CMakeLists.txt.noqcmb psi4-1.11/tests/dftd3/CMakeLists.txt
+--- psi4-1.11/tests/dftd3/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dftd3/CMakeLists.txt 2026-07-23 10:43:03.906712877 +0000
+@@ -2,4 +2,6 @@ add_subdirectory(energy)
+ add_subdirectory(grad)
+ add_subdirectory(psithon2)
+ add_subdirectory(version)
+-add_subdirectory(nbody-cp-gradient)
++if(ENABLE_qcmanybody)
++ add_subdirectory(nbody-cp-gradient)
++endif()
+diff -up psi4-1.11/tests/dftd3/nbody-cp-gradient/test_input.py.noqcmb psi4-1.11/tests/dftd3/nbody-cp-gradient/test_input.py
+--- psi4-1.11/tests/dftd3/nbody-cp-gradient/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dftd3/nbody-cp-gradient/test_input.py 2026-07-23 10:43:03.830801705 +0000
+@@ -1,6 +1,7 @@
+ from addons import *
+
+ @uusing("dftd3")
+-@ctest_labeler("cart;nbody;gradient")
++@uusing("qcmanybody")
++@ctest_labeler("cart;gradient")
+ def test_dftd3_nbody_cp_gradient():
+ ctest_runner(__file__)
+diff -up psi4-1.11/tests/dlpnocc-3/CMakeLists.txt.noqcmb psi4-1.11/tests/dlpnocc-3/CMakeLists.txt
+--- psi4-1.11/tests/dlpnocc-3/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dlpnocc-3/CMakeLists.txt 2026-07-23 10:43:03.906874829 +0000
+@@ -1,3 +1,3 @@
+ include(TestingMacros)
+
+-add_regression_test(dlpnocc-3 "psi;dlpno;cc;quick")
+\ No newline at end of file
++add_regression_test(dlpnocc-3 "psi;dlpno;cc;quick")
+diff -up psi4-1.11/tests/dlpnocc-3/test_input.py.noqcmb psi4-1.11/tests/dlpnocc-3/test_input.py
+--- psi4-1.11/tests/dlpnocc-3/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/dlpnocc-3/test_input.py 2026-07-23 10:43:03.909042167 +0000
+@@ -1,5 +1,6 @@
+ from addons import *
+
++@uusing("qcmanybody")
+ @ctest_labeler("dlpno;cc;quick")
+ def test_dlpnocc_3():
+- ctest_runner(__file__)
+\ No newline at end of file
++ ctest_runner(__file__)
+diff -up psi4-1.11/tests/gcp/CMakeLists.txt.noqcmb psi4-1.11/tests/gcp/CMakeLists.txt
+--- psi4-1.11/tests/gcp/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/gcp/CMakeLists.txt 2026-07-23 10:43:03.909174652 +0000
+@@ -1,5 +1,7 @@
+ add_subdirectory(pbeh3c)
+-add_subdirectory(hf3c)
++if (ENABLE_qcmanybody)
++ add_subdirectory(hf3c)
++endif()
+ add_subdirectory(hf3c-gradient)
+ add_subdirectory(hf3c-hessian)
+ add_subdirectory(dft-custom-hybrid)
+diff -up psi4-1.11/tests/gcp/hf3c/test_input.py.noqcmb psi4-1.11/tests/gcp/hf3c/test_input.py
+--- psi4-1.11/tests/gcp/hf3c/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/gcp/hf3c/test_input.py 2026-07-23 10:43:03.909313094 +0000
+@@ -1,5 +1,6 @@
+ from addons import *
+
++@uusing("qcmanybody")
+ @uusing("gcp")
+ @uusing("dftd3")
+ @ctest_labeler("quick;smoke")
+diff -up psi4-1.11/tests/mp2-def2/test_input.py.noqcmb psi4-1.11/tests/mp2-def2/test_input.py
+--- psi4-1.11/tests/mp2-def2/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/mp2-def2/test_input.py 2026-07-23 10:43:03.830928242 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("mp2;cart;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("mp2;cart")
+ def test_mp2_def2():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-convergence/test_input.py.noqcmb psi4-1.11/tests/nbody-convergence/test_input.py
+--- psi4-1.11/tests/nbody-convergence/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-convergence/test_input.py 2026-07-23 10:43:03.831049950 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;gradient")
++@uusing("qcmanybody")
++@ctest_labeler("gradient")
+ def test_nbody_convergence():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-cp-gradient/test_input.py.noqcmb psi4-1.11/tests/nbody-cp-gradient/test_input.py
+--- psi4-1.11/tests/nbody-cp-gradient/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-cp-gradient/test_input.py 2026-07-23 10:43:03.831174042 +0000
+@@ -1,12 +1,12 @@
+ import pytest
+ from addons import *
+
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("distributed", [
+ pytest.param(False, id="internal"),
+ pytest.param(True, id="snowflake", marks=using("qcfractal_next")),
+ ])
+-@ctest_labeler("nbody;gradient")
++@ctest_labeler("gradient")
+ def test_nbody_cp_gradient(distributed):
+ setenv = ["_PSI4_USE_QCF"] if distributed else None
+ ctest_runner(__file__, setenv=setenv)
+-
+diff -up psi4-1.11/tests/nbody-freq/test_input.py.noqcmb psi4-1.11/tests/nbody-freq/test_input.py
+--- psi4-1.11/tests/nbody-freq/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-freq/test_input.py 2026-07-23 10:43:03.831297430 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;freq;hessian;gradient;opt")
++@uusing("qcmanybody")
++@ctest_labeler("freq;hessian;gradient;opt")
+ def test_nbody_freq():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-he-4b/test_input.py.noqcmb psi4-1.11/tests/nbody-he-4b/test_input.py
+--- psi4-1.11/tests/nbody-he-4b/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-he-4b/test_input.py 2026-07-23 10:43:03.831420061 +0000
+@@ -1,12 +1,12 @@
+ import pytest
+ from addons import *
+
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("distributed", [
+ pytest.param(False, id="internal"),
+ pytest.param(True, id="snowflake", marks=using("qcfractal_next")),
+ ])
+-@ctest_labeler("nbody;cart")
++@ctest_labeler("cart")
+ def test_nbody_he_4b(distributed):
+ setenv = ["_PSI4_USE_QCF"] if distributed else None
+ ctest_runner(__file__, setenv=setenv)
+-
+diff -up psi4-1.11/tests/nbody-he-cluster/test_input.py.noqcmb psi4-1.11/tests/nbody-he-cluster/test_input.py
+--- psi4-1.11/tests/nbody-he-cluster/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-he-cluster/test_input.py 2026-07-23 10:43:03.831541486 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;cart")
++@uusing("qcmanybody")
++@ctest_labeler("cart")
+ def test_nbody_he_cluster():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-hessian/test_input.py.noqcmb psi4-1.11/tests/nbody-hessian/test_input.py
+--- psi4-1.11/tests/nbody-hessian/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-hessian/test_input.py 2026-07-23 10:43:03.831665428 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;hessian")
++@uusing("qcmanybody")
++@ctest_labeler("hessian")
+ def test_nbody_hessian():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-intermediates/CMakeLists.txt.noqcmb psi4-1.11/tests/nbody-intermediates/CMakeLists.txt
+--- psi4-1.11/tests/nbody-intermediates/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-intermediates/CMakeLists.txt 2026-07-23 10:43:03.907163741 +0000
+@@ -1,3 +1,3 @@
+ include(TestingMacros)
+
+-add_regression_test(nbody-intermediates "psi;nbody")
++add_regression_test(nbody-intermediates "psi;nbody")
+diff -up psi4-1.11/tests/nbody-intermediates/test_input.py.noqcmb psi4-1.11/tests/nbody-intermediates/test_input.py
+--- psi4-1.11/tests/nbody-intermediates/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-intermediates/test_input.py 2026-07-23 10:43:03.831820726 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody")
++@uusing("qcmanybody")
++@ctest_labeler("")
+ def test_nbody_intermediates():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-multi-level-2/test_input.py.noqcmb psi4-1.11/tests/nbody-multi-level-2/test_input.py
+--- psi4-1.11/tests/nbody-multi-level-2/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-multi-level-2/test_input.py 2026-07-23 10:43:03.831945212 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody")
++@uusing("qcmanybody")
++@ctest_labeler("")
+ def test_nbody_multi_level_2():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-multi-level/input.dat.noqcmb psi4-1.11/tests/nbody-multi-level/input.dat
+--- psi4-1.11/tests/nbody-multi-level/input.dat.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-multi-level/input.dat 2026-07-23 10:43:03.926832837 +0000
+@@ -24,7 +24,7 @@ units bohr
+ set cc_type df
+ set df_basis_mp2 def2-qzvpp-ri # not a recommendation. present to compensate for change in default
+
+-species_comparison_dict = {"§A_(2)@(2)": -74.9994424129044, "§B_(2)@(2)": -74.96344779297539}
++species_comparison_dict = {f"{chr(0xA7)}A_(2)@(2)": -74.9994424129044, f"{chr(0xA7)}B_(2)@(2)": -74.96344779297539}
+ species_comparison_dict = {f"n-body {k} total energy": v for k, v in species_comparison_dict.items()} #TEST
+
+ # Compute 1-body contribution with ccsd(t) and 2-body contribution with mp2
+diff -up psi4-1.11/tests/nbody-multi-level/test_input.py.noqcmb psi4-1.11/tests/nbody-multi-level/test_input.py
+--- psi4-1.11/tests/nbody-multi-level/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-multi-level/test_input.py 2026-07-23 10:43:03.832075734 +0000
+@@ -1,7 +1,8 @@
+ import pytest
+ from addons import *
+
+-@ctest_labeler("nbody;extern")
++@uusing("qcmanybody")
++@ctest_labeler("extern")
+ @pytest.mark.parametrize("distributed", [
+ pytest.param(False, id="internal"),
+ pytest.param(True, id="snowflake", marks=[*using("qcfractal_next"), pytest.mark.medlong]),
+@@ -10,4 +11,3 @@ def test_nbody_multi_level(distributed,
+ setenv = ["_PSI4_USE_QCF"] if distributed else None
+ monkeypatch.setenv("QCMANYBODY_EMBEDDING_CHARGES", "1")
+ ctest_runner(__file__, setenv=setenv)
+-
+diff -up psi4-1.11/tests/nbody-nocp-gradient/test_input.py.noqcmb psi4-1.11/tests/nbody-nocp-gradient/test_input.py
+--- psi4-1.11/tests/nbody-nocp-gradient/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-nocp-gradient/test_input.py 2026-07-23 10:43:03.832207967 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;gradient")
++@uusing("qcmanybody")
++@ctest_labeler("gradient")
+ def test_nbody_nocp_gradient():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-vmfc-gradient/test_input.py.noqcmb psi4-1.11/tests/nbody-vmfc-gradient/test_input.py
+--- psi4-1.11/tests/nbody-vmfc-gradient/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-vmfc-gradient/test_input.py 2026-07-23 10:43:03.832329523 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("nbody;gradient")
++@uusing("qcmanybody")
++@ctest_labeler("gradient")
+ def test_nbody_vmfc_gradient():
+ ctest_runner(__file__)
+-
+diff -up psi4-1.11/tests/nbody-vmfc-hessian/test_input.py.noqcmb psi4-1.11/tests/nbody-vmfc-hessian/test_input.py
+--- psi4-1.11/tests/nbody-vmfc-hessian/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/nbody-vmfc-hessian/test_input.py 2026-07-23 10:43:03.832457609 +0000
+@@ -1,7 +1,8 @@
+ import pytest
+ from addons import *
+
+-@ctest_labeler("nbody;hessian;d2ints")
++@uusing("qcmanybody")
++@ctest_labeler("hessian;d2ints")
+
+ @pytest.mark.parametrize("distributed", [
+ pytest.param(False, id="internal"),
+@@ -10,4 +11,3 @@ from addons import *
+ def test_nbody_vmfc_hessian(distributed):
+ setenv = ["_PSI4_USE_QCF"] if distributed else None
+ ctest_runner(__file__, setenv=setenv)
+-
+diff -up psi4-1.11/tests/pcmsolver/CMakeLists.txt.noqcmb psi4-1.11/tests/pcmsolver/CMakeLists.txt
+--- psi4-1.11/tests/pcmsolver/CMakeLists.txt.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pcmsolver/CMakeLists.txt 2026-07-23 10:43:03.926106672 +0000
+@@ -3,7 +3,9 @@ add_subdirectory(dipole)
+ add_subdirectory(scf)
+ add_subdirectory(opt-fd)
+ add_subdirectory(ccsd-pte)
+-add_subdirectory(ghost)
++if (ENABLE_qcmanybody)
++ add_subdirectory(ghost)
++endif()
+ add_subdirectory(alpha)
+ add_subdirectory(tdscf)
+ add_subdirectory(uhf-tdscf)
+diff -up psi4-1.11/tests/pcmsolver/ghost/test_input.py.noqcmb psi4-1.11/tests/pcmsolver/ghost/test_input.py
+--- psi4-1.11/tests/pcmsolver/ghost/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pcmsolver/ghost/test_input.py 2026-07-23 10:43:03.909452883 +0000
+@@ -1,5 +1,6 @@
+ from addons import *
+
++@uusing("qcmanybody")
+ @uusing("pcmsolver")
+ @ctest_labeler("quick;smoke;ghosts")
+ def test_pcmsolver_ghost():
+diff -up psi4-1.11/tests/pytests/addons.py.noqcmb psi4-1.11/tests/pytests/addons.py
+--- psi4-1.11/tests/pytests/addons.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/addons.py 2026-07-23 10:43:03.917720783 +0000
+@@ -90,6 +90,7 @@ _programs = {
+ "qcfractal": which_import("qcfractal", return_bool=True),
+ "qcfractal_next": is_qcfractal_new_enough("0.49"),
+ "qcportal": which_import("qcportal", return_bool=True),
++ "qcmanybody": which_import("qcmanybody", return_bool=True),
+ "bse": which_import("basis_set_exchange", return_bool=True),
+ "einsums": psi4.addons("einsums"),
+ "pyeinsums": which_import("einsums", return_bool=True),
+@@ -126,7 +127,10 @@ def _using(program: str) -> None:
+ general = pytest.mark.addon
+ particular = getattr(pytest.mark, program)
+
+- all_marks = (skip, general, particular)
++ if program == "qcmanybody":
++ all_marks = (skip, general, particular, getattr(pytest.mark, "nbody"))
++ else:
++ all_marks = (skip, general, particular)
+ _using_cache[program] = [_compose_decos(all_marks), all_marks]
+
+
+@@ -200,6 +204,10 @@ def ctest_runner(inputdatloc, *, extra_i
+ else:
+ env["PYTHONPATH"] = str(psiimport)
+
++ # On Windows, ensure UTF-8 encoding for stdout to handle section symbols and other Unicode
++ if sys.platform.startswith("win"):
++ env["PYTHONIOENCODING"] = "utf-8"
++
+ if setenv:
+ for ev in setenv:
+ env[ev] = "1"
+diff -up psi4-1.11/tests/pytests/test_addons.py.noqcmb psi4-1.11/tests/pytests/test_addons.py
+--- psi4-1.11/tests/pytests/test_addons.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_addons.py 2026-07-23 10:43:03.832923591 +0000
+@@ -913,7 +913,7 @@ def test_gpu_dfcc():
+
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @uusing("dftd3")
+ @uusing("gcp")
+ def test_grimme_3c():
+diff -up psi4-1.11/tests/pytests/test_addons_qcschema.py.noqcmb psi4-1.11/tests/pytests/test_addons_qcschema.py
+--- psi4-1.11/tests/pytests/test_addons_qcschema.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_addons_qcschema.py 2026-07-23 10:43:03.833354891 +0000
+@@ -680,7 +680,7 @@ def test_v2rdm_casscf(schver):
+ # assert psi4.compare_values(en_gpu_dfcc, en_dfcc, 8, "CCSD total energy")
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @uusing("dftd3")
+ @uusing("gcp")
+ @pytest.mark.parametrize("schver", [pytest.param(1, marks=[pytest.mark.skipif(_ispy314, reason="Py314+QCSk1")]), pytest.param(2)])
+diff -up psi4-1.11/tests/pytests/test_compositejk.py.noqcmb psi4-1.11/tests/pytests/test_compositejk.py
+--- psi4-1.11/tests/pytests/test_compositejk.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_compositejk.py 2026-07-23 10:43:03.833806034 +0000
+@@ -111,7 +111,7 @@ def test_composite_call(j_algo, k_algo,
+ "molecule" : "h2o_nap1",
+ "bsse_type" : "CP",
+ },
+- marks=pytest.mark.nbody,
++ marks=using("qcmanybody"),
+ id="h2o/na+ (rhf ie)"),
+ ],
+ )
+@@ -213,7 +213,7 @@ def test_seminum(inp, scf, mols, request
+ "molecule" : "h2o_nap1",
+ "bsse_type" : "CP",
+ },
+- marks=pytest.mark.nbody,
++ marks=using("qcmanybody"),
+ id="h2o/na+ (rhf ie)"),
+ ],
+ )
+diff -up psi4-1.11/tests/pytests/test_dft_benchmarks.py.noqcmb psi4-1.11/tests/pytests/test_dft_benchmarks.py
+--- psi4-1.11/tests/pytests/test_dft_benchmarks.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_dft_benchmarks.py 2026-07-23 10:43:03.834022531 +0000
+@@ -2,7 +2,7 @@ import numpy as np
+
+ import pytest
+ from utils import *
+-from addons import using
++from addons import using, uusing
+
+ import psi4
+
+@@ -176,7 +176,7 @@ def test_dft_bench_ionization(func, expe
+
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @pytest.mark.scf
+ @pytest.mark.dft
+ @pytest.mark.long
+diff -up psi4-1.11/tests/pytests/test_dftd3.py.noqcmb psi4-1.11/tests/pytests/test_dftd3.py
+--- psi4-1.11/tests/pytests/test_dftd3.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_dftd3.py 2026-07-23 10:43:03.834206292 +0000
+@@ -113,7 +113,7 @@ s16_r2scanh_psi4 = np.array([-155.681254
+ s16_r2scan50_psi4 = np.array([-155.6575747, -78.4586347, -77.1962996])
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("mode", [
+ pytest.param("abs", marks=pytest.mark.long),
+ pytest.param("ie", marks=pytest.mark.quick),
+@@ -185,4 +185,3 @@ def test_grimme_3c(mtdbas, ref, mode):
+
+ ene = psi4.energy(mtdbas, bsse_type='nocp')
+ assert psi4.compare_values(kcal * (ref[0] - ref[1] - ref[2]), kcal * ene, 1.1e-3, mtdbas)
+-
+diff -up psi4-1.11/tests/pytests/test_missing_qcmanybody.py.noqcmb psi4-1.11/tests/pytests/test_missing_qcmanybody.py
+--- psi4-1.11/tests/pytests/test_missing_qcmanybody.py.noqcmb 2026-07-23 10:43:03.907486451 +0000
++++ psi4-1.11/tests/pytests/test_missing_qcmanybody.py 2026-07-23 10:43:03.905397449 +0000
+@@ -0,0 +1,111 @@
++import sys
++
++import pytest
++from qcelemental.util import which_import
++
++import psi4
++from psi4.driver.task_planner import task_planner
++
++pytestmark = [
++ pytest.mark.quick,
++ pytest.mark.psi,
++ pytest.mark.api,
++ pytest.mark.skipif(
++ which_import("qcmanybody", return_bool=True),
++ reason="qcmanybody installed; tests target missing-addon behavior",
++ ),
++]
++
++
++_MSG = "Python module qcmanybody not found"
++
++
++@pytest.fixture
++def dimer():
++ return psi4.geometry(
++ """
++ He 0 0 -2
++ --
++ He 0 0 2
++ units au
++ """
++ )
++
++
++@pytest.mark.parametrize(
++ "driver,method,kwargs",
++ [
++ (psi4.energy, "hf", {"bsse_type": "cp"}),
++ (psi4.gradient, "hf", {"bsse_type": "cp"}),
++ (psi4.hessian, "hf", {"bsse_type": "cp", "dertype": "energy"}),
++ ],
++)
++def test_missing_qcmanybody_via_driver(driver, method, kwargs, dimer):
++ with pytest.raises(ModuleNotFoundError, match=_MSG):
++ driver(method, molecule=dimer, **kwargs)
++
++
++def test_missing_qcmanybody_via_return_plan(dimer):
++ with pytest.raises(ModuleNotFoundError, match=_MSG):
++ psi4.gradient("HF/cc-pV[D,T]Z", molecule=dimer, bsse_type="cp", return_plan=True)
++
++
++@pytest.mark.parametrize("driver,method", [("energy", "MP2/cc-pVDZ"), ("gradient", "MP2/cc-pV[D,T]Z")])
++def test_missing_qcmanybody_via_task_planner(driver, method, dimer):
++ with pytest.raises(ModuleNotFoundError, match=_MSG):
++ task_planner(driver, method, dimer, bsse_type="cp")
++
++
++@pytest.mark.parametrize("schver", [1, 2])
++def test_missing_qcmanybody_via_qcschema(schver, dimer):
++ if schver == 1:
++ qcs_input = {
++ "schema_name": "qcschema_input",
++ "schema_version": 1,
++ "molecule": dimer.to_schema(dtype=2),
++ "driver": "energy",
++ "model": {"method": "hf", "basis": "sto-3g"},
++ "keywords": {"function_kwargs": {"bsse_type": ["cp", "nocp"], "return_total_data": True}},
++ }
++ else:
++ qcs_input = {
++ "schema_name": "qcschema_atomic_input",
++ "schema_version": 2,
++ "molecule": dimer.to_schema(dtype=3),
++ "specification": {
++ "driver": "energy",
++ "model": {"method": "hf", "basis": "sto-3g"},
++ "keywords": {"function_kwargs": {"bsse_type": ["cp", "nocp"], "return_total_data": True}},
++ },
++ }
++
++ return_version = 2 if schver == 1 and sys.version_info >= (3, 14) else -1
++ ret = psi4.schema_wrapper.run_qcschema(qcs_input, return_version=return_version)
++
++ assert not ret.success
++ assert ret.error.error_type == "ModuleNotFoundError"
++ assert _MSG in ret.error.error_message
++
++
++def test_missing_qcmanybody_via_qcschema_levels(dimer):
++ qcs_input = {
++ "schema_name": "qcschema_atomic_input",
++ "schema_version": 2,
++ "molecule": dimer.to_schema(dtype=3),
++ "specification": {
++ "driver": "energy",
++ "model": {"method": "", "basis": "(auto)"},
++ "keywords": {
++ "function_kwargs": {
++ "bsse_type": "nocp",
++ "levels": {1: "mp2/sto-3g", "supersystem": "scf/sto-3g"},
++ }
++ },
++ },
++ }
++
++ ret = psi4.schema_wrapper.run_qcschema(qcs_input)
++
++ assert not ret.success
++ assert ret.error.error_type == "ModuleNotFoundError"
++ assert _MSG in ret.error.error_message
+diff -up psi4-1.11/tests/pytests/test_nbody_multi_level_qcschema.py.noqcmb psi4-1.11/tests/pytests/test_nbody_multi_level_qcschema.py
+--- psi4-1.11/tests/pytests/test_nbody_multi_level_qcschema.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_nbody_multi_level_qcschema.py 2026-07-23 10:43:03.834550516 +0000
+@@ -4,10 +4,11 @@ import copy
+ import pprint
+
+ import pytest
++from addons import uusing
+
+ import psi4
+
+-pytestmark = [pytest.mark.psi, pytest.mark.api, pytest.mark.nbody]
++pytestmark = [pytest.mark.psi, pytest.mark.api]
+
+ _sch_name = {1: "qcschema_output", 2: "qcschema_atomic_result"}
+ _ispy314 = sys.version_info >= (3, 14)
+@@ -88,6 +89,7 @@ def base_schema():
+ 'VMFC-CORRECTED TOTAL ENERGY THROUGH 2-BODY': -224.943882712817},
+ id='nbody-embedded', marks=pytest.mark.extern),
+ ])
++@uusing("qcmanybody")
+ def test_nbody_levels(inp, expected, base_schema, monkeypatch, schver):
+ monkeypatch.setenv("QCMANYBODY_EMBEDDING_CHARGES", "1")
+ # reference for nbody-multilevel generated with this larger fitting basis for sto-3g. fails otherwise by 3.e-5
+@@ -112,4 +114,3 @@ def test_nbody_levels(inp, expected, bas
+
+ for b, v in expected.items():
+ assert psi4.compare_values(v, otp.extras["qcvars"][b], 6, b)
+-
+diff -up psi4-1.11/tests/pytests/test_nbody.py.noqcmb psi4-1.11/tests/pytests/test_nbody.py
+--- psi4-1.11/tests/pytests/test_nbody.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_nbody.py 2026-07-23 10:43:03.914320623 +0000
+@@ -4,9 +4,10 @@ import re
+ import pytest
+ import numpy as np
+ from qcelemental.testing import compare, compare_values
++from addons import uusing
+ import psi4
+
+-pytestmark = [pytest.mark.psi, pytest.mark.api, pytest.mark.nbody]
++pytestmark = [pytest.mark.psi, pytest.mark.api]
+
+ _sch_name = {1: "qcschema_output", 2: "qcschema_atomic_result"}
+ _ispy314 = sys.version_info >= (3, 14)
+@@ -62,35 +63,47 @@ _ie_uncp_grad = np.array(
+ [ 0. , 0. , 0.000044919089]])
+
+
++_SEC_A = chr(0xA7) + "A"
++
++
++def _normalize_nbody_text(s: str) -> str:
++ """Normalize section symbol encoding on Windows to handle mojibake patterns."""
++ return (
++ s.replace("\ufffdA", "§A") # '�A' -> '§A' (replacement char mojibake)
++ .replace("§", "§") # Windows cp1252 double-encoding
++ .replace("\xa7", "§") # Direct byte representation
++ )
++
++
+ _stdouts = {
+- "cp_T": r"""
++ "cp_T": rf"""
+ \s* ==> N-Body: Counterpoise Corrected \(CP\) energies <==
+ \s* MC n-Body\s+Total Energy Interaction Energy N-body Contribution to Interaction Energy
+ \s* \[Eh\] \[Eh\] \[kcal/mol\] \[Eh\] \[kcal/mol\]
+-\s* §A\s+1 -155.405884\d\d\d\d\d\d 0.000000000000 0.000000000000 0.000000000000 0.000000000000
+-\s* FULL/RTN §A\s+2 -155.407610\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d
++\s* {_SEC_A}\s+1 -155.405884\d\d\d\d\d\d 0.000000000000 0.000000000000 0.000000000000 0.000000000000
++\s* FULL/RTN {_SEC_A}\s+2 -155.407610\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d
+ \s*
+-\s*MC Legend: §A: "\(auto\)"
++\s*MC Legend: {_SEC_A}: "\(auto\)"
+ \s*
+ """,
+- "cp_F": r"""
++ "cp_F": rf"""
+ \s* ==> N-Body: Counterpoise Corrected \(CP\) energies <==
+ \s* MC n-Body\s+Total Energy Interaction Energy N-body Contribution to Interaction Energy
+ \s* \[Eh\] \[Eh\] \[kcal/mol\] \[Eh\] \[kcal/mol\]
+-\s* §A\s+1 N/A 0.000000000000 0.000000000000 0.000000000000 0.000000000000
+-\s* FULL/RTN §A\s+2 N/A -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d
++\s* {_SEC_A}\s+1 N/A 0.000000000000 0.000000000000 0.000000000000 0.000000000000
++\s* FULL/RTN {_SEC_A}\s+2 N/A -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d -0.001726\d\d\d\d\d\d -1.0831\d\d\d\d\d\d\d\d
+ \s*
+-\s*MC Legend: §A: "\(auto\)"
++\s*MC Legend: {_SEC_A}: "\(auto\)"
+ \s*
+ """,
+- "uncp": r"""
++ "uncp": rf"""
+ \s* ==> N-Body: Non-Counterpoise Corrected \(NoCP\) energies <==
+ \s* MC n-Body\s+Total Energy Interaction Energy N-body Contribution to Interaction Energy
+ \s* \[Eh\] \[Eh\] \[kcal/mol\] \[Eh\] \[kcal/mol\]
+-\s* §A\s+1 -155.405884\d\d\d\d\d\d 0.000000000000 0.000000000000 0.000000000000 0.000000000000
+-\s* FULL/RTN §A\s+2 -155.408871\d\d\d\d\d\d -0.002987\d\d\d\d\d\d -1.8746\d\d\d\d\d\d\d\d -0.002987\d\d\d\d\d\d -1.8746\d\d\d\d\d\d\d\d
++\s* {_SEC_A}\s+1 -155.405884\d\d\d\d\d\d 0.000000000000 0.000000000000 0.000000000000 0.000000000000
++\s* FULL/RTN {_SEC_A}\s+2 -155.408871\d\d\d\d\d\d -0.002987\d\d\d\d\d\d -1.8746\d\d\d\d\d\d\d\d -0.002987\d\d\d\d\d\d -1.8746\d\d\d\d\d\d\d\d
+ \s*
+-\s*MC Legend: §A: "\(auto\)"
++\s*MC Legend: {_SEC_A}: "\(auto\)"
+ \s*
+ """,
+ }
+@@ -126,6 +139,7 @@ _stdouts["uncpcp"] = _stdouts["uncp"] +
+ ("gradient", ["nocp", "cp"], None , 5, _tot_uncp_grad, "uncpcp"), # return tot G 5
+ ("gradient", ["nocp", "ssfc"], None , 5, _tot_uncp_grad, "uncpcp"), # return tot G 5
+ ])
++@uusing("qcmanybody")
+ def test_nbody_number(driver, bsse_type, return_total_data, nbody_number, return_result, stdoutkey):
+
+ eneyne = psi4.geometry("""
+@@ -195,4 +209,4 @@ H 0.000000 0.000000 3.963929
+
+ assert compare_values(return_result, ret.return_result, atol=1.e-6, label="manybody")
+ assert compare(nbody_number, ret.extras["qcvars"]["NBODY NUMBER"], label="nbody number")
+- assert re.search(_stdouts[stdoutkey], ret.stdout, re.MULTILINE), f"N-Body pattern not found: {_stdouts[stdoutkey]}"
++ assert re.search(_stdouts[stdoutkey], _normalize_nbody_text(ret.stdout), re.MULTILINE), f"N-Body pattern not found: {_stdouts[stdoutkey]}"
+diff -up psi4-1.11/tests/pytests/test_psi4.py.noqcmb psi4-1.11/tests/pytests/test_psi4.py
+--- psi4-1.11/tests/pytests/test_psi4.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_psi4.py 2026-07-23 10:43:03.834711682 +0000
+@@ -1,5 +1,6 @@
+ import numpy as np
+ import pytest
++from addons import uusing
+
+ import psi4
+
+@@ -112,7 +113,7 @@ def test_psi4_cas():
+ assert psi4.compare_values(-76.073865006902, casscf_energy, 6, 'CASSCF Energy')
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @pytest.mark.smoke
+ def test_psi4_dfmp2():
+ """dfmp2-1"""
+diff -up psi4-1.11/tests/pytests/test_psi4_qcschema.py.noqcmb psi4-1.11/tests/pytests/test_psi4_qcschema.py
+--- psi4-1.11/tests/pytests/test_psi4_qcschema.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_psi4_qcschema.py 2026-07-23 10:43:03.926271703 +0000
+@@ -5,6 +5,7 @@ import pytest
+ import pprint
+ import os
+ from shutil import copytree
++from addons import uusing
+
+ import psi4
+
+@@ -113,7 +114,7 @@ def test_psi4_cas(datadir, schver):
+ assert psi4.compare_values(-76.073865006902, atres.return_result, 6, 'CASSCF Energy')
+
+
+-@pytest.mark.nbody
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("schver", [pytest.param(1, marks=[pytest.mark.skipif(_ispy314, reason="Py314+QCSk1")]), pytest.param(2)])
+ def test_psi4_dfmp2(datadir, schver):
+ """dfmp2-1"""
+diff -up psi4-1.11/tests/pytests/test_qcfractal.py.noqcmb psi4-1.11/tests/pytests/test_qcfractal.py
+--- psi4-1.11/tests/pytests/test_qcfractal.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_qcfractal.py 2026-07-23 10:43:03.907462347 +0000
+@@ -11,6 +11,7 @@ pytestmark = [pytest.mark.psi, pytest.ma
+
+ @uusing("qcfractal")
+ @uusing("qcportal")
++@uusing("qcmanybody")
+ @pytest.mark.cbs
+ @pytest.mark.smoke
+ @pytest.mark.quick
+diff -up psi4-1.11/tests/pytests/test_qcmanybody.py.noqcmb psi4-1.11/tests/pytests/test_qcmanybody.py
+diff -up psi4-1.11/tests/pytests/test_task_planner.py.noqcmb psi4-1.11/tests/pytests/test_task_planner.py
+--- psi4-1.11/tests/pytests/test_task_planner.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/pytests/test_task_planner.py 2026-07-23 10:43:03.905840127 +0000
+@@ -101,6 +101,7 @@ def test_cbs_extrapolation_gradient_1_0(
+ assert plan3.driver == "energy"
+
+
++@uusing("qcmanybody")
+ def test_nbody_dimer():
+ mol = psi4.geometry(
+ """
+@@ -133,6 +134,7 @@ def test_nbody_dimer():
+ assert kmol["real"] == ghostiness[k2][1]
+
+
++@uusing("qcmanybody")
+ def test_nbody_dimer_gradient():
+ mol = psi4.geometry(
+ """
+@@ -165,6 +167,7 @@ def test_nbody_dimer_gradient():
+ assert kmol["real"] == ghostiness[k2][1]
+
+
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("mtd, kw", [("mp2", {"dertype": 0}), ("mp5", {})])
+ def test_nbody_dimer_gradient_1_0(mtd, kw):
+ mol = psi4.geometry(
+@@ -231,6 +234,7 @@ def test_nbody_dimer_gradient_1_0(mtd, k
+ # assert plan3.keywords['E_CONVERGENCE'] == 1.e-10
+
+
++@uusing("qcmanybody")
+ def test_nbody_dimer_cbs():
+ mol = psi4.geometry(
+ """
+@@ -255,6 +259,7 @@ def test_nbody_dimer_cbs():
+ assert plan3.driver == "energy"
+
+
++@uusing("qcmanybody")
+ def test_nbody_dimer_cbs_gradient():
+ mol = psi4.geometry(
+ """
+@@ -279,6 +284,7 @@ def test_nbody_dimer_cbs_gradient():
+ assert plan3.driver == "gradient"
+
+
++@uusing("qcmanybody")
+ @pytest.mark.parametrize("mtd, kw", [("mp2", {"dertype": 0}), ("mp5", {})])
+ def test_nbody_dimer_cbs_gradient_1_0(mtd, kw):
+ mol = psi4.geometry(
+diff -up psi4-1.11/tests/tu6-cp-ne2/test_input.py.noqcmb psi4-1.11/tests/tu6-cp-ne2/test_input.py
+--- psi4-1.11/tests/tu6-cp-ne2/test_input.py.noqcmb 2026-06-30 02:22:36.000000000 +0000
++++ psi4-1.11/tests/tu6-cp-ne2/test_input.py 2026-07-23 10:43:03.835099850 +0000
+@@ -1,6 +1,6 @@
+ from addons import *
+
+-@ctest_labeler("tutorial;nbody")
++@uusing("qcmanybody")
++@ctest_labeler("tutorial")
+ def test_tu6_cp_ne2():
+ ctest_runner(__file__)
+-
diff --git a/3400.patch b/3400.patch
deleted file mode 100644
index 795a244..0000000
--- a/3400.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From 18f43c3713c8e791e80e797fa0bd3e1feb98a709 Mon Sep 17 00:00:00 2001
-From: Susi Lehtola <susi.lehtola@gmail.com>
-Date: Mon, 18 May 2026 19:25:31 +0300
-Subject: [PATCH] cmake: forward per-config flag variants to psi4-core subbuild
-
-The outer superbuild's ExternalProject_Add(psi4-core ...) was forwarding
-CMAKE_<LANG>_FLAGS but none of the per-configuration variants
-(CMAKE_<LANG>_FLAGS_{DEBUG,RELEASE,RELWITHDEBINFO,MINSIZEREL}). A user
-override like -DCMAKE_CXX_FLAGS_RELEASE="-DNDEBUG" on the outer cmake
-landed in the outer cache but never reached the inner psi4-core build,
-which silently fell back to CMake's auto-populated defaults.
-
-Forward all four configuration variants for C, C++, and Fortran.
-
-Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
----
- CMakeLists.txt | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 26eeb21e6a..0ba53433c9 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -276,9 +276,17 @@ ExternalProject_Add(psi4-core
- -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
- -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
- -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-+ -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG}
-+ -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
-+ -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO}
-+ -DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL}
- -DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}
- -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
- -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-+ -DCMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}
-+ -DCMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}
-+ -DCMAKE_C_FLAGS_RELWITHDEBINFO=${CMAKE_C_FLAGS_RELWITHDEBINFO}
-+ -DCMAKE_C_FLAGS_MINSIZEREL=${CMAKE_C_FLAGS_MINSIZEREL}
- -DCMAKE_CXX_STANDARD=${psi4_CXX_STANDARD}
- -DCMAKE_CXX_STANDARD_REQUIRED=ON
- -DCMAKE_CXX_EXTENSIONS=OFF
-@@ -287,6 +295,10 @@ ExternalProject_Add(psi4-core
- -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE}
- -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}
- -DCMAKE_Fortran_FLAGS=${CMAKE_Fortran_FLAGS}
-+ -DCMAKE_Fortran_FLAGS_DEBUG=${CMAKE_Fortran_FLAGS_DEBUG}
-+ -DCMAKE_Fortran_FLAGS_RELEASE=${CMAKE_Fortran_FLAGS_RELEASE}
-+ -DCMAKE_Fortran_FLAGS_RELWITHDEBINFO=${CMAKE_Fortran_FLAGS_RELWITHDEBINFO}
-+ -DCMAKE_Fortran_FLAGS_MINSIZEREL=${CMAKE_Fortran_FLAGS_MINSIZEREL}
- -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}
- -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR}
- -DCMAKE_INSTALL_DATADIR=${CMAKE_INSTALL_DATADIR}
diff --git a/psi4-1.3.2-python3.patch b/psi4-1.3.2-python3.patch
deleted file mode 100644
index 5747941..0000000
--- a/psi4-1.3.2-python3.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up psi4-1.3.2/tests/runtest.py.python3 psi4-1.3.2/tests/runtest.py
---- psi4-1.3.2/tests/runtest.py.python3 2019-05-15 17:05:49.000000000 +0200
-+++ psi4-1.3.2/tests/runtest.py 2020-01-13 22:30:59.679991141 +0100
-@@ -118,7 +118,7 @@ elif os.path.isfile(infile.replace(".dat
- else:
- os.environ["PYTHONPATH"] = psilibdir
- outfile = os.path.dirname(infile) + os.path.sep + outfile
-- pyexitcode = backtick(["python", infile, " > ", outfile])
-+ pyexitcode = backtick(["python3", infile, " > ", outfile])
- else:
- raise Exception("\n\nError: Input file %s not found\n" % infile)
-
diff --git a/psi4.spec b/psi4.spec
index 28db742..72daf38 100644
--- a/psi4.spec
+++ b/psi4.spec
@@ -14,19 +14,16 @@ ExcludeArch: %{ix86}
Name: psi4
Epoch: 1
-Version: 1.10.0
-Release: 0.2.alpha%{?dist}
+Version: 1.11
+Release: 1%{?dist}
Summary: An ab initio quantum chemistry package
# Automatically converted from old format: LGPLv3 and MIT - review is highly recommended.
License: LGPL-3.0-only AND LicenseRef-Callaway-MIT
URL: http://www.psicode.org/
-#Source0: https://github.com/psi4/psi4/archive/v%{version}/psi4-%{version}.tar.gz
-Source0: https://github.com/psi4/psi4/archive/refs/heads/master.zip
+Source0: https://github.com/psi4/psi4/archive/v%{version}/psi4-%{version}.tar.gz
-# Make qcmanybody optional
-Patch0: https://github.com/psi4/psi4/pull/3389.patch
-# Fix the propagation of cmake flags to the deeper build
-Patch1: https://github.com/psi4/psi4/pull/3400.patch
+# Make qcmanybody optional, from https://github.com/psi4/psi4/pull/3389.patch
+Patch0: 3389_new.patch
BuildRequires: cmake
BuildRequires: bison-devel
@@ -80,6 +77,7 @@ Requires: python3-qcengine
Requires: python3-qcelemental
Requires: python3-deepdiff
Requires: python3-optking
+Requires: python3-dftd4
# For directory ownership
Requires: cmake
@@ -116,10 +114,8 @@ This package contains necessary data files for PSI4, e.g., basis sets
and the quadrature grids.
%prep
-#setup -q
-%setup -q -n psi4-master
+%setup -q
%patch -P 0 -p 1 -b .noqcmb
-%patch -P 1 -p 1 -b .cmakeflags
# Prevent versioner from seeing any top-level git directories
sed -i 's/if is_git_repo(cwd=cwd, extraneous_toplevel_patterns=.*):/if False:/' psi4/versioner.py
@@ -174,6 +170,9 @@ ctest -L smoketests --output-on-failure
%{_datadir}/psi4/
%changelog
+* Wed Jul 29 2026 Susi Lehtola <jussilehtola@fedoraproject.org> - 1:1.11-1
+- Update to 1.11.
+
* Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 1:1.10.0-0.2.alpha
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-29 13:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-29 13:28 [rpms/psi4] rawhide: Update to 1.11 Susi Lehtola
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox