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

max() over itertools.ifilter() is broken in 0.18.0 #510

Closed
xeron opened this issue Oct 16, 2019 · 7 comments
Closed

max() over itertools.ifilter() is broken in 0.18.0 #510

xeron opened this issue Oct 16, 2019 · 7 comments

Comments

@xeron
Copy link

xeron commented Oct 16, 2019

Python 2.7.16.
macOS 10.14.6.

Reproducible with:

import builtins
import operator

from itertools import ifilter
from random import shuffle


class Backend(object):
    def __init__(self, priority):
        super(Backend, self).__init__()
        self.priority = priority


def max(*args, **kwargs):
    """
    Add support for 'default' kwarg.

    >>> max([], default='res')
    'res'

    >>> max(default='res')
    Traceback (most recent call last):
    ...
    TypeError: ...

    >>> max('a', 'b', default='other')
    'b'
    """
    missing = object()
    default = kwargs.pop('default', missing)
    try:
        mmax = builtins.max(*args, **kwargs)
        return mmax
    except ValueError as exc:
        if 'empty sequence' in str(exc) and default is not missing:
            return default
        raise


by_priority = operator.attrgetter('priority')

backends = [Backend(5), Backend(1), Backend(0.5), Backend(0.6)]

while True:
    shuffle(backends)
    filtered_backends = ifilter(None, backends)
    max_object = max(filtered_backends, key=by_priority)
    print(max_object.priority)
    if max_object.priority != 5:
        exit(1)

Can't reproduce with 0.17.1.

This affects older versions of keyring library using similar code to select keychain backend where it wants max priority backend but returns the wrong one.

Also it looks like it depends on the order of the list.

@xeron xeron changed the title max() over ifilter() is broken in 0.18.0 max() over itertools.ifilter() is broken in 0.18.0 Oct 16, 2019
@jmadler
Copy link
Contributor

jmadler commented Oct 17, 2019

Can you submit a bugfix please? I'll include it in a release in the next few days.

@xeron
Copy link
Author

xeron commented Oct 17, 2019

Sorry, I have no idea how to fix this. We've just downgraded to 0.17.1 for now.

@gazpachoking
Copy link
Contributor

I think I'm running into a related issue. The new min and new max function consume the first item of an iterator before passing to the underlying min and max functions. I'll take a stab at a PR if I get time tonight.

@megies
Copy link
Contributor

megies commented Oct 21, 2019

I'm running into problems with with min/max of generators as well. Can't tell what the above code is doing, but it sounds related.

For me specifically, the problem seems to be min() or max() over a generator with only a single item in it. Here is a minimal example:

from future.builtins import *
min(x for x in [1])

I bisected this and it starts failing on master with commit f141395.

I checked current state of #514 and can confirm that it fixes this issue. Thanks @gazpachoking

@jmadler
Copy link
Contributor

jmadler commented Oct 24, 2019

Thanks megies for the confirmation!

Thanks all for helping make this software better :)

@jmadler jmadler closed this as completed Oct 24, 2019
@xeron
Copy link
Author

xeron commented Oct 24, 2019

Fix has not been merged yet, right?

@megies
Copy link
Contributor

megies commented Oct 25, 2019

It's been merged now :)

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

No branches or pull requests

4 participants