fix: indexing, __setitem__ flow transfer, and fill edge cases#1149
Merged
Conversation
…and __dir__ Part of #1143: - B8b: Axis.__getitem__ no longer wraps ax[-size-1] into the underflow bin; out-of-range negative indices now raise IndexError, and the error message reports the requested index and the axis size. - B9: _isstr no longer treats empty sequences/arrays as strings, so numerical axes accept .index([]). StrCategory still accepts empty sized iterables, and one-shot iterators are no longer consumed by the check. - B14c: passing a transform class (e.g. transform.Pow) or a non-AxisTransform object (e.g. 'log') now raises a clear TypeError instead of relying on direct-base introspection or failing with AttributeError. - B15: ArrayTuple.__dir__ now lists ndarray attributes instead of calling dir() on a string literal. Assisted-by: ClaudeCode:claude-fable-5
Part of #1143 (B10): the guarded _core import in histogram.py was dead code, since boost_histogram/__init__.py imported submodules (which import _core directly) before histogram.py ever ran, so users only saw a bare ModuleNotFoundError. Move the guard into the package __init__, before any submodule import, and drop the redundant guard in histogram.py (which keeps its plain import). Also pass the combined message (original error plus hint) on Python 3.10, as originally intended. Assisted-by: ClaudeCode:claude-fable-5
…nds, and clearer errors Part of #1143: - B1: setting from a Histogram (h[...] = h2) now keeps the value's flow bins; np.asarray(value) called __array__, which silently dropped them so the expanded-setting branch could never match for histogram values. - B5: threaded fill no longer crashes on scalar positional arguments or 0-d array weights/samples; scalars are broadcast against each thread's chunk, and an all-scalar fill is performed exactly once instead of once per thread. - B8a: integer indexing accepts -size (bin 0); the bounds check used abs(), wrongly rejecting it. - B14a: a plain string index (h['a']) now raises a clear IndexError pointing at the locator protocol instead of being treated as a per-character list of indices. - B14b: invalid storage arguments raise TypeError with an accurate message both for non-storage objects (previously an issubclass() crash) and for uninitialized storage classes (previously a KeyError with an inverted message). Assisted-by: ClaudeCode:claude-fable-5
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 🤖
Part of #1143. Fixes the following verified findings, all in the Python layer, each with regression tests:
__setitem__silently dropped flow bins when the value was aHistogram—np.asarray(value)invoked__array__(view(flow=False)), so the expanded-setting branch could never match. Histogram values now useview(flow=True).np.array_spliton a 0-d array) and on 0-d array weights (np.isscalar(np.array(2.0))isFalse). Scalars now broadcast against each thread's chunk,np.ndim(...) == 0is used for weight/sample, and an all-scalar fill is performed exactly once instead of once per thread.h[-size](valid bin 0) was rejected by anabs()-based check, andax[-size-1]wrapped into the underflow bin; both now raise/accept correctly, with accurate error messages._isstrreturnedTruefor empty iterables (all()over nothing), soRegular(...).index([])raisedTypeError. Empty sequences/arrays are no longer treated as strings,StrCategory.index([])still works, and one-shot iterators are no longer consumed by the check._corefirst). The guarded import now lives inboost_histogram/__init__.pybefore any submodule import.h["a"]) raises a cleanIndexErrorinstead of per-character list indexing;storage=42/storage=bh.storage.DoubleraiseTypeErrorwith accurate messages (previouslyissubclass()crash / invertedKeyError);transform="log"/transform=Powraise clearTypeErrors (previouslyAttributeError/ direct-base-only check).ArrayTuple.__dir__calleddir()on a string literal; it now lists ndarray attributes.Test suite: 1017 passed, 1 xfailed (pre-existing);
mypystrict clean;prek -aclean.🤖 Generated with Claude Code