From fe8fa8bc66f56fbbbf20d00d25da40ce89f72bc4 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 27 Nov 2024 21:08:39 +0000 Subject: [PATCH 01/10] ENH: add `setdiff1d` Co-authored-by: Omar Salman Co-authored-by: Olivier Grisel --- codecov.yml | 1 + src/array_api_extra/__init__.py | 4 +- src/array_api_extra/_compat.py | 165 ++++++++++++++++++++++++++++++++ src/array_api_extra/_funcs.py | 30 +++++- src/array_api_extra/_typing.py | 5 +- src/array_api_extra/_utils.py | 63 ++++++++++++ 6 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 src/array_api_extra/_compat.py create mode 100644 src/array_api_extra/_utils.py diff --git a/codecov.yml b/codecov.yml index f76a2bc1..dd755284 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,4 @@ comment: false ignore: + - "src/array_api_extra/_compat" - "src/array_api_extra/_typing" diff --git a/src/array_api_extra/__init__.py b/src/array_api_extra/__init__.py index b7751594..46b1388f 100644 --- a/src/array_api_extra/__init__.py +++ b/src/array_api_extra/__init__.py @@ -1,9 +1,10 @@ from __future__ import annotations -from ._funcs import atleast_nd, cov, create_diagonal, expand_dims, kron, sinc +from ._funcs import atleast_nd, cov, create_diagonal, expand_dims, kron, setdiff1d, sinc __version__ = "0.2.1.dev0" +# pylint: disable=duplicate-code __all__ = [ "__version__", "atleast_nd", @@ -11,5 +12,6 @@ "create_diagonal", "expand_dims", "kron", + "setdiff1d", "sinc", ] diff --git a/src/array_api_extra/_compat.py b/src/array_api_extra/_compat.py new file mode 100644 index 00000000..e836ba78 --- /dev/null +++ b/src/array_api_extra/_compat.py @@ -0,0 +1,165 @@ +### Helpers borrowed from array-api-compat + +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 + +import inspect +import sys +import typing + +if typing.TYPE_CHECKING: + from ._typing import Array, Device + +__all__ = ["device"] + + +# Placeholder object to represent the dask device +# when the array backend is not the CPU. +# (since it is not easy to tell which device a dask array is on) +class _dask_device: # pylint: disable=invalid-name + def __repr__(self) -> str: + return "DASK_DEVICE" + + +_DASK_DEVICE = _dask_device() + + +# device() is not on numpy.ndarray or dask.array and to_device() is not on numpy.ndarray +# or cupy.ndarray. They are not included in array objects of this library +# because this library just reuses the respective ndarray classes without +# wrapping or subclassing them. These helper functions can be used instead of +# the wrapper functions for libraries that need to support both NumPy/CuPy and +# other libraries that use devices. +def device(x: Array, /) -> Device: + """ + Hardware device the array data resides on. + + This is equivalent to `x.device` according to the `standard + `__. + This helper is included because some array libraries either do not have + the `device` attribute or include it with an incompatible API. + + Parameters + ---------- + x: array + array instance from an array API compatible library. + + Returns + ------- + out: device + a ``device`` object (see the `Device Support `__ + section of the array API specification). + + Notes + ----- + + For NumPy the device is always `"cpu"`. For Dask, the device is always a + special `DASK_DEVICE` object. + + See Also + -------- + + to_device : Move array data to a different device. + + """ + if _is_numpy_array(x): + return "cpu" + if _is_dask_array(x): + # Peek at the metadata of the jax array to determine type + try: + import numpy as np # pylint: disable=import-outside-toplevel + + if isinstance(x._meta, np.ndarray): # pylint: disable=protected-access + # Must be on CPU since backed by numpy + return "cpu" + except ImportError: + pass + return _DASK_DEVICE + if _is_jax_array(x): + # JAX has .device() as a method, but it is being deprecated so that it + # can become a property, in accordance with the standard. In order for + # this function to not break when JAX makes the flip, we check for + # both here. + if inspect.ismethod(x.device): + return x.device() + return x.device + if _is_pydata_sparse_array(x): + # `sparse` will gain `.device`, so check for this first. + x_device = getattr(x, "device", None) + if x_device is not None: + return x_device + # Everything but DOK has this attr. + try: + inner = x.data + except AttributeError: + return "cpu" + # Return the device of the constituent array + return device(inner) + return x.device + + +def _is_numpy_array(x: Array) -> bool: + """Return True if `x` is a NumPy array.""" + # Avoid importing NumPy if it isn't already + if "numpy" not in sys.modules: + return False + + import numpy as np # pylint: disable=import-outside-toplevel + + # TODO: Should we reject ndarray subclasses? + return isinstance(x, (np.ndarray, np.generic)) and not _is_jax_zero_gradient_array( + x + ) + + +def _is_dask_array(x: Array) -> bool: + """Return True if `x` is a dask.array Array.""" + # Avoid importing dask if it isn't already + if "dask.array" not in sys.modules: + return False + + # pylint: disable=import-error, import-outside-toplevel + import dask.array # type: ignore[import-not-found] + + return isinstance(x, dask.array.Array) + + +def _is_jax_zero_gradient_array(x: Array) -> bool: + """Return True if `x` is a zero-gradient array. + + These arrays are a design quirk of Jax that may one day be removed. + See https://github.com/google/jax/issues/20620. + """ + if "numpy" not in sys.modules or "jax" not in sys.modules: + return False + + # pylint: disable=import-error, import-outside-toplevel + import jax # type: ignore[import-not-found] + import numpy as np # pylint: disable=import-outside-toplevel + + return isinstance(x, np.ndarray) and x.dtype == jax.float0 + + +def _is_jax_array(x: Array) -> bool: + """Return True if `x` is a JAX array.""" + # Avoid importing jax if it isn't already + if "jax" not in sys.modules: + return False + + # pylint: disable=import-error, import-outside-toplevel + import jax + + return isinstance(x, jax.Array) or _is_jax_zero_gradient_array(x) + + +def _is_pydata_sparse_array(x: Array) -> bool: + """Return True if `x` is an array from the `sparse` package.""" + + # Avoid importing jax if it isn't already + if "sparse" not in sys.modules: + return False + + # pylint: disable=import-error, import-outside-toplevel + import sparse # type: ignore[import-not-found] + + # TODO: Account for other backends. + return isinstance(x, sparse.SparseArray) diff --git a/src/array_api_extra/_funcs.py b/src/array_api_extra/_funcs.py index a305bfb5..660b15f1 100644 --- a/src/array_api_extra/_funcs.py +++ b/src/array_api_extra/_funcs.py @@ -1,4 +1,4 @@ -from __future__ import annotations +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 import typing import warnings @@ -6,7 +6,17 @@ if typing.TYPE_CHECKING: from ._typing import Array, ModuleType -__all__ = ["atleast_nd", "cov", "create_diagonal", "expand_dims", "kron", "sinc"] +from . import _utils + +__all__ = [ + "atleast_nd", + "cov", + "create_diagonal", + "expand_dims", + "kron", + "setdiff1d", + "sinc", +] def atleast_nd(x: Array, /, *, ndim: int, xp: ModuleType) -> Array: @@ -399,6 +409,22 @@ def kron(a: Array, b: Array, /, *, xp: ModuleType) -> Array: return xp.reshape(result, tuple(xp.multiply(a_shape, b_shape))) +def setdiff1d( + x1: Array, x2: Array, /, *, assume_unique: bool = False, xp: ModuleType +) -> Array: + """Find the set difference of two arrays. + + Return the unique values in `x1` that are not in `x2`. + """ + + if assume_unique: + x1 = xp.reshape(x1, (-1,)) + else: + x1 = xp.unique_values(x1) + x2 = xp.unique_values(x2) + return x1[_utils.in1d(x1, x2, assume_unique=True, invert=True, xp=xp)] + + def sinc(x: Array, /, *, xp: ModuleType) -> Array: r""" Return the normalized sinc function. diff --git a/src/array_api_extra/_typing.py b/src/array_api_extra/_typing.py index 5584d511..b32f67b6 100644 --- a/src/array_api_extra/_typing.py +++ b/src/array_api_extra/_typing.py @@ -1,9 +1,10 @@ -from __future__ import annotations +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 from types import ModuleType from typing import Any # To be changed to a Protocol later (see data-apis/array-api#589) Array = Any # type: ignore[no-any-explicit] +Device = Any -__all__ = ["Array", "ModuleType"] +__all__ = ["Array", "Device", "ModuleType"] diff --git a/src/array_api_extra/_utils.py b/src/array_api_extra/_utils.py new file mode 100644 index 00000000..26fbb56a --- /dev/null +++ b/src/array_api_extra/_utils.py @@ -0,0 +1,63 @@ +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 + +import typing + +if typing.TYPE_CHECKING: + from ._typing import Array, ModuleType + +from . import _compat + +__all__ = ["in1d"] + + +def in1d( + x1: Array, + x2: Array, + /, + *, + assume_unique: bool = False, + invert: bool = False, + xp: ModuleType, +) -> Array: + """Checks whether each element of an array is also present in a + second array. + + Returns a boolean array the same length as `x1` that is True + where an element of `x1` is in `x2` and False otherwise. + + This function has been adapted using the original implementation + present in numpy: + https://github.com/numpy/numpy/blob/v1.26.0/numpy/lib/arraysetops.py#L524-L758 + """ + + # This code is run to make the code significantly faster + if x2.shape[0] < 10 * x1.shape[0] ** 0.145: + if invert: + mask = xp.ones(x1.shape[0], dtype=xp.bool, device=x1.device) + for a in x2: + mask &= x1 != a + else: + mask = xp.zeros(x1.shape[0], dtype=xp.bool, device=x1.device) + for a in x2: + mask |= x1 == a + return mask + + if not assume_unique: + x1, rev_idx = xp.unique_inverse(x1) + x2 = xp.unique_values(x2) + + ar = xp.concat((x1, x2)) + device_ = _compat.device(ar) + # We need this to be a stable sort. + order = xp.argsort(ar, stable=True) + reverse_order = xp.argsort(order, stable=True) + sar = xp.take(ar, order, axis=0) + bool_ar = sar[1:] != sar[:-1] if invert else sar[1:] == sar[:-1] + flag = xp.concat((bool_ar, xp.asarray([invert], device=device_))) + ret = xp.take(flag, reverse_order, axis=0) + + if assume_unique: + return ret[: x1.shape[0]] + # https://github.com/pylint-dev/pylint/issues/10095 + # pylint: disable=possibly-used-before-assignment + return xp.take(ret, rev_idx, axis=0) From bcae393b0b4e986f37f4cae6d1eede030e06b573 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 27 Nov 2024 21:53:10 +0000 Subject: [PATCH 02/10] (temp) switch to pyright --- pixi.lock | 59 ++++++++++++---------------------- pyproject.toml | 28 ++++++++++------ src/array_api_extra/_compat.py | 13 +++++--- src/array_api_extra/_typing.py | 2 +- src/array_api_extra/_utils.py | 3 +- 5 files changed, 50 insertions(+), 55 deletions(-) diff --git a/pixi.lock b/pixi.lock index c4169a62..4f35e002 100644 --- a/pixi.lock +++ b/pixi.lock @@ -438,12 +438,11 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.23.0-py313h80202fe_1.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -556,12 +555,11 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.23.0-py313hf2da073_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.6-hb46c0d2_0.conda - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -677,12 +675,11 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h8ffe710_2.tar.bz2 - conda: https://prefix.dev/conda-forge/win-64/zstandard-0.23.0-py313h574b89f_1.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.6-h0ea2cb4_0.conda - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -961,8 +958,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.28.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: . osx-arm64: - conda: https://prefix.dev/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_0.conda @@ -1022,8 +1018,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.28.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: . win-64: - conda: https://prefix.dev/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_0.conda @@ -1087,8 +1082,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/vs2015_runtime-14.42.34433-hdffcdeb_23.conda - conda: https://prefix.dev/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h8ffe710_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - pypi: . tests: channels: @@ -1274,7 +1268,7 @@ packages: name: array-api-extra version: 0.2.1.dev0 path: . - sha256: 8df2522a223b90e904144fd84d4a1c3119b3e3eaa1a17f12d3fa98070195d147 + sha256: 3c0d9a9d1c6e4479531aaf3a82562c6e17fb30a4625aa4e43b72403497473308 requires_dist: - furo>=2023.8.17 ; extra == 'docs' - myst-parser>=0.13 ; extra == 'docs' @@ -1420,14 +1414,6 @@ packages: - pkg:pypi/basedmypy?source=hash-mapping size: 1808422 timestamp: 1732706894788 -- kind: pypi - name: basedpyright - version: 1.22.0 - url: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - sha256: 6376107086ad25525429b8a94a2ffdb67c6dd2b1a6be38bf3c6ea9b5c3d1f688 - requires_dist: - - nodejs-wheel-binaries>=20.13.1 - requires_python: '>=3.8' - kind: conda name: basedtyping version: 0.1.10 @@ -3451,24 +3437,6 @@ packages: - pkg:pypi/nodeenv?source=hash-mapping size: 34489 timestamp: 1717585382642 -- kind: pypi - name: nodejs-wheel-binaries - version: 22.11.0 - url: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl - sha256: 8310ab182ee159141e08c85bc07f11e67ac3044922e6e4958f4a8f3ba6860185 - requires_python: '>=3.7' -- kind: pypi - name: nodejs-wheel-binaries - version: 22.11.0 - url: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl - sha256: 00afada277fd6e945a74f881831aaf1bb7f853a15e15e8c998238ab88d327f6a - requires_python: '>=3.7' -- kind: pypi - name: nodejs-wheel-binaries - version: 22.11.0 - url: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: a9545cc43f1ba2c9f467f3444e9cd7f8db059933be1a5215135610dee5b38bf3 - requires_python: '>=3.7' - kind: conda name: numpy version: 2.1.3 @@ -3946,6 +3914,19 @@ packages: - pkg:pypi/pylint?source=hash-mapping size: 352873 timestamp: 1727266530261 +- kind: pypi + name: pyright + version: 1.1.389 + url: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + sha256: 41e9620bba9254406dc1f621a88ceab5a88af4c826feb4f614d95691ed243a60 + requires_dist: + - nodeenv>=1.6.0 + - typing-extensions>=4.1 + - twine>=3.4.1 ; extra == 'all' + - nodejs-wheel-binaries ; extra == 'all' + - twine>=3.4.1 ; extra == 'dev' + - nodejs-wheel-binaries ; extra == 'nodejs' + requires_python: '>=3.7' - kind: conda name: pysocks version: 1.7.1 diff --git a/pyproject.toml b/pyproject.toml index 5bc15b9e..289cea00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,14 +78,16 @@ numpy = "*" pytest = "*" [tool.pixi.feature.lint.pypi-dependencies] -basedpyright = "*" +# basedpyright = "*" +pyright = "*" [tool.pixi.feature.lint.tasks] pre-commit-install = { cmd = "pre-commit install" } pre-commit = { cmd = "pre-commit run -v --all-files --show-diff-on-failure" } mypy = { cmd = "mypy", cwd = "." } pylint = { cmd = ["pylint", "array_api_extra"], cwd = "src" } -pyright = { cmd = "basedpyright", cwd = "." } +# pyright = { cmd = "basedpyright", cwd = "." } +pyright = { cmd = "pyright", cwd = "." } lint = { depends-on = ["pre-commit", "pylint", "mypy", "pyright"] } [tool.pixi.feature.tests.dependencies] @@ -180,17 +182,25 @@ disallow_incomplete_defs = true # pyright -[tool.basedpyright] +# [tool.basedpyright] +# include = ["src", "tests"] +# pythonVersion = "3.10" +# pythonPlatform = "All" +# typeCheckingMode = "all" + +# # data-apis/array-api#589 +# reportAny = false +# reportExplicitAny = false +# # data-apis/array-api-strict#6 +# reportUnknownMemberType = false + +[tool.pyright] include = ["src", "tests"] pythonVersion = "3.10" pythonPlatform = "All" -typeCheckingMode = "all" - -# data-apis/array-api#589 -reportAny = false -reportExplicitAny = false -# data-apis/array-api-strict#6 +typeCheckingMode = "strict" reportUnknownMemberType = false +reportImportCycles = true # Ruff diff --git a/src/array_api_extra/_compat.py b/src/array_api_extra/_compat.py index e836ba78..b9577ff3 100644 --- a/src/array_api_extra/_compat.py +++ b/src/array_api_extra/_compat.py @@ -6,6 +6,8 @@ import sys import typing +from typing_extensions import override + if typing.TYPE_CHECKING: from ._typing import Array, Device @@ -16,6 +18,7 @@ # when the array backend is not the CPU. # (since it is not easy to tell which device a dask array is on) class _dask_device: # pylint: disable=invalid-name + @override def __repr__(self) -> str: return "DASK_DEVICE" @@ -118,7 +121,7 @@ def _is_dask_array(x: Array) -> bool: return False # pylint: disable=import-error, import-outside-toplevel - import dask.array # type: ignore[import-not-found] + import dask.array # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] return isinstance(x, dask.array.Array) @@ -133,10 +136,10 @@ def _is_jax_zero_gradient_array(x: Array) -> bool: return False # pylint: disable=import-error, import-outside-toplevel - import jax # type: ignore[import-not-found] + import jax # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] import numpy as np # pylint: disable=import-outside-toplevel - return isinstance(x, np.ndarray) and x.dtype == jax.float0 + return isinstance(x, np.ndarray) and x.dtype == jax.float0 # pyright: ignore[reportUnknownVariableType] def _is_jax_array(x: Array) -> bool: @@ -146,7 +149,7 @@ def _is_jax_array(x: Array) -> bool: return False # pylint: disable=import-error, import-outside-toplevel - import jax + import jax # pyright: ignore[reportMissingImports] return isinstance(x, jax.Array) or _is_jax_zero_gradient_array(x) @@ -159,7 +162,7 @@ def _is_pydata_sparse_array(x: Array) -> bool: return False # pylint: disable=import-error, import-outside-toplevel - import sparse # type: ignore[import-not-found] + import sparse # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # TODO: Account for other backends. return isinstance(x, sparse.SparseArray) diff --git a/src/array_api_extra/_typing.py b/src/array_api_extra/_typing.py index b32f67b6..13079807 100644 --- a/src/array_api_extra/_typing.py +++ b/src/array_api_extra/_typing.py @@ -5,6 +5,6 @@ # To be changed to a Protocol later (see data-apis/array-api#589) Array = Any # type: ignore[no-any-explicit] -Device = Any +Device = Any # type: ignore[no-any-explicit] __all__ = ["Array", "Device", "ModuleType"] diff --git a/src/array_api_extra/_utils.py b/src/array_api_extra/_utils.py index 26fbb56a..f77ee1fe 100644 --- a/src/array_api_extra/_utils.py +++ b/src/array_api_extra/_utils.py @@ -58,6 +58,7 @@ def in1d( if assume_unique: return ret[: x1.shape[0]] + # https://github.com/KotlinIsland/basedmypy/issues/826 # https://github.com/pylint-dev/pylint/issues/10095 # pylint: disable=possibly-used-before-assignment - return xp.take(ret, rev_idx, axis=0) + return xp.take(ret, rev_idx, axis=0) # type: ignore[possibly-undefined] # pyright: ignore[reportPossiblyUnboundVariable] From 6aa975cbc7f65b017721714382c6bf1d4aab8572 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 21:12:42 +0000 Subject: [PATCH 03/10] appease linter --- pixi.lock | 173 ++++++++++++---------- pyproject.toml | 5 +- src/array_api_extra/_funcs.py | 2 +- src/array_api_extra/{ => _lib}/_compat.py | 2 +- src/array_api_extra/{ => _lib}/_utils.py | 2 +- 5 files changed, 105 insertions(+), 79 deletions(-) rename src/array_api_extra/{ => _lib}/_compat.py (99%) rename src/array_api_extra/{ => _lib}/_utils.py (97%) diff --git a/pixi.lock b/pixi.lock index 4f35e002..c3a6f80c 100644 --- a/pixi.lock +++ b/pixi.lock @@ -46,6 +46,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - pypi: . @@ -81,6 +82,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - pypi: . @@ -116,6 +118,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda - conda: https://prefix.dev/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda @@ -163,12 +166,13 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - pypi: . @@ -200,12 +204,13 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - pypi: . @@ -237,12 +242,13 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/pthreads-win32-2.9.1-h2466b09_4.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tbb-2021.13.0-hc790b64_0.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda - conda: https://prefix.dev/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda @@ -273,10 +279,11 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.4.0-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - pypi: . @@ -290,10 +297,11 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.4.0-h39f12f2_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - pypi: . @@ -306,9 +314,10 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/libsqlite-3.47.0-h2466b09_1.conda - conda: https://prefix.dev/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://prefix.dev/conda-forge/win-64/openssl-3.4.0-h2466b09_0.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda - conda: https://prefix.dev/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda @@ -357,7 +366,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/ipython-8.29.0-pyh707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ipython-8.30.0-pyh707e725_0.conda - conda: https://prefix.dev/conda-forge/noarch/isort-5.13.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jedi-0.19.2-pyhff2d567_0.conda - conda: https://prefix.dev/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda @@ -403,7 +412,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda @@ -479,7 +488,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/ipython-8.29.0-pyh707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ipython-8.30.0-pyh707e725_0.conda - conda: https://prefix.dev/conda-forge/noarch/isort-5.13.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jedi-0.19.2-pyhff2d567_0.conda - conda: https://prefix.dev/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda @@ -520,7 +529,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda @@ -597,7 +606,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda - - conda: https://prefix.dev/conda-forge/noarch/ipython-8.29.0-pyh7428d3b_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ipython-8.30.0-pyh7428d3b_0.conda - conda: https://prefix.dev/conda-forge/noarch/isort-5.13.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jedi-0.19.2-pyhff2d567_0.conda - conda: https://prefix.dev/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda @@ -635,7 +644,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda @@ -729,7 +738,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda @@ -747,6 +756,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 @@ -792,7 +802,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda @@ -810,6 +820,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 @@ -853,7 +864,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2 - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda @@ -870,6 +881,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda - conda: https://prefix.dev/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda @@ -943,7 +955,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py313h536fd9c_1.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda @@ -1003,7 +1015,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.2-py313h20a7fcf_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda @@ -1063,7 +1075,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pylint-3.3.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/pyyaml-6.0.2-py313ha7868ed_1.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda @@ -1124,12 +1136,13 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - pypi: . @@ -1161,12 +1174,13 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - pypi: . @@ -1198,12 +1212,13 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/pthreads-win32-2.9.1-h2466b09_4.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda + - conda: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://prefix.dev/conda-forge/win-64/tbb-2021.13.0-hc790b64_0.conda - conda: https://prefix.dev/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://prefix.dev/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda - conda: https://prefix.dev/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda @@ -1268,8 +1283,9 @@ packages: name: array-api-extra version: 0.2.1.dev0 path: . - sha256: 3c0d9a9d1c6e4479531aaf3a82562c6e17fb30a4625aa4e43b72403497473308 + sha256: 153eb2cfe6d87235358f00f2c229f9cd4a84e3c73f8cb4a3e771087d4a41193b requires_dist: + - typing-extensions - furo>=2023.8.17 ; extra == 'docs' - myst-parser>=0.13 ; extra == 'docs' - sphinx-autodoc-typehints ; extra == 'docs' @@ -1780,6 +1796,7 @@ packages: arch: x86_64 platform: win license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 319434 @@ -1801,6 +1818,7 @@ packages: arch: x86_64 platform: linux license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 294004 @@ -1822,6 +1840,7 @@ packages: arch: arm64 platform: osx license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 293158 @@ -1843,6 +1862,7 @@ packages: arch: x86_64 platform: linux license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 371219 @@ -1864,6 +1884,7 @@ packages: arch: arm64 platform: osx license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 370706 @@ -1886,6 +1907,7 @@ packages: arch: x86_64 platform: win license: Apache-2.0 + license_family: APACHE purls: - pkg:pypi/coverage?source=hash-mapping size: 396450 @@ -2168,13 +2190,13 @@ packages: timestamp: 1723739573141 - kind: conda name: ipython - version: 8.29.0 + version: 8.30.0 build: pyh707e725_0 subdir: noarch noarch: python - url: https://prefix.dev/conda-forge/noarch/ipython-8.29.0-pyh707e725_0.conda - sha256: 606723272a208cca1036852e04fbb61741b78451784746e75edd1becb70347d2 - md5: 56db21d7d51410fcfbfeca3d1a6b4269 + url: https://prefix.dev/conda-forge/noarch/ipython-8.30.0-pyh707e725_0.conda + sha256: 65cdc105e5effea2943d3979cc1592590c923a589009b484d07672faaf047af1 + md5: 5d6e5cb3a4b820f61b2073f0ad5431f1 depends: - __unix - decorator @@ -2193,17 +2215,17 @@ packages: license_family: BSD purls: - pkg:pypi/ipython?source=hash-mapping - size: 599356 - timestamp: 1729866495921 + size: 600248 + timestamp: 1732897026255 - kind: conda name: ipython - version: 8.29.0 + version: 8.30.0 build: pyh7428d3b_0 subdir: noarch noarch: python - url: https://prefix.dev/conda-forge/noarch/ipython-8.29.0-pyh7428d3b_0.conda - sha256: 2208dbe96e94ba653c4e0a5f302e36f16df73eec1968cfb85eff2d9775c9ced1 - md5: 9dc505b3569b4c26cffc241c50695f75 + url: https://prefix.dev/conda-forge/noarch/ipython-8.30.0-pyh7428d3b_0.conda + sha256: 94ee8215bd1f614c9c984437b184e8dbe61a4014eb5813c276e3dcb18aaa7f46 + md5: 6cdaebbc9e3feb2811eb9f52ed0b89e1 depends: - __win - colorama @@ -2222,8 +2244,8 @@ packages: license_family: BSD purls: - pkg:pypi/ipython?source=hash-mapping - size: 600237 - timestamp: 1729866942619 + size: 600466 + timestamp: 1732897444811 - kind: conda name: isort version: 5.13.2 @@ -4106,83 +4128,83 @@ packages: - kind: conda name: python version: 3.13.0 - build: h75c3a9f_100_cp313 - build_number: 100 - subdir: osx-arm64 - url: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-h75c3a9f_100_cp313.conda - sha256: be9464399b76ae1fef77853eed70267ef657a98a5f69f7df012b7c6a34792151 - md5: 94ae22ea862d056ad1bc095443d02d73 + build: h9ebbce0_101_cp313 + build_number: 101 + subdir: linux-64 + url: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda + sha256: 66a7997b24b2dca636df11402abec7bd2199ddf6971eb47a3ee6b1d27d4faee9 + md5: f4fea9d5bb3f2e61a39950a7ab70ee4e depends: - - __osx >=11.0 + - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.3,<3.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 + - libgcc >=13 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.46.1,<4.0a0 + - libsqlite >=3.47.0,<4.0a0 + - libuuid >=2.38.1,<3.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.3.2,<4.0a0 + - openssl >=3.4.0,<4.0a0 - python_abi 3.13.* *_cp313 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - xz >=5.2.6,<6.0a0 - arch: arm64 - platform: osx + arch: x86_64 + platform: linux license: Python-2.0 purls: [] - size: 12804842 - timestamp: 1729168680448 + size: 33054218 + timestamp: 1732736838043 - kind: conda name: python version: 3.13.0 - build: h9ebbce0_100_cp313 - build_number: 100 - subdir: linux-64 - url: https://prefix.dev/conda-forge/linux-64/python-3.13.0-h9ebbce0_100_cp313.conda - sha256: 6ab5179679f0909db828d8316f3b8b379014a82404807310fe7df5a6cf303646 - md5: 08e9aef080f33daeb192b2ddc7e4721f + build: hbbac1ca_101_cp313 + build_number: 101 + subdir: osx-arm64 + url: https://prefix.dev/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda + sha256: 742544a4cf9a10cf2c16d35d96fb696c27d58b9df0cc29fbef5629283aeca941 + md5: e972e146a1e0cfb1f26da42cb6f6648c depends: - - __glibc >=2.17,<3.0.a0 + - __osx >=11.0 - bzip2 >=1.0.8,<2.0a0 - - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.6.3,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - - libgcc >=13 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.46.1,<4.0a0 - - libuuid >=2.38.1,<3.0a0 + - libsqlite >=3.47.0,<4.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.3.2,<4.0a0 + - openssl >=3.4.0,<4.0a0 - python_abi 3.13.* *_cp313 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - xz >=5.2.6,<6.0a0 - arch: x86_64 - platform: linux + arch: arm64 + platform: osx license: Python-2.0 purls: [] - size: 33112481 - timestamp: 1728419573472 + size: 12806496 + timestamp: 1732735488999 - kind: conda name: python version: 3.13.0 - build: hf5aa216_100_cp313 - build_number: 100 + build: hf5aa216_101_cp313 + build_number: 101 subdir: win-64 - url: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_100_cp313.conda - sha256: 18f3f0bd514c9101d38d57835b2d027958f3ae4b3b65c22d187a857aa26b3a08 - md5: 3c2f7ad3f598480fe2a09e4e33cb1a2a + url: https://prefix.dev/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda + sha256: b8eba57bd86c7890b27e67b477b52b5bd547946c354f29b9dbbc70ad83f2863b + md5: 158d6077a635cf0c0c23bec3955a4833 depends: - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.3,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.46.1,<4.0a0 + - libsqlite >=3.47.0,<4.0a0 - libzlib >=1.3.1,<2.0a0 - - openssl >=3.3.2,<4.0a0 + - openssl >=3.4.0,<4.0a0 - python_abi 3.13.* *_cp313 - tk >=8.6.13,<8.7.0a0 - tzdata @@ -4194,8 +4216,8 @@ packages: platform: win license: Python-2.0 purls: [] - size: 16641177 - timestamp: 1728417810202 + size: 16697406 + timestamp: 1732734725404 - kind: conda name: python_abi version: '3.10' @@ -5089,6 +5111,7 @@ packages: - platformdirs >=3.9.1,<5 - python >=3.9 license: MIT + license_family: MIT purls: - pkg:pypi/virtualenv?source=hash-mapping size: 3350255 diff --git a/pyproject.toml b/pyproject.toml index 289cea00..98789ca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,9 @@ classifiers = [ "Typing :: Typed", ] dynamic = ["version"] -dependencies = [] +dependencies = [ + "typing_extensions", +] [project.optional-dependencies] tests = [ @@ -64,6 +66,7 @@ platforms = ["linux-64", "osx-arm64", "win-64"] [tool.pixi.dependencies] python = ">=3.10.15,<3.14" +typing_extensions = "*" [tool.pixi.pypi-dependencies] array-api-extra = { path = ".", editable = true } diff --git a/src/array_api_extra/_funcs.py b/src/array_api_extra/_funcs.py index 660b15f1..3bb20b81 100644 --- a/src/array_api_extra/_funcs.py +++ b/src/array_api_extra/_funcs.py @@ -6,7 +6,7 @@ if typing.TYPE_CHECKING: from ._typing import Array, ModuleType -from . import _utils +from ._lib import _utils __all__ = [ "atleast_nd", diff --git a/src/array_api_extra/_compat.py b/src/array_api_extra/_lib/_compat.py similarity index 99% rename from src/array_api_extra/_compat.py rename to src/array_api_extra/_lib/_compat.py index b9577ff3..c883065e 100644 --- a/src/array_api_extra/_compat.py +++ b/src/array_api_extra/_lib/_compat.py @@ -9,7 +9,7 @@ from typing_extensions import override if typing.TYPE_CHECKING: - from ._typing import Array, Device + from .._typing import Array, Device __all__ = ["device"] diff --git a/src/array_api_extra/_utils.py b/src/array_api_extra/_lib/_utils.py similarity index 97% rename from src/array_api_extra/_utils.py rename to src/array_api_extra/_lib/_utils.py index f77ee1fe..ea027424 100644 --- a/src/array_api_extra/_utils.py +++ b/src/array_api_extra/_lib/_utils.py @@ -3,7 +3,7 @@ import typing if typing.TYPE_CHECKING: - from ._typing import Array, ModuleType + from .._typing import Array, ModuleType from . import _compat From 72f9a3e953e1e69b5a4866cad7a83676212b1dc9 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 21:17:00 +0000 Subject: [PATCH 04/10] cleanup --- codecov.yml | 4 +- pixi.lock | 59 +++++++++++++++-------- pyproject.toml | 28 ++++------- src/array_api_extra/_funcs.py | 2 +- src/array_api_extra/_lib/_compat.py | 2 +- src/array_api_extra/{ => _lib}/_typing.py | 0 src/array_api_extra/_lib/_utils.py | 2 +- tests/test_funcs.py | 2 +- 8 files changed, 54 insertions(+), 45 deletions(-) rename src/array_api_extra/{ => _lib}/_typing.py (100%) diff --git a/codecov.yml b/codecov.yml index dd755284..1a517b3a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,4 +1,4 @@ comment: false ignore: - - "src/array_api_extra/_compat" - - "src/array_api_extra/_typing" + - "src/array_api_extra/_lib/_compat" + - "src/array_api_extra/_lib/_typing" diff --git a/pixi.lock b/pixi.lock index c3a6f80c..a0ef5266 100644 --- a/pixi.lock +++ b/pixi.lock @@ -447,11 +447,12 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.23.0-py313h80202fe_1.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -564,11 +565,12 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.23.0-py313hf2da073_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.6-hb46c0d2_0.conda + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -684,11 +686,12 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h8ffe710_2.tar.bz2 - conda: https://prefix.dev/conda-forge/win-64/zstandard-0.23.0-py313h574b89f_1.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.6-h0ea2cb4_0.conda + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/fa/ae/322d05bec884977b89eced3af811c228652a9e25f9646ee6236890987214/sphinx_autodoc_typehints-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl - pypi: . @@ -970,7 +973,8 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.28.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: . osx-arm64: - conda: https://prefix.dev/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_0.conda @@ -1030,7 +1034,8 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.28.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl - pypi: . win-64: - conda: https://prefix.dev/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_0.conda @@ -1094,7 +1099,8 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/vs2015_runtime-14.42.34433-hdffcdeb_23.conda - conda: https://prefix.dev/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h8ffe710_2.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl - pypi: . tests: channels: @@ -1283,7 +1289,7 @@ packages: name: array-api-extra version: 0.2.1.dev0 path: . - sha256: 153eb2cfe6d87235358f00f2c229f9cd4a84e3c73f8cb4a3e771087d4a41193b + sha256: 9e2749304aa75f47b7108c3d45874ab2e8b0acc9de80c47f8c067fe9b6438ef3 requires_dist: - typing-extensions - furo>=2023.8.17 ; extra == 'docs' @@ -1430,6 +1436,14 @@ packages: - pkg:pypi/basedmypy?source=hash-mapping size: 1808422 timestamp: 1732706894788 +- kind: pypi + name: basedpyright + version: 1.22.0 + url: https://files.pythonhosted.org/packages/1b/d2/1783a17c041a48faa1fd056a7dd1029e419a0026ecc2c070b7c7516018d0/basedpyright-1.22.0-py3-none-any.whl + sha256: 6376107086ad25525429b8a94a2ffdb67c6dd2b1a6be38bf3c6ea9b5c3d1f688 + requires_dist: + - nodejs-wheel-binaries>=20.13.1 + requires_python: '>=3.8' - kind: conda name: basedtyping version: 0.1.10 @@ -3459,6 +3473,24 @@ packages: - pkg:pypi/nodeenv?source=hash-mapping size: 34489 timestamp: 1717585382642 +- kind: pypi + name: nodejs-wheel-binaries + version: 22.11.0 + url: https://files.pythonhosted.org/packages/68/69/f0dbbf72c8bdd9149ee00427c282d392da7fad9c53bd96f4844c2ab9021c/nodejs_wheel_binaries-22.11.0-py2.py3-none-win_amd64.whl + sha256: 8310ab182ee159141e08c85bc07f11e67ac3044922e6e4958f4a8f3ba6860185 + requires_python: '>=3.7' +- kind: pypi + name: nodejs-wheel-binaries + version: 22.11.0 + url: https://files.pythonhosted.org/packages/a5/16/4cd2c0791567ee7b0203c3c6b59341854f0aeecb7315159d634c2b54b6d4/nodejs_wheel_binaries-22.11.0-py2.py3-none-macosx_11_0_arm64.whl + sha256: 00afada277fd6e945a74f881831aaf1bb7f853a15e15e8c998238ab88d327f6a + requires_python: '>=3.7' +- kind: pypi + name: nodejs-wheel-binaries + version: 22.11.0 + url: https://files.pythonhosted.org/packages/d8/16/e34cf573096e7b25c85829e99f7e47d6cda0a6cdc4bd078d6bcdcb4dc979/nodejs_wheel_binaries-22.11.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: a9545cc43f1ba2c9f467f3444e9cd7f8db059933be1a5215135610dee5b38bf3 + requires_python: '>=3.7' - kind: conda name: numpy version: 2.1.3 @@ -3936,19 +3968,6 @@ packages: - pkg:pypi/pylint?source=hash-mapping size: 352873 timestamp: 1727266530261 -- kind: pypi - name: pyright - version: 1.1.389 - url: https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl - sha256: 41e9620bba9254406dc1f621a88ceab5a88af4c826feb4f614d95691ed243a60 - requires_dist: - - nodeenv>=1.6.0 - - typing-extensions>=4.1 - - twine>=3.4.1 ; extra == 'all' - - nodejs-wheel-binaries ; extra == 'all' - - twine>=3.4.1 ; extra == 'dev' - - nodejs-wheel-binaries ; extra == 'nodejs' - requires_python: '>=3.7' - kind: conda name: pysocks version: 1.7.1 diff --git a/pyproject.toml b/pyproject.toml index 98789ca6..069c180f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,16 +81,14 @@ numpy = "*" pytest = "*" [tool.pixi.feature.lint.pypi-dependencies] -# basedpyright = "*" -pyright = "*" +basedpyright = "*" [tool.pixi.feature.lint.tasks] pre-commit-install = { cmd = "pre-commit install" } pre-commit = { cmd = "pre-commit run -v --all-files --show-diff-on-failure" } mypy = { cmd = "mypy", cwd = "." } pylint = { cmd = ["pylint", "array_api_extra"], cwd = "src" } -# pyright = { cmd = "basedpyright", cwd = "." } -pyright = { cmd = "pyright", cwd = "." } +pyright = { cmd = "basedpyright", cwd = "." } lint = { depends-on = ["pre-commit", "pylint", "mypy", "pyright"] } [tool.pixi.feature.tests.dependencies] @@ -185,25 +183,17 @@ disallow_incomplete_defs = true # pyright -# [tool.basedpyright] -# include = ["src", "tests"] -# pythonVersion = "3.10" -# pythonPlatform = "All" -# typeCheckingMode = "all" - -# # data-apis/array-api#589 -# reportAny = false -# reportExplicitAny = false -# # data-apis/array-api-strict#6 -# reportUnknownMemberType = false - -[tool.pyright] +[tool.basedpyright] include = ["src", "tests"] pythonVersion = "3.10" pythonPlatform = "All" -typeCheckingMode = "strict" +typeCheckingMode = "all" + +# data-apis/array-api#589 +reportAny = false +reportExplicitAny = false +# data-apis/array-api-strict#6 reportUnknownMemberType = false -reportImportCycles = true # Ruff diff --git a/src/array_api_extra/_funcs.py b/src/array_api_extra/_funcs.py index 3bb20b81..3d7b9313 100644 --- a/src/array_api_extra/_funcs.py +++ b/src/array_api_extra/_funcs.py @@ -4,7 +4,7 @@ import warnings if typing.TYPE_CHECKING: - from ._typing import Array, ModuleType + from ._lib._typing import Array, ModuleType from ._lib import _utils diff --git a/src/array_api_extra/_lib/_compat.py b/src/array_api_extra/_lib/_compat.py index c883065e..b9577ff3 100644 --- a/src/array_api_extra/_lib/_compat.py +++ b/src/array_api_extra/_lib/_compat.py @@ -9,7 +9,7 @@ from typing_extensions import override if typing.TYPE_CHECKING: - from .._typing import Array, Device + from ._typing import Array, Device __all__ = ["device"] diff --git a/src/array_api_extra/_typing.py b/src/array_api_extra/_lib/_typing.py similarity index 100% rename from src/array_api_extra/_typing.py rename to src/array_api_extra/_lib/_typing.py diff --git a/src/array_api_extra/_lib/_utils.py b/src/array_api_extra/_lib/_utils.py index ea027424..f77ee1fe 100644 --- a/src/array_api_extra/_lib/_utils.py +++ b/src/array_api_extra/_lib/_utils.py @@ -3,7 +3,7 @@ import typing if typing.TYPE_CHECKING: - from .._typing import Array, ModuleType + from ._typing import Array, ModuleType from . import _compat diff --git a/tests/test_funcs.py b/tests/test_funcs.py index 827da9c4..9127600a 100644 --- a/tests/test_funcs.py +++ b/tests/test_funcs.py @@ -13,7 +13,7 @@ from array_api_extra import atleast_nd, cov, create_diagonal, expand_dims, kron, sinc if typing.TYPE_CHECKING: - from array_api_extra._typing import Array + from array_api_extra._lib._typing import Array class TestAtLeastND: From f83550272658091ca9882487c0345e40e817c542 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 21:18:13 +0000 Subject: [PATCH 05/10] upgrade deps --- pixi.lock | 2 +- pyproject.toml | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pixi.lock b/pixi.lock index a0ef5266..eaf64305 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1289,7 +1289,7 @@ packages: name: array-api-extra version: 0.2.1.dev0 path: . - sha256: 9e2749304aa75f47b7108c3d45874ab2e8b0acc9de80c47f8c067fe9b6438ef3 + sha256: 8e5573eb0fdab83a4df5f31277f541ecbf3b046edb8730d82dc1580593ced2d6 requires_dist: - typing-extensions - furo>=2023.8.17 ; extra == 'docs' diff --git a/pyproject.toml b/pyproject.toml index 069c180f..ec5fcbf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,9 +26,7 @@ classifiers = [ "Typing :: Typed", ] dynamic = ["version"] -dependencies = [ - "typing_extensions", -] +dependencies = ["typing-extensions"] [project.optional-dependencies] tests = [ @@ -66,7 +64,7 @@ platforms = ["linux-64", "osx-arm64", "win-64"] [tool.pixi.dependencies] python = ">=3.10.15,<3.14" -typing_extensions = "*" +typing_extensions = ">=4.12.2,<4.13" [tool.pixi.pypi-dependencies] array-api-extra = { path = ".", editable = true } From fadf70100258721ad65b7f5b3b2cf56331ddd791 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 23:21:37 +0000 Subject: [PATCH 06/10] TST: setdiff1d: add tests --- src/array_api_extra/_lib/_utils.py | 5 +++- tests/test_funcs.py | 38 +++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/array_api_extra/_lib/_utils.py b/src/array_api_extra/_lib/_utils.py index f77ee1fe..a7c2c202 100644 --- a/src/array_api_extra/_lib/_utils.py +++ b/src/array_api_extra/_lib/_utils.py @@ -52,7 +52,10 @@ def in1d( order = xp.argsort(ar, stable=True) reverse_order = xp.argsort(order, stable=True) sar = xp.take(ar, order, axis=0) - bool_ar = sar[1:] != sar[:-1] if invert else sar[1:] == sar[:-1] + if sar.size >= 1: + bool_ar = sar[1:] != sar[:-1] if invert else sar[1:] == sar[:-1] + else: + bool_ar = xp.asarray([False]) if invert else xp.asarray([True]) flag = xp.concat((bool_ar, xp.asarray([invert], device=device_))) ret = xp.take(flag, reverse_order, axis=0) diff --git a/tests/test_funcs.py b/tests/test_funcs.py index 9127600a..3cd8af5a 100644 --- a/tests/test_funcs.py +++ b/tests/test_funcs.py @@ -10,7 +10,15 @@ import pytest from numpy.testing import assert_allclose, assert_array_equal, assert_equal -from array_api_extra import atleast_nd, cov, create_diagonal, expand_dims, kron, sinc +from array_api_extra import ( + atleast_nd, + cov, + create_diagonal, + expand_dims, + kron, + setdiff1d, + sinc, +) if typing.TYPE_CHECKING: from array_api_extra._lib._typing import Array @@ -263,6 +271,34 @@ def test_positive_negative_repeated(self): expand_dims(a, axis=(3, -3), xp=xp) +class TestSetDiff1D: + def test_setdiff1d(self): + x1 = xp.asarray([6, 5, 4, 7, 1, 2, 7, 4]) + x2 = xp.asarray([2, 4, 3, 3, 2, 1, 5]) + + expected = xp.asarray([6, 7]) + actual = setdiff1d(x1, x2, xp=xp) + assert_array_equal(actual, expected) + + x1 = xp.arange(21) + x2 = xp.arange(19) + expected = xp.asarray([19, 20]) + actual = setdiff1d(x1, x2, xp=xp) + assert_array_equal(actual, expected) + + assert_array_equal(setdiff1d(xp.empty(0), xp.empty(0), xp=xp), xp.empty(0)) + x1 = xp.empty(0, dtype=xp.uint32) + x2 = x1 + assert_equal(setdiff1d(x1, x2, xp=xp).dtype, xp.uint32) + + def test_setdiff1d_unique(self): + x1 = xp.asarray([3, 2, 1]) + x2 = xp.asarray([7, 5, 2]) + expected = xp.asarray([3, 1]) + actual = setdiff1d(x1, x2, assume_unique=True, xp=xp) + assert_array_equal(actual, expected) + + class TestSinc: def test_simple(self): assert_array_equal(sinc(xp.asarray(0.0), xp=xp), xp.asarray(1.0)) From 0b7c4e7b96446fe08edb3c67003f959544e84186 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 23:32:26 +0000 Subject: [PATCH 07/10] TST: `_utils.in1d`: add tests --- tests/test_funcs.py | 4 ++-- tests/test_utils.py | 17 +++++++++++++++++ tests/test_version.py | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/test_utils.py diff --git a/tests/test_funcs.py b/tests/test_funcs.py index 3cd8af5a..36411958 100644 --- a/tests/test_funcs.py +++ b/tests/test_funcs.py @@ -1,4 +1,4 @@ -from __future__ import annotations +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 import contextlib import typing @@ -291,7 +291,7 @@ def test_setdiff1d(self): x2 = x1 assert_equal(setdiff1d(x1, x2, xp=xp).dtype, xp.uint32) - def test_setdiff1d_unique(self): + def test_assume_unique(self): x1 = xp.asarray([3, 2, 1]) x2 = xp.asarray([7, 5, 2]) expected = xp.asarray([3, 1]) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 00000000..6854569d --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,17 @@ +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 + +# data-apis/array-api-strict#6 +import array_api_strict as xp # type: ignore[import-untyped] # pyright: ignore[reportMissingTypeStubs] +from numpy.testing import assert_array_equal + +from array_api_extra._lib._utils import in1d + + +# some test coverage already provided by TestSetDiff1D +class TestIn1D: + def test_no_invert_assume_unique(self): + x1 = xp.asarray([1, 2, 3]) + x2 = xp.asarray([3, 4, 5]) + expected = xp.asarray([False, False, True]) + actual = in1d(x1, x2, xp=xp) + assert_array_equal(actual, expected) diff --git a/tests/test_version.py b/tests/test_version.py index 21d43d17..1b20232f 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -1,4 +1,4 @@ -from __future__ import annotations +from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 import importlib.metadata From 5cc1140d7e8e226837ccada62ec4880294a6f9c1 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 29 Nov 2024 23:37:36 +0000 Subject: [PATCH 08/10] adjust test to hit alternative path --- tests/test_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 6854569d..b2f6bd93 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -10,8 +10,8 @@ # some test coverage already provided by TestSetDiff1D class TestIn1D: def test_no_invert_assume_unique(self): - x1 = xp.asarray([1, 2, 3]) - x2 = xp.asarray([3, 4, 5]) - expected = xp.asarray([False, False, True]) + x1 = xp.asarray([3, 8, 20]) + x2 = xp.arange(15) + expected = xp.asarray([True, True, False]) actual = in1d(x1, x2, xp=xp) assert_array_equal(actual, expected) From 0b4135dd9948c5c94ce467169da8c85b82419830 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Sat, 30 Nov 2024 00:02:33 +0000 Subject: [PATCH 09/10] cover all cases --- src/array_api_extra/_lib/_utils.py | 6 ++---- tests/test_utils.py | 11 +++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/array_api_extra/_lib/_utils.py b/src/array_api_extra/_lib/_utils.py index a7c2c202..bf65340e 100644 --- a/src/array_api_extra/_lib/_utils.py +++ b/src/array_api_extra/_lib/_utils.py @@ -42,6 +42,7 @@ def in1d( mask |= x1 == a return mask + rev_idx = xp.empty(0) # placeholder if not assume_unique: x1, rev_idx = xp.unique_inverse(x1) x2 = xp.unique_values(x2) @@ -61,7 +62,4 @@ def in1d( if assume_unique: return ret[: x1.shape[0]] - # https://github.com/KotlinIsland/basedmypy/issues/826 - # https://github.com/pylint-dev/pylint/issues/10095 - # pylint: disable=possibly-used-before-assignment - return xp.take(ret, rev_idx, axis=0) # type: ignore[possibly-undefined] # pyright: ignore[reportPossiblyUnboundVariable] + return xp.take(ret, rev_idx, axis=0) diff --git a/tests/test_utils.py b/tests/test_utils.py index b2f6bd93..a34ec56f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,17 +1,24 @@ from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990 +import typing + # data-apis/array-api-strict#6 import array_api_strict as xp # type: ignore[import-untyped] # pyright: ignore[reportMissingTypeStubs] +import pytest from numpy.testing import assert_array_equal from array_api_extra._lib._utils import in1d +if typing.TYPE_CHECKING: + from array_api_extra._lib._typing import Array + # some test coverage already provided by TestSetDiff1D class TestIn1D: - def test_no_invert_assume_unique(self): + # cover both code paths + @pytest.mark.parametrize("x2", [xp.arange(9), xp.arange(15)]) + def test_no_invert_assume_unique(self, x2: Array): x1 = xp.asarray([3, 8, 20]) - x2 = xp.arange(15) expected = xp.asarray([True, True, False]) actual = in1d(x1, x2, xp=xp) assert_array_equal(actual, expected) From fe99300924136f85357b2528967d6defd08039bd Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Sat, 30 Nov 2024 00:17:22 +0000 Subject: [PATCH 10/10] DOC: setdiff1d: add docs --- docs/api-reference.md | 1 + src/array_api_extra/_funcs.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index 1307b6fc..ffe68f24 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -11,5 +11,6 @@ create_diagonal expand_dims kron + setdiff1d sinc ``` diff --git a/src/array_api_extra/_funcs.py b/src/array_api_extra/_funcs.py index 3d7b9313..4062c56f 100644 --- a/src/array_api_extra/_funcs.py +++ b/src/array_api_extra/_funcs.py @@ -412,9 +412,40 @@ def kron(a: Array, b: Array, /, *, xp: ModuleType) -> Array: def setdiff1d( x1: Array, x2: Array, /, *, assume_unique: bool = False, xp: ModuleType ) -> Array: - """Find the set difference of two arrays. + """ + Find the set difference of two arrays. Return the unique values in `x1` that are not in `x2`. + + Parameters + ---------- + x1 : array + Input array. + x2 : array + Input comparison array. + assume_unique : bool + If ``True``, the input arrays are both assumed to be unique, which + can speed up the calculation. Default is ``False``. + xp : array_namespace + The standard-compatible namespace for `x1` and `x2`. + + Returns + ------- + res : array + 1D array of values in `x1` that are not in `x2`. The result + is sorted when `assume_unique` is ``False``, but otherwise only sorted + if the input is sorted. + + Examples + -------- + >>> import array_api_strict as xp + >>> import array_api_extra as xpx + + >>> x1 = xp.asarray([1, 2, 3, 2, 4, 1]) + >>> x2 = xp.asarray([3, 4, 5, 6]) + >>> xpx.setdiff1d(x1, x2, xp=xp) + Array([1, 2], dtype=array_api_strict.int64) + """ if assume_unique: