Repository: scikit-hep/hist
Pull request #598 (2025-02-01 12:57:05)

chore(deps): bump actions/attest-build-provenance from 2.1.0 to 2.2.0 in the actions group
Bumps the actions group with 1 update: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).

Updates `actions/attest-build-provenance` from 2.1.0 to 2.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/attest-build-provenance/releases">actions/attest-build-provenance's releases</a>.</em></p>
<blockquote>
<h2>v2.2.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump actions/attest from v2.1.0 to v2.2.0 by <a href="https://github.com/bdehamer"><code>@​bdehamer</code></a> in <a href="https://redirect.github.com/actions/attest-build-provenance/pull/449">actions/attest-build-provenance#449</a>
<ul>
<li>Includes support for now <code>subject-checksums</code> input parameter</li>
</ul>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/actions/attest-build-provenance/compare/v2.1.0...v2.2.0">https://github.com/actions/attest-build-provenance/compare/v2.1.0...v2.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/attest-build-provenance/commit/520d128f165991a6c774bcb264f323e3d70747f4"><code>520d128</code></a> bump actions/attest from v2.1.0 to v2.2.0 (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/449">#449</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/5d2ced98e37711f730ee81bf4f290e59f429cea9"><code>5d2ced9</code></a> Add example of upload-artifaction integration (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/450">#450</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/3c016c14be1000a987f5724861e76009e48945d1"><code>3c016c1</code></a> bump actions/attest from v2.1.0 to v2.2.0 (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/449">#449</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/e06bbafba962e6346493c5fd57cfcfe0873b0474"><code>e06bbaf</code></a> Bump the npm-development group with 3 updates (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/447">#447</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/47c6e87ba15264d457c4b3aeeaca0aa4ef36cfc8"><code>47c6e87</code></a> Bump the npm-development group with 4 updates (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/444">#444</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/c083b467494a647632714fee9685ca81f12ca4d6"><code>c083b46</code></a> Bump the npm-development group with 2 updates (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/438">#438</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/1b4b366241fcfed280d0cc0db3d44132575a6a87"><code>1b4b366</code></a> Bump typescript-eslint in the npm-development group (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/434">#434</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/963f8a02f24ac90336362e63ca6730cf69ad102e"><code>963f8a0</code></a> Bump the npm-development group with 2 updates (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/429">#429</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/4ecada3c132a6497cc654fcac5c8644da6815ca6"><code>4ecada3</code></a> Bump the npm-development group across 1 directory with 3 updates (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/422">#422</a>)</li>
<li><a href="https://github.com/actions/attest-build-provenance/commit/f4b7552a127d7acf1bef22d5bc9f315117aebfcd"><code>f4b7552</code></a> bump eslint from 8.57.1 to 9.16.0 (<a href="https://redirect.github.com/actions/attest-build-provenance/issues/418">#418</a>)</li>
<li>See full diff in <a href="https://github.com/actions/attest-build-provenance/compare/7668571508540a607bdfd90a87a560489fe372eb...520d128f165991a6c774bcb264f323e3d70747f4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/attest-build-provenance&package-manager=github_actions&previous-version=2.1.0&new-version=2.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions


</details>


Patch:
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
index d172848..d2a31fe 100644
--- a/.github/workflows/cd.yml
+++ b/.github/workflows/cd.yml
@@ -39,7 +39,7 @@ jobs:
         path: dist
 
     - name: Generate artifact attestation for sdist and wheel
-      uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
+      uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
       with:
         subject-path: "dist/hist-*"
 
diff --git a/src/hist/basehist.py b/src/hist/basehist.py
index 1bd9768..3f21a02 100644
--- a/src/hist/basehist.py
+++ b/src/hist/basehist.py
@@ -1,6 +1,8 @@
 from __future__ import annotations
 
+import fnmatch
 import functools
+import itertools
 import operator
 import typing
 import warnings
@@ -346,11 +348,38 @@ class BaseHist(bh.Histogram, metaclass=MetaConstructor, family=hist):
             # This can only return Self, not float, etc., so we ignore the extra types here
             return self[{axis: [bh.loc(x) for x in sorted_cats]}]  # type: ignore[dict-item, return-value]
 
-    def _loc_shortcut(self, x: Any) -> Any:
+    def _convert_index_wildcards(self, x: Any, ax_id: str | int | None = None) -> Any:
         """
-        Convert some specific indices to location.
+        Convert wildcards to available indices before passing to bh.loc
         """
 
+        if not any(
+            isinstance(x, t) for t in [str, list]
+        ):  # Process only lists and strings
+            return x
+        _x = x if isinstance(x, list) else [x]  # Convert to list if not already
+        if not all(isinstance(n, str) for n in _x):
+            return x
+        if any(any(special in pattern for special in ["*", "?"]) for pattern in _x):
+            available = [n for n in self.axes[ax_id] if isinstance(n, str)]
+            all_matches = []
+            for pattern in _x:
+                all_matches.append(
+                    [k for k in available if fnmatch.fnmatch(k, pattern)]
+                )
+            matches = list(
+                dict.fromkeys(list(itertools.chain.from_iterable(all_matches)))
+            )
+            if len(matches) == 0:
+                raise ValueError(f"No matches found for {x}")
+            return matches
+        return x
+
+    def _loc_shortcut(self, x: Any, ax_id: str | int | None = None) -> Any:
+        """
+        Convert some specific indices to location.
+        """
+        x = self._convert_index_wildcards(x, ax_id)
         if isinstance(x, list):
             return [self._loc_shortcut(each) for each in x]
         if isinstance(x, slice):
@@ -382,9 +411,7 @@ class BaseHist(bh.Histogram, metaclass=MetaConstructor, family=hist):
             raise ValueError("The imaginary part should be an integer")
         return bh.rebin(int(x.imag))
 
-    def _index_transform(
-        self, index: list[IndexingExpr] | IndexingExpr
-    ) -> bh.IndexingExpr:
+    def _index_transform(self, index: list[IndexingExpr] | IndexingExpr) -> Any:
         """
         Auxiliary function for __getitem__ and __setitem__.
         """
@@ -393,7 +420,7 @@ class BaseHist(bh.Histogram, metaclass=MetaConstructor, family=hist):
             new_indices = {
                 (
                     self._name_to_index(k) if isinstance(k, str) else k
-                ): self._loc_shortcut(v)
+                ): self._loc_shortcut(v, k)
                 for k, v in index.items()
             }
             if len(new_indices) != len(index):
@@ -405,7 +432,7 @@ class BaseHist(bh.Histogram, metaclass=MetaConstructor, family=hist):
         if not isinstance(index, tuple):
             index = (index,)  # type: ignore[assignment]
 
-        return tuple(self._loc_shortcut(v) for v in index)  # type: ignore[union-attr, union-attr, union-attr, union-attr]
+        return tuple(self._loc_shortcut(v, i) for i, (v) in enumerate(index))  # type: ignore[arg-type]
 
     def __getitem__(  # type: ignore[override]
         self, index: IndexingExpr


Test patch:
diff --git a/tests/test_general.py b/tests/test_general.py
index 4be9eaf..bf7c618 100644
--- a/tests/test_general.py
+++ b/tests/test_general.py
@@ -932,6 +932,14 @@ def test_select_by_index_imag():
     assert tuple(h[[8j, 7j]].axes[0]) == (8, 7)
 
 
+@pytest.mark.filterwarnings("ignore:List indexing selection is experimental")
+def test_select_by_index_wildcards():
+    h = hist.new.Reg(10, 0, 10).StrCat(["ABC", "BCD", "CDE", "DEF"]).Weight()
+    assert tuple(h[:, "*E*"].axes[1]) == ("CDE", "DEF")
+    assert tuple(h[:, ["*B*", "CDE"]].axes[1]) == ("ABC", "BCD", "CDE")
+    assert tuple(h[:, ["*B*", "?D?"]].axes[1]) == ("ABC", "BCD", "CDE")
+
+
 def test_sorted_simple():
     h = Hist.new.IntCat([4, 1, 2]).StrCat(["AB", "BCC", "BC"]).Double()
     assert tuple(h.sort(0).axes[0]) == (1, 2, 4)