array-api-extra 0.9.2__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/PKG-INFO +9 -29
  2. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/contributing.md +2 -0
  3. array_api_extra-0.10.0/meson.build +39 -0
  4. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/pyproject.toml +88 -85
  5. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/__init__.py +3 -1
  6. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_delegation.py +89 -0
  7. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_at.py +1 -1
  8. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_backends.py +1 -1
  9. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_funcs.py +73 -6
  10. array_api_extra-0.10.0/tests/meson.build +13 -0
  11. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_funcs.py +241 -18
  12. array_api_extra-0.10.0/vendor_tests/meson.build +8 -0
  13. array_api_extra-0.9.2/.gitattributes +0 -2
  14. array_api_extra-0.9.2/.github/pull_request_template.md +0 -5
  15. array_api_extra-0.9.2/.github/workflows/cd.yml +0 -47
  16. array_api_extra-0.9.2/.github/workflows/ci.yml +0 -79
  17. array_api_extra-0.9.2/.github/workflows/docs-build.yml +0 -27
  18. array_api_extra-0.9.2/.github/workflows/docs-deploy.yml +0 -36
  19. array_api_extra-0.9.2/.gitignore +0 -173
  20. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/.all-contributorsrc +0 -0
  21. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/.dprint.jsonc +0 -0
  22. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/.editorconfig +0 -0
  23. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/CONTRIBUTORS.md +0 -0
  24. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/LICENSE +0 -0
  25. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/README.md +0 -0
  26. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/api-lazy.md +0 -0
  27. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/api-reference.md +0 -0
  28. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/conf.py +0 -0
  29. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/contributors.md +0 -0
  30. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/docs/index.md +0 -0
  31. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/lefthook.yml +0 -0
  32. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/__init__.py +0 -0
  33. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_lazy.py +0 -0
  34. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_testing.py +0 -0
  35. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/__init__.py +0 -0
  36. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/_compat.py +0 -0
  37. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/_compat.pyi +0 -0
  38. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/_helpers.py +0 -0
  39. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/_typing.py +0 -0
  40. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/_lib/_utils/_typing.pyi +0 -0
  41. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/py.typed +0 -0
  42. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/src/array_api_extra/testing.py +0 -0
  43. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/__init__.py +0 -0
  44. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/conftest.py +0 -0
  45. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_at.py +0 -0
  46. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_helpers.py +0 -0
  47. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_lazy.py +0 -0
  48. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_testing.py +0 -0
  49. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/tests/test_version.py +0 -0
  50. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/typos.toml +0 -0
  51. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/vendor_tests/__init__.py +0 -0
  52. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/vendor_tests/_array_api_compat_vendor.py +0 -0
  53. {array_api_extra-0.9.2 → array_api_extra-0.10.0}/vendor_tests/test_vendor.py +0 -0
@@ -1,46 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: array-api-extra
3
- Version: 0.9.2
3
+ Version: 0.10.0
4
4
  Summary: Extra array functions built on top of the array API standard.
5
- Project-URL: Homepage, https://github.com/data-apis/array-api-extra
6
- Project-URL: Bug Tracker, https://github.com/data-apis/array-api-extra/issues
7
- Project-URL: Changelog, https://github.com/data-apis/array-api-extra/releases
8
- Author-email: Lucas Colley <lucas.colley8@gmail.com>
9
- License: MIT License
10
-
11
- Copyright (c) 2024 Consortium for Python Data API Standards
12
-
13
- Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
19
-
20
- The above copyright notice and this permission notice shall be included in all
21
- copies or substantial portions of the Software.
22
-
23
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
- SOFTWARE.
5
+ Author-Email: Lucas Colley <lucas.colley8@gmail.com>
6
+ License-Expression: MIT
30
7
  License-File: LICENSE
31
8
  Classifier: Intended Audience :: Developers
32
9
  Classifier: Operating System :: OS Independent
33
10
  Classifier: Programming Language :: Python
34
11
  Classifier: Programming Language :: Python :: 3
35
12
  Classifier: Programming Language :: Python :: 3 :: Only
36
- Classifier: Programming Language :: Python :: 3.10
37
13
  Classifier: Programming Language :: Python :: 3.11
38
14
  Classifier: Programming Language :: Python :: 3.12
39
15
  Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
40
17
  Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
41
18
  Classifier: Typing :: Typed
42
- Requires-Python: >=3.10
43
- Requires-Dist: array-api-compat<2,>=1.12.0
19
+ Project-URL: Homepage, https://github.com/data-apis/array-api-extra
20
+ Project-URL: Bug Tracker, https://github.com/data-apis/array-api-extra/issues
21
+ Project-URL: Changelog, https://github.com/data-apis/array-api-extra/releases
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: array-api-compat<2,>=1.13.0
44
24
  Description-Content-Type: text/markdown
45
25
 
46
26
  # array-api-extra
@@ -20,6 +20,8 @@ Thanks to [all contributors](contributors.md) so far!
20
20
  - Import your function to `src/array_api_extra/__init__.py` and add it to
21
21
  `__all__` there.
22
22
  - Add a test class for your function in `tests/test_funcs.py`.
23
+ - Ensure that `lazy_xp_function` is called on the function if lazy backends
24
+ are supposed to be tested.
23
25
  - Add your function to `docs/api-reference.md`.
24
26
  - [Make a PR!](https://github.com/data-apis/array-api-extra/pulls)
25
27
 
@@ -0,0 +1,39 @@
1
+ project(
2
+ 'array-api-extra',
3
+ version: '0.10.0'
4
+ )
5
+
6
+ py = import('python').find_installation()
7
+
8
+ # NOTE: downstream projects may rely on this variable name when vendoring,
9
+ # do not change it without consulting with downstream projects
10
+ sources = {
11
+ 'array_api_extra': files(
12
+ 'src/array_api_extra/__init__.py',
13
+ 'src/array_api_extra/_delegation.py',
14
+ 'src/array_api_extra/testing.py',
15
+ ),
16
+ 'array_api_extra/_lib': files(
17
+ 'src/array_api_extra/_lib/__init__.py',
18
+ 'src/array_api_extra/_lib/_at.py',
19
+ 'src/array_api_extra/_lib/_backends.py',
20
+ 'src/array_api_extra/_lib/_funcs.py',
21
+ 'src/array_api_extra/_lib/_lazy.py',
22
+ 'src/array_api_extra/_lib/_testing.py',
23
+ ),
24
+ 'array_api_extra/_lib/_utils': files(
25
+ 'src/array_api_extra/_lib/_utils/__init__.py',
26
+ 'src/array_api_extra/_lib/_utils/_compat.py',
27
+ 'src/array_api_extra/_lib/_utils/_compat.pyi',
28
+ 'src/array_api_extra/_lib/_utils/_helpers.py',
29
+ 'src/array_api_extra/_lib/_utils/_typing.py',
30
+ 'src/array_api_extra/_lib/_utils/_typing.pyi',
31
+ ),
32
+ }
33
+
34
+ foreach subdir, files : sources
35
+ py.install_sources(files, subdir: subdir)
36
+ endforeach
37
+
38
+ subdir('tests')
39
+ subdir('vendor_tests')
@@ -1,77 +1,113 @@
1
1
  [build-system]
2
- requires = ["hatchling"]
3
- build-backend = "hatchling.build"
2
+ requires = ["meson-python"]
3
+ build-backend = "mesonpy"
4
4
 
5
5
  [project]
6
6
  name = "array-api-extra"
7
+ version = "0.10.0"
7
8
  authors = [
8
9
  { name = "Lucas Colley", email = "lucas.colley8@gmail.com" },
9
10
  # { name = "Open Source Contributors" }, # https://github.com/pypi/warehouse/issues/14813
10
11
  ]
11
12
  description = "Extra array functions built on top of the array API standard."
12
13
  readme = "README.md"
13
- license.file = "LICENSE"
14
- requires-python = ">=3.10"
14
+ license = "MIT"
15
+ license-files = ["LICENSE"]
16
+ requires-python = ">=3.11"
15
17
  classifiers = [
16
18
  "Intended Audience :: Developers",
17
19
  "Operating System :: OS Independent",
18
20
  "Programming Language :: Python",
19
21
  "Programming Language :: Python :: 3",
20
22
  "Programming Language :: Python :: 3 :: Only",
21
- "Programming Language :: Python :: 3.10",
22
23
  "Programming Language :: Python :: 3.11",
23
24
  "Programming Language :: Python :: 3.12",
24
25
  "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
25
27
  "Programming Language :: Python :: Free Threading :: 3 - Stable",
26
28
  "Typing :: Typed",
27
29
  ]
28
- dynamic = ["version"]
29
- dependencies = ["array-api-compat>=1.12.0,<2"]
30
+ dependencies = ["array-api-compat>=1.13.0,<2"]
30
31
 
31
32
  [project.urls]
32
33
  Homepage = "https://github.com/data-apis/array-api-extra"
33
34
  "Bug Tracker" = "https://github.com/data-apis/array-api-extra/issues"
34
35
  Changelog = "https://github.com/data-apis/array-api-extra/releases"
35
36
 
36
- # Hatch
37
-
38
- [tool.hatch]
39
- version.path = "src/array_api_extra/__init__.py"
40
-
41
- [tool.hatch.build.targets.sdist]
42
- exclude = ["codecov.yml", "pixi.lock", "RELEASING.md", "renovate.json"]
43
-
44
- #  Pixi
37
+ # Pixi
45
38
 
46
39
  [tool.pixi.workspace]
47
40
  channels = ["https://prefix.dev/conda-forge"]
48
41
  platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"]
42
+ preview = ["pixi-build"]
43
+
44
+ ### array-api-extra package definition ###
45
+
46
+ [tool.pixi.package.build.backend]
47
+ name = "pixi-build-python"
48
+ version = "*"
49
+
50
+ [tool.pixi.package.host-dependencies]
51
+ meson-python = "*"
52
+ uv = "*" # interfaces with meson-python instead of pip
53
+
54
+ [tool.pixi.package.run-dependencies]
55
+ array-api-compat = "*"
56
+
57
+ ### workspace environments ###
58
+
59
+ [tool.pixi.environments]
60
+ default = { features = ["py314"], solve-group = "py314" }
61
+ lint = { features = ["py314", "lint"], solve-group = "py314" }
62
+ docs = { features = ["py314", "docs"], solve-group = "py314" }
63
+ tests = { features = ["py314", "tests"], solve-group = "py314" }
64
+ tests-py314 = { features = ["py314", "tests"], solve-group = "py314" } # alias of tests
65
+
66
+ # Some backends may pin numpy; use separate solve-group
67
+ dev = { features = ["py314", "lint", "tests", "docs", "dev", "backends"], solve-group = "backends" }
68
+ tests-backends = { features = ["py314", "tests", "backends"], solve-group = "backends" }
69
+ tests-backends-py311 = { features = ["py311", "tests", "backends"] }
70
+
71
+ # CUDA not available on free github actions and on some developers' PCs
72
+ dev-cuda = { features = ["py314", "lint", "tests", "docs", "dev", "backends", "cuda-backends"], solve-group = "cuda" }
73
+ tests-cuda = { features = ["py314", "tests", "backends", "cuda-backends"], solve-group = "cuda" }
74
+ tests-cuda-py311 = { features = ["py311", "tests", "backends", "cuda-backends"] }
75
+
76
+ # Ungrouped environments
77
+ tests-numpy1 = ["py311", "tests", "numpy1"]
78
+ tests-py311 = ["py311", "tests"]
79
+ tests-nogil = ["nogil", "tests"]
80
+
81
+ ### default feature definition ###
82
+
83
+ [tool.pixi.dev]
84
+ # this pulls in array-api-extra's host and run dependencies
85
+ array-api-extra.path = "."
49
86
 
50
87
  [tool.pixi.dependencies]
51
- array-api-compat = ">=1.12.0,<2"
88
+ array-api-extra.path = "."
52
89
 
53
- [tool.pixi.pypi-dependencies]
54
- array-api-extra = { path = ".", editable = true }
90
+ ### non-default feature definitions ###
55
91
 
56
92
  [tool.pixi.feature.lint.dependencies]
57
93
  typing-extensions = ">=4.15.0"
58
94
  pylint = ">=4.0.4"
59
95
  mypy = ">=1.19.1"
60
- basedpyright = ">=1.36.1"
96
+ basedpyright = ">=1.37.4"
61
97
  numpydoc = ">=1.10.0,<2"
62
98
  # import dependencies for mypy:
63
99
  array-api-strict = ">=2.4.1,<2.5"
64
100
  numpy = ">=2.1.3"
65
- hypothesis = ">=6.148.2"
66
- dask-core = ">=2025.12.0" # No distributed, tornado, etc.
101
+ hypothesis = ">=6.151.2"
102
+ dask-core = ">=2026.1.2" # No distributed, tornado, etc.
67
103
  dprint = ">=0.50.0,<0.51"
68
- lefthook = ">=2.0.12,<3"
69
- ruff = ">=0.14.10,<0.15"
70
- typos = ">=1.40.0,<2"
71
- actionlint = ">=1.7.9,<2"
104
+ lefthook = ">=2.1.0,<3"
105
+ ruff = ">=0.15.0,<0.16"
106
+ typos = ">=1.43.3,<2"
107
+ actionlint = ">=1.7.10,<2"
72
108
  blacken-docs = ">=1.20.0,<2"
73
109
  pytest = ">=9.0.2,<10"
74
- validate-pyproject = ">=0.24.1,<0.25"
110
+ validate-pyproject = ">=0.25,<0.26"
75
111
  # NOTE: don't add cupy, jax, pytorch, or sparse here,
76
112
  # as they slow down mypy and are not portable across target OSs
77
113
 
@@ -95,7 +131,7 @@ lint = { cmd = "lefthook run pre-commit --all-files --force", description = "Run
95
131
  [tool.pixi.feature.tests.dependencies]
96
132
  pytest = ">=9.0.2"
97
133
  pytest-cov = ">=7.0.0"
98
- hypothesis = ">=6.148.2"
134
+ hypothesis = ">=6.151.2"
99
135
  array-api-strict = ">=2.4.1,<2.5"
100
136
  numpy = ">=1.22.0"
101
137
 
@@ -116,11 +152,11 @@ open-coverage = { cmd = "open htmlcov/index.html", depends-on = ["coverage"], de
116
152
  [tool.pixi.feature.docs.dependencies]
117
153
  sphinx = ">=7.4.7"
118
154
  furo = ">=2024.8.6"
119
- myst-parser = ">=4.0.1"
155
+ myst-parser = ">=5.0.0"
120
156
  sphinx-copybutton = ">=0.5.2"
121
157
  sphinx-autodoc-typehints = ">=1.25.3"
122
158
  # Needed to import parsed modules with autodoc
123
- dask-core = ">=2025.12.0" # No distributed, tornado, etc.
159
+ dask-core = ">=2026.1.2" # No distributed, tornado, etc.
124
160
  pytest = ">=9.0.2"
125
161
  typing-extensions = ">=4.15.0"
126
162
  numpy = ">=2.1.3"
@@ -135,35 +171,32 @@ ipython = ">=7.33.0"
135
171
  [tool.pixi.feature.dev.tasks]
136
172
  ipython = { cmd = "ipython", description = "Launch ipython" }
137
173
 
138
- [tool.pixi.feature.py310.dependencies]
139
- python = "~=3.10.0"
174
+ [tool.pixi.feature.py311.dependencies]
175
+ python = "~=3.11.0"
140
176
 
141
- [tool.pixi.feature.py313.dependencies]
142
- python = "~=3.13.0"
177
+ [tool.pixi.feature.py314.dependencies]
178
+ python = "~=3.14.0"
143
179
 
144
180
  [tool.pixi.feature.numpy1.dependencies]
145
181
  # Oldest NumPy version supported by scikit-learn.
146
182
  # Note that this is older than what SPEC0 recommends.
147
- numpy = "=1.22.0"
183
+ numpy = "=1.24.1"
148
184
 
149
185
  # Backends that can run on CPU-only hosts
150
186
  # Note: JAX and PyTorch will install CPU variants.
151
187
  [tool.pixi.feature.backends.dependencies]
152
- pytorch = ">=2.7.1"
153
- dask-core = ">=2025.12.0" # No distributed, tornado, etc.
188
+ pytorch = ">=2.10.0"
189
+ dask-core = ">=2026.1.2" # No distributed, tornado, etc.
154
190
  sparse = ">=0.17.0"
155
191
 
156
192
  [tool.pixi.feature.backends.target.linux-64.dependencies]
157
- # On CPU Python 3.10, use 0.6.2
158
- # On CPU Python >=3.11, use >=0.7.0
159
- # On GPU, use 0.6.0 (0.6.2 and 0.7.0 both segfault); see jaxlib pin below.
160
- jax = ">=0.6.0"
193
+ jax = ">=0.7.2"
161
194
 
162
195
  [tool.pixi.feature.backends.target.osx-64.dependencies]
163
- jax = ">=0.6.0"
196
+ jax = ">=0.7.2"
164
197
 
165
198
  [tool.pixi.feature.backends.target.osx-arm64.dependencies]
166
- jax = ">=0.6.0"
199
+ jax = ">=0.7.2"
167
200
 
168
201
  [tool.pixi.feature.backends.target.win-64.dependencies]
169
202
  # jax = "*" # unavailable
@@ -177,60 +210,30 @@ jax = ">=0.6.0"
177
210
  [tool.pixi.feature.cuda-backends]
178
211
  system-requirements = { cuda = "12" }
179
212
 
180
- [tool.pixi.feature.cuda-backends.target.linux-64.dependencies]
213
+ [tool.pixi.feature.cuda-backends.target.linux.dependencies]
181
214
  cupy = ">=13.6.0"
182
- # JAX 0.6.2 and 0.7.0 segfault on CUDA
183
- jaxlib = { version = ">=0.6.0,!=0.6.2,!=0.7.0", build = "cuda12*" }
184
- pytorch = { version = ">=2.7.1", build = "cuda12*" }
185
-
186
- [tool.pixi.feature.cuda-backends.target.osx-64.dependencies]
187
- # cupy = "*" # unavailable
188
- # jaxlib = { version = "*", build = "cuda12*" } # unavailable
189
- # pytorch = { version = "*", build = "cuda12*" } # unavailable
215
+ jaxlib = { version = ">=0.7.2", build = "cuda12*" }
216
+ pytorch = { version = ">=2.10.0", build = "cuda12*" }
190
217
 
191
- [tool.pixi.feature.cuda-backends.target.osx-arm64.dependencies]
218
+ [tool.pixi.feature.cuda-backends.target.osx.dependencies]
192
219
  # cupy = "*" # unavailable
193
220
  # jaxlib = { version = "*", build = "cuda12*" } # unavailable
194
221
  # pytorch = { version = "*", build = "cuda12*" } # unavailable
195
222
 
196
- [tool.pixi.feature.cuda-backends.target.win-64.dependencies]
223
+ [tool.pixi.feature.cuda-backends.target.win.dependencies]
197
224
  cupy = ">=13.6.0"
198
225
  # jaxlib = { version = "*", build = "cuda12*" } # unavailable
199
- pytorch = { version = ">=2.8.0", build = "cuda12*" }
226
+ pytorch = { version = ">=2.10.0", build = "cuda12*" }
200
227
 
201
228
  [tool.pixi.feature.nogil.dependencies]
202
229
  python-freethreading = "~=3.13.0"
203
- pytest-run-parallel = ">=0.8.0"
230
+ pytest-run-parallel = ">=0.8.2"
204
231
  numpy = ">=2.3.5"
205
232
  # pytorch = "*" # Not available on Python 3.13t yet
206
- dask-core = ">=2025.12.0" # No distributed, tornado, etc.
233
+ dask-core = ">=2026.1.2" # No distributed, tornado, etc.
207
234
  # sparse = "*" # numba not available on Python 3.13t yet
208
235
  # jax = "*" # ml_dtypes not available on Python 3.13t yet
209
236
 
210
- [tool.pixi.environments]
211
- default = { features = ["py313"], solve-group = "py313" }
212
- lint = { features = ["py313", "lint"], solve-group = "py313" }
213
- docs = { features = ["py313", "docs"], solve-group = "py313" }
214
- tests = { features = ["py313", "tests"], solve-group = "py313" }
215
- tests-py313 = { features = ["py313", "tests"], solve-group = "py313" } # alias of tests
216
-
217
- # Some backends may pin numpy; use separate solve-group
218
- dev = { features = ["py313", "lint", "tests", "docs", "dev", "backends"], solve-group = "backends" }
219
- tests-backends = { features = ["py313", "tests", "backends"], solve-group = "backends" }
220
- # Note: Python 3.10 has already been dropped by some backends (like JAX),
221
- # so this is testing older versions.
222
- tests-backends-py310 = { features = ["py310", "tests", "backends"] }
223
-
224
- # CUDA not available on free github actions and on some developers' PCs
225
- dev-cuda = { features = ["py313", "lint", "tests", "docs", "dev", "backends", "cuda-backends"], solve-group = "cuda" }
226
- tests-cuda = { features = ["py313", "tests", "backends", "cuda-backends"], solve-group = "cuda" }
227
- tests-cuda-py310 = { features = ["py310", "tests", "backends", "cuda-backends"] }
228
-
229
- # Ungrouped environments
230
- tests-numpy1 = ["py310", "tests", "numpy1"]
231
- tests-py310 = ["py310", "tests"]
232
- tests-nogil = ["nogil", "tests"]
233
-
234
237
  # pytest
235
238
 
236
239
  [tool.pytest.ini_options]
@@ -254,7 +257,7 @@ run.source = ["array_api_extra"]
254
257
 
255
258
  [tool.mypy]
256
259
  files = ["src", "tests"]
257
- python_version = "3.10"
260
+ python_version = "3.11"
258
261
  warn_unused_configs = true
259
262
  strict = true
260
263
  enable_error_code = ["ignore-without-code", "truthy-bool"]
@@ -273,7 +276,7 @@ disable_error_code = ["no-untyped-def"] # test(...) without -> None
273
276
 
274
277
  [tool.basedpyright]
275
278
  include = ["src", "tests"]
276
- pythonVersion = "3.10"
279
+ pythonVersion = "3.11"
277
280
  pythonPlatform = "All"
278
281
  typeCheckingMode = "all"
279
282
 
@@ -304,7 +307,7 @@ executionEnvironments = [
304
307
  # Ruff
305
308
 
306
309
  [tool.ruff]
307
- target-version = "py310"
310
+ target-version = "py311"
308
311
 
309
312
  [tool.ruff.lint]
310
313
  extend-select = [
@@ -349,7 +352,7 @@ ignore = [
349
352
  # Pylint
350
353
 
351
354
  [tool.pylint]
352
- py-version = "3.10"
355
+ py-version = "3.11"
353
356
  reports.output-format = "colorized"
354
357
  messages_control.disable = [
355
358
  "design", # ignore heavily opinionated design checks
@@ -12,6 +12,7 @@ from ._delegation import (
12
12
  one_hot,
13
13
  pad,
14
14
  partition,
15
+ searchsorted,
15
16
  setdiff1d,
16
17
  sinc,
17
18
  union1d,
@@ -26,7 +27,7 @@ from ._lib._funcs import (
26
27
  )
27
28
  from ._lib._lazy import lazy_apply
28
29
 
29
- __version__ = "0.9.2"
30
+ __version__ = "0.10.0"
30
31
 
31
32
  # pylint: disable=duplicate-code
32
33
  __all__ = [
@@ -49,6 +50,7 @@ __all__ = [
49
50
  "one_hot",
50
51
  "pad",
51
52
  "partition",
53
+ "searchsorted",
52
54
  "setdiff1d",
53
55
  "sinc",
54
56
  "union1d",
@@ -27,6 +27,7 @@ __all__ = [
27
27
  "nan_to_num",
28
28
  "one_hot",
29
29
  "pad",
30
+ "searchsorted",
30
31
  "sinc",
31
32
  ]
32
33
 
@@ -632,6 +633,85 @@ def pad(
632
633
  return _funcs.pad(x, pad_width, constant_values=constant_values, xp=xp)
633
634
 
634
635
 
636
+ def searchsorted(
637
+ x1: Array,
638
+ x2: Array,
639
+ /,
640
+ *,
641
+ side: Literal["left", "right"] = "left",
642
+ xp: ModuleType | None = None,
643
+ ) -> Array:
644
+ """
645
+ Find indices where elements should be inserted to maintain order.
646
+
647
+ Find the indices into a sorted array ``x1`` such that if the elements in ``x2``
648
+ were inserted before the indices, the resulting array would remain sorted.
649
+
650
+ The behavior of this function is similar to that of `array_api.searchsorted`,
651
+ but it relaxes the requirement that `x1` must be one-dimensional.
652
+ This function is vectorized, treating slices along the last axis
653
+ as elements and preceding axes as batch (or "loop") dimensions.
654
+
655
+ Parameters
656
+ ----------
657
+ x1 : Array
658
+ Input array. Should have a real-valued data type. Must be sorted in ascending
659
+ order along the last axis.
660
+ x2 : Array
661
+ Array containing search values. Should have a real-valued data type. Must have
662
+ the same shape as ``x1`` except along the last axis.
663
+ side : {'left', 'right'}, optional
664
+ Argument controlling which index is returned if an element of ``x2`` is equal to
665
+ one or more elements of ``x1``: ``'left'`` returns the index of the first of
666
+ these elements; ``'right'`` returns the next index after the last of these
667
+ elements. Default: ``'left'``.
668
+ xp : array_namespace, optional
669
+ The standard-compatible namespace for the array arguments. Default: infer.
670
+
671
+ Returns
672
+ -------
673
+ Array: integer array
674
+ An array of indices with the same shape as ``x2``.
675
+
676
+ Examples
677
+ --------
678
+ >>> import array_api_strict as xp
679
+ >>> import array_api_extra as xpx
680
+ >>> x = xp.asarray([11, 12, 13, 13, 14, 15])
681
+ >>> xpx.searchsorted(x, xp.asarray([10, 11.5, 14.5, 16]), xp=xp)
682
+ Array([0, 1, 5, 6], dtype=array_api_strict.int64)
683
+ >>> xpx.searchsorted(x, xp.asarray(13), xp=xp)
684
+ Array(2, dtype=array_api_strict.int64)
685
+ >>> xpx.searchsorted(x, xp.asarray(13), side='right', xp=xp)
686
+ Array(4, dtype=array_api_strict.int64)
687
+
688
+ `searchsorted` is vectorized along the last axis.
689
+
690
+ >>> x1 = xp.asarray([[1., 2., 3., 4.], [5., 6., 7., 8.]])
691
+ >>> x2 = xp.asarray([[1.1, 3.3], [6.6, 8.8]])
692
+ >>> xpx.searchsorted(x1, x2, xp=xp)
693
+ Array([[1, 3],
694
+ [2, 4]], dtype=array_api_strict.int64)
695
+ """
696
+ if xp is None:
697
+ xp = array_namespace(x1, x2)
698
+
699
+ if side not in {"left", "right"}:
700
+ message = "`side` must be either 'left' or 'right'."
701
+ raise ValueError(message)
702
+
703
+ xp_default_int = _funcs.default_dtype(xp, kind="integral")
704
+ x2_0d = x2.ndim == 0
705
+ x1_1d = x1.ndim <= 1
706
+
707
+ if x1_1d or is_torch_namespace(xp):
708
+ x2 = xp.reshape(x2, ()) if (x2_0d and x1_1d) else x2
709
+ out = xp.searchsorted(x1, x2, side=side)
710
+ return xp.astype(out, xp_default_int, copy=False)
711
+
712
+ return _funcs.searchsorted(x1, x2, side=side, xp=xp)
713
+
714
+
635
715
  def setdiff1d(
636
716
  x1: Array | complex,
637
717
  x2: Array | complex,
@@ -1048,6 +1128,15 @@ def union1d(a: Array, b: Array, /, *, xp: ModuleType | None = None) -> Array:
1048
1128
  -------
1049
1129
  Array
1050
1130
  Unique, sorted union of the input arrays.
1131
+
1132
+ See Also
1133
+ --------
1134
+ jax.numpy.union1d : Corresponding function in JAX.
1135
+
1136
+ Notes
1137
+ -----
1138
+ This function is not compatible with `jax.jit`.
1139
+ See the docstring of the corresponding JAX function for more information.
1051
1140
  """
1052
1141
  if xp is None:
1053
1142
  xp = array_namespace(a, b)
@@ -21,7 +21,7 @@ from ._utils._typing import Array, SetIndex
21
21
 
22
22
  if TYPE_CHECKING: # pragma: no cover
23
23
  # TODO import from typing (requires Python >=3.11)
24
- from typing_extensions import Self
24
+ from typing import Self
25
25
 
26
26
 
27
27
  class _AtOp(Enum):
@@ -10,7 +10,7 @@ import pytest
10
10
 
11
11
  __all__ = ["NUMPY_VERSION", "Backend"]
12
12
 
13
- NUMPY_VERSION = tuple(int(v) for v in np.__version__.split(".")[:3]) # pyright: ignore[reportUnknownArgumentType]
13
+ NUMPY_VERSION = tuple(int(v) for v in np.__version__.split(".")[:3])
14
14
 
15
15
 
16
16
  class Backend(Enum): # numpydoc ignore=PR02