Skip to content

Commit

Permalink
ENH: improved error message on invalid getitem key (closes #1101)
Browse files Browse the repository at this point in the history
  • Loading branch information
gdementen committed Jul 18, 2024
1 parent 7bf1afc commit a7ca643
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 4 deletions.
34 changes: 34 additions & 0 deletions doc/source/changes/version_0_34_3.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,40 @@ New features
* added support for Python 3.12 (closes :issue:`1109`).


Miscellaneous improvements
^^^^^^^^^^^^^^^^^^^^^^^^^^

* improved the error message when selecting several labels at the same time and some of them were wrong.
In that case, it was hard to know which labels were wrong. This was especially annoying if the axis was long and
thus not shown in its entirety in the error message. For example, given the following array: ::

>>> arr = la.ndtest('a=a0,a1;b=b0..b2,b4..b7')
>>> arr
a\b b0 b1 b2 b4 b5 b6 b7
a0 0 1 2 3 4 5 6
a1 7 8 9 10 11 12 13

This code: ::

>>> arr['b0,b2,b3,b7']

used to produce the following error: ::

ValueError: 'b0,b2,b3,b7' is not a valid label for any axis:
a [2]: 'a0' 'a1'
b [7]: 'b0' 'b1' 'b2' ... 'b5' 'b6' 'b7'

which did not contain enough information to determine the problem was with 'b3'. It now produces this instead: ::

ValueError: 'b0,b2,b3,b7' is not a valid subset for any axis:
a [2]: 'a0' 'a1'
b [7]: 'b0' 'b1' 'b2' ... 'b5' 'b6' 'b7'
Some of those labels are valid though:
* axis 'b' contains 3 out of 4 labels (missing labels: 'b3')

Closes :issue:`1101`.


Fixes
^^^^^

Expand Down
33 changes: 32 additions & 1 deletion larray/core/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2681,7 +2681,38 @@ def _translate_nice_key(self, axis_key):
except KeyError:
continue
if not valid_axes:
raise ValueError(f"{axis_key!r} is not a valid label for any axis:\n{self._axes_summary()}")
# if the key has several labels
nicer_key = _to_key(axis_key)
sequence_types = (tuple, list, np.ndarray, ABCArray)
if (isinstance(nicer_key, sequence_types) or
(isinstance(nicer_key, Group) and isinstance(nicer_key.key, sequence_types))):

# we use a different "base" message in this case (because axis_key is not really a *label*)
msg = f"{axis_key!r} is not a valid subset for any axis:\n{self._axes_summary()}"

# ... and check for partial matches
if isinstance(nicer_key, Group):
nicer_key = nicer_key.eval()
key_label_set = set(nicer_key)
partial_matches = {}
for axis in self:
missing_labels = key_label_set - set(axis.labels)
if missing_labels < key_label_set:
partial_matches[axis] = missing_labels

if partial_matches:
partial_matches_str = '\n'.join(
f" * axis '{self.axis_id(axis)}' contains {len(key_label_set) - len(missing_labels)}"
f' out of {len(key_label_set)}'
f' labels (missing labels: {", ".join(repr(label) for label in missing_labels)})'
for axis, missing_labels in partial_matches.items()
)
msg += f"\nSome of those labels are valid though:\n{partial_matches_str}"
else:
# we have single label
msg = f"{axis_key!r} is not a valid label for any axis:\n{self._axes_summary()}"

raise ValueError(msg)
elif len(valid_axes) > 1:
raise ValueError(f'{axis_key!r} is ambiguous, it is valid in the following axes:\n'
f'{self._axes_summary(valid_axes)}')
Expand Down
8 changes: 5 additions & 3 deletions larray/tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ def test_getitem_guess_axis(array):
_ = array[[1, 2], 999]

# key with invalid label list (ie list of labels not found on any axis)
with must_raise(ValueError, """[998, 999] is not a valid label for any axis:
with must_raise(ValueError, """[998, 999] is not a valid subset for any axis:
a [19]: 0 1 2 ... 16 17 18
b [12]: 'b0' 'b1' 'b2' ... 'b10' 'b11' 'b3'
c [2]: 'c0' 'c1'
Expand All @@ -678,11 +678,13 @@ def test_getitem_guess_axis(array):
"7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18"):
_ = array[[1, 2], [3, 999]]

with must_raise(ValueError, """[999, 4] is not a valid label for any axis:
with must_raise(ValueError, """[999, 4] is not a valid subset for any axis:
a [19]: 0 1 2 ... 16 17 18
b [12]: 'b0' 'b1' 'b2' ... 'b10' 'b11' 'b3'
c [2]: 'c0' 'c1'
d [6]: 'd1' 'd2' 'd3' 'd4' 'd5' 'd6'"""):
d [6]: 'd1' 'd2' 'd3' 'd4' 'd5' 'd6'
Some of those labels are valid though:
* axis 'a' contains 1 out of 2 labels (missing labels: 999)"""):
_ = array[[1, 2], [999, 4]]

# ambiguous key
Expand Down

0 comments on commit a7ca643

Please sign in to comment.