Open asmeurer opened 7 months ago
Sounds like a good idea.
Related: we may want to add a py.typed
marker and a mypy
CI job. When this code was inside numpy.array_api
, it relied on numpy
having a py.typed
marker.
These are the errors I get when I run mypy
on array-api-strict:
array_api_strict/_creation_functions.py:94: error: Argument 1 to "arange" has incompatible type "int | float"; expected "bool | bool_ | int | integer[Any]" [arg-type]
array_api_strict/_creation_functions.py:94: error: Argument "stop" to "arange" has incompatible type "int | float | None"; expected "bool | bool_ | int | integer[Any]" [arg-type]
array_api_strict/_creation_functions.py:94: error: Argument "step" to "arange" has incompatible type "int | float"; expected "bool | bool_ | int | integer[Any]" [arg-type]
array_api_strict/_creation_functions.py:94: error: Argument "dtype" to "arange" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:115: error: Argument "dtype" to "empty" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:133: error: Argument "dtype" to "empty_like" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:157: error: Argument "dtype" to "eye" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:163: error: Argument 1 to "from_dlpack" has incompatible type "object"; expected "_SupportsDLPack[None]" [arg-type]
array_api_strict/_creation_functions.py:187: error: Argument "dtype" to "full" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:215: error: Argument "dtype" to "full_like" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:245: error: Argument "dtype" to "linspace" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:264: error: Argument "indexing" to "meshgrid" has incompatible type "str"; expected "Literal['xy', 'ij']" [arg-type]
array_api_strict/_creation_functions.py:286: error: Argument "dtype" to "ones" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:304: error: Argument "dtype" to "ones_like" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:353: error: Argument "dtype" to "zeros" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_creation_functions.py:371: error: Argument "dtype" to "zeros_like" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_array_object.py:162: error: Item "bool" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:162: error: Item "int" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:162: error: Item "float" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:174: error: Item "bool" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:174: error: Item "int" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:174: error: Item "float" of "bool | int | float | Array" has no attribute "dtype" [union-attr]
array_api_strict/_array_object.py:177: error: Incompatible return value type (got "bool | int | float | Array", expected "Array") [return-value]
array_api_strict/_array_object.py:507: error: Incompatible return value type (got "tuple[int, Literal[0]]", expected "tuple[IntEnum, int]") [return-value]
array_api_strict/_array_object.py:509: error: Return type "Array" of "__eq__" incompatible with return type "bool" in supertype "object" [override]
array_api_strict/_array_object.py:509: error: Argument 1 of "__eq__" is incompatible with supertype "object"; supertype defines the argument type as "object" [override]
array_api_strict/_array_object.py:509: note: This violates the Liskov substitution principle
array_api_strict/_array_object.py:509: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
array_api_strict/_array_object.py:509: note: It is recommended for "__eq__" to work with arbitrary objects, for example:
array_api_strict/_array_object.py:509: note: def __eq__(self, other: object) -> bool:
array_api_strict/_array_object.py:509: note: if not isinstance(other, Array):
array_api_strict/_array_object.py:509: note: return NotImplemented
array_api_strict/_array_object.py:509: note: return <logic to compare two Array instances>
array_api_strict/_array_object.py:575: error: Incompatible types in assignment (expression has type "ndarray[Any, dtype[Any]]", variable has type "int | slice | ellipsis | tuple[int | slice | ellipsis | None, ...] | Array") [assignment]
array_api_strict/_array_object.py:685: error: Return type "Array" of "__ne__" incompatible with return type "bool" in supertype "object" [override]
array_api_strict/_array_object.py:685: error: Argument 1 of "__ne__" is incompatible with supertype "object"; supertype defines the argument type as "object" [override]
array_api_strict/_array_object.py:685: note: This violates the Liskov substitution principle
array_api_strict/_array_object.py:685: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
array_api_strict/_array_object.py:765: error: Incompatible types in assignment (expression has type "ndarray[Any, dtype[Any]]", variable has type "int | slice | ellipsis | tuple[int | slice | ellipsis, ...] | Array") [assignment]
array_api_strict/_array_object.py:1095: error: "Array" has no attribute "_dtype"; maybe "dtype"? [attr-defined]
array_api_strict/_statistical_functions.py:70: error: Incompatible types in assignment (expression has type "type[floating[Any]]", variable has type "_DType | None") [assignment]
array_api_strict/_statistical_functions.py:72: error: Incompatible types in assignment (expression has type "type[complexfloating[Any, Any]]", variable has type "_DType | None") [assignment]
array_api_strict/_statistical_functions.py:75: error: Argument "dtype" to "prod" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_statistical_functions.py:107: error: Incompatible types in assignment (expression has type "type[floating[Any]]", variable has type "_DType | None") [assignment]
array_api_strict/_statistical_functions.py:109: error: Incompatible types in assignment (expression has type "type[complexfloating[Any, Any]]", variable has type "_DType | None") [assignment]
array_api_strict/_statistical_functions.py:112: error: Argument "axis" to "sum" has incompatible type "int | tuple[int, ...] | None"; expected "None" [arg-type]
array_api_strict/_statistical_functions.py:112: error: Argument "dtype" to "sum" has incompatible type "_DType | None"; expected "None" [arg-type]
array_api_strict/_sorting_functions.py:23: error: Argument "kind" to "argsort" has incompatible type "str"; expected "Literal['quicksort', 'mergesort', 'heapsort', 'stable'] | None" [arg-type]
array_api_strict/_sorting_functions.py:29: error: Argument "kind" to "argsort" has incompatible type "str"; expected "Literal['quicksort', 'mergesort', 'heapsort', 'stable'] | None" [arg-type]
array_api_strict/_sorting_functions.py:51: error: No overload variant of "sort" matches argument types "ndarray[Any, dtype[Any]]", "int", "str" [call-overload]
array_api_strict/_sorting_functions.py:51: note: Possible overload variants:
array_api_strict/_sorting_functions.py:51: note: def [_SCT <: generic] sort(a: _SupportsArray[dtype[_SCT]] | _NestedSequence[_SupportsArray[dtype[_SCT]]], axis: SupportsIndex | None = ..., kind: Literal['quicksort', 'mergesort', 'heapsort', 'stable'] | None = ..., order: str | Sequence[str] | None = ...) -> ndarray[Any, dtype[_SCT]]
array_api_strict/_sorting_functions.py:51: note: def sort(a: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes], axis: SupportsIndex | None = ..., kind: Literal['quicksort', 'mergesort', 'heapsort', 'stable'] | None = ..., order: str | Sequence[str] | None = ...) -> ndarray[Any, dtype[Any]]
array_api_strict/_indexing_functions.py:8: error: Name "Optional" is not defined [name-defined]
array_api_strict/_indexing_functions.py:8: note: Did you forget to import it from "typing"? (Suggestion: "from typing import Optional")
array_api_strict/_data_type_functions.py:113: error: Need type annotation for "fi" [var-annotated]
array_api_strict/_data_type_functions.py:113: error: Argument 1 to "finfo" has incompatible type "_DType | Array"; expected "inexact[Never] | dtype[inexact[Never]] | type[inexact[Never]] | _SupportsDType[dtype[inexact[Never]]]" [arg-type]
array_api_strict/_data_type_functions.py:122: error: Argument 6 to "finfo_object" has incompatible type "dtype[floating[Any]]"; expected "_DType" [arg-type]
array_api_strict/_data_type_functions.py:134: error: Need type annotation for "ii" [var-annotated]
array_api_strict/_data_type_functions.py:134: error: Argument 1 to "iinfo" has incompatible type "_DType | Array"; expected "dtype[Never] | type[Never] | _SupportsDType[dtype[Never]]" [arg-type]
array_api_strict/_data_type_functions.py:135: error: Argument 4 to "iinfo_object" has incompatible type "dtype[Any]"; expected "_DType" [arg-type]
array_api_strict/fft.py:69: error: Incompatible default for argument "s" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:69: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:69: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:70: error: Incompatible default for argument "axes" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:70: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:70: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:91: error: Incompatible default for argument "s" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:91: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:91: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:92: error: Incompatible default for argument "axes" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:92: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:92: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:157: error: Incompatible default for argument "s" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:157: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:157: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:158: error: Incompatible default for argument "axes" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:158: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:158: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:179: error: Incompatible default for argument "s" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:179: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:179: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:180: error: Incompatible default for argument "axes" (default has type "None", argument has type "Sequence[int]") [assignment]
array_api_strict/fft.py:180: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:180: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:261: error: Incompatible default for argument "axes" (default has type "None", argument has type "int | Sequence[int]") [assignment]
array_api_strict/fft.py:261: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:261: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/fft.py:271: error: Incompatible default for argument "axes" (default has type "None", argument has type "int | Sequence[int]") [assignment]
array_api_strict/fft.py:271: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
array_api_strict/fft.py:271: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
array_api_strict/_manipulation_functions.py:22: error: Generator has incompatible item type "ndarray[Any, dtype[Any]]"; expected "Array" [misc]
array_api_strict/_manipulation_functions.py:60: error: Name "Bool" is not defined [name-defined]
array_api_strict/_manipulation_functions.py:111: error: Generator has incompatible item type "ndarray[Any, dtype[Any]]"; expected "Array" [misc]
array_api_strict/linalg.py:17: error: Cannot find implementation or library stub for module named "numpy._core.numeric" [import-not-found]
array_api_strict/linalg.py:17: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
array_api_strict/linalg.py:19: error: Module "numpy.core.numeric" has no attribute "normalize_axis_tuple" [attr-defined]
array_api_strict/linalg.py:23: error: Module "array_api_strict._typing" has no attribute "Optional" [attr-defined]
array_api_strict/linalg.py:23: error: Module "array_api_strict._typing" has no attribute "Tuple" [attr-defined]
array_api_strict/linalg.py:309: error: Cannot find implementation or library stub for module named "numpy.linalg._linalg" [import-not-found]
array_api_strict/linalg.py:472: error: "int" has no attribute "__iter__"; maybe "__int__"? (not iterable) [attr-defined]
Found 67 errors in 9 files (checked 28 source files)
It looks like it's mostly issues with the numpy type hints. I'm not sure I understand where these type hints come from. It seems to think the arange
arguments are typed as bool | bool_ | int | integer[Any]
, but arange is defined using overloads, which should include float: https://github.com/numpy/numpy/blob/261c4c0f34cea844dbb2f6aa86a7997b984efb09/numpy/_core/multiarray.pyi#L733.
I'm not sure I understand where these type hints come from.
They're shipped with numpy in .pyi
files.
That looks like a long list of errors, nice to fix but not super urgent I'd say.
In numpy.array_api, we said that type checking that inputs were
Array
was too much overhead, and we would just rely on the the type signatures and type checking to do this.However, given that we are no longer thinking of this library as something that is used in production, I don't think we need to worry so much about the overhead of type checking. It might be a good idea to add explicit type checks to functions. This would prevent a sufficiently duck-typed object from silently passing through, although that's pretty unlikely since basically every function uses
x._array
on its input. The real reason would be to provide better error messages thatAttributeError
on bad inputs.Maybe this can be done automatically from the type signatures using one of those fancy libraries I know nothing about.