Skip to content

Optional key to itertools.groupby #6377

Closed

Description

@achampion

itertools.groupby has an @overload type signature but this seems makes Optional[Callable[[T], S]] not match, e.g.:

def fn(iterable: Iterable[T], key: Optional[Callable[[T], S]] = None):
    iterator: Iterator[Tuple[S, Iterator[T]]] = itertools.groupby(iterable, key)

Fails with:

error: Argument 2 to "groupby" has incompatible type "Optional[Callable[[T], S]]"; expected "Callable[[T], S]"

The revealed type of itertools.groupby:

Overload(def [_T] (iterable: typing.Iterable[_T`-1]) -> typing.Iterator[Tuple[_T`-1, typing.Iterator[_T`-1]]], def [_T, _S] (iterable: typing.Iterable[_T`-1], key: def (_T`-1) -> _S`-2) -> typing.Iterator[Tuple[_S`-2, typing.Iterator[_T`-1]]])

It is legitimate to explicitly pass None as key, so is this expected behaviour?
You can do a similar @overload for myfunc to overcome the error.

Versions:
Python 3.7.2
MyPy 0.670

Activity

  1. ilevkivskyi commented on Feb 11, 2019

    @ilevkivskyi
    Member

    I just tried and groupby([1, 2, 3, 3, 3], None) indeed doesn't crash, but according to typeshed this call is illegal. You can open an issue there, if you are sure this is actually intended/documented behavior, or you can also try something like this:

    if key is not None:
        iterator = itertools.groupby(iterable, key)
    else:
        ...
  2. achampion commented on Feb 11, 2019

    @achampion
    Author

    Thanks will do. Wasn't sure if this was a mypy issue or a typeshed issue.
    With the @overloads for itertools.groupby(), should Optional[Callable[[T], S]] match?

    While you can do if key is not None: the problem with that is you can't effectively describe the type of iterator, e.g.:

    iterator: Iterator[Tuple[S, Iterator[T]]]
    if key is not None:
        iterator = itertools.groupby(iterable, key)
    else:
        iterator = itertools.groupby(iterable)  # Fail
    

    You get the error:

    error: Incompatible types in assignment (expression has type "Iterator[Tuple[T, Iterator[T]]]", variable has type "Iterator[Tuple[S, Iterator[T]]]")
    

    And you can't declare the types in each branch because you will get a redeclaration error Name 'iterator' already defined on line ...

  3. ilevkivskyi commented on Feb 11, 2019

    @ilevkivskyi
    Member

    With the @overloads for itertools.groupby(), should Optional[Callable[[T], S]] match?

    No, with current definition in typeshed it is illegal, Optional means it can be None (not that it is an optional argument), while with current definition neither of two overloads accepts None.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions