Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[MNT]: Type hints for the data keyword argument #25634

Open
@ksunden

Description

@ksunden

Summary

The data keyword argument presents a tricky edge case for typing that is currently not ideal.

#25632 Provides the first step, untyped but present in the type stubs (so stubtest will check them at least.

Proposed fix

The OO api type hints: overloads

The most properly the type hint would look something like:

    @overload
    def hlines(
        self,
        y: float | ArrayLike,
        xmin: float | ArrayLike,
        xmax: float | ArrayLike,
        colors: Sequence[ColorType] | None = ...,
        linestyles: LineStyleType = ...,
        label: str = ...,
        *,
        data: None =...,
        **kwargs
    ) -> LineCollection: ...
    @overload
    def hlines(
        self,
        y: float | ArrayLike | str,
        xmin: float | ArrayLike | str,
        xmax: float | ArrayLike | str,
        colors: Sequence[ColorType] | None | str = ...,
        linestyles: LineStyleType = ...,
        label: str = ...,
        *,
        data: Mapping[str, ArrayLike],
        **kwargs
    ) -> LineCollection: ...

That is to say:

An overloaded call where one call has data of type None, and the other has data with type Mapping[str, ArrayLike] (and also appends str to the valid types for affected parameters)

Note that technically str does pass as ArrayLike, as that is a broad union which includes scalars (and str specifically), but communicating explicitly that str is expected for the case where data is not None is a bit better.

If **kwargs is not included, the first overload could simply omit data all together, making it a required keyword arg.

The problem: pyplot

Current pyplot generation code (tools/boilerplate.py) only looks at the first signature of overloads.
This currently only affects a small number of methods that are in the autogenerated portion of pyplot and have overloads in their definitions (e.g. Axes.legend), which simply don't get the full type hints in pyplot.

Currently, none of the affected methods result in a type hint being added which is not correct, just type hints being omitted (and thus to mypy are Any) and so not deriving the value of having type hints for that small number of methods

The above overload for data would not be the same, as it would either get None OR Mapping[...], not the union. In the latter case, this would be a problem as the default would not match the hint. In the former, it would fail if you tried to use the arg. If no **kwargs and data is simply omitted, it would simply be as it already was where pyplot gets no type hint for data, but it does appear in the signature.

The pyplot generation code may need to be be more comprehensive and explicitly handle the case of overloads. This is certainly possible, but not easy.

Considerations for inline type hints

Since data does not appear in the actual signature this is mildly complicated for if we ever do want to move towards inline type hints. Such a move is not in the current plans, but worth writing down why this is a complicating factor.

If we use overloads, I think it may actually just wash away, so maybe not as complicated as otherwise.

PEP 612 addresses allowing static typing of decorators which modify signatures by adding positional arguments, but explicitly excludes the case of adding a keyword-only arg, as is the case for the _preprocess_data. So statically using the decorator to transparently modify the signature for the type checker is not possible.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions