Skip to content

WYSIWYG reporting of generic type arguments default #2461

@jorenham

Description

@jorenham

In recent versions of NumPy, the two np.ndarray generic type parameters default to tuple[Any, ...] and numpy.dtype, respectively. The generic type parameter of numpy.dtype defaults to Any.
So writing _: np.ndarray is equivalent to writing _: np.ndarray[tuple[Any, ...], np.dtype[Any]]. And of course, the opposite is also the case, i.e., _: np.ndarray[tuple[Any, ...], np.dtype[Any]] can be written more compactly as _: np.ndarray.

When reporting types, it looks like pyrefly currently always chooses to "fill in" the defaults of type parameters that aren't provided. For example:

from typing import reveal_type

import numpy as np

def f(a: np.ndarray, /) -> None:
    reveal_type(a)
 INFO revealed type: ndarray[tuple[Any, ...], dtype[Any]] [reveal-type]

One obvious issue is that this is needlessly verbose: "ndarray[tuple[Any, ...], dtype[Any]]" counts 36 characters, while "ndarray" requires only 7; that's a factor of >5x.

It can also be confusing to users to see the type they explicitly wrote as ndarray to be printed as ndarray[tuple[Any, ...], dtype[Any]]. I can imagine that users new to typing in Python would not understand where the [tuple[Any, ...], dtype[Any]] came from.

There's also subjective loss of information: In natural language there are many synonyms, but even though they mean the same, there are often subtle context-dependent nuances that cause people to use them with specific intent, so that they can express themselves a little bit better. The way I see it, the same can be said about ndarray. For example, if one writes _: ndarray[tuple[Any, ...]] it highlights that the shape-type is unknown but relevant, whereas writing _: ndarray could mean that the shape-type isn't relevant.

So all things considered, I would like for pyrefly to report types as they are written. So with this WYSIWYG approach you'd have

def f(a: np.ndarray, /) -> None:
    reveal_type(a)  # revealed type: ndarray [reveal-type]

def f(a: np.ndarray[tuple[Any, ...]], /) -> None:
    reveal_type(a)  # revealed type: ndarray[tuple[Any, ...]] [reveal-type]

and so forth.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions