Skip to content

TYP: pad improved shape-typing and mode-dependend kwargs - #32576

Merged
charris merged 1 commit into
numpy:mainfrom
jorenham:typing/pad/shape-typing
Sep 10, 2026
Merged

charris merged 1 commit into
numpy:mainfrom
jorenham:typing/pad/shape-typing

Conversation

@jorenham

Copy link
Copy Markdown
Member

np.pad now returns exact shape-types for <=2d array-likes and propagates all shape-types for ndarray input. It now also has explicit overloads for the mode values with allowed keyword arguments spelled out.


Pair programmed and pre-reviewed with AI

@jorenham jorenham added this to the 2.6.0 Release milestone Sep 10, 2026
@github-actions

Copy link
Copy Markdown

Diff from mypy_primer, showing the effect of this PR on type check results on a corpus of open source code:

colour (https://github.com/colour-science/colour)
- colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[ShapeT, DTypeT]
- colour/io/luts/lut.py:1433: note:     def [ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[ScalarT]] | _NestedSequence[_SupportsArray[dtype[ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[ScalarT]]
- colour/io/luts/lut.py:1433: note:     def pad(array: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[Any]]
+ colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant'] = ..., *, constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ...) -> ndarray[ShapeT, DTypeT]
+ colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['linear_ramp'], *, end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ...) -> ndarray[ShapeT, DTypeT]
+ colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['maximum', 'mean', 'median', 'minimum'], *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ...) -> ndarray[ShapeT, DTypeT]
+ colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['reflect', 'symmetric'], *, reflect_type: Literal['odd', 'even'] = ...) -> ndarray[ShapeT, DTypeT]
- colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: _ModeFunc, **kwargs: Any) -> ndarray[ShapeT, DTypeT]
+ colour/io/luts/lut.py:1433: note:     def [ShapeT: tuple[int, ...], DTypeT: dtype[Any]] pad(array: ndarray[ShapeT, DTypeT], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['edge', 'wrap', 'empty'] | _ModeFunc) -> ndarray[ShapeT, DTypeT]
+ colour/io/luts/lut.py:1433: note:     def pad(array: list[bool], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int], dtype[numpy.bool[builtins.bool]]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: list[int], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int], dtype[signedinteger[_32Bit | _64Bit]]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: list[float], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int], dtype[float64]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: list[complex], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int], dtype[complex128]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: Sequence[list[bool]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int, int], dtype[numpy.bool[builtins.bool]]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: Sequence[list[int]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int, int], dtype[signedinteger[_32Bit | _64Bit]]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: Sequence[list[float]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int, int], dtype[float64]]
+ colour/io/luts/lut.py:1433: note:     def pad(array: Sequence[list[complex]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant', 'linear_ramp'] | Literal['maximum', 'mean', 'median', 'minimum'] | Literal['reflect', 'symmetric'] | Literal['edge', 'wrap', 'empty'] | _ModeFunc = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[int, int], dtype[complex128]]
+ colour/io/luts/lut.py:1433: note:     def [ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[ScalarT]] | _NestedSequence[_SupportsArray[dtype[ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['constant'] = ..., *, constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ...) -> ndarray[tuple[Any, ...], dtype[ScalarT]]
+ colour/io/luts/lut.py:1433: note:     def [ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[ScalarT]] | _NestedSequence[_SupportsArray[dtype[ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['linear_ramp'], *, end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ...) -> ndarray[tuple[Any, ...], dtype[ScalarT]]
+ colour/io/luts/lut.py:1433: note:     def [ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[ScalarT]] | _NestedSequence[_SupportsArray[dtype[ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | dict[int, int] | dict[int, tuple[int, int]] | dict[int, int | tuple[int, int]], mode: Literal['maximum', 'mean', 'median', 'minimum'], *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ...) -> ndarray[tuple[Any, ...], dtype[ScalarT]]

... (truncated 9 lines) ...

@jorenham

Copy link
Copy Markdown
Member Author

The colour diff only should note: changes, so it's safe to ignore

@charris
charris merged commit 4659542 into numpy:main Sep 10, 2026
16 checks passed
@jorenham
jorenham deleted the typing/pad/shape-typing branch September 10, 2026 16:47
@charris

charris commented Sep 10, 2026

Copy link
Copy Markdown
Member

Thanks Joren. What does "note" signify?

@jorenham

Copy link
Copy Markdown
Member Author

Thanks Joren. What does "note" signify?

It's some context that mypy reports for a pre-existing typing error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants