Skip to content

Commit 37c3728

Browse files
committed
refactor(quantity): use [[deprecated]] attr, TORCH_WARN_DEPRECATION, and remove quantity-based unit conversion
- Add [[deprecated]] attribute to quantity() getter and set_quantity() in model.hpp for compile-time warnings - Switch from TORCH_WARN to TORCH_WARN_DEPRECATION with std::once_flag in set_quantity() for proper runtime deprecation signaling - Remove quantity-based unit conversion logic from model.py; unit conversion now uses declared/requested unit fields directly - Revert conftest.py files to strict stderr checking; catch deprecation warnings explicitly at emission sites using capfd in affected tests and fixtures - Add filterwarnings for ModelOutput.quantity DeprecationWarning in ASE and torchsim pyproject.toml
1 parent 409b32c commit 37c3728

11 files changed

Lines changed: 65 additions & 77 deletions

File tree

metatomic-torch/include/metatomic/torch/model.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,17 @@ class METATOMIC_TORCH_EXPORT ModelOutputHolder: public torch::CustomClassHolder
5555
/// description of this output, defaults to empty string of not set by the user
5656
std::string description;
5757

58-
/// quantity of the output (e.g. energy, dipole, ). If this is an empty
58+
/// quantity of the output (e.g. energy, dipole, ...). If this is an empty
5959
/// string, no unit conversion will be performed.
6060
/// @deprecated This field is no longer required for unit conversion.
6161
/// The unit parser determines dimensions from the expression itself.
62+
[[deprecated("quantity is no longer required for unit conversion, use unit directly")]]
6263
const std::string& quantity() const {
6364
return quantity_;
6465
}
6566

6667
/// set the quantity of the output
68+
[[deprecated("quantity is no longer required for unit conversion, use unit directly")]]
6769
void set_quantity(std::string quantity);
6870

6971
/// unit of the output. If this is an empty string, no unit conversion will

metatomic-torch/src/model.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <cstring>
2+
#include <mutex>
23

