Repository: scikit-hep/hist

Issue:
[FEATURE] storage string aliases
**Describe the feature you'd like**

I'm not sure if there are technical reason that would prevent this, but it would be nice if you could add string aliases for the storage options. So for example

```python
import hist
from hist import Hist

# Supported
h1 = Hist.new.Reg(100, -10, 10, name="x").Double()
h2 = Hist(hist.axis.Regular(100, -10, 10, name="x"), storage=hist.storage.Double())
# Feature request
h3 = Hist(hist.axis.Regular(100, -10, 10, name="x"), storage="double")
```

would all create equivalent histograms.


Comments:

Patch:
diff --git a/README.md b/README.md
index fb17fe3..00c2c63 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,8 @@ Hist currently provides everything boost-histogram provides, and the following e
 - The `Hist` class augments `bh.Histogram` with reduced typing construction:
   - Optional import-free construction system
   - `flow=False` is a fast way to turn off flow
+  - Storages can be given by string
+  - `storage=` can be omitted
 
 - Hist implements UHI+; an extension to the UHI (Unified Histogram Indexing) system designed for import-free interactivity:
   - Uses `j` suffix to switch to data coordinates in access or slices
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 20da761..77c373c 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,12 +4,17 @@ Changelog
 Version 2.1.0
 --------------------
 
+* Support shortcuts for setting storages by string or position
+  `#129 <https://github.com/scikit-hep/hist/pull/129>`_
+
 Updated dependencies:
 
-- `boost-histogram` 0.11.0 to 0.13.0.
-    - major new features, including PlottableProtocol
-- `histoprint` >=1.4 to >=1.6.
-- `mplhep` >=0.2.16 when `[plot]` given
+* ``boost-histogram`` 0.11.0 to 0.13.0.
+    * Major new features, including PlottableProtocol
+
+* ``histoprint`` >=1.4 to >=1.6.
+
+* ``mplhep`` >=0.2.16 when ``[plot]`` given
 
 
 Version 2.0.1
diff --git a/src/hist/basehist.py b/src/hist/basehist.py
index c1c2bdf..0304057 100644
--- a/src/hist/basehist.py
+++ b/src/hist/basehist.py
@@ -2,6 +2,7 @@ from .axestuple import NamedAxesTuple
 from .quick_construct import MetaConstructor
 from .utils import set_family, HIST_FAMILY
 from .storage import Storage
+from .axis import AxisProtocol
 
 import warnings
 import functools
@@ -36,15 +37,31 @@ def _proc_kw_for_lw(kwargs):
 class BaseHist(bh.Histogram, metaclass=MetaConstructor):
     __slots__ = ()
 
-    def __init__(self, *args, storage: Optional[Storage] = None, metadata=None):
+    def __init__(
+        self,
+        *args: Union[AxisProtocol, Storage, str, Tuple[int, float, float]],
+        storage: Optional[Union[Storage, str]] = None,
+        metadata=None,
+    ):
         """
         Initialize BaseHist object. Axis params can contain the names.
         """
         self._hist: Any = None
         self.axes: NamedAxesTuple
 
-        if len(args):
-            if isinstance(storage, type):
+        if args and storage is None and isinstance(args[-1], (Storage, str)):
+            storage = args[-1]
+            args = args[:-1]
+
+        if args:
+            if isinstance(storage, str):
+                storage_str = storage.title()
+                if storage_str == "Atomicint64":
+                    storage_str = "AtomicInt64"
+                elif storage_str == "Weightedmean":
+                    storage_str = "WeightedMean"
+                storage = getattr(bh.storage, storage_str)()
+            elif isinstance(storage, type):
                 msg = (
                     f"Please use '{storage.__name__}()' instead of '{storage.__name__}'"
                 )


Test patch:
diff --git a/tests/test_general.py b/tests/test_general.py
index b9495b5..627527e 100644
--- a/tests/test_general.py
+++ b/tests/test_general.py
@@ -1,4 +1,4 @@
-from hist import Hist, axis
+from hist import Hist, axis, storage
 
 import boost_histogram as bh
 import pytest
@@ -432,6 +432,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Double()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "double")._storage_type
+            == storage.Double
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="DouBle")._storage_type
+            == storage.Double
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Double())._storage_type
+            == storage.Double
+        )
+
     def test_int64(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Int64().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -441,6 +454,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Int64()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "int64")._storage_type
+            == storage.Int64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="INT64")._storage_type
+            == storage.Int64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Int64())._storage_type
+            == storage.Int64
+        )
+
     def test_atomic_int64(self):
         h = Hist.new.Reg(10, 0, 1, name="x").AtomicInt64().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -450,6 +476,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.AtomicInt64()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "atomicint64")._storage_type
+            == storage.AtomicInt64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="AtomicINT64")._storage_type
+            == storage.AtomicInt64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.AtomicInt64())._storage_type
+            == storage.AtomicInt64
+        )
+
     def test_weight(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Weight().fill([0.5, 0.5])
         assert h[0.5j].variance == 2
@@ -459,6 +498,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Weight()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "WeighT")._storage_type
+            == storage.Weight
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="weight")._storage_type
+            == storage.Weight
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Weight())._storage_type
+            == storage.Weight
+        )
+
     def test_mean(self):
         h = (
             Hist.new.Reg(10, 0, 1, name="x")
@@ -473,6 +525,18 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Mean()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "MEAn")._storage_type == storage.Mean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="mean")._storage_type
+            == storage.Mean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Mean())._storage_type
+            == storage.Mean
+        )
+
     def test_weighted_mean(self):
         h = (
             Hist.new.Reg(10, 0, 1, name="x")
@@ -488,6 +552,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.WeightedMean()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "WeighTEDMEAn")._storage_type
+            == storage.WeightedMean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="weightedMean")._storage_type
+            == storage.WeightedMean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.WeightedMean())._storage_type
+            == storage.WeightedMean
+        )
+
     def test_unlimited(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Unlimited().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -496,6 +573,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Unlimited()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "unlimited")._storage_type
+            == storage.Unlimited
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="UNLImited")._storage_type
+            == storage.Unlimited
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Unlimited())._storage_type
+            == storage.Unlimited
+        )
+
 
 def test_general_transform_proxy():
     """