python / python/mypy

Overloads with Generics "does not accept all possible arguments"

Open
#19,053 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

I have a function whose return type is determined by the type of an input parameter (with a default value). I have attempted to type-hint it with generics. I get "error: Overloaded function implementation does not accept all possible arguments of signature".

To Reproduce

In the toy example below, the function has two return types (original-type or list) depending on two possible types of the force_list input (Force or NoForce). For completeness I have overloaded all 4 permutations of the input and output types.

Playground: https://mypy-play.net/?mypy=latest&python=3.12&gist=283290e33e2618dfcdf447513d0f4543

  from typing import TypeVar, assert_type, overload
  
  class Force: ...
  ForceInstance = Force()
  
  class NoForce: ...
  NoForceInstance = NoForce()
  
  T = TypeVar("T")
  
  @overload
  def list_or_orig(x: list[T], force_list: Force = ...) -> list[T]: ...
  
  @overload
  def list_or_orig(x: list[T], force_list: NoForce = ...) -> list[T]: ...
  
  @overload
  def list_or_orig(x: T, force_list: Force = ...) -> list[T]: ...
  
  @overload
  def list_or_orig(x: T, force_list: NoForce = ...) -> T: ...
  
  def list_or_orig(x: list[T] | T, force_list: Force | NoForce = ForceInstance) -> list[T] | T:
      """Return a list or scalar depending on force_list flag."""
      if isinstance(x, list):
          return x
      elif isinstance(force_list, Force):
          return [x]
      else:
          return x
  
  
  a_list = list_or_orig(1)  # Since default is Force, this will return list[int]
  assert_type(a_list, list[int])
  
  b_list = list_or_orig(1, ForceInstance)
  assert_type(b_list, list[int])
  
  a_int = list_or_orig(1, NoForceInstance)  # This will return int
  assert_type(a_int, int)

Expected Behavior

No errors when running through mypy.

Actual Behavior

main.py:29: error: Overloaded function implementation does not accept all possible arguments of signature 1  [misc]
main.py:29: error: Overloaded function implementation does not accept all possible arguments of signature 2  [misc]
Found 2 errors in 1 file (checked 1 source file)

Notes

If I replace the generic type T with a specific type, say, int then it's fine.

I appreciate there is an ambiguity between list[T] and T but have included the less-general list[T] first in the overloads.

The same code passes in the pyright playground.

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

Start by running the minimal Python example from the issue with mypy and compare its result with the linked Pyright behavior. Trace the overload implementation-compatibility check that reports signatures 1 and 2. Done means the example produces no compatibility errors while preserving the shown assert_type results.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.