@@ -223,10 +223,13 @@ def __init_subclass__(cls, *, family: object | None = None) -> None:
223223 cls ._family = family if family is not None else object ()
224224
225225 @typing .overload
226- def __init__ (self , * args : Histogram ) -> None : ...
226+ def __init__ (self , arg : Histogram , / , * , metadata : Any = ... ) -> None : ...
227227
228228 @typing .overload
229- def __init__ (self , * args : CppHistogram , metadata : Any = ...) -> None : ...
229+ def __init__ (self , arg : dict [str , Any ], / , * , metadata : Any = ...) -> None : ...
230+
231+ @typing .overload
232+ def __init__ (self , arg : CppHistogram , / , * , metadata : Any = ...) -> None : ...
230233
231234 @typing .overload
232235 def __init__ (
@@ -238,8 +241,8 @@ def __init__(
238241
239242 def __init__ (
240243 self ,
241- * axes : Axis | CppAxis | Histogram | CppHistogram ,
242- storage : Storage = Double (), # noqa: B008
244+ * axes : Axis | CppAxis | Histogram | CppHistogram | dict [ str , Any ] ,
245+ storage : Storage | None = None ,
243246 metadata : Any = None ,
244247 ) -> None :
245248 """
@@ -259,31 +262,44 @@ def __init__(
259262 Data that is passed along if a new histogram is created
260263 """
261264 self ._variance_known = True
265+ storage_err_msg = "storage= is not allowed with conversion constructor"
262266
263267 # Allow construction from a raw histogram object (internal)
264268 if len (axes ) == 1 and isinstance (axes [0 ], tuple (_histograms )):
269+ if storage is not None :
270+ raise TypeError (storage_err_msg )
265271 cpp_hist : CppHistogram = axes [0 ] # type: ignore[assignment]
266- self ._from_histogram_cpp (cpp_hist )
267- if metadata is not None :
268- self .metadata = metadata
272+ self ._from_histogram_cpp (cpp_hist , metadata = None )
269273 return
270274
271275 # If we construct with another Histogram as the only positional argument,
272276 # support that too
273277 if len (axes ) == 1 and isinstance (axes [0 ], Histogram ):
274- normal_hist : Histogram = axes [0 ]
275- self ._from_histogram_object (normal_hist )
276- if metadata is not None :
277- self .metadata = metadata
278+ if storage is not None :
279+ raise TypeError (storage_err_msg )
280+ self ._from_histogram_object (axes [0 ], metadata = metadata )
278281 return
279282
280283 # Support objects that provide a to_boost method, like Uproot
281284 if len (axes ) == 1 and hasattr (axes [0 ], "_to_boost_histogram_" ):
282- self ._from_histogram_object (axes [0 ]._to_boost_histogram_ ())
285+ if storage is not None :
286+ raise TypeError (storage_err_msg )
287+ self ._from_histogram_object (
288+ axes [0 ]._to_boost_histogram_ (), metadata = metadata
289+ )
290+ return
291+
292+ # Support UHI
293+ if len (axes ) == 1 and isinstance (axes [0 ], dict ) and "uhi_schema" in axes [0 ]:
294+ if storage is not None :
295+ raise TypeError (storage_err_msg )
296+ self ._from_histogram_object (
297+ serialization .from_uhi (axes [0 ]), metadata = metadata
298+ )
283299 return
284300
285301 if storage is None :
286- storage = Double () # type: ignore[unreachable]
302+ storage = Double ()
287303
288304 self .metadata = metadata
289305
@@ -356,16 +372,16 @@ def _new_hist(self, _hist: CppHistogram, memo: Any = NOTHING) -> Self:
356372 """
357373 return self .__class__ ._clone (_hist , other = self , memo = memo )
358374
359- def _from_histogram_cpp (self , other : CppHistogram ) -> None :
375+ def _from_histogram_cpp (self , other : CppHistogram , * , metadata : Any = None ) -> None :
360376 """
361377 Import a Cpp histogram.
362378 """
363379 self ._variance_known = True
364380 self ._hist = other
365- self .metadata = None
381+ self .metadata = metadata
366382 self .axes = self ._generate_axes_ ()
367383
368- def _from_histogram_object (self , other : Histogram ) -> None :
384+ def _from_histogram_object (self , other : Histogram , * , metadata : Any = None ) -> None :
369385 """
370386 Convert self into a new histogram object based on another, possibly
371387 converting from a different subclass.
@@ -375,6 +391,7 @@ def _from_histogram_object(self, other: Histogram) -> None:
375391 self .axes = self ._generate_axes_ ()
376392 for ax in self .axes :
377393 ax .__dict__ = copy .copy (ax ._ax .raw_metadata )
394+ self .metadata = other .metadata if metadata is None else metadata
378395
379396 # Allow custom behavior on either "from" or "to"
380397 other ._export_bh_ (self )
0 commit comments