diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 31348ae..2924783 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -16,7 +16,7 @@ env: CIBW_TEST_COMMAND: >- python -c "import importlib.util, XpongeCPP, Xponge, XpongeCPP.io_bundle, XpongeCPP.metal_assignment; - assert XpongeCPP.__version__ == '0.2.7'; + assert XpongeCPP.__version__ == '0.2.8'; assert not hasattr(XpongeCPP, 'MC' + 'PB'); assert importlib.util.find_spec('XpongeCPP.' + ('MC' + 'PB').lower()) is None" CIBW_BEFORE_ALL_LINUX: >- diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 9026f7a..a435129 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,7 +12,7 @@ env: CIBW_TEST_COMMAND: >- python -c "import importlib.util, XpongeCPP, Xponge, XpongeCPP.io_bundle, XpongeCPP.metal_assignment; - assert XpongeCPP.__version__ == '0.2.7'; + assert XpongeCPP.__version__ == '0.2.8'; assert not hasattr(XpongeCPP, 'MC' + 'PB'); assert importlib.util.find_spec('XpongeCPP.' + ('MC' + 'PB').lower()) is None" CIBW_BEFORE_ALL_LINUX: >- diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 157898e..d8ed8a3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,18 @@ +# XpongeCPP 0.2.8 + +Compatibility target: Xponge-origin 1.7.1. + +This patch release restores the Python instance-attribute behavior required +by the Xponge RESP diagnostics contract. The pybind-backed `Assign` type now +supports compatibility attributes, allowing `calculate_charge(..., +return_diagnostics=True)` and `return_metadata=True` to retain +`charge_fit_diagnostics` and `charge_fit_metadata` after fitting. + +Regression coverage verifies diagnostics, metadata, and general legacy +extension attributes without requiring a QM backend. Release validation also +includes a real PySCF RESP calculation and the complete compatibility suite +against the official Xponge 1.7.1 package. + # XpongeCPP 0.2.7 Compatibility target: Xponge-origin 1.7b11. diff --git a/cpp/python/bindings_assign.cpp b/cpp/python/bindings_assign.cpp index 492835e..d0f5bbe 100644 --- a/cpp/python/bindings_assign.cpp +++ b/cpp/python/bindings_assign.cpp @@ -50,7 +50,7 @@ void save_assignment_pdb_object(const Assign& assignment, const std::string& fil } // namespace void bind_assign_module(py::module_& m) { - py::class_>(m, "Assign") + py::class_>(m, "Assign", py::dynamic_attr()) .def(py::init(), py::arg("name") = "ASN") .def_readwrite("name", &Assign::name) .def_property_readonly("atom_count", &Assign::atom_count) diff --git a/pyproject.toml b/pyproject.toml index 6c626bd..30f755e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,13 @@ build-backend = "scikit_build_core.build" [project] name = "XpongeCPP" -version = "0.2.7" -description = "C++ core rewrite of Xponge workflows, compatible with Xponge-origin 1.7b11" +version = "0.2.8" +description = "C++ core rewrite of Xponge workflows, compatible with Xponge-origin 1.7.1" readme = "README.md" requires-python = ">=3.10,<3.13" authors = [{ name = "The XpongeCPP contributors" }] license = { text = "Apache License 2.0" } -keywords = ["molecular-dynamics", "molecular-mechanics", "Xponge-origin-1.7b11"] +keywords = ["molecular-dynamics", "molecular-mechanics", "Xponge-origin-1.7.1"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", diff --git a/src/XpongeCPP/__init__.py b/src/XpongeCPP/__init__.py index 6e72e63..ccebfd1 100644 --- a/src/XpongeCPP/__init__.py +++ b/src/XpongeCPP/__init__.py @@ -194,7 +194,7 @@ def _get_molecule_charge(molecule): from .legacy_types import _LegacyResidueTypeHandle from .template_ops import load_mol2 -__version__ = "0.2.7" +__version__ = "0.2.8" __mokda_backend__ = "xpongecpp" __implementation_version__ = __version__ pi = np.pi diff --git a/tests/test_compat_assign.py b/tests/test_compat_assign.py index 2ed0cb1..8531508 100644 --- a/tests/test_compat_assign.py +++ b/tests/test_compat_assign.py @@ -210,3 +210,36 @@ def test_assign_legacy_atom_numbers_and_residuetype_aliases_match_old_mokda_usag assert residue_type.name == "TES" assert len(residue_type.atoms) == 1 + + +def test_assign_resp_preserves_diagnostics_and_metadata_attributes(monkeypatch): + import Xponge + from XpongeCPP.assign import resp + + assign = Xponge.Assign("RESP_ATTRIBUTES") + assign.add_atom("O", 0.0, 0.0, 0.0, name="O1") + diagnostics = {"max_constraint_residual": 0.0} + metadata = {"backend": "mock"} + + def fake_resp_fit(*_args, **kwargs): + assert kwargs["return_diagnostics"] is True + assert kwargs["return_metadata"] is True + return { + "charges": [0.0], + "diagnostics": diagnostics, + "metadata": metadata, + } + + monkeypatch.setattr(resp, "resp_fit", fake_resp_fit) + + assign.calculate_charge( + "resp", + return_diagnostics=True, + return_metadata=True, + ) + + assert assign.charges == [0.0] + assert assign.charge_fit_diagnostics == diagnostics + assert assign.charge_fit_metadata == metadata + assign.legacy_extension = "available" + assert assign.legacy_extension == "available" diff --git a/tests/test_release_025.py b/tests/test_release_025.py index 1308ac7..ef4e9fe 100644 --- a/tests/test_release_025.py +++ b/tests/test_release_025.py @@ -1,4 +1,4 @@ -"""Release-contract checks for the Xponge-origin 1.7b11 alignment.""" +"""Release-contract checks for the Xponge-origin 1.7.1 alignment.""" from __future__ import annotations @@ -18,8 +18,8 @@ def test_release_version_and_compatibility_target(): metadata = tomllib.loads( (ROOT / "pyproject.toml").read_text(encoding="utf-8") )["project"] - assert metadata["version"] == XpongeCPP.__version__ == "0.2.7" - assert "Xponge-origin 1.7b11" in metadata["description"] + assert metadata["version"] == XpongeCPP.__version__ == "0.2.8" + assert "Xponge-origin 1.7.1" in metadata["description"] assert metadata["requires-python"] == ">=3.10,<3.13"