34
#include <sstream>
45
#include <filesystem>
@@ -55,11 +56,14 @@ static void read_vector_int_json(
5556

5657
void ModelOutputHolder::set_quantity(std::string quantity) {
5758
if (!quantity.empty()) {
58-
TORCH_WARN(
59-
"ModelOutput.quantity is deprecated and will be removed in a future version. "
60-
"The quantity field is no longer required for unit conversion since the "
61-
"unit parser determines dimensions from the expression itself."
62-
);
59+
static std::once_flag warn_flag;
60+
std::call_once(warn_flag, []() {
61+
TORCH_WARN_DEPRECATION(
62+
"ModelOutput.quantity is deprecated and will be removed in a future version. "
63+
"The quantity field is no longer required for unit conversion since the "
64+
"unit parser determines dimensions from the expression itself."
65+
);
66+
});
6367
}
6468
if (valid_quantity(quantity)) {
6569
validate_unit(quantity, unit_);

python/metatomic_ase/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ python_files = ["*.py"]
4444
testpaths = ["tests"]
4545
filterwarnings = [
4646
"error",
47+
# ModelOutput.quantity deprecation (C++ TORCH_WARN_DEPRECATION)
48+
"ignore:ModelOutput.quantity is deprecated:DeprecationWarning",
4749
# TorchScript deprecation warnings
4850
"ignore:`torch.jit.script` is deprecated. Please switch to `torch.compile` or `torch.export`:DeprecationWarning",
4951
"ignore:`torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`:DeprecationWarning",

python/metatomic_ase/tests/calculator.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737

3838

3939
@pytest.fixture
40-
def model():
41-
return metatomic_lj_test.lennard_jones_model(
40+
def model(capfd):
41+
m = metatomic_lj_test.lennard_jones_model(
4242
atomic_type=28,
4343
cutoff=CUTOFF,
4444
sigma=SIGMA,
@@ -47,11 +47,16 @@ def model():
4747
energy_unit="eV",
4848
with_extension=False,
4949
)
50+
# consume the once-per-process quantity deprecation warning from C++
51+
captured = capfd.readouterr()
52+
if captured.err:
53+
assert "ModelOutput.quantity is deprecated" in captured.err
54+
return m
5055

5156

5257
@pytest.fixture
53-
def model_different_units():
54-
return metatomic_lj_test.lennard_jones_model(
58+
def model_different_units(capfd):
59+
m = metatomic_lj_test.lennard_jones_model(
5560
atomic_type=28,
5661
cutoff=CUTOFF / ase.units.Bohr,
5762
sigma=SIGMA / ase.units.Bohr,
@@ -60,6 +65,10 @@ def model_different_units():
6065
energy_unit="kJ/mol",
6166
with_extension=False,
6267
)
68+
captured = capfd.readouterr()
69+
if captured.err:
70+
assert "ModelOutput.quantity is deprecated" in captured.err
71+
return m
6372

6473

6574
@pytest.fixture
@@ -793,7 +802,7 @@ def forward(
793802
}
794803

795804

796-
def test_additional_input(atoms):
805+
def test_additional_input(atoms, capfd):
797806
inputs = {
798807
"masses": ModelOutput(quantity="mass", unit="u", per_atom=True),
799808
"velocities": ModelOutput(quantity="velocity", unit="A/fs", per_atom=True),
@@ -833,6 +842,11 @@ def test_additional_input(atoms):
833842

834843
assert np.allclose(values, expected)
835844

845+
# consume the once-per-process quantity deprecation warning from C++
846+
captured = capfd.readouterr()
847+
if captured.err:
848+
assert "ModelOutput.quantity is deprecated" in captured.err
849+
836850

837851
@pytest.mark.parametrize("device,dtype", ALL_DEVICE_DTYPE)
838852
def test_mixed_pbc(model, device, dtype):
Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import re
2-
31
import pytest
42

53

@@ -8,17 +6,5 @@ def fail_test_with_output(capfd):
86
yield
97
captured = capfd.readouterr()
108
# the code should not print anything to stdout or stderr
11-
# except for expected deprecation warnings
129
assert captured.out == ""
13-
# Filter out expected deprecation warnings
14-
stderr_lines = captured.err.splitlines()
15-
unexpected_errors = [
16-
line
17-
for line in stderr_lines
18-
if not re.search(
19-
r"(ModelOutput\.quantity is deprecated|"
20-
r"compute_requested_neighbors_from_options.*is deprecated)",
21-
line,
22-
)
23-
]
24-
assert "".join(unexpected_errors) == "", f"Unexpected stderr output: {captured.err}"
10+
assert captured.err == ""

python/metatomic_torch/metatomic/torch/model.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ class AtomisticModel(torch.nn.Module):
265265
>>> capabilities = ModelCapabilities(
266266
... outputs={
267267
... "energy": ModelOutput(
268-
... quantity="energy",
269268
... unit="eV",
270269
... per_atom=False,
271270
... explicit_gradients=[],
@@ -507,21 +506,9 @@ def forward(
507506
for name, output in outputs.items():
508507
declared = self._capabilities.outputs[name]
509508
requested = options.outputs.get(name, ModelOutput())
510-
if declared.quantity == "" or requested.quantity == "":
509+
if declared.unit == "" or requested.unit == "":
511510
continue
512511

513-
# Note: Deprecation warning for quantity is emitted from C++ when
514-
# ModelOutput is constructed with non-empty quantity.
515-
# We don't warn here because TorchScript can't handle
516-
# DeprecationWarning.
517-
518-
if declared.quantity != requested.quantity:
519-
raise ValueError(
520-
f"model produces values as '{declared.quantity}' for the "
521-
f"'{name}' output, but the engine requested "
522-
f"'{requested.quantity}'"
523-
)
524-
525512
conversion = unit_conversion_factor(
526513
declared.unit,
527514
requested.unit,
Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import re
2-
31
import pytest
42

53

@@ -8,17 +6,5 @@ def fail_test_with_output(capfd):
86
yield
97
captured = capfd.readouterr()
108
# the code should not print anything to stdout or stderr
11-
# except for expected deprecation warnings
129
assert captured.out == ""
13-
# Filter out expected deprecation warnings
14-
stderr_lines = captured.err.splitlines()
15-
unexpected_errors = [
16-
line
17-
for line in stderr_lines
18-
if not re.search(
19-
r"(ModelOutput\.quantity is deprecated|"
20-
r"compute_requested_neighbors_from_options.*is deprecated)",
21-
line,
22-
)
23-
]
24-
assert "".join(unexpected_errors) == "", f"Unexpected stderr output: {captured.err}"
10+
assert captured.err == ""

python/metatomic_torch/tests/units.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,9 @@ def test_micro_sign_microsecond():
317317
# ---- Quantity-unit mismatch ----
318318

319319

320-
def test_quantity_unit_mismatch():
320+
def test_quantity_unit_mismatch(capfd):
321321
# energy quantity with force unit
322322
# quantity parameter is deprecated, but we still test unit validation
323-
# Warning is emitted via C++ TORCH_WARN, not Python warnings
324323
with pytest.raises((ValueError, RuntimeError), match="incompatible with quantity"):
325324
ModelOutput(quantity="energy", unit="eV/A")
326325

@@ -332,6 +331,12 @@ def test_quantity_unit_mismatch():
332331
with pytest.raises((ValueError, RuntimeError), match="incompatible with quantity"):
333332
ModelOutput(quantity="length", unit="eV/A^3")
334333

334+
# consume the once-per-process quantity deprecation warning from C++
335+
captured = capfd.readouterr()
336+
assert captured.out == ""
337+
if captured.err:
338+
assert "ModelOutput.quantity is deprecated" in captured.err
339+
335340

336341
# ---- Deprecation warning for 3-arg C++ op ----
337342

python/metatomic_torchsim/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ python_files = ["*.py"]
4545
testpaths = ["tests"]
4646
filterwarnings = [
4747
"error",
48+
# ModelOutput.quantity deprecation (C++ TORCH_WARN_DEPRECATION)
49+
"ignore:ModelOutput.quantity is deprecated:DeprecationWarning",
4850
# TorchScript deprecation warnings
4951
"ignore:`torch.jit.script` is deprecated. Please switch to `torch.compile` or `torch.export`:DeprecationWarning",
5052
"ignore:`torch.jit.script_method` is deprecated. Please switch to `torch.compile` or `torch.export`:DeprecationWarning",
Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import re
2-
31
import pytest
42

53

@@ -8,17 +6,5 @@ def fail_test_with_output(capfd):
86
yield
97
captured = capfd.readouterr()
108
# the code should not print anything to stdout or stderr
11-
# except for expected deprecation warnings
129
assert captured.out == ""
13-
# Filter out expected deprecation warnings
14-
stderr_lines = captured.err.splitlines()
15-
unexpected_errors = [
16-
line
17-
for line in stderr_lines
18-
if not re.search(
19-
r"(ModelOutput\.quantity is deprecated|"
20-
r"compute_requested_neighbors_from_options.*is deprecated)",
21-
line,
22-
)
23-
]
24-
assert "".join(unexpected_errors) == "", f"Unexpected stderr output: {captured.err}"
10+
assert captured.err == ""

0 commit comments

Comments
 (0)