Pyright: Bug with generic functions taking generic callbacks

Created on 3 Dec 2020  路  3Comments  路  Source: microsoft/pyright

Environment data

  • Language Server version: Pylance language server 2020.12.1-pre.1 (pyright ea581b3f)
  • OS and version: Mac OS X 11.0.1
  • Python version (& distribution if applicable, e.g. Anaconda): Python 3.9 (brew)

Expected behaviour

Pylance should be able to assign a function that takes e.g an int as arg to a generic function that returns a TSource expects a function that takes a TSource as arg, and then returns a TSource. The current version of Pylance is unable to see that TSource is int. It's a bit complex so please look at the self-contained code snippet below.

Actual behaviour

Screenshot 2020-12-03 at 09 41 23

Logs

[Info  - 7:43:16 AM] Pylance language server 2020.12.1-pre.1 (pyright ea581b3f) starting
[Info  - 7:43:16 AM] Server root directory: /Users/dbrattli/.vscode/extensions/ms-python.vscode-pylance-2020.12.1-pre.1/dist
[Error - 7:43:16 AM] stubPath /Users/dbrattli/Developer/Github/Expression/typings is not a valid directory.
[Info  - 9:27:27 AM] No configuration file found.
[Info  - 9:27:27 AM] Setting pythonPath for service "Expression": "/usr/local/opt/[email protected]/bin/python3"
...
Nothing special here

Code Snippet / Additional information

import asyncio
from asyncio import Future
from typing import Awaitable, Callable, TypeVar

TSource = TypeVar("TSource")

Continuation = Callable[[TSource], None]
#Callback = Callable[[Continuation[TSource]], None]


def from_continuation(callback: Callable[[Continuation[TSource]], None]) -> Awaitable[TSource]:
    future: Future[TSource] = asyncio.Future()

    def done(value: TSource) -> None:
        future.set_result(value)

    callback(done)
    return asyncio.ensure_future(future)


async def test() -> int:
    def callback(done: Continuation[int]) -> None:
        done(42)

    return await from_continuation(callback)

Making a type alias for the callback (code below) does not help either but also gives an additional error:

Screenshot 2020-12-03 at 09 44 01

import asyncio
from asyncio import Future
from typing import Awaitable, Callable, TypeVar

TSource = TypeVar("TSource")

Continuation = Callable[[TSource], None]
Callback = Callable[[Continuation[TSource]], None]


def from_continuation(callback: Callback[TSource]) -> Awaitable[TSource]:
    future: Future[TSource] = asyncio.Future()

    def done(value: TSource) -> None:
        future.set_result(value)

    callback(done)
    return asyncio.ensure_future(future)


async def test() -> int:
    def callback(done: Continuation[int]) -> None:
        done(42)

    return await from_continuation(callback)

Example of real usage (a bit more complex):

addressed in next version bug

All 3 comments

Thanks for the bug report. There were two separate bugs here. The first had to do with nested Callable types (i.e. a Callable that included a Callable parameter). The second had to do with generic type aliases that included Callable types. Both of these bugs will be fixed in the next release.

This is now fixed in Pyright 1.1.92, which I just published. It will also be addressed in next week's Pylance release.

Thanks for fixing!

Was this page helpful?
0 / 5 - 0 ratings