Skip to content

mypy 0.930: regression: no longer keeping contextmanager generic return value #11852

Closed

Description

@asottile

Bug Report

I bisected this, the regression was introduced in #11352 CC @BarnabyShearer @sobolevn

here's a minimal case split out from pre-commit:

import concurrent.futures
import contextlib
from typing import Callable
from typing import Generator
from typing import Iterable
from typing import TypeVar

TArg = TypeVar('TArg')
TRet = TypeVar('TRet')

@contextlib.contextmanager
def _thread_mapper(maxsize: int) -> Generator[
    Callable[[Callable[[TArg], TRet], Iterable[TArg]], Iterable[TRet]],
    None, None,
]:
    if maxsize == 1:
        yield map
    else:
        with concurrent.futures.ThreadPoolExecutor(maxsize) as ex:
            yield ex.map


def double(x: int) -> int: return x * 2

with _thread_mapper(1) as m:
    print(list(m(double, [2, 3])))

To Reproduce

  1. mypy t.py

Expected Behavior

I expect it to pass (as it did with 0.920)

Actual Behavior

$ mypy ../t.py
../t.py:25: error: Need type annotation for "m"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 0.930 (regression from 0.920)
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.8.10
  • Operating system and version: ubuntu 20.04

Activity

  1. sobolevn commented on Dec 27, 2021

    @sobolevn
    Member

    Thanks, I will have a look! 👍

  2. asottile commented on Dec 27, 2021

    @asottile
    ContributorAuthor

    @sobolevn I think it was a misunderstanding about send type in that PR -- there's no meaning of send types for @contextmanager since it only uses the yield type -- removing detach_callable fixes my snippet above

    let me know if you want me to turn this into a patch:

    diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py
    index 67587090e..c57c5f9a1 100644
    --- a/mypy/plugins/default.py
    +++ b/mypy/plugins/default.py
    @@ -15,7 +15,6 @@ from mypy.types import (
     from mypy.subtypes import is_subtype
     from mypy.typeops import make_simplified_union
     from mypy.checkexpr import is_literal_type_like
    -from mypy.checker import detach_callable
     
     
     class DefaultPlugin(Plugin):
    @@ -192,12 +191,12 @@ def contextmanager_callback(ctx: FunctionContext) -> Type:
                     and isinstance(default_return, CallableType)):
                 # The stub signature doesn't preserve information about arguments so
                 # add them back here.
    -            return detach_callable(default_return.copy_modified(
    +            return default_return.copy_modified(
                     arg_types=arg_type.arg_types,
                     arg_kinds=arg_type.arg_kinds,
                     arg_names=arg_type.arg_names,
                     variables=arg_type.variables,
    -                is_ellipsis_args=arg_type.is_ellipsis_args))
    +                is_ellipsis_args=arg_type.is_ellipsis_args)
         return ctx.default_return_type
     
     
    diff --git a/test-data/unit/check-default-plugin.test b/test-data/unit/check-default-plugin.test
    index fc9f132ab..6a89aa266 100644
    --- a/test-data/unit/check-default-plugin.test
    +++ b/test-data/unit/check-default-plugin.test
    @@ -29,10 +29,9 @@ from contextlib import contextmanager
     from typing import TypeVar, Generator
     
     T = TypeVar('T')
    -S = TypeVar('S')
     
     @contextmanager
    -def yield_id(item: T) -> Generator[T, S, None]:
    +def yield_id(item: T) -> Generator[T, None, None]:
         yield item
     
     reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> contextlib.GeneratorContextManager[T`-1]"
    @@ -70,10 +69,9 @@ from contextlib import asynccontextmanager
     from typing import TypeVar, AsyncGenerator
     
     T = TypeVar('T')
    -S = TypeVar('S')
     
     @asynccontextmanager
    -async def yield_id(item: T) -> AsyncGenerator[T, S]:
    +async def yield_id(item: T) -> AsyncGenerator[T, None]:
         yield item
     
     reveal_type(yield_id) # N: Revealed type is "def [T] (item: T`-1) -> typing.AsyncContextManager[T`-1]"
  3. sobolevn commented on Dec 29, 2021

    @sobolevn
    Member

    @asottile please, go ahead. Let's try this solution.
    Can you also attach the failing case as a test?

  4. asottile commented on Dec 29, 2021

    @asottile
    ContributorAuthor

    @sobolevn yep! done -- #11870

  5. added 2 commits that reference this issue on Jan 5, 2022
    06afa7c
    bc22e2a
  6. added a commit that references this issue on Jan 20, 2022
    a3e890f
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

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions