python / python/mypy

`tuple[*Ts]` subtype with extra type parameter not gradually assignable to itself

Open
#19,908 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

This demonstrates the issue:

from typing import Any

class Array[DataT, *ShapeTs](tuple[*ShapeTs]): ...

type Float2D = Array[float, *tuple[int, int]]  # or Array[float, int, int]
type FloatND = Array[float, *tuple[Any, ...]]

def from_2d(a: Float2D) -> FloatND:
    return a  # mypy: ✅, pyright: ✅

def into_2d(a: FloatND) -> Float2D:
    return a  # mypy: ❌, pyright: ✅

https://mypy-play.net/?mypy=latest&python=3.13&flags=strict&gist=1b95c702df6de35fa3f61aa7b5dfef16

Without the additional DataT typar, the false positive disappears

from typing import Any

class Array[*ShapeTs](tuple[*ShapeTs]): ...

type Float2D = Array[*tuple[int, int]]  # or Array[int, int]
type FloatND = Array[*tuple[Any, ...]]

def from_2d(a: Float2D) -> FloatND:
    return a  # mypy: ✅, pyright: ✅

def into_2d(a: FloatND) -> Float2D:
    return a  # mypy: ✅, pyright: ✅

https://mypy-play.net/?mypy=latest&python=3.13&flags=strict&gist=be0dfedeb0e7ed14da359cd52d2901e7

The issue also disappears when tuple is no longer a base class

from typing import Any

class Array[float, *ShapeTs]: ...

type Float2D = Array[float, *tuple[int, int]]  # or Array[float, int, int]
type FloatND = Array[float, *tuple[Any, ...]]

def from_2d(a: Float2D) -> FloatND:
    return a  # mypy: ✅, pyright: ✅

def into_2d(a: FloatND) -> Float2D:
    return a  # mypy: ✅, pyright: ✅

https://mypy-play.net/?mypy=latest&python=3.13&flags=strict&gist=a1439e7c3037239bc4663b981534fb17

Potentially related issues:

  • #18665
  • #19106
  • #19109
  • #19110
  • #19860
  • #19858

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 two Python reproductions in the linked mypy-play examples with mypy 3.13 strict settings, comparing the from_2d and into_2d assignments and the variants without DataT or the tuple base class. Review related issues #18665, #19106, #19109, #19110, #19860, and #19858; done means the problematic assignment is handled consistently without breaking the cases that already pass.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.