fix(basehist): normalize negative integer indices#699
Draft
henryiii wants to merge 1 commit into
Draft
Conversation
Thread the per-axis id into _loc_shortcut so plain negative ints in slice bounds and direct access (h[-2], h[1:-2]) are normalized against the axis length, matching NumPy semantics. Complex/loc/rebin indices are untouched. Closes #559. Assisted-by: ClaudeCode:claude-opus-4.8
9030b81 to
3c0fdc1
Compare
henryiii
added a commit
to scikit-hep/boost-histogram
that referenced
this pull request
Jun 26, 2026
* fix: normalize negative integer slice bounds in indexing Negative slice bounds raised `ValueError: begin < end required` (e.g. `h[1:-2]`) because plain negative ints were passed straight to Boost.Histogram, which does not apply NumPy-style negative indexing. `Axis._process_callable` now normalizes plain negative ints relative to the axis length, like Python/NumPy. Locators (`bh.loc`, `bh.tag.at`, rebin/sum steps) are callables handled earlier and stay untouched. The fix flows through `_process_loc`, so it applies to both `__getitem__` and `__setitem__`. Scalar negative indexing already worked via `_compute_uhi_index`. Mirrors scikit-hep/hist#699, fixing the bug at the underlying layer. Assisted-by: ClaudeCode:claude-opus-4.8 * feat: clamp out-of-range slice bounds to match NumPy Out-of-range slice bounds now clamp to [0, len] like NumPy slicing (e.g. h[5:100] -> h[5:], h[-15:5] -> h[:5]), instead of relying on Boost's internal behavior or raising low-level errors. NumPy returns an empty array for slices like h[1:-15] or h[5:2], but a Boost.Histogram axis cannot have zero bins. These now raise a clear IndexError explaining the limitation instead of the cryptic "begin < end required" / "bins > 0 required". The check lives in _handle_slice so that intentional flow access via integration (e.g. h[3::sum] summing the overflow) is preserved. Assisted-by: ClaudeCode:claude-opus-4.8 * ci: pin numpy<2.5 in hist nox session numpy 2.5's stubs use a `type X = ...` statement that mypy rejects under the downstream hist session ("Type statement is only supported in Python 3.12 and greater"), failing the Hist 3.14 job. Pin numpy below 2.5 until the toolchain catches up. Assisted-by: ClaudeCode:claude-opus-4.8 * style: pre-commit fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
Closes #559.
Negative slice bounds raised
ValueError: begin < end required(e.g.h[1:-2]) because plain negative ints were passed straight to boost-histogram, which does not apply NumPy-style negative indexing._loc_shortcutnow threads the per-axis id through to slice bounds and normalizes plain negativeint/np.integeragainst the axis length.bool,complex(by-value /loc),None, rebinstep, etc. are untouched.Test:
tests/test_general.py::test_negative_index_access—h[-1]==h[9],h[1:-2]==h[1:8],h[-3:-1]==h[7:9], dict-form equivalents, and a two-axis per-axis-length case. Confirmed failing before, passing after.