Skip to content

Commit ef876c9

Browse files
authored
fix: unset classic metadata shouldn't show up in serialization (#1039)
Signed-off-by: Henry Schreiner <[email protected]>
1 parent ca1ca56 commit ef876c9

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

src/boost_histogram/histogram.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ def _combine_group_contents(
192192

193193
H = TypeVar("H", bound="Histogram")
194194

195+
NO_METADATA = object()
196+
195197

196198
# We currently do not cast *to* a histogram, but this is consistent
197199
# and could be used later.
@@ -203,7 +205,8 @@ class Histogram:
203205
"_hist",
204206
"axes",
205207
)
206-
# .metadata and ._variance_known are part of the dict
208+
# .metadata and ._variance_known are part of the dict.
209+
# .metadata will not be placed in the dict if not passed.
207210

208211
_family: ClassVar[object] = boost_histogram
209212

@@ -243,7 +246,7 @@ def __init__(
243246
self,
244247
*axes: Axis | CppAxis | Histogram | CppHistogram | dict[str, Any],
245248
storage: Storage | None = None,
246-
metadata: Any = None,
249+
metadata: Any = NO_METADATA,
247250
) -> None:
248251
"""
249252
Construct a new histogram.
@@ -259,7 +262,8 @@ def __init__(
259262
storage : Storage = bh.storage.Double()
260263
Select a storage to use in the histogram
261264
metadata : Any = None
262-
Data that is passed along if a new histogram is created
265+
Data that is passed along if a new histogram is created. No not use
266+
in new code; set properties in __dict__ directly instead.
263267
"""
264268
self._variance_known = True
265269
storage_err_msg = "storage= is not allowed with conversion constructor"
@@ -269,7 +273,7 @@ def __init__(
269273
if storage is not None:
270274
raise TypeError(storage_err_msg)
271275
cpp_hist: CppHistogram = axes[0] # type: ignore[assignment]
272-
self._from_histogram_cpp(cpp_hist, metadata=None)
276+
self._from_histogram_cpp(cpp_hist, metadata=metadata)
273277
return
274278

275279
# If we construct with another Histogram as the only positional argument,
@@ -301,7 +305,8 @@ def __init__(
301305
if storage is None:
302306
storage = Double()
303307

304-
self.metadata = metadata
308+
if metadata is not NO_METADATA:
309+
self.metadata = metadata
305310

306311
# Check for missed parenthesis or incorrect types
307312
if not isinstance(storage, Storage):
@@ -342,7 +347,7 @@ def _clone(
342347

343348
self = cls.__new__(cls)
344349
if isinstance(_hist, tuple(_histograms)):
345-
self._from_histogram_cpp(_hist) # type: ignore[arg-type]
350+
self._from_histogram_cpp(_hist, metadata=NO_METADATA) # type: ignore[arg-type]
346351
if other is not None:
347352
return cls._clone(self, other=other, memo=memo)
348353
return self
@@ -352,7 +357,7 @@ def _clone(
352357
if other is None:
353358
other = _hist
354359

355-
self._from_histogram_object(_hist)
360+
self._from_histogram_object(_hist, metadata=NO_METADATA)
356361

357362
if memo is NOTHING:
358363
self.__dict__ = copy.copy(other.__dict__)
@@ -372,16 +377,17 @@ def _new_hist(self, _hist: CppHistogram, memo: Any = NOTHING) -> Self:
372377
"""
373378
return self.__class__._clone(_hist, other=self, memo=memo)
374379

375-
def _from_histogram_cpp(self, other: CppHistogram, *, metadata: Any = None) -> None:
380+
def _from_histogram_cpp(self, other: CppHistogram, *, metadata: Any) -> None:
376381
"""
377382
Import a Cpp histogram.
378383
"""
379384
self._variance_known = True
380385
self._hist = other
381-
self.metadata = metadata
386+
if metadata is not NO_METADATA:
387+
self.metadata = metadata
382388
self.axes = self._generate_axes_()
383389

384-
def _from_histogram_object(self, other: Histogram, *, metadata: Any = None) -> None:
390+
def _from_histogram_object(self, other: Histogram, *, metadata: Any) -> None:
385391
"""
386392
Convert self into a new histogram object based on another, possibly
387393
converting from a different subclass.
@@ -391,7 +397,10 @@ def _from_histogram_object(self, other: Histogram, *, metadata: Any = None) -> N
391397
self.axes = self._generate_axes_()
392398
for ax in self.axes:
393399
ax.__dict__ = copy.copy(ax._ax.raw_metadata)
394-
self.metadata = other.metadata if metadata is None else metadata
400+
if metadata is not NO_METADATA:
401+
self.metadata = metadata
402+
elif "metadata" in other.__dict__:
403+
self.metadata = other.metadata
395404

396405
# Allow custom behavior on either "from" or "to"
397406
other._export_bh_(self)
@@ -420,6 +429,14 @@ def _generate_axes_(self) -> AxesTuple:
420429

421430
return AxesTuple(self._axis(i) for i in range(self.ndim))
422431

432+
# Backward compat for metadata default
433+
def __getattr__(self, name: str) -> Any:
434+
if name == "metadata":
435+
msg = ".metadata was not set, returning None instead of Attribute error, boost-histogram 1.7+ will error."
436+
warnings.warn(msg, FutureWarning, stacklevel=2)
437+
return None
438+
return super().__getattribute__(name)
439+
423440
def _to_uhi_(self) -> dict[str, Any]:
424441
"""
425442
Convert to a UHI histogram.
@@ -695,7 +712,7 @@ def storage_type(self) -> type[Storage]:
695712
def _storage_type(self) -> type[Storage]:
696713
warnings.warn(
697714
"Accessing storage type has changed from _storage_type to storage_type, and will be removed in future.",
698-
DeprecationWarning,
715+
FutureWarning,
699716
stacklevel=2,
700717
)
701718
return cast(self, self._hist._storage_type, Storage) # type: ignore[return-value]

tests/test_serialization_uhi.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def test_unserializable_metadata() -> None:
244244
h.__dict__["@b"] = 2
245245
data = to_uhi(h)
246246

247-
assert data["metadata"] == {"a": 1, "_variance_known": True, "metadata": None}
247+
assert data["metadata"] == {"a": 1, "_variance_known": True}
248248
assert data["axes"][0]["metadata"] == {"c": 3}
249249

250250

@@ -261,5 +261,4 @@ def test_histogram_metadata() -> None:
261261
"label": "hi",
262262
"other": 3,
263263
"_variance_known": True,
264-
"metadata": None,
265264
}

0 commit comments

Comments
 (0)