Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update recipes.iter_index to match CPython PR 102360 #690

Merged
merged 1 commit into from
Mar 3, 2023

Conversation

bbayles
Copy link
Collaborator

@bbayles bbayles commented Mar 2, 2023

This PR updates more_itertools.recipes.iter_index to match python/cpython#102360.

We still support Python 3.7, so we're not using the Walrus operator.

@bbayles bbayles merged commit dc84bd6 into master Mar 3, 2023
@bbayles bbayles deleted the iter_index_update branch March 3, 2023 17:01
@vbrozik
Copy link

vbrozik commented Jul 24, 2023

The function iter_index(iterable, value, start=0) will silently suppress ValueError exceptions raised by a generator passed to the argument iterable.

@bbayles
Copy link
Collaborator Author

bbayles commented Jul 24, 2023

Is this also a problem with the version in the CPython docs?

@vbrozik
Copy link

vbrozik commented Jul 24, 2023

Yes, thanks, it is the same. Just to be sure I prepared a demonstration of the bug here:

https://github.com/vbrozik/python-ntb/blob/main/problems_from_forums/2023-07-24_iter_index.ipynb

def assert_no_value(iterable, forbidden_value):
    """Pass the iterable but raise ValueError if forbidden_value is found."""
    for item in iterable:
        if item == forbidden_value:
            raise ValueError(f'Value {forbidden_value!r} is not allowed.')
        yield item

# Here we should get ValueError exception
# but it is being silently suppressed by iter_index()
list(iter_index(assert_no_value('AABCADEAF', 'B'), 'A'))

So I should probably create an issue for the CPython docs, right?

@bbayles
Copy link
Collaborator Author

bbayles commented Jul 24, 2023

Yes, probably a good idea!

@rhettinger
Copy link
Contributor

rhettinger commented Jul 25, 2023

@bbayles It's going to take a while for the CPython docs issue to resolve because the best solution involves adding a new exception type to distinguish between the two sources of ValueError. Without that change, operator.indexOf cannot be reliably used with iterators or exotic sequences.

For more-itertools, the safest play is to revert this PR which was only an optimization.

Alternatively, the optimization could be preserved by inspecting the exception to distinguish between the two cases:

try:                                                   # <==== new
    operator.indexOf('abc', 'd')                       # <==== new
except ValueError as e:                                # <==== new
    _index_of_value_error_repr = repr(e)               # <==== new
    
def iter_index(iterable, value, start=0):
    "Return indices where a value occurs in a sequence or iterable."
    # iter_index('AABCADEAF', 'A') --> 0 1 4 7
    try:
        seq_index = iterable.index
    except AttributeError:
        # Slow path for general iterables
        it = islice(iterable, start, None)
        i = start - 1
        try:
            while True:
                yield (i := i + operator.indexOf(it, value) + 1)
        except ValueError as e:
            if repr(e) != _index_of_value_error_repr:  # <==== new
                raise                                  # <==== new
    else:
        # Fast path for sequences
        i = start - 1
        try:
            while True:
                yield (i := seq_index(value, i+1))
        except ValueError:
            pass

@bbayles
Copy link
Collaborator Author

bbayles commented Jul 25, 2023

@rhettinger - thanks for the comments.

The code prior to the optimization in python/cpython#102360 also has a ValueError catch in the "Fast path for sequences," yes? I presume that one is also problematic, at least in theory.

@vbrozik
Copy link

vbrozik commented Jul 25, 2023

@bbayles you are right. In the fast path the problem was already there although it is less common to define own sequence class raising a ValueError.

Here Stefan @pochmann replicated the problem: python/cpython#107208 (comment)

@bbayles
Copy link
Collaborator Author

bbayles commented Jul 25, 2023

Thanks - I subscribed to that thread.

@rhettinger
Copy link
Contributor

I'm not concerned about ValueError capture for the sequence path. The technique of looping over seq.index() calls and catching ValueError is as old as the hills and is the only reason that index was ever given a start argument. The technique doesn't seem to have ever been a problem in practice and is sure not worth hobbling the recipe. That would just make everyone pay for a problem that no one actually has.

