GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||
GeezerVison is showing github.com — require Generator for `contextmanager` by asottile · Pull Request #7430 · python/typeshed Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Contributor
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Contributor
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Collaborator
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Contributor
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
|
There was an error while loading. Please reload this page.
|
Seems like I'm in the minority, but I'm -1 on this. Breaking almost every use case of contextmanager for something pretty niche is too much for me. Other than your reports, I haven't encountered instances of people running into this. There are zero emojis on the issue report. There are two out links, neither of which seems to actually have the bug in question. Maybe a failure of my imagination, but I'm also struggling to think of the real world code that motivates someone to return an iterator here. On the other hand, it's very common for users with correct code to get confused when adding types for Iterable, Iterator, Generator. By steering users to use the scary and not ergonomic Generator, this is a real loss of usability in the 99.99% use case going forward as well. There's a reason there's so much code out there that this would break. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
It's a shame we don't have something like the following construct in _T_co = TypeVar("_T_co", covariant=True) SimpleGenerator = Generator[_T_co, None, None] Returning |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
it would be a bit nicer if we had TypeVar defaults so we could just write |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Also note that a linter could warn for contextmanager decorated functions that don't yield. Could be a good check to add to pylint or flake8-bugbear. Since this wouldn't look at annotations, it'd side step the issue of forcing users to change their annotations. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
the case I had would not have been detected by that -- it returned an iterable from another function call. I think this really needs type checkers to do the proper thing |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
@asottile I'm not sure I understand. If you have a function like this: @contextmanager def func(): return other_generator_function() Then a flake8 plugin could easily require that you do this instead, ensuring type safety: @contextmanager def func(): yield from other_generator_function() It doesn't need to do any fancy guesswork about whether We can agree that this would definitely be an imperfect solution, but it would be far less disruptive. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I prefer Another possible solution would be mypy automatically inferring the correct return type for functions that |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
But it's also confusing. A generator function return a generator after all (which happens to be an iterator as well). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
You really shouldn't have to care. The type annotation in this case should IMO be something simple that doesn't get in the way, not something full of |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I'm still in favor of allowing |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@asottile could you share more thoughts on why your case couldn't be caught by a simple and much less disruptive new linter check? It's unclear to at least Alex and I, see #7430 (comment) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@hauntsaninja I addressed that here: #7430 (comment) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
additionally, the recommendation also does not work for async where there's no |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
When changes are really disruptive, like python#7430, we truncate output. Mention this, so that it's known that the change is even more disruptive than it might appear.
fwiw, one outage easily costs more than that |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Yeah, it can cost more than than, but not every outage will be this expensive? It seems hard to estimate the likelihood of a change like this preventing an outage, though -- or is there an actual outage you're familiar with? The likelihood of many users having to update code is very high, since I have an alternative proposal that would mostly solve the original issue and wouldn't require a lot of work from end users: special case the Type checkers would allow these: @contextmanager def f() -> Iterator[None]: yield None @contextmanager def f() -> Generator[None, None, None]: return <some generator> But this wouldn't pass, since the decorated function isn't a generator function: @contextmanager def f() -> Iterator[None]: return iter(...) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
this particular typing wart has already cost 3x more than your estimates above just from my experiences, and I'm sure I'm not alone in this. I also believe you're over-estimating the fix cost here, it is a simple find and replace to resolve the issue for the easiest case (and points out real bugs in the not-easiest case!). the typeshed stubs-no-longer-included migration easily dwarfs this in toil to mypy users. this is an exceptionally easy mistake to make even above while arguing against the change!. and again, your suggestion won't help anything except for the most basic situation (which could already be detected by a linter) my situation looks roughly like: async def other_funtion_which_is_async_generator() -> AsyncIterator[...]: if some_precondition: return [...] # bug was here elif ...: yield ... return ... yield ... return ... @asynccontextmanger async def ctx() -> AsyncIterator[...]: if some_complicated_condition: return other_function_which_is_async_generator() elif other_condition: async with ..." yield ... return yield ... return unless your suggestion is to transparently change all "returns iterator but is a generator" functions from: def f() -> Iterator[T]: yield ... to def f() -> Generator[T, None, None]: yield ... then I don't think it will help (and even then I'm not sure it helps my case given it's not yielding on all branches but returning another function) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@asottile Thanks for the additional context! This change now makes more sense to me.
Generally imports need to be adjusted as well to update code, which is somewhat hard to to do using find/replace tools. I agree that the fix is quite easy, but figuring out what needs to be done, and investigating whether this is a false positive or a mypy issue + the required context switch, creating a PR/change request, possibly getting it reviewed, waiting for CI, etc. is included in my 15 minute estimate (which is still pretty arbitrary). To reduce the toil, we could add a dedicated error message about the non-Generator return type with clear instructions about what needs to be done. Providing a tool to automatically upgrade simple cases in affected code would further help, if it could also update imports.
Yes, we knew that to have a big cost. We decided to move forward with it since not doing it risked making every future mypy upgrade painful for larger projects (mainly due to requiring all third-party stubs to be upgraded in lockstep with mypy). We try to avoid similar big breakages whenever there is a good alternative. That's why I'm trying to figure out if there is something less disruptive we could do here. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for considering this change. I came here after learning that I have to wrap async generators in an Unfortunately,
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Diff from mypy_primer, showing the effect of this PR on open source code: vision (https://github.com/pytorch/vision) + torchvision/datasets/imagenet.py:127: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[str]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + torchvision/datasets/imagenet.py:142: error: Need type annotation for "tmp_dir" [var-annotated] pegen (https://github.com/we-like-parsers/pegen) + src/pegen/parser_generator.py:64: error: Argument 1 to "contextmanager" has incompatible type "Callable[[ParserGenerator], Iterator[None]]"; expected "Callable[[ParserGenerator], Generator[<nothing>, Any, Any]]" [arg-type] + src/pegen/parser_generator.py:78: error: Argument 1 to "contextmanager" has incompatible type "Callable[[ParserGenerator], Iterator[None]]"; expected "Callable[[ParserGenerator], Generator[<nothing>, Any, Any]]" [arg-type] porcupine (https://github.com/Akuli/porcupine) + porcupine/textutils.py:445: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Text], Iterator[None]]"; expected "Callable[[Text], Generator[<nothing>, Any, Any]]" [arg-type] streamlit (https://github.com/streamlit/streamlit) + lib/streamlit/runtime/caching/cache_utils.py: note: In class "CacheWarningCallStack": + lib/streamlit/runtime/caching/cache_utils.py:285:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[CacheWarningCallStack, FunctionType], Iterator[None]]"; expected "Callable[[CacheWarningCallStack, FunctionType], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/runtime/caching/cache_utils.py:293:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[CacheWarningCallStack], Iterator[None]]"; expected "Callable[[CacheWarningCallStack], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/runtime/caching/cache_utils.py: note: In class "CacheMessagesCallStack": + lib/streamlit/runtime/caching/cache_utils.py:389:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[CacheMessagesCallStack], Iterator[None]]"; expected "Callable[[CacheMessagesCallStack], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/runtime/legacy_caching/caching.py: note: At top level: + lib/streamlit/runtime/legacy_caching/caching.py:165:2: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Callable[..., Any]], Iterator[None]]"; expected "Callable[[Callable[..., Any]], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/runtime/legacy_caching/caching.py:174:2: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/runtime/caching/__init__.py:72:2: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + lib/streamlit/__init__.py:393:2: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[None]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" [arg-type] jax (https://github.com/google/jax) + jax/_src/config.py:902: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/config.py:913: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/config.py:1006: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[None]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/source_info_util.py:198: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[NameStack]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/source_info_util.py:209: error: Argument 1 to "contextmanager" has incompatible type "Callable[[NameStack], Iterator[None]]"; expected "Callable[[NameStack], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/source_info_util.py:219: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + jax/_src/source_info_util.py:224: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[NameStack]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" [arg-type] mypy-protobuf (https://github.com/dropbox/mypy-protobuf) + mypy_protobuf/main.py:229: error: Argument 1 to "contextmanager" has incompatible type "Callable[[PkgWriter], Iterator[None]]"; expected "Callable[[PkgWriter], Generator[<nothing>, Any, Any]]" [arg-type] + mypy_protobuf/main.py:973: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[Tuple[CodeGeneratorRequest, CodeGeneratorResponse]]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + mypy_protobuf/main.py:1005: error: <nothing> object is not iterable [misc] + mypy_protobuf/main.py:1007: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1008: error: Cannot determine type of "response" [has-type] + mypy_protobuf/main.py:1009: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1010: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1011: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1017: error: <nothing> object is not iterable [misc] + mypy_protobuf/main.py:1019: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1020: error: Cannot determine type of "response" [has-type] + mypy_protobuf/main.py:1021: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1022: error: Cannot determine type of "request" [has-type] + mypy_protobuf/main.py:1023: error: Cannot determine type of "request" [has-type] black (https://github.com/psf/black) + src/blib2to3/pgen2/parse.py:74:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Recorder, int], Iterator[None]]"; expected "Callable[[Recorder, int], Generator[<nothing>, Any, Any]]" [arg-type] + src/blib2to3/pgen2/parse.py:85:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Recorder], Iterator[None]]"; expected "Callable[[Recorder], Generator[<nothing>, Any, Any]]" [arg-type] + src/blib2to3/pgen2/driver.py:68:6: error: Argument 1 to "contextmanager" has incompatible type "Callable[[TokenProxy], Iterator[TokenProxy]]"; expected "Callable[[TokenProxy], Generator[<nothing>, Any, Any]]" [arg-type] + src/black/__init__.py:1334:2: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] kopf (https://github.com/nolar/kopf) + kopf/_core/actions/invocation.py:73: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Iterable[Tuple[ContextVar[Any], Any]]], Iterator[None]]"; expected "Callable[[Iterable[Tuple[ContextVar[Any], Any]]], Generator[<nothing>, Any, Any]]" + kopf/_core/actions/execution.py:193: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[], AsyncIterator[None]]"; expected "Callable[[], AsyncGenerator[<nothing>, Any]]" + kopf/_cogs/clients/watching.py:71: error: Need type annotation for "operator_pause_waiter" + kopf/_cogs/clients/watching.py:89: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[NamedArg(Resource, 'resource'), NamedArg(Optional[NamespaceName], 'namespace'), DefaultNamedArg(Optional[ToggleSet], 'operator_paused')], AsyncIterator[Future[Any]]]"; expected "Callable[[NamedArg(Resource, 'resource'), NamedArg(Optional[NamespaceName], 'namespace'), DefaultNamedArg(Optional[ToggleSet], 'operator_paused')], AsyncGenerator[<nothing>, Any]]" + kopf/_core/reactor/subhandling.py:17: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[], AsyncIterator[None]]"; expected "Callable[[], AsyncGenerator[<nothing>, Any]]" isort (https://github.com/pycqa/isort) + isort/io.py:55: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[str, Path]], Iterator[File]]"; expected "Callable[[Union[str, Path]], Generator[<nothing>, Any, Any]]" + isort/deprecated/finders.py:40: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[None]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" + isort/api.py:337: error: Need type annotation for "source_file" + isort/api.py:353: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[TextIO]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" + isort/api.py:358: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[str, Path], File], Iterator[TextIO]]"; expected "Callable[[Union[str, Path], File], Generator[<nothing>, Any, Any]]" + isort/api.py:405: error: Need type annotation for "source_file" + isort/api.py:423: error: Need type annotation for "output_stream_context" + isort/api.py:591: error: Need type annotation for "source_file" + isort/pylama_isort.py:13: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" pandas (https://github.com/pandas-dev/pandas) + pandas/util/_exceptions.py:10: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str, str], Iterator[None]]"; expected "Callable[[str, str], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_config/config.py:745: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any], Iterator[None]]"; expected "Callable[[Any], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_config/localization.py:20: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[str, Tuple[str, str]], int], Iterator[Union[str, Tuple[str, str]]]]"; expected "Callable[[Union[str, Tuple[str, str]], int], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/core/common.py:536: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any, str, Any], Iterator[None]]"; expected "Callable[[Any, str, Any], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/plotting/_misc.py:596: error: Argument 1 to "contextmanager" has incompatible type "Callable[[_Options, Any, Any], Iterator[_Options]]"; expected "Callable[[_Options, Any, Any], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/io/formats/format.py:1208: error: Need type annotation for "f" [var-annotated] + pandas/io/formats/format.py:1212: error: Unused "type: ignore" comment + pandas/io/formats/format.py:1216: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[Union[str, PathLike[str]], WriteBuffer[str], None], Optional[str]], Union[Iterator[WriteBuffer[str]], Iterator[StringIO]]]"; expected "Callable[[Union[Union[str, PathLike[str]], WriteBuffer[str], None], Optional[str]], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/core/groupby/groupby.py:1108: error: Argument 1 to "contextmanager" has incompatible type "Callable[[GroupBy[NDFrameT]], Iterator[GroupBy[Any]]]"; expected "Callable[[GroupBy[NDFrameT]], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/compat/pickle_compat.py:296: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:22: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any, Any], Iterator[IO[bytes]]]"; expected "Callable[[Any, Any], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:43: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[None]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:129: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[str]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:148: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:164: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any, KwArg(Any)], Iterator[None]]"; expected "Callable[[Any, KwArg(Any)], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/_testing/contexts.py:198: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any, Any], Iterator[None]]"; expected "Callable[[Any, Any], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/util/_test_decorators.py:259: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + pandas/plotting/_matplotlib/converter.py:101: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] pybind11 (https://github.com/pybind/pybind11) + setup.py:114: error: Argument 1 to "contextmanager" has incompatible type "Callable[[VarArg(str)], Iterator[None]]"; expected "Callable[[VarArg(str)], Generator[<nothing>, Any, Any]]" [arg-type] + pybind11/setup_helpers.py:215: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[str]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] paasta (https://github.com/yelp/paasta) + paasta_tools/utils.py:1657: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[None]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" + paasta_tools/utils.py:1759: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[IOBase, IO[Any]]], Iterator[None]]"; expected "Callable[[Union[IOBase, IO[Any]]], Generator[<nothing>, Any, Any]]" + paasta_tools/utils.py:1768: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[IOBase, IO[Any]], int], Iterator[None]]"; expected "Callable[[Union[IOBase, IO[Any]], int], Generator[<nothing>, Any, Any]]" + paasta_tools/utils.py:1774: error: Need type annotation for "flock_context" + paasta_tools/utils.py:2828: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str], Iterator[IO[Any]]]"; expected "Callable[[str], Generator[<nothing>, Any, Any]]" + paasta_tools/bounce_lib.py:132: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str, Optional[SystemPaastaConfig]], Iterator[Any]]"; expected "Callable[[str, Optional[SystemPaastaConfig]], Generator[<nothing>, Any, Any]]" + paasta_tools/generate_deployments_for_service.py:236: error: Need type annotation for "newf" + paasta_tools/autoscaling/autoscaling_service_lib.py:984: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str, str], Iterator[None]]"; expected "Callable[[str, str], Generator[<nothing>, Any, Any]]" core (https://github.com/home-assistant/core) + homeassistant/components/fjaraskupan/__init__.py:105: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[Coordinator], AsyncIterator[Any]]"; expected "Callable[[Coordinator], AsyncGenerator[<nothing>, Any]]" [arg-type] + homeassistant/components/file_upload/__init__.py:31: error: Argument 1 to "contextmanager" has incompatible type "Callable[[HomeAssistant, str], Iterator[Path]]"; expected "Callable[[HomeAssistant, str], Generator[<nothing>, Any, Any]]" [arg-type] + homeassistant/components/zha/config_flow.py:408: error: Need type annotation for "file_path" [var-annotated] + homeassistant/components/script/trace.py:21: error: Argument 1 to "contextmanager" has incompatible type "Callable[[HomeAssistant, str, Dict[str, Any], Dict[str, Any], Context, Dict[str, Any]], Iterator[ScriptTrace]]"; expected "Callable[[HomeAssistant, str, Dict[str, Any], Dict[str, Any], Context, Dict[str, Any]], Generator[<nothing>, Any, Any]]" [arg-type] + homeassistant/components/fjaraskupan/number.py:61: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/light.py:50: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/light.py:60: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/fan.py:88: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/fan.py:109: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/fan.py:126: error: Need type annotation for "device" [var-annotated] + homeassistant/components/fjaraskupan/fan.py:133: error: Need type annotation for "device" [var-annotated] + homeassistant/components/amcrest/__init__.py:208: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[AmcrestChecker, VarArg(Any), KwArg(Any)], AsyncIterator[Any]]"; expected "Callable[[AmcrestChecker, VarArg(Any), KwArg(Any)], AsyncGenerator[<nothing>, Any]]" [arg-type] + homeassistant/components/amcrest/__init__.py:217: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[AmcrestChecker], AsyncIterator[None]]"; expected "Callable[[AmcrestChecker], AsyncGenerator[<nothing>, Any]]" [arg-type] spark (https://github.com/apache/spark) + python/pyspark/pandas/utils.py:489: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Dict[str, Any], DefaultNamedArg(Optional[SparkSession], 'spark')], Iterator[None]]"; expected "Callable[[Dict[str, Any], DefaultNamedArg(Optional[SparkSession], 'spark')], Generator[<nothing>, Any, Any]]" [arg-type] + python/pyspark/pandas/config.py:375: error: Argument 1 to "contextmanager" has incompatible type "Callable[[VarArg(Any)], Iterator[None]]"; expected "Callable[[VarArg(Any)], Generator[<nothing>, Any, Any]]" [arg-type] pyinstrument (https://github.com/joerick/pyinstrument) - pyinstrument/vendor/decorator.py:295: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, VarArg(Any), KwArg(Any)], Any]", variable has type "Callable[[_GeneratorContextManager[_T_co], Callable[..., Iterator[_T_co]], Tuple[Any, ...], Dict[str, Any]], None]") + pyinstrument/vendor/decorator.py:295: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, VarArg(Any), KwArg(Any)], Any]", variable has type "Callable[[_GeneratorContextManager[_T_co], Callable[..., Generator[_T_co, Any, Any]], Tuple[Any, ...], Dict[str, Any]], None]") - pyinstrument/vendor/decorator.py:301: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, VarArg(Any), KwArg(Any)], Any]", variable has type "Callable[[_GeneratorContextManager[_T_co], Callable[..., Iterator[_T_co]], Tuple[Any, ...], Dict[str, Any]], None]") + pyinstrument/vendor/decorator.py:301: error: Incompatible types in assignment (expression has type "Callable[[Any, Any, VarArg(Any), KwArg(Any)], Any]", variable has type "Callable[[_GeneratorContextManager[_T_co], Callable[..., Generator[_T_co, Any, Any]], Tuple[Any, ...], Dict[str, Any]], None]") poetry (https://github.com/python-poetry/poetry) + src/poetry/config/file_config_source.py:34: error: Need type annotation for "toml" [var-annotated] + src/poetry/config/file_config_source.py:49: error: Need type annotation for "toml" [var-annotated] + src/poetry/config/file_config_source.py:65: error: Argument 1 to "contextmanager" has incompatible type "Callable[[FileConfigSource], Iterator[Any]]"; expected "Callable[[FileConfigSource], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/utils/helpers.py:30: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Path], Iterator[Path]]"; expected "Callable[[Path], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/utils/helpers.py:89: error: Need type annotation for "update_context" [var-annotated] + src/poetry/utils/env.py:1751: error: Argument 1 to "contextmanager" has incompatible type "Callable[[VirtualEnv], Iterator[None]]"; expected "Callable[[VirtualEnv], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/utils/env.py:1885: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Union[str, Path, None], Optional[Dict[str, bool]]], Iterator[VirtualEnv]]"; expected "Callable[[Union[str, Path, None], Optional[Dict[str, bool]]], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/utils/env.py:1901: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Any, Optional[Env], Optional[Any]], Iterator[Env]]"; expected "Callable[[Any, Optional[Env], Optional[Any]], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/utils/env.py:1913: error: Need type annotation for "venv" [var-annotated] + src/poetry/inspection/info.py:578: error: Need type annotation for "venv" [var-annotated] + src/poetry/puzzle/provider.py:66: error: Argument 1 to "contextmanager" has incompatible type "Callable[[], Iterator[Callable[[Optional[str]], None]]]"; expected "Callable[[], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/puzzle/provider.py:178: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Provider, Path], Iterator[Provider]]"; expected "Callable[[Provider, Path], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/puzzle/provider.py:188: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Provider, Env], Iterator[Provider]]"; expected "Callable[[Provider, Env], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/puzzle/provider.py:201: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Provider, Collection[Any]], Iterator[Provider]]"; expected "Callable[[Provider, Collection[Any]], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/puzzle/solver.py:62: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Solver, Env], Iterator[None]]"; expected "Callable[[Solver, Env], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/puzzle/solver.py:104: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Solver], Iterator[None]]"; expected "Callable[[Solver], Generator[<nothing>, Any, Any]]" [arg-type] + src/poetry/masonry/builders/editable.py:86: error: Need type annotation for "env" [var-annotated] + src/poetry/console/commands/build.py:26: error: Need type annotation for "env" [var-annotated] pylint (https://github.com/pycqa/pylint) + pylint/lint/utils.py:88: error: Argument 1 to "contextmanager" has incompatible type "Callable[[Sequence[str]], Iterator[None]]"; expected "Callable[[Sequence[str]], Generator[<nothing>, Any, Any]]" [arg-type] + pylint/lint/pylinter.py:670: error: Need type annotation for "check_astroid_module" [var-annotated] + pylint/lint/pylinter.py:719: error: Need type annotation for "check_astroid_module" [var-annotated] + pylint/lint/pylinter.py:916: error: Argument 1 to "contextmanager" has incompatible type "Callable[[PyLinter], Iterator[Callable[[Any], Optional[bool]]]]"; expected "Callable[[PyLinter], Generator[<nothing>, Any, Any]]" [arg-type] ibis (https://github.com/ibis-project/ibis) + ibis/config.py:141: error: Argument 1 to "contextmanager" has incompatible type "Callable[[str, Any], Iterator[None]]"; expected "Callable[[str, Any], Generator[<nothing>, Any, Any]]" jinja (https://github.com/pallets/jinja) + src/jinja2/compiler.py:1753: error: Argument 1 to "contextmanager" has incompatible type "Callable[[CodeGenerator, Union[Filter, Test], Frame, bool], Iterator[None]]"; expected "Callable[[CodeGenerator, Union[Filter, Test], Frame, bool], Generator[<nothing>, Any, Any]]" [arg-type] rotki (https://github.com/rotki/rotki) + rotkehlchen/db/upgrades/v34_v35.py:100: error: Need type annotation for "write_cursor" + rotkehlchen/db/upgrades/v33_v34.py:13: error: Need type annotation for "write_cursor" + rotkehlchen/globaldb/handler.py:1131: error: Need type annotation for "user_db_cursor" + rotkehlchen/assets/utils.py:100: error: Need type annotation for "cursor" + rotkehlchen/db/upgrades/v32_v33.py:485: error: Need type annotation for "cursor" + rotkehlchen/db/ledger_actions.py:138: error: Need type annotation for "cursor" + rotkehlchen/db/history_events.py:86: error: Need type annotation for "cursor" + rotkehlchen/db/history_events.py:120: error: Need type annotation for "cursor" + rotkehlchen/db/eth2.py:120: error: Need type annotation for "cursor" + rotkehlchen/db/eth2.py:227: error: Need type annotation for "cursor" + rotkehlchen/db/eth2.py:252: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/yearn/vaults.py:772: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/yearn/vaults.py:823: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/yearn/vaults.py:879: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/l2/loopring.py:540: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/balancer/balancer.py:319: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/balancer/balancer.py:1101: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/balancer/balancer.py:1121: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/adex/adex.py:516: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/adex/adex.py:756: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/adex/adex.py:896: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/adex/adex.py:972: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/aave/graph.py:808: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/interfaces/ammswap/ammswap.py:425: error: Need type annotation for "cursor" + rotkehlchen/chain/bitcoin/xpub.py:212: error: Need type annotation for "cursor" + rotkehlchen/chain/bitcoin/xpub.py:274: error: Need type annotation for "cursor" + rotkehlchen/balances/manual.py:87: error: Need type annotation for "cursor" + rotkehlchen/balances/manual.py:107: error: Need type annotation for "cursor" + rotkehlchen/balances/manual.py:124: error: Need type annotation for "cursor" + rotkehlchen/exchanges/exchange.py:288: error: Need type annotation for "cursor" + rotkehlchen/exchanges/exchange.py:339: error: Need type annotation for "cursor" + rotkehlchen/exchanges/exchange.py:401: error: Need type annotation for "cursor" + rotkehlchen/exchanges/exchange.py:458: error: Need type annotation for "cursor" + rotkehlchen/db/upgrade_manager.py:115: error: Need type annotation for "cursor" + rotkehlchen/db/upgrade_manager.py:170: error: Need type annotation for "cursor" + rotkehlchen/db/ethtx.py:224: error: Need type annotation for "cursor" + rotkehlchen/db/ethtx.py:466: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/nfts.py:201: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/nfts.py:271: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/nfts.py:287: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/sushiswap/sushiswap.py:223: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/eth2/eth2.py:91: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/eth2/eth2.py:148: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/eth2/eth2.py:266: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/eth2/eth2.py:477: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/aave/aave.py:204: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/aave/aave.py:311: error: Need type annotation for "cursor" + rotkehlchen/exchanges/kraken.py:1172: error: Need type annotation for "write_cursor" + rotkehlchen/chain/ethereum/modules/yearn/vaultsv2.py:347: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/yearn/vaultsv2.py:370: error: Need type annotation for "cursor" + rotkehlchen/chain/ethereum/modules/uniswap/uniswap.py:343: error: Need type annotation for "cursor" + rotkehlchen/exchanges/manager.py:120: error: Need type annotation for "cursor" + rotkehlchen/db/reports.py:87: error: Need type annotation for "cursor" + rotkehlchen/db/reports.py:131: error: Need type annotation for "cursor" + rotkehlchen/db/reports.py:242: error: Need type annotation for "cursor" + rotkehlchen/db/reports.py:267: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:268: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:536: error: Argument 1 to "contextmanager" has incompatible type "Callable[[DBHandler], Iterator[DBCursor]]"; expected "Callable[[DBHandler], Generator[<nothing>, Any, Any]]" + rotkehlchen/db/dbhandler.py:558: error: Argument 1 to "contextmanager" has incompatible type "Callable[[DBHandler], Iterator[DBCursor]]"; expected "Callable[[DBHandler], Generator[<nothing>, Any, Any]]" + rotkehlchen/db/dbhandler.py:607: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:677: error: Need type annotation for "write_cursor" + rotkehlchen/db/dbhandler.py:1025: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:1660: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:2359: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:2606: error: Need type annotation for "write_cursor" + rotkehlchen/db/dbhandler.py:3114: error: Need type annotation for "write_cursor" + rotkehlchen/db/dbhandler.py:3278: error: Need type annotation for "cursor" + rotkehlchen/db/dbhandler.py:3299: error: Need type ... (truncated 521 lines) ... |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Question for other maintainers: What is needed for this to go in?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I think this is too disruptive until we have PEP-696 (TypeVar defaults). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I also think this is just too disruptive, I'm afraid :( I'd much prefer it if type checkers could add some special-casing for this, as @JukkaL suggested. This is one of those occasions where it really should be solved in the stubs... but I just don't think the backwards-compatibility break is worth the cost (and I don't want to have to tell people they need to make their type hints much uglier every time they use |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
The mypy-primer output looks disruptive but these cases are all easy to fix (for example in pandas pandas-dev/pandas#48383). Importantly, it is only necessary to fix the few(er) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I'm against merging python#7430 because: - Generator is not an ergonomic type - It's very widely breaking - Safety could easily be enforced by a linter that ensures use of `yield from` instead of `return` in an @contextmanager To expand on that a little: - I care about the typing system being accessible. Generator with its three type vars is not a friendly type. I see enough confusion about Iterable, Iterator, Generator as it is. - Maintaining a high signal to noise / effort ratio is an important part of making typing accessible. Breaking changes that seem arbitrary to a casual user reinforce existing negative impressions of typing that hurt the ecosystem as a whole. - In all the years of typing, this has come up basically never (reported twice by asottile, none of the outlinks from the issue contain the bug, issue itself is not popular), so I think this is 99.99% noise. Between typeshed and mypy, I've seen a lot of typing issue reports. But I'm willing to admit that the considerations are slightly different for asynccontextmanager: - async is less widely used than sync, so maybe this is less widely breaking (let's at least see primer) - async is typically used by more experienced Python users, so there's already an accessibility floor here - There is no equivalent to `yield from` in async that a linter could enforce, so this genuinely can only be solved in type checkers - The issue that led to python#7430 was with asynccontextmanager - We've gotten away with some pedantic narrowings of async types before This is just an experiment, I'm not sure whether I'm actually in favour of this change, but I'm a lot more willing to consider it. Note that I'm not open to slippery slope consistency arguments here; if a constraint is that we do both async and sync or neither, then I'm firmly in the neither camp.
There was an error while loading. Please reload this page.
|
There are currently three maintainers against and one maintainer for, so I'm closing this PR. We can think about revisiting if PEP 696 is accepted and implemented. I do think the pros and cons are slightly different for contextmanager vs asynccontextmanager, so I'm willing to consider the asynccontextmanager change on its own. This is #8698 If you stumble upon this, I'm also interested in hearing about non-hypothetical cases where you actually have first-hand run into issues preventable by this; please comment on issue #2772 if so. Hearing about such cases helps us make informed decisions about the value of changes like this. As is mentioned in this PR, if you're looking for safety in the sync case, a linter can enforce use of @contextmanager def func(): return other_generator_function() A linter could ask you to change to: @contextmanager def func(): yield from other_generator_function() You may need an empty return if you have something that does branching and you need to short circuit. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.