python / python/cpython

Wrong Signature for singledispatch'ed functions/methods

Open
#101,602 5 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

stdlib type-bug
Dominant language
Python
Stars
77.2k
Forks
36k
PR merge metrics
PR metrics pending

Description

An example:

$ cat -n spam.py 
     1  from __future__ import annotations
     2  from functools import singledispatch
     3  
     4  @singledispatch
     5  def foo(x: int) -> int:
     6      return x + 1
     7  
     8  @foo.register
     9  def _(x: str) -> str:
    10      return "Hello, " + x
$ python
Python 3.11.1+ (heads/3.11:ba88628808, Jan 14 2023, 08:40:06) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect, spam
>>> inspect.signature(spam.foo)
<Signature (x: 'int') -> 'int'>

I would expect here something like <Signature (x: int | str) -> int | str> (i.e. union of types for returned value, same for argument) or an exception.

I'm not sure that the first option is on the table: more accurately this situation fits to case of multiple function signatures (like we have in the stdlib e.g. for the min/max). But the current signature() output is misleading.

UPD: In fact, the Signature must be like <Signature (x: int | str, /) -> int | str>, because:

>>> spam.foo(x=1)
Traceback (most recent call last):
  ...
TypeError: foo requires at least 1 positional argument

Or we can make singledispatch'ed function to be with a positional-only argument iff argument names for different overloaded implementations are different.

PS: Inspired by https://discuss.python.org/t/signatures-a-call-to-action/23580

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

Reproduce the example using functools.singledispatch and inspect.signature, including the positional-argument behavior shown in the report. Decide which signature semantics are intended, then add regression coverage demonstrating the agreed result; the issue is done when singledispatch signatures no longer misleadingly represent only the base implementation.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.