Skip to content

Commit 1939c10

Browse files
committed
Convert fields from sc.Variable
1 parent fb11253 commit 1939c10

File tree

2 files changed

+44
-18
lines changed

2 files changed

+44
-18
lines changed

src/scippneutron/metadata/_model.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,27 @@
44

55
import enum
66
from datetime import datetime
7+
from typing import Annotated, Any
78

9+
import scipp as sc
810
import scippnexus as snx
911
from dateutil.parser import parse as parse_datetime
10-
from pydantic import BaseModel, EmailStr
12+
from pydantic import BaseModel, BeforeValidator, EmailStr
1113

1214
from ._orcid import ORCIDiD
1315

1416

17+
def _unpack_variable(value: object) -> Any:
18+
"""Before validator to support passing scalar scipp variables as inputs."""
19+
if isinstance(value, sc.Variable):
20+
if value.dims:
21+
raise ValueError("Must be a scalar")
22+
if value.unit and value.unit != '':
23+
raise ValueError("Must be dimensionless or have no unit at all")
24+
return value.value
25+
return value
26+
27+
1528
class Beamline(BaseModel):
1629
"""A beamline / instrument.
1730
@@ -39,13 +52,13 @@ class Beamline(BaseModel):
3952
which version of the beamline was used.
4053
"""
4154

42-
name: str
55+
name: Annotated[str, BeforeValidator(_unpack_variable)]
4356
"""Name of the beamline."""
44-
facility: str | None = None
57+
facility: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
4558
"""Facility where the beamline is located."""
46-
site: str | None = None
59+
site: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
4760
"""Site where the facility is located."""
48-
revision: str | None = None
61+
revision: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
4962
"""Revision of the beamline in case of upgrades."""
5063

5164
@classmethod
@@ -105,14 +118,16 @@ class Measurement(BaseModel):
105118
``start_time`` and ``end_time``.
106119
"""
107120

108-
title: str | None
121+
title: Annotated[str | None, BeforeValidator(_unpack_variable)]
109122
"""The title of the measurement."""
110-
run_number: str | None = None
123+
run_number: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
111124
"""Run number of the measurement."""
112-
experiment_id: str | None = None
125+
experiment_id: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
113126
"""An ID for the experiment that this measurement is part of, e.g., proposal ID."""
114-
experiment_doi: str | None = None
127+
experiment_doi: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
115128
"""A DOI for the experiment that this measurement is part of."""
129+
# These do not support conversion from variables because variables are naive w.r.t.
130+
# timezones and converting them to datetime.datetime would require extra info.
116131
start_time: datetime | None = None
117132
"""Date and time when the measurement started."""
118133
end_time: datetime | None = None
@@ -164,16 +179,16 @@ class Person(BaseModel):
164179
and can usually be omitted when an ORCID iD is provided.
165180
"""
166181

167-
name: str
182+
name: Annotated[str, BeforeValidator(_unpack_variable)]
168183
"""Free form name of the person."""
169-
orcid_id: ORCIDiD | None = None
184+
orcid_id: Annotated[ORCIDiD | None, BeforeValidator(_unpack_variable)] = None
170185
"""ORCID iD of the person."""
171186

172187
corresponding: bool = False
173188
"""Whether the person is the corresponding / contact author."""
174189
owner: bool = True
175190
"""Whether the person owns the data."""
176-
role: str | None = None
191+
role: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
177192
"""The role that the person played in collecting / processing the data.
178193
179194
`NeXus <https://manual.nexusformat.org/classes/base_classes/NXuser.html#nxuser>`_
@@ -182,11 +197,11 @@ class Person(BaseModel):
182197
list possible roles.
183198
"""
184199

185-
address: str | None = None
200+
address: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
186201
"""Physical (work) address of the person."""
187-
email: EmailStr | None = None
202+
email: Annotated[EmailStr | None, BeforeValidator(_unpack_variable)] = None
188203
"""Email address of the person."""
189-
affiliation: str | None = None
204+
affiliation: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
190205
"""Affiliation of the person."""
191206

192207

@@ -350,7 +365,7 @@ class Source(BaseModel):
350365
The ESS source is provided as ``scippneutron.metadata.ESS_SOURCE``.
351366
"""
352367

353-
name: str | None = None
368+
name: Annotated[str | None, BeforeValidator(_unpack_variable)] = None
354369
"""Name of the source."""
355370
source_type: SourceType
356371
"""Type of this source."""

tests/metadata/metadata_model_test.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
33

4-
54
import pytest
65
import scipp as sc
76
import scippnexus as snx
@@ -12,7 +11,7 @@
1211
from scippneutron import metadata
1312

1413

15-
def test_experiment_from_nexus_entry() -> None:
14+
def test_measurement_from_nexus_entry() -> None:
1615
with snx.File(scn.data.get_path('PG3_4844_event.nxs')) as f:
1716
experiment = metadata.Measurement.from_nexus_entry(f['entry'])
1817
assert experiment.title == 'diamond cw0.533 4.22e12 60Hz [10x30]'
@@ -23,6 +22,18 @@ def test_experiment_from_nexus_entry() -> None:
2322
assert experiment.experiment_doi is None
2423

2524

25+
def test_measurement_from_individual_variables() -> None:
26+
experiment = metadata.Measurement(
27+
title=sc.scalar('The title'),
28+
run_number='12b',
29+
experiment_id=sc.scalar('EXP-1', unit=''),
30+
)
31+
assert experiment.title == 'The title'
32+
assert experiment.run_number == '12b'
33+
assert experiment.experiment_id == 'EXP-1'
34+
assert experiment.experiment_doi is None
35+
36+
2637
def test_beamline_from_nexus_entry() -> None:
2738
with snx.File(scn.data.get_path('PG3_4844_event.nxs')) as f:
2839
beamline = metadata.Beamline.from_nexus_entry(f['entry'])

0 commit comments

Comments
 (0)