array-api-strict 2.4.1__tar.gz → 2.6__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 (79) hide show
  1. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/dependabot.yml +2 -0
  2. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/array-api-tests.yml +11 -7
  3. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/dependabot-auto-merge.yml +1 -1
  4. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/docs-build.yml +3 -3
  5. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/docs-deploy.yml +2 -2
  6. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/publish-package.yml +7 -7
  7. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/ruff.yml +2 -2
  8. {array_api_strict-2.4.1 → array_api_strict-2.6}/.github/workflows/tests.yml +12 -7
  9. {array_api_strict-2.4.1 → array_api_strict-2.6}/CHANGELOG.md +102 -1
  10. {array_api_strict-2.4.1/array_api_strict.egg-info → array_api_strict-2.6}/PKG-INFO +4 -1
  11. {array_api_strict-2.4.1 → array_api_strict-2.6}/array-api-tests-xfails.txt +23 -0
  12. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/__init__.py +4 -2
  13. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_array_object.py +49 -40
  14. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_creation_functions.py +106 -39
  15. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_data_type_functions.py +16 -4
  16. array_api_strict-2.6/array_api_strict/_devices.py +136 -0
  17. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_dtypes.py +3 -1
  18. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_elementwise_functions.py +6 -4
  19. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_fft.py +21 -1
  20. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_flags.py +3 -2
  21. array_api_strict-2.6/array_api_strict/_info.py +75 -0
  22. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_linalg.py +62 -1
  23. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_manipulation_functions.py +1 -1
  24. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_searching_functions.py +8 -2
  25. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_set_functions.py +23 -1
  26. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_statistical_functions.py +8 -2
  27. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_version.py +16 -3
  28. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_array_object.py +69 -10
  29. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_creation_functions.py +161 -2
  30. array_api_strict-2.6/array_api_strict/tests/test_device_support.py +80 -0
  31. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_elementwise_functions.py +22 -5
  32. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_flags.py +11 -11
  33. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_searching_functions.py +1 -1
  34. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_statistical_functions.py +16 -0
  35. {array_api_strict-2.4.1 → array_api_strict-2.6/array_api_strict.egg-info}/PKG-INFO +4 -1
  36. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict.egg-info/SOURCES.txt +1 -0
  37. array_api_strict-2.6/array_api_strict.egg-info/requires.txt +5 -0
  38. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/changelog.md +102 -1
  39. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/index.md +12 -11
  40. {array_api_strict-2.4.1 → array_api_strict-2.6}/pyproject.toml +4 -1
  41. array_api_strict-2.4.1/array_api_strict/_info.py +0 -134
  42. array_api_strict-2.4.1/array_api_strict/tests/test_device_support.py +0 -38
  43. array_api_strict-2.4.1/array_api_strict.egg-info/requires.txt +0 -1
  44. {array_api_strict-2.4.1 → array_api_strict-2.6}/.gitattributes +0 -0
  45. {array_api_strict-2.4.1 → array_api_strict-2.6}/.gitignore +0 -0
  46. {array_api_strict-2.4.1 → array_api_strict-2.6}/LICENSE +0 -0
  47. {array_api_strict-2.4.1 → array_api_strict-2.6}/README.md +0 -0
  48. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_constants.py +0 -0
  49. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_helpers.py +0 -0
  50. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_indexing_functions.py +0 -0
  51. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_linear_algebra_functions.py +0 -0
  52. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_sorting_functions.py +0 -0
  53. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_typing.py +0 -0
  54. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/_utility_functions.py +0 -0
  55. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/py.typed +0 -0
  56. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/__init__.py +0 -0
  57. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/conftest.py +0 -0
  58. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_data_type_functions.py +0 -0
  59. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_indexing_functions.py +0 -0
  60. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_linalg.py +0 -0
  61. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_manipulation_functions.py +0 -0
  62. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_set_functions.py +0 -0
  63. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_sorting_functions.py +0 -0
  64. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict/tests/test_validation.py +0 -0
  65. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict.egg-info/dependency_links.txt +0 -0
  66. {array_api_strict-2.4.1 → array_api_strict-2.6}/array_api_strict.egg-info/top_level.txt +0 -0
  67. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/Makefile +0 -0
  68. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/_static/custom.css +0 -0
  69. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/_static/favicon.png +0 -0
  70. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/api.rst +0 -0
  71. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/conf.py +0 -0
  72. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/make.bat +0 -0
  73. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/releasing.md +0 -0
  74. {array_api_strict-2.4.1 → array_api_strict-2.6}/docs/requirements.txt +0 -0
  75. {array_api_strict-2.4.1 → array_api_strict-2.6}/pytest.ini +0 -0
  76. {array_api_strict-2.4.1 → array_api_strict-2.6}/requirements-dev.txt +0 -0
  77. {array_api_strict-2.4.1 → array_api_strict-2.6}/requirements.txt +0 -0
  78. {array_api_strict-2.4.1 → array_api_strict-2.6}/ruff.toml +0 -0
  79. {array_api_strict-2.4.1 → array_api_strict-2.6}/setup.cfg +0 -0
@@ -5,6 +5,8 @@ updates:
5
5
  directory: "/"
6
6
  schedule:
7
7
  interval: "weekly"
8
+ cooldown:
9
+ default-days: 7 # optional
8
10
  groups:
9
11
  actions:
10
12
  patterns:
@@ -4,36 +4,38 @@ on: [push, pull_request]
4
4
 
5
5
  env:
6
6
  PYTEST_ARGS: "-v -rxXfE --hypothesis-disable-deadline --max-examples 500 -n 4"
7
- API_VERSIONS: "2023.12 2024.12"
7
+ API_VERSIONS: "2023.12 2024.12 2025.12"
8
8
 
9
9
  jobs:
10
10
  array-api-tests:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- python-version: ['3.10', '3.11', '3.12', '3.13']
15
- numpy-version: ['1.26', '2.3', 'dev']
14
+ python-version: ['3.10', '3.13', '3.14']
15
+ numpy-version: ['1.26', 'latest', 'dev']
16
16
  exclude:
17
17
  - python-version: '3.10'
18
- numpy-version: '2.3'
18
+ numpy-version: 'latest'
19
19
  - python-version: '3.10'
20
20
  numpy-version: 'dev'
21
21
  - python-version: '3.13'
22
22
  numpy-version: '1.26'
23
+ - python-version: '3.14'
24
+ numpy-version: '1.26'
23
25
  fail-fast: false
24
26
  steps:
25
27
  - name: Checkout array-api-strict
26
- uses: actions/checkout@v4
28
+ uses: actions/checkout@v7.0.0
27
29
  with:
28
30
  path: array-api-strict
29
31
  - name: Checkout array-api-tests
30
- uses: actions/checkout@v4
32
+ uses: actions/checkout@v7.0.0
31
33
  with:
32
34
  repository: data-apis/array-api-tests
33
35
  submodules: 'true'
34
36
  path: array-api-tests
35
37
  - name: Set up Python ${{ matrix.python-version }}
36
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@v6.3.0
37
39
  with:
38
40
  python-version: ${{ matrix.python-version }}
39
41
  - name: Install Dependencies
@@ -41,6 +43,8 @@ jobs:
41
43
  python -m pip install --upgrade pip
42
44
  if [[ "${{ matrix.numpy-version }}" == "dev" ]]; then
43
45
  python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy;
46
+ elif [[ "${{ matrix.numpy-version }}" == "latest" ]]; then
47
+ python -m pip install numpy
44
48
  else
45
49
  python -m pip install 'numpy=='${{ matrix.numpy-version }};
46
50
  fi
@@ -13,7 +13,7 @@ jobs:
13
13
  steps:
14
14
  - name: Dependabot metadata
15
15
  id: metadata
16
- uses: dependabot/fetch-metadata@v2
16
+ uses: dependabot/fetch-metadata@v3
17
17
  with:
18
18
  github-token: "${{ secrets.GITHUB_TOKEN }}"
19
19
  - name: Enable auto-merge for Dependabot PRs
@@ -6,8 +6,8 @@ jobs:
6
6
  docs-build:
7
7
  runs-on: ubuntu-latest
8
8
  steps:
9
- - uses: actions/checkout@v4
10
- - uses: actions/setup-python@v5
9
+ - uses: actions/checkout@v7.0.0
10
+ - uses: actions/setup-python@v6.3.0
11
11
  - name: Install Dependencies
12
12
  run: |
13
13
  python -m pip install -r docs/requirements.txt
@@ -16,7 +16,7 @@ jobs:
16
16
  cd docs
17
17
  make html
18
18
  - name: Upload Artifact
19
- uses: actions/upload-artifact@v4
19
+ uses: actions/upload-artifact@v7
20
20
  with:
21
21
  name: docs-build
22
22
  path: docs/_build/html
@@ -11,9 +11,9 @@ jobs:
11
11
  environment:
12
12
  name: docs-deploy
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@v7.0.0
15
15
  - name: Download Artifact
16
- uses: dawidd6/action-download-artifact@v11
16
+ uses: dawidd6/action-download-artifact@v21
17
17
  with:
18
18
  workflow: docs-build.yml
19
19
  name: docs-build
@@ -30,12 +30,12 @@ jobs:
30
30
  runs-on: ubuntu-latest
31
31
 
32
32
  steps:
33
- - uses: actions/checkout@v4
33
+ - uses: actions/checkout@v7.0.0
34
34
  with:
35
35
  fetch-depth: 0
36
36
 
37
37
  - name: Set up Python
38
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@v6.3.0
39
39
  with:
40
40
  python-version: '3.x'
41
41
 
@@ -62,7 +62,7 @@ jobs:
62
62
  run: python -m zipfile --list dist/array_api_strict-*.whl
63
63
 
64
64
  - name: Upload distribution artifact
65
- uses: actions/upload-artifact@v4
65
+ uses: actions/upload-artifact@v7
66
66
  with:
67
67
  name: dist-artifact
68
68
  path: dist
@@ -83,7 +83,7 @@ jobs:
83
83
 
84
84
  steps:
85
85
  - name: Download distribution artifact
86
- uses: actions/download-artifact@v4
86
+ uses: actions/download-artifact@v8
87
87
  with:
88
88
  name: dist-artifact
89
89
  path: dist
@@ -97,19 +97,19 @@ jobs:
97
97
  # if: >-
98
98
  # (github.event_name == 'push' && startsWith(github.ref, 'refs/tags'))
99
99
  # || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true')
100
- # uses: pypa/gh-action-pypi-publish@v1.12.4
100
+ # uses: pypa/gh-action-pypi-publish@v1.14.0
101
101
  # with:
102
102
  # repository-url: https://test.pypi.org/legacy/
103
103
  # print-hash: true
104
104
 
105
105
  - name: Publish distribution 📦 to PyPI
106
106
  if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
107
- uses: pypa/gh-action-pypi-publish@v1.12.4
107
+ uses: pypa/gh-action-pypi-publish@v1.14.0
108
108
  with:
109
109
  print-hash: true
110
110
 
111
111
  - name: Create GitHub Release from a Tag
112
- uses: softprops/action-gh-release@v2
112
+ uses: softprops/action-gh-release@v3
113
113
  if: startsWith(github.ref, 'refs/tags/')
114
114
  with:
115
115
  files: dist/*
@@ -5,9 +5,9 @@ jobs:
5
5
  runs-on: ubuntu-latest
6
6
  continue-on-error: true
7
7
  steps:
8
- - uses: actions/checkout@v4
8
+ - uses: actions/checkout@v7.0.0
9
9
  - name: Install Python
10
- uses: actions/setup-python@v5
10
+ uses: actions/setup-python@v6.3.0
11
11
  with:
12
12
  python-version: "3.11"
13
13
  - name: Install dependencies
@@ -5,19 +5,21 @@ jobs:
5
5
  runs-on: ubuntu-latest
6
6
  strategy:
7
7
  matrix:
8
- python-version: ['3.10', '3.11', '3.12', '3.13']
9
- numpy-version: ['1.26', '2.3', 'dev']
8
+ python-version: ['3.10', '3.13', '3.14']
9
+ numpy-version: ['1.26', 'latest', 'dev']
10
10
  exclude:
11
11
  - python-version: '3.10'
12
- numpy-version: '2.3'
12
+ numpy-version: 'latest'
13
13
  - python-version: '3.10'
14
14
  numpy-version: 'dev'
15
15
  - python-version: '3.13'
16
16
  numpy-version: '1.26'
17
+ - python-version: '3.14'
18
+ numpy-version: '1.26'
17
19
  fail-fast: false
18
20
  steps:
19
- - uses: actions/checkout@v4
20
- - uses: actions/setup-python@v5
21
+ - uses: actions/checkout@v7.0.0
22
+ - uses: actions/setup-python@v6.3.0
21
23
  with:
22
24
  python-version: ${{ matrix.python-version }}
23
25
  - name: Install Dependencies
@@ -25,10 +27,13 @@ jobs:
25
27
  python -m pip install --upgrade pip
26
28
  if [[ "${{ matrix.numpy-version }}" == "dev" ]]; then
27
29
  python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy;
30
+ elif [[ "${{ matrix.numpy-version }}" == "latest" ]]; then
31
+ python -m pip install numpy
28
32
  else
29
- python -m pip install 'numpy>=1.26,<2.0';
33
+ python -m pip install 'numpy=='${{ matrix.numpy-version }}
30
34
  fi
31
- python -m pip install -r requirements-dev.txt
35
+ python -m pip install pytest hypothesis
36
+ python -c'import numpy as np; print(f"{np.__version__ = }")'
32
37
  - name: Run Tests
33
38
  run: |
34
39
  pytest
@@ -1,5 +1,107 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.6 (2026-07-09)
4
+
5
+ - `__setitem__` method of array objects got stricter:
6
+
7
+ - `__setitem__` method now disallows device transfers: if the right-hand side
8
+ argument is an array on a device which differs from the device of the left-hand
9
+ argument, an error is raised. Note that this change follows
10
+ the draft of a future Array API standard revision, see
11
+ [gh-1005](https://github.com/data-apis/array-api/pull/1005) for discussion.
12
+ - `None` is no longer allowed as an indexing key.
13
+
14
+ - Array objects expose a DLPack device number, via their `__dlpack_device__` method.
15
+ - `from_dlpack` function now supports `copy=` argument.
16
+
17
+ - `Device` objects are now allowed to only support a subset of data types, and can
18
+ have a device-dependent default data types. Note that this enhancement follows
19
+ the draft of a future Array API standard revision, see
20
+ [gh-1005](https://github.com/data-apis/array-api/pull/1005) for discussion.
21
+ - A new device object, `Device("no_float64")` was added which only supports
22
+ single-precision float and complex data types; this device mimics the behavior
23
+ of a "metal"/MPS device which does not support double precision floats.
24
+ Attempting to create an array with float64 or complex128 data type on this device
25
+ raises an error.
26
+ - The existing `Device("device2")` object has been modified: it supports float64 data
27
+ type but defaults to float32 and complex64:
28
+ `asarray([1.0], device=Device("device2")).dtype` is `float32`.
29
+
30
+
31
+ ### Contributors
32
+
33
+ The following users contributed to this release:
34
+
35
+ Evgeni Burovski,
36
+ Lucas Colley,
37
+ Ralf Gommers,
38
+ Tim Head.
39
+
40
+
41
+ ## 2.5 (2026-02-23)
42
+
43
+ This release targets the 2025.12 revision of the Array API standard, and supports
44
+ Python versions 3.10--3.14.
45
+
46
+ ### Major Changes
47
+
48
+ - The default version of the array API standard is now 2025.12. Previous versions can
49
+ still be enabled via the [flags API](array-api-strict-flags), e.g., by calling
50
+ `set_array_api_strict_flags(api_version='2024.12')` or setting
51
+ `ARRAY_API_STRICT_API_VERSION=2024.12`.
52
+
53
+ Note that this support is still relatively undertested. Please [report any
54
+ issues](https://github.com/data-apis/array-api-strict/issues) you find.
55
+
56
+ - The following functions, new in the 2025.12 revision, are implemented:
57
+
58
+ - `isin`
59
+ - `broadcast_shapes`
60
+ - `linalg.eig`
61
+ - `linalg.eigvals`
62
+
63
+ The following updates to existing APIs have been implemented, per the 2025.12 Array API
64
+ standard revision:
65
+
66
+ - `searchsorted` now accepts a python scalar for its second argument,
67
+ `x2`.
68
+ - `expand_dims` now accepts tuples of axes.
69
+ - `permute_dims` now accepts negative axes, with the usual meaning (`axis=-1` is
70
+ the last axis, `-2` is the second-to-last axis, and so on).
71
+
72
+ The following functions now return tuples instead of lists:
73
+
74
+ - `__array_namespace_info__().devices`
75
+ - `broadcast_arrays`
76
+ - `meshgrid`
77
+
78
+
79
+ - Array objects can now be pickled.
80
+
81
+
82
+ ### Minor Changes
83
+
84
+ - Several functions were diverging from the standard, and have been fixed to follow
85
+ the 2025.12 revision of the standard:
86
+
87
+ - `clip` has been updated to accept python `int` scalars for its `min` and `max`
88
+ arguments for clipping a floating-point array.
89
+ - `clip` has been updated to always returns a copy of an input array.
90
+ - `full` and `full_like` now reject array values for the `fill_value` argument.
91
+ - `expand_dims` accepts its axis argument as either positional or keyword argument.
92
+
93
+ - `sign` of a complex zero, `sign(0 + 0j)` has been fixed to return zero.
94
+
95
+
96
+ ### Contributors
97
+
98
+ The following users contributed to this release:
99
+
100
+ Evgeni Burovski,
101
+ Lucas Colley,
102
+ Lucy Liu
103
+
104
+
3
105
  ## 2.4.1 (2025-07-27)
4
106
 
5
107
  ### Major Changes
@@ -8,7 +110,6 @@
8
110
 
9
111
  - Support for Python versions 3.10 and 3.11 has been reinstated.
10
112
 
11
-
12
113
  ### Minor Changes
13
114
 
14
115
  - Arithmetic operations no longer accept NumPy arrays.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: array_api_strict
3
- Version: 2.4.1
3
+ Version: 2.6
4
4
  Summary: A strict, minimal implementation of the Python array API standard.
5
5
  Author: Consortium for Python Data API Standards
6
6
  License: Copyright (c) 2021-2024, NumPy Developers, Consortium for Python Data API Standards
@@ -48,6 +48,9 @@ Requires-Python: >=3.10
48
48
  Description-Content-Type: text/markdown
49
49
  License-File: LICENSE
50
50
  Requires-Dist: numpy
51
+ Provides-Extra: test
52
+ Requires-Dist: pytest; extra == "test"
53
+ Requires-Dist: hypothesis; extra == "test"
51
54
 
52
55
  # array-api-strict
53
56
 
@@ -29,3 +29,26 @@ array_api_tests/test_statistical_functions.py::test_sum
29
29
 
30
30
  array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
31
31
 
32
+ # complex special cases which failed "forever"
33
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is +infinity and imag(x_i) is +0) -> +infinity + 0j]
34
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is -infinity and imag(x_i) is +infinity) -> -1 + 0j]
35
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is +infinity and imag(x_i) is +infinity) -> infinity + NaN j]
36
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is -infinity and imag(x_i) is NaN) -> -1 + 0j]
37
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is +infinity and imag(x_i) is NaN) -> infinity + NaN j]
38
+ array_api_tests/test_special_cases.py::test_unary[expm1(real(x_i) is NaN and imag(x_i) is +0) -> NaN + 0j]
39
+ array_api_tests/test_special_cases.py::test_unary[expm1((real(x_i) is +0 or real(x_i) == -0) and imag(x_i) is +0) -> 0 + 0j]
40
+
41
+ array_api_tests/test_special_cases.py::test_unary[sign((real(x_i) is -0 or real(x_i) == +0) and (imag(x_i) is -0 or imag(x_i) == +0)) -> 0 + 0j]
42
+ array_api_tests/test_special_cases.py::test_unary[tanh(real(x_i) is +infinity and isfinite(imag(x_i)) and imag(x_i) > 0) -> 1 + 0j]
43
+
44
+ # this acosh failure is only seen with python==3.10 and numpy==2.2.6, and not e.g. python 3.12 & numpy 2.4.1
45
+ array_api_tests/test_special_cases.py::test_unary[acosh(real(x_i) is +0 and imag(x_i) is NaN) -> NaN \xb1 \u03c0j/2]
46
+
47
+ array_api_tests/test_special_cases.py::test_unary[sqrt(real(x_i) is +infinity and isfinite(imag(x_i)) and imag(x_i) > 0) -> +0 + infinity j]
48
+
49
+ # remove this when array-api-strict 2.6 is released: this is only for array-api-tests,
50
+ # which runs self-tests against a released array-api-strict
51
+ array_api_tests/test_dlpack.py::test_from_dlpack
52
+
53
+ # NumPy 1.26 : NotImplementedError: The copy argument to __dlpack__ is not yet implemented
54
+ array_api_tests/test_dlpack.py::test_dunder_dlpack
@@ -73,6 +73,7 @@ __all__ += [
73
73
  from ._data_type_functions import (
74
74
  astype,
75
75
  broadcast_arrays,
76
+ broadcast_shapes,
76
77
  broadcast_to,
77
78
  can_cast,
78
79
  finfo,
@@ -84,6 +85,7 @@ from ._data_type_functions import (
84
85
  __all__ += [
85
86
  "astype",
86
87
  "broadcast_arrays",
88
+ "broadcast_shapes",
87
89
  "broadcast_to",
88
90
  "can_cast",
89
91
  "finfo",
@@ -299,9 +301,9 @@ from ._searching_functions import argmax, argmin, nonzero, count_nonzero, search
299
301
 
300
302
  __all__ += ["argmax", "argmin", "nonzero", "count_nonzero", "searchsorted", "where"]
301
303
 
302
- from ._set_functions import unique_all, unique_counts, unique_inverse, unique_values
304
+ from ._set_functions import unique_all, unique_counts, unique_inverse, unique_values, isin
303
305
 
304
- __all__ += ["unique_all", "unique_counts", "unique_inverse", "unique_values"]
306
+ __all__ += ["unique_all", "unique_counts", "unique_inverse", "unique_values", "isin"]
305
307
 
306
308
  from ._sorting_functions import argsort, sort
307
309
 
@@ -20,7 +20,7 @@ import sys
20
20
  from collections.abc import Iterator
21
21
  from enum import IntEnum
22
22
  from types import EllipsisType, ModuleType
23
- from typing import Any, Final, Literal, SupportsIndex
23
+ from typing import Any, Literal, SupportsIndex, Callable
24
24
 
25
25
  import numpy as np
26
26
  import numpy.typing as npt
@@ -40,35 +40,14 @@ from ._dtypes import (
40
40
  _real_to_complex_map,
41
41
  _result_type,
42
42
  )
43
+ from ._devices import (
44
+ CPU_DEVICE, Device, device_supports_dtype, _normalize_dl_device, _DLPACK_DEVICE_FOR,
45
+ DLDeviceType
46
+ )
43
47
  from ._flags import get_array_api_strict_flags, set_array_api_strict_flags
44
48
  from ._typing import PyCapsule
45
49
 
46
50
 
47
- class Device:
48
- _device: Final[str]
49
- __slots__ = ("_device", "__weakref__")
50
-
51
- def __init__(self, device: str = "CPU_DEVICE"):
52
- if device not in ("CPU_DEVICE", "device1", "device2"):
53
- raise ValueError(f"The device '{device}' is not a valid choice.")
54
- self._device = device
55
-
56
- def __repr__(self) -> str:
57
- return f"array_api_strict.Device('{self._device}')"
58
-
59
- def __eq__(self, other: object) -> bool:
60
- if not isinstance(other, Device):
61
- return False
62
- return self._device == other._device
63
-
64
- def __hash__(self) -> int:
65
- return hash(("Device", self._device))
66
-
67
-
68
- CPU_DEVICE = Device()
69
- ALL_DEVICES = (CPU_DEVICE, Device("device1"), Device("device2"))
70
-
71
-
72
51
  class Array:
73
52
  """
74
53
  n-d array object for the array API namespace.
@@ -113,10 +92,15 @@ class Array:
113
92
  raise TypeError(
114
93
  f"The array_api_strict namespace does not support the dtype '{x.dtype}'"
115
94
  )
116
- obj._array = x
117
- obj._dtype = _dtype
95
+
118
96
  if device is None:
119
97
  device = CPU_DEVICE
98
+ if not device_supports_dtype(device, _dtype):
99
+ raise ValueError(f"Device {device!r} does not support dtype={_dtype!r}.")
100
+
101
+ obj._array = x
102
+ obj._dtype = _dtype
103
+
120
104
  obj._device = device
121
105
  return obj
122
106
 
@@ -125,6 +109,9 @@ class Array:
125
109
  raise TypeError(
126
110
  "The array_api_strict Array object should not be instantiated directly. Use an array creation function, such as asarray(), instead."
127
111
  )
112
+
113
+ def __reduce__(self) -> tuple[Callable, tuple[npt.NDArray[Any], Device]]:
114
+ return (self._new, (self._array, self._device))
128
115
 
129
116
  # These functions are not required by the spec, but are implemented for
130
117
  # the sake of usability.
@@ -397,7 +384,7 @@ class Array:
397
384
  isinstance(i, SupportsIndex) # i.e. ints
398
385
  or isinstance(i, slice)
399
386
  or i == Ellipsis
400
- or i is None
387
+ or (op == "getitem" and i is None) # `None` disallowed in setitem
401
388
  or isinstance(i, Array)
402
389
  or isinstance(i, np.ndarray)
403
390
  ):
@@ -627,22 +614,40 @@ class Array:
627
614
  raise NotImplementedError("The copy argument to __dlpack__ is not yet implemented")
628
615
 
629
616
  return self._array.__dlpack__(stream=stream)
630
- else:
631
- kwargs = {'stream': stream}
632
- if max_version is not _undef:
633
- kwargs['max_version'] = max_version
634
- if dl_device is not _undef:
635
- kwargs['dl_device'] = dl_device
636
- if copy is not _undef:
637
- kwargs['copy'] = copy
638
- return self._array.__dlpack__(**kwargs)
617
+
618
+ kwargs: dict[str, Any] = {'stream': stream}
619
+ self_dl_device = _normalize_dl_device(*_DLPACK_DEVICE_FOR[self._device])
620
+ cpu_dl_device = _normalize_dl_device(DLDeviceType.kDLCPU, 0)
621
+ numpy_dl_device: tuple[IntEnum, int] | None = None
622
+
623
+ if dl_device not in [_undef, None]:
624
+ requested = _normalize_dl_device(dl_device[0], dl_device[1])
625
+ if requested == self_dl_device:
626
+ pass
627
+ elif requested == cpu_dl_device and self_dl_device != cpu_dl_device:
628
+ if copy is False:
629
+ raise BufferError(
630
+ "Cannot export array to CPU without copying when copy=False"
631
+ )
632
+ if copy is _undef:
633
+ copy = True
634
+ numpy_dl_device = (DLDeviceType.kDLCPU, 0)
635
+ else:
636
+ raise BufferError("unsupported device requested")
637
+
638
+ if max_version is not _undef:
639
+ kwargs['max_version'] = max_version
640
+ if numpy_dl_device is not None:
641
+ kwargs['dl_device'] = numpy_dl_device
642
+ if copy is not _undef:
643
+ kwargs['copy'] = copy
644
+ return self._array.__dlpack__(**kwargs)
639
645
 
640
646
  def __dlpack_device__(self) -> tuple[IntEnum, int]:
641
647
  """
642
648
  Performs the operation __dlpack_device__.
643
649
  """
644
- # Note: device support is required for this
645
- return self._array.__dlpack_device__()
650
+ return _DLPACK_DEVICE_FOR[self._device]
646
651
 
647
652
  def __eq__(self, other: Array | complex, /) -> Array: # type: ignore[override]
648
653
  """
@@ -957,6 +962,10 @@ class Array:
957
962
  other = value
958
963
  if isinstance(value, (bool, int, float, complex)):
959
964
  other = self._promote_scalar(value)
965
+ else:
966
+ if value.device != self.device:
967
+ raise ValueError(f"mismatched devices: {self.device = } != {value.device =}.")
968
+
960
969
  dt = _result_type(self.dtype, other.dtype)
961
970
  if dt != self.dtype:
962
971
  raise TypeError(f"mismatched dtypes: {self.dtype = } and {other.dtype = }")