lengau pushed a commit to canonical/charmcraft that referenced this pull request Jul 25, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [more-itertools](https://togithub.com/more-itertools/more-itertools) |
`==9.1.0` -> `==10.0.0` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/more-itertools/10.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/more-itertools/10.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/more-itertools/9.1.0/10.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/more-itertools/9.1.0/10.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>more-itertools/more-itertools (more-itertools)</summary>

###
[`v10.0.0`](https://togithub.com/more-itertools/more-itertools/releases/tag/v10.0.0):
Version 10.0.0

[Compare
Source](https://togithub.com/more-itertools/more-itertools/compare/v9.1.0...v10.0.0)

##### What's Changed

- Update recipes.iter_index to match CPython PR 102360 by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#690
- fixup - add missing commas to the readme function table by
[@&#8203;lonnen](https://togithub.com/lonnen) in
[more-itertools/more-itertools#692
- fixup remove 3.6 from tox by
[@&#8203;lonnen](https://togithub.com/lonnen) in
[more-itertools/more-itertools#693
- seekable: Add relative_seek by
[@&#8203;karlb](https://togithub.com/karlb) in
[more-itertools/more-itertools#694
- Optimize \_chunked_even_finite() by
[@&#8203;elliotwutingfeng](https://togithub.com/elliotwutingfeng) in
[more-itertools/more-itertools#699
- Indexing of combinations with replacement by
[@&#8203;Schoyen](https://togithub.com/Schoyen) in
[more-itertools/more-itertools#689
- Add notes for transposing empty inputs by
[@&#8203;XuehaiPan](https://togithub.com/XuehaiPan) in
[more-itertools/more-itertools#700
- Add the polynomial_eval recipe by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#703
- Add nth_combination_with_replacement by
[@&#8203;Schoyen](https://togithub.com/Schoyen) in
[more-itertools/more-itertools#704
- Add sum_of_squares, sync with itertools by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#706
- Issue
[#&#8203;707](https://togithub.com/more-itertools/more-itertools/issues/707):
fix `iterate()` to enable `func` to raise StopIteration + 3 unittests by
[@&#8203;jrebiffe](https://togithub.com/jrebiffe) in
[more-itertools/more-itertools#708
- Update polynomial_from roots and convolve by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#709
- Issue
[#&#8203;677](https://togithub.com/more-itertools/more-itertools/issues/677):
Improve `partition` by [@&#8203;pochmann](https://togithub.com/pochmann)
in
[more-itertools/more-itertools#710
- Issue
[#&#8203;713](https://togithub.com/more-itertools/more-itertools/issues/713):
Fix `partial_product` (also simplify and clean up) by
[@&#8203;pochmann](https://togithub.com/pochmann) in
[more-itertools/more-itertools#714
- Issue
[#&#8203;711](https://togithub.com/more-itertools/more-itertools/issues/711):
Optimize `pairwise` by [@&#8203;pochmann](https://togithub.com/pochmann)
in
[more-itertools/more-itertools#712
- Issue
[#&#8203;715](https://togithub.com/more-itertools/more-itertools/issues/715):
Simplify/optimize `partial_product` by
[@&#8203;pochmann](https://togithub.com/pochmann) in
[more-itertools/more-itertools#716
- Issue
[#&#8203;717](https://togithub.com/more-itertools/more-itertools/issues/717):
Improve `duplicates_justseen` by
[@&#8203;pochmann](https://togithub.com/pochmann) in
[more-itertools/more-itertools#718
- Fix unique_in_window to match described behavior by
[@&#8203;elliotwutingfeng](https://togithub.com/elliotwutingfeng) in
[more-itertools/more-itertools#720
- Add polynomial_derivative recipe by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#723
- Update recipes with CPython PRs: 105403 and 106371 by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#731
- Changes for version 10.0.0 by
[@&#8203;bbayles](https://togithub.com/bbayles) in
[more-itertools/more-itertools#734
- Delay computation of numeric_range len until needed by
[@&#8203;eltoder](https://togithub.com/eltoder) in
[more-itertools/more-itertools#674

##### New Contributors

- [@&#8203;karlb](https://togithub.com/karlb) made their first
contribution in
[more-itertools/more-itertools#694
- [@&#8203;elliotwutingfeng](https://togithub.com/elliotwutingfeng) made
their first contribution in
[more-itertools/more-itertools#699
- [@&#8203;Schoyen](https://togithub.com/Schoyen) made their first
contribution in
[more-itertools/more-itertools#689
- [@&#8203;XuehaiPan](https://togithub.com/XuehaiPan) made their first
contribution in
[more-itertools/more-itertools#700
- [@&#8203;jrebiffe](https://togithub.com/jrebiffe) made their first
contribution in
[more-itertools/more-itertools#708
- [@&#8203;pochmann](https://togithub.com/pochmann) made their first
contribution in
[more-itertools/more-itertools#710
- [@&#8203;eltoder](https://togithub.com/eltoder) made their first
contribution in
[more-itertools/more-itertools#674

**Full Changelog**:
more-itertools/more-itertools@v9.1.1...v10.0.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" in timezone Etc/UTC,
Automerge - "before 07:00" in timezone Etc/UTC.

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/canonical/charmcraft).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4xMS4wIiwidXBkYXRlZEluVmVyIjoiMzYuMTEuMCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants