Skip to content

Commit 5eb83da

Browse files
committed
Fix DPA-ADAPT docs and backend helpers
1 parent dd6dc9e commit 5eb83da

7 files changed

Lines changed: 78 additions & 41 deletions

File tree

doc/cli.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,21 @@
33
Command line interface
44
======================
55

6+
DeePMD-kit ``dp`` command
7+
-------------------------
8+
69
.. argparse::
710
:module: deepmd.tf.entrypoints.main
811
:func: main_parser
912
:prog: dp
13+
14+
DPA-ADAPT command line interface
15+
--------------------------------
16+
17+
The ``dpaad`` command is a short alias for ``dpa-adapt`` and exposes the same
18+
subcommands and options.
19+
20+
.. argparse::
21+
:module: dpa_adapt.cli
22+
:func: get_parser
23+
:prog: dpa-adapt

doc/dpa_adapt/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ Installs `scikit-learn`, `dpdata`, `ase`, `rdkit`, and `e3nn` alongside DeePMD-k
1414

1515
For a complete runnable example (QM9 HOMO–LUMO gap, ~5 min on CPU), see [`../../examples/dpa_adapt/`](../../examples/dpa_adapt/).
1616

17+
```{toctree}
18+
:maxdepth: 2
19+
20+
input_formats
21+
```
22+
1723
## Fine-tuning strategies
1824

1925
The strategy is the core choice. All four share the same pre-trained DPA backbone and differ in how much of it gets updated:

doc/index.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ DeePMD-kit is a package written in Python/C++, designed to minimize the effort r
4444
test/index
4545
inference/index
4646
dpa_adapt/README
47-
dpa_adapt/input_formats
4847
cli
4948
third-party/index
5049
agent-skills

dpa_adapt/__init__.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,6 @@
99

1010
__version__ = "0.1.0"
1111

12-
__all__ = [
13-
"ConditionManager",
14-
"DPAConditionError",
15-
"DPAFineTuner",
16-
"DPAPredictor",
17-
"DPATrainer",
18-
"MFTFineTuner",
19-
"SmilesDataResult",
20-
"attach_labels",
21-
"check_data",
22-
"convert",
23-
"cross_validate",
24-
"extract_descriptors",
25-
"formula_to_npy",
26-
"load_dataset",
27-
"smiles_to_npy",
28-
"train_test_split",
29-
]
30-
3112
_LAZY = {
3213
"ConditionManager": (".conditions", "ConditionManager"),
3314
"DPAConditionError": (".conditions", "DPAConditionError"),
@@ -47,6 +28,8 @@
4728
"DPATrainer": (".trainer", "DPATrainer"),
4829
}
4930

31+
__all__ = list(_LAZY)
32+
5033

5134
def __getattr__(name: str):
5235
if name in _LAZY:

dpa_adapt/_backend.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,19 @@ def resolve_dp_command() -> str:
2929
import os as _os
3030
import shutil as _shutil
3131
import sys as _sys
32+
import sysconfig as _sysconfig
3233
from pathlib import Path as _Path
3334

3435
exe_name = "dp.exe" if _os.name == "nt" else "dp"
35-
candidate = _Path(_sys.executable).resolve().parent / exe_name
36-
if candidate.is_file():
37-
return _os.fspath(candidate)
36+
scripts_dir = _sysconfig.get_path("scripts")
37+
candidates = [
38+
_Path(_sys.executable).parent / exe_name,
39+
]
40+
if scripts_dir:
41+
candidates.append(_Path(scripts_dir) / exe_name)
42+
for candidate in candidates:
43+
if candidate.is_file():
44+
return _os.fspath(candidate)
3845

3946
found = _shutil.which("dp")
4047
if found:

dpa_adapt/data/__init__.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,6 @@
66
dpdata, torch, or rdkit.
77
"""
88

9-
__all__ = [
10-
"DPADataError",
11-
"Issue",
12-
"SmilesDataResult",
13-
"attach_labels",
14-
"check_data",
15-
"convert",
16-
"formula_to_npy",
17-
"load_data",
18-
"load_dataset",
19-
"read_checkpoint_type_map",
20-
"read_data_type_map_union",
21-
"read_mol_coords",
22-
"smiles_to_3d_coords",
23-
"smiles_to_npy",
24-
"validate_type_map_subset",
25-
]
26-
279
_LAZY = {
2810
"load_data": (".loader", "load_data"),
2911
"load_dataset": (".dataset", "load_dataset"),
@@ -44,6 +26,8 @@
4426
"records_from_direct_data": (".smiles", "records_from_direct_data"),
4527
}
4628

29+
__all__ = list(_LAZY)
30+
4731

4832
def __getattr__(name: str):
4933
if name in _LAZY:

source/tests/dpa_adapt/test_backend_contract.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,50 @@ def test_forward_common_fails_without_grad(self, _extractor):
249249
class TestBackendHelpers:
250250
"""Unit-level checks for _backend utility functions."""
251251

252+
def test_resolve_dp_command_keeps_symlinked_venv_scripts(self, tmp_path, monkeypatch):
253+
import os
254+
import sys
255+
from pathlib import (
256+
Path,
257+
)
258+
259+
from dpa_adapt._backend import (
260+
resolve_dp_command,
261+
)
262+
263+
exe_name = "dp.exe" if os.name == "nt" else "dp"
264+
python_name = "python.exe" if os.name == "nt" else "python"
265+
266+
real_bin = tmp_path / "real" / "bin"
267+
venv_bin = tmp_path / "venv" / "bin"
268+
real_bin.mkdir(parents=True)
269+
venv_bin.mkdir(parents=True)
270+
271+
real_python = real_bin / python_name
272+
real_python.write_text("")
273+
symlink_python = venv_bin / python_name
274+
symlink_python.write_text("")
275+
276+
wrong_dp = real_bin / exe_name
277+
wrong_dp.write_text("")
278+
expected_dp = venv_bin / exe_name
279+
expected_dp.write_text("")
280+
281+
def _fake_resolve(self):
282+
if self == symlink_python:
283+
return real_python
284+
return self
285+
286+
monkeypatch.setattr(Path, "resolve", _fake_resolve)
287+
monkeypatch.setattr(sys, "executable", os.fspath(symlink_python))
288+
monkeypatch.setattr(
289+
"sysconfig.get_path",
290+
lambda name: os.fspath(tmp_path / "other") if name == "scripts" else "",
291+
)
292+
monkeypatch.setattr("shutil.which", lambda name: None)
293+
294+
assert resolve_dp_command() == os.fspath(expected_dp)
295+
252296
def test_get_torch_device_returns_device(self):
253297
import sys
254298
from unittest.mock import (

0 commit comments

Comments
 (0)