python / python/mypy

Can't resolve generic type from return type of callable passed as (default) argument?

Open
#10,854 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-type-variables
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

UPDATE: Probably a dup of #3737 and #10504.


What I want to do is define a function that takes a callable that returns a generic as an argument where that generic influences the return type of the function. Something like this:

def doit(constructor: Callable[..., T]) -> List[T]:
    ...

I can't seem to figure out a way to get that done, though, especially when I am supplying a default argument for the callable. Here are my test cases:

from typing import Callable, List, Protocol, TypeVar

_T = TypeVar("_T")

# error: Incompatible default for argument "constructor" (default has type "Type[str]", argument has type "Callable[[int], _T]")
def generate(n: int, constructor: Callable[[int], _T] = str) -> List[_T]:
    return [constructor(i) for i in range(n)]

# error: Need type annotation for "res" (hint: "res: List[<type>] = ...")
res = generate(5)  # res should be of type List[str]
assert res == ["0", "1", "2", "3", "4"]
assert generate(5, float) == [0.0, 1.0, 2.0, 3.0, 4.0]

_T_co = TypeVar("_T_co", covariant=True)

class Constructor(Protocol[_T_co]):
    def __call__(self, n: int) -> _T_co:
        ...

def generate2(n: int, constructor: Constructor[_T] = str) -> List[_T]:
    return [constructor(i) for i in range(n)]

# error: Need type annotation for "res2" (hint: "res2: List[<type>] = ...")
res2 = generate2(5, float)  # res2 should be of type List[float]
assert res2 == [0.0, 1.0, 2.0, 3.0, 4.0]

Runtime:

% python --version
Python 3.9.6
% python test.py
% mypy --version
mypy 0.910
% mypy --config-file=/dev/null test.py
/dev/null: No [mypy] section in config file
test.py:6: error: Incompatible default for argument "constructor" (default has type "Type[str]", argument has type "Callable[[int], _T]")
test.py:10: error: Need type annotation for "res" (hint: "res: List[<type>] = ...")
test.py:24: error: Need type annotation for "res2" (hint: "res2: List[<type>] = ...")
Found 3 errors in 1 file (checked 1 source file)

I tried searching for a similar issue, but was unable to find what I was looking for.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The reproduction is in test.py; first review the related issues #3737 and #10504, then run mypy --config-file=/dev/null test.py. Done means the callable default is accepted and the generate calls infer List[str] and List[float] without the reported errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers, devtools
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.