array-api-strict 2.5__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.
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/dependabot.yml +2 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/array-api-tests.yml +8 -6
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/dependabot-auto-merge.yml +1 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/docs-build.yml +3 -3
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/docs-deploy.yml +2 -2
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/publish-package.yml +7 -7
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/ruff.yml +2 -2
- {array_api_strict-2.5 → array_api_strict-2.6}/.github/workflows/tests.yml +7 -5
- {array_api_strict-2.5 → array_api_strict-2.6}/CHANGELOG.md +38 -0
- {array_api_strict-2.5/array_api_strict.egg-info → array_api_strict-2.6}/PKG-INFO +1 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array-api-tests-xfails.txt +7 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_array_object.py +46 -40
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_creation_functions.py +94 -34
- array_api_strict-2.6/array_api_strict/_devices.py +136 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_dtypes.py +3 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_fft.py +21 -1
- array_api_strict-2.6/array_api_strict/_info.py +75 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_statistical_functions.py +8 -2
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_version.py +3 -3
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_array_object.py +44 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_creation_functions.py +159 -2
- array_api_strict-2.6/array_api_strict/tests/test_device_support.py +80 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_elementwise_functions.py +6 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_searching_functions.py +1 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_statistical_functions.py +16 -0
- {array_api_strict-2.5 → array_api_strict-2.6/array_api_strict.egg-info}/PKG-INFO +1 -1
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict.egg-info/SOURCES.txt +1 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/changelog.md +38 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/pyproject.toml +1 -1
- array_api_strict-2.5/array_api_strict/_info.py +0 -137
- array_api_strict-2.5/array_api_strict/tests/test_device_support.py +0 -38
- {array_api_strict-2.5 → array_api_strict-2.6}/.gitattributes +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/.gitignore +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/LICENSE +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/README.md +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/__init__.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_constants.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_data_type_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_elementwise_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_flags.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_helpers.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_indexing_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_linalg.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_linear_algebra_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_manipulation_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_searching_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_set_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_sorting_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_typing.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/_utility_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/py.typed +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/__init__.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/conftest.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_data_type_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_flags.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_indexing_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_linalg.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_manipulation_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_set_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_sorting_functions.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict/tests/test_validation.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict.egg-info/dependency_links.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict.egg-info/requires.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/array_api_strict.egg-info/top_level.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/Makefile +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/_static/custom.css +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/_static/favicon.png +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/api.rst +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/conf.py +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/index.md +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/make.bat +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/releasing.md +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/docs/requirements.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/pytest.ini +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/requirements-dev.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/requirements.txt +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/ruff.toml +0 -0
- {array_api_strict-2.5 → array_api_strict-2.6}/setup.cfg +0 -0
|
@@ -11,11 +11,11 @@ jobs:
|
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
strategy:
|
|
13
13
|
matrix:
|
|
14
|
-
python-version: ['3.10', '3.
|
|
15
|
-
numpy-version: ['1.26', '
|
|
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: '
|
|
18
|
+
numpy-version: 'latest'
|
|
19
19
|
- python-version: '3.10'
|
|
20
20
|
numpy-version: 'dev'
|
|
21
21
|
- python-version: '3.13'
|
|
@@ -25,17 +25,17 @@ jobs:
|
|
|
25
25
|
fail-fast: false
|
|
26
26
|
steps:
|
|
27
27
|
- name: Checkout array-api-strict
|
|
28
|
-
uses: actions/checkout@
|
|
28
|
+
uses: actions/checkout@v7.0.0
|
|
29
29
|
with:
|
|
30
30
|
path: array-api-strict
|
|
31
31
|
- name: Checkout array-api-tests
|
|
32
|
-
uses: actions/checkout@
|
|
32
|
+
uses: actions/checkout@v7.0.0
|
|
33
33
|
with:
|
|
34
34
|
repository: data-apis/array-api-tests
|
|
35
35
|
submodules: 'true'
|
|
36
36
|
path: array-api-tests
|
|
37
37
|
- name: Set up Python ${{ matrix.python-version }}
|
|
38
|
-
uses: actions/setup-python@v6
|
|
38
|
+
uses: actions/setup-python@v6.3.0
|
|
39
39
|
with:
|
|
40
40
|
python-version: ${{ matrix.python-version }}
|
|
41
41
|
- name: Install Dependencies
|
|
@@ -43,6 +43,8 @@ jobs:
|
|
|
43
43
|
python -m pip install --upgrade pip
|
|
44
44
|
if [[ "${{ matrix.numpy-version }}" == "dev" ]]; then
|
|
45
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
|
|
46
48
|
else
|
|
47
49
|
python -m pip install 'numpy=='${{ matrix.numpy-version }};
|
|
48
50
|
fi
|
|
@@ -6,8 +6,8 @@ jobs:
|
|
|
6
6
|
docs-build:
|
|
7
7
|
runs-on: ubuntu-latest
|
|
8
8
|
steps:
|
|
9
|
-
- uses: actions/checkout@
|
|
10
|
-
- uses: actions/setup-python@v6
|
|
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@
|
|
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@
|
|
14
|
+
- uses: actions/checkout@v7.0.0
|
|
15
15
|
- name: Download Artifact
|
|
16
|
-
uses: dawidd6/action-download-artifact@
|
|
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@
|
|
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@v6
|
|
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@
|
|
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@
|
|
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.
|
|
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.
|
|
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@
|
|
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@
|
|
8
|
+
- uses: actions/checkout@v7.0.0
|
|
9
9
|
- name: Install Python
|
|
10
|
-
uses: actions/setup-python@v6
|
|
10
|
+
uses: actions/setup-python@v6.3.0
|
|
11
11
|
with:
|
|
12
12
|
python-version: "3.11"
|
|
13
13
|
- name: Install dependencies
|
|
@@ -5,11 +5,11 @@ jobs:
|
|
|
5
5
|
runs-on: ubuntu-latest
|
|
6
6
|
strategy:
|
|
7
7
|
matrix:
|
|
8
|
-
python-version: ['3.10', '3.
|
|
9
|
-
numpy-version: ['1.26', '
|
|
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: '
|
|
12
|
+
numpy-version: 'latest'
|
|
13
13
|
- python-version: '3.10'
|
|
14
14
|
numpy-version: 'dev'
|
|
15
15
|
- python-version: '3.13'
|
|
@@ -18,8 +18,8 @@ jobs:
|
|
|
18
18
|
numpy-version: '1.26'
|
|
19
19
|
fail-fast: false
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
22
|
-
- uses: actions/setup-python@v6
|
|
21
|
+
- uses: actions/checkout@v7.0.0
|
|
22
|
+
- uses: actions/setup-python@v6.3.0
|
|
23
23
|
with:
|
|
24
24
|
python-version: ${{ matrix.python-version }}
|
|
25
25
|
- name: Install Dependencies
|
|
@@ -27,6 +27,8 @@ jobs:
|
|
|
27
27
|
python -m pip install --upgrade pip
|
|
28
28
|
if [[ "${{ matrix.numpy-version }}" == "dev" ]]; then
|
|
29
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
|
|
30
32
|
else
|
|
31
33
|
python -m pip install 'numpy=='${{ matrix.numpy-version }}
|
|
32
34
|
fi
|
|
@@ -1,5 +1,43 @@
|
|
|
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
|
+
|
|
3
41
|
## 2.5 (2026-02-23)
|
|
4
42
|
|
|
5
43
|
This release targets the 2025.12 revision of the Array API standard, and supports
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: array_api_strict
|
|
3
|
-
Version: 2.
|
|
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
|
|
@@ -45,3 +45,10 @@ array_api_tests/test_special_cases.py::test_unary[tanh(real(x_i) is +infinity an
|
|
|
45
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
46
|
|
|
47
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
|
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
|
@@ -400,7 +384,7 @@ class Array:
|
|
|
400
384
|
isinstance(i, SupportsIndex) # i.e. ints
|
|
401
385
|
or isinstance(i, slice)
|
|
402
386
|
or i == Ellipsis
|
|
403
|
-
or i is None
|
|
387
|
+
or (op == "getitem" and i is None) # `None` disallowed in setitem
|
|
404
388
|
or isinstance(i, Array)
|
|
405
389
|
or isinstance(i, np.ndarray)
|
|
406
390
|
):
|
|
@@ -630,22 +614,40 @@ class Array:
|
|
|
630
614
|
raise NotImplementedError("The copy argument to __dlpack__ is not yet implemented")
|
|
631
615
|
|
|
632
616
|
return self._array.__dlpack__(stream=stream)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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)
|
|
642
645
|
|
|
643
646
|
def __dlpack_device__(self) -> tuple[IntEnum, int]:
|
|
644
647
|
"""
|
|
645
648
|
Performs the operation __dlpack_device__.
|
|
646
649
|
"""
|
|
647
|
-
|
|
648
|
-
return self._array.__dlpack_device__()
|
|
650
|
+
return _DLPACK_DEVICE_FOR[self._device]
|
|
649
651
|
|
|
650
652
|
def __eq__(self, other: Array | complex, /) -> Array: # type: ignore[override]
|
|
651
653
|
"""
|
|
@@ -960,6 +962,10 @@ class Array:
|
|
|
960
962
|
other = value
|
|
961
963
|
if isinstance(value, (bool, int, float, complex)):
|
|
962
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
|
+
|
|
963
969
|
dt = _result_type(self.dtype, other.dtype)
|
|
964
970
|
if dt != self.dtype:
|
|
965
971
|
raise TypeError(f"mismatched dtypes: {self.dtype = } and {other.dtype = }")
|
|
@@ -5,7 +5,11 @@ from typing import TYPE_CHECKING, Literal
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
|
-
from ._dtypes import DType, _all_dtypes, _np_dtype
|
|
8
|
+
from ._dtypes import DType, _all_dtypes, _np_dtype, bool as xp_bool
|
|
9
|
+
from ._devices import (
|
|
10
|
+
Device, device_supports_dtype, get_default_dtypes,
|
|
11
|
+
check_device as _check_device
|
|
12
|
+
)
|
|
9
13
|
from ._flags import get_array_api_strict_flags
|
|
10
14
|
from ._typing import NestedSequence, SupportsBufferProtocol, SupportsDLPack
|
|
11
15
|
|
|
@@ -14,7 +18,7 @@ if TYPE_CHECKING:
|
|
|
14
18
|
from typing_extensions import TypeIs
|
|
15
19
|
|
|
16
20
|
# Circular import
|
|
17
|
-
from ._array_object import Array
|
|
21
|
+
from ._array_object import Array
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
class Undef(Enum):
|
|
@@ -24,10 +28,15 @@ class Undef(Enum):
|
|
|
24
28
|
_undef = Undef.UNDEF
|
|
25
29
|
|
|
26
30
|
|
|
27
|
-
def _check_valid_dtype(dtype: DType | None) -> None:
|
|
31
|
+
def _check_valid_dtype(dtype: DType | None, device: Device | None = None) -> None:
|
|
28
32
|
# Note: Only spelling dtypes as the dtype objects is supported.
|
|
29
|
-
if dtype not
|
|
30
|
-
|
|
33
|
+
if dtype is not None:
|
|
34
|
+
if dtype not in _all_dtypes:
|
|
35
|
+
raise ValueError(f"dtype must be one of the supported dtypes, got {dtype!r}")
|
|
36
|
+
|
|
37
|
+
if device is not None:
|
|
38
|
+
if not device_supports_dtype(device, dtype):
|
|
39
|
+
raise ValueError(f"Device {device!r} does not support dtype={dtype!r}.")
|
|
31
40
|
|
|
32
41
|
|
|
33
42
|
def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
|
|
@@ -38,18 +47,6 @@ def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
|
|
|
38
47
|
return True
|
|
39
48
|
|
|
40
49
|
|
|
41
|
-
def _check_device(device: Device | None) -> None:
|
|
42
|
-
# _array_object imports in this file are inside the functions to avoid
|
|
43
|
-
# circular imports
|
|
44
|
-
from ._array_object import ALL_DEVICES, Device
|
|
45
|
-
|
|
46
|
-
if device is not None and not isinstance(device, Device):
|
|
47
|
-
raise ValueError(f"Unsupported device {device!r}")
|
|
48
|
-
|
|
49
|
-
if device is not None and device not in ALL_DEVICES:
|
|
50
|
-
raise ValueError(f"Unsupported device {device!r}")
|
|
51
|
-
|
|
52
|
-
|
|
53
50
|
def asarray(
|
|
54
51
|
obj: Array | complex | NestedSequence[complex] | SupportsBufferProtocol,
|
|
55
52
|
/,
|
|
@@ -65,11 +62,12 @@ def asarray(
|
|
|
65
62
|
"""
|
|
66
63
|
from ._array_object import Array
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
_check_device(device)
|
|
66
|
+
_check_valid_dtype(dtype, device)
|
|
69
67
|
_np_dtype = None
|
|
70
68
|
if dtype is not None:
|
|
71
69
|
_np_dtype = dtype._np_dtype
|
|
72
|
-
|
|
70
|
+
|
|
73
71
|
if isinstance(obj, Array) and device is None:
|
|
74
72
|
device = obj.device
|
|
75
73
|
|
|
@@ -108,6 +106,27 @@ def asarray(
|
|
|
108
106
|
raise OverflowError("Integer out of bounds for array dtypes")
|
|
109
107
|
|
|
110
108
|
res = np.array(obj, dtype=_np_dtype, copy=copy)
|
|
109
|
+
|
|
110
|
+
# numpy default dtype may differ; if so, adjust the dtype
|
|
111
|
+
if dtype is None and device is not None:
|
|
112
|
+
res_dtype = DType(res.dtype)
|
|
113
|
+
# The dtype selected by Numpy might not be the default dtype
|
|
114
|
+
# on this device. We thus find the default dtype for the dtype "kind", and
|
|
115
|
+
# cast to the device-appropriate default.
|
|
116
|
+
from ._data_type_functions import isdtype
|
|
117
|
+
if isdtype(res_dtype, "bool"):
|
|
118
|
+
target_dtype = DType("bool")
|
|
119
|
+
elif isdtype(res_dtype, "integral"):
|
|
120
|
+
target_dtype = get_default_dtypes(device)["integral"]
|
|
121
|
+
elif isdtype(res_dtype, "real floating"):
|
|
122
|
+
target_dtype = get_default_dtypes(device)["real floating"]
|
|
123
|
+
elif isdtype(res_dtype, "complex floating"):
|
|
124
|
+
target_dtype = get_default_dtypes(device)["complex floating"]
|
|
125
|
+
else:
|
|
126
|
+
raise ValueError(f"{res_dtype = } not understood.")
|
|
127
|
+
|
|
128
|
+
res = res.astype(target_dtype._np_dtype)
|
|
129
|
+
|
|
111
130
|
return Array._new(res, device=device)
|
|
112
131
|
|
|
113
132
|
|
|
@@ -127,8 +146,13 @@ def arange(
|
|
|
127
146
|
"""
|
|
128
147
|
from ._array_object import Array
|
|
129
148
|
|
|
130
|
-
_check_valid_dtype(dtype)
|
|
131
149
|
_check_device(device)
|
|
150
|
+
_check_valid_dtype(dtype, device)
|
|
151
|
+
if dtype is None:
|
|
152
|
+
if any(isinstance(x, float) for x in (start, stop, step)):
|
|
153
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
154
|
+
else:
|
|
155
|
+
dtype = get_default_dtypes(device)["integral"]
|
|
132
156
|
|
|
133
157
|
return Array._new(
|
|
134
158
|
np.arange(start, stop, step, dtype=_np_dtype(dtype)),
|
|
@@ -149,8 +173,10 @@ def empty(
|
|
|
149
173
|
"""
|
|
150
174
|
from ._array_object import Array
|
|
151
175
|
|
|
152
|
-
_check_valid_dtype(dtype)
|
|
153
176
|
_check_device(device)
|
|
177
|
+
_check_valid_dtype(dtype, device)
|
|
178
|
+
if dtype is None:
|
|
179
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
154
180
|
|
|
155
181
|
return Array._new(np.empty(shape, dtype=_np_dtype(dtype)), device=device)
|
|
156
182
|
|
|
@@ -165,10 +191,12 @@ def empty_like(
|
|
|
165
191
|
"""
|
|
166
192
|
from ._array_object import Array
|
|
167
193
|
|
|
168
|
-
_check_valid_dtype(dtype)
|
|
169
194
|
_check_device(device)
|
|
170
195
|
if device is None:
|
|
171
196
|
device = x.device
|
|
197
|
+
if dtype is None:
|
|
198
|
+
dtype = x.dtype
|
|
199
|
+
_check_valid_dtype(dtype, device)
|
|
172
200
|
|
|
173
201
|
return Array._new(np.empty_like(x._array, dtype=_np_dtype(dtype)), device=device)
|
|
174
202
|
|
|
@@ -189,8 +217,10 @@ def eye(
|
|
|
189
217
|
"""
|
|
190
218
|
from ._array_object import Array
|
|
191
219
|
|
|
192
|
-
_check_valid_dtype(dtype)
|
|
193
220
|
_check_device(device)
|
|
221
|
+
_check_valid_dtype(dtype, device)
|
|
222
|
+
if dtype is None:
|
|
223
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
194
224
|
|
|
195
225
|
return Array._new(
|
|
196
226
|
np.eye(n_rows, M=n_cols, k=k, dtype=_np_dtype(dtype)), device=device
|
|
@@ -212,15 +242,20 @@ def from_dlpack(
|
|
|
212
242
|
if copy is not _undef:
|
|
213
243
|
raise ValueError("The copy argument to from_dlpack requires at least version 2023.12 of the array API")
|
|
214
244
|
|
|
215
|
-
# Going to wait for upstream numpy support
|
|
216
245
|
if device is not _undef:
|
|
217
246
|
_check_device(device)
|
|
218
247
|
else:
|
|
219
248
|
device = None
|
|
220
|
-
|
|
221
|
-
|
|
249
|
+
if hasattr(x, "__dlpack_device__"):
|
|
250
|
+
from ._devices import _device_from_dlpack_device
|
|
222
251
|
|
|
223
|
-
|
|
252
|
+
dl_type, dl_id = x.__dlpack_device__()
|
|
253
|
+
device = _device_from_dlpack_device(dl_type, dl_id)
|
|
254
|
+
if copy in [_undef, None]:
|
|
255
|
+
# numpy 1.26 does not have the copy= arg
|
|
256
|
+
return Array._new(np.from_dlpack(x), device=device)
|
|
257
|
+
|
|
258
|
+
return Array._new(np.from_dlpack(x, copy=copy), device=device)
|
|
224
259
|
|
|
225
260
|
|
|
226
261
|
def full(
|
|
@@ -237,12 +272,22 @@ def full(
|
|
|
237
272
|
"""
|
|
238
273
|
from ._array_object import Array
|
|
239
274
|
|
|
240
|
-
_check_valid_dtype(dtype)
|
|
241
275
|
_check_device(device)
|
|
276
|
+
_check_valid_dtype(dtype, device)
|
|
242
277
|
|
|
243
278
|
if not isinstance(fill_value, bool | int | float | complex):
|
|
244
279
|
msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
|
|
245
280
|
raise TypeError(msg)
|
|
281
|
+
|
|
282
|
+
if dtype is None:
|
|
283
|
+
if type(fill_value) == bool:
|
|
284
|
+
dtype = xp_bool
|
|
285
|
+
else:
|
|
286
|
+
kind = {
|
|
287
|
+
int: "integral", float: "real floating", complex: "complex floating"
|
|
288
|
+
}[type(fill_value)]
|
|
289
|
+
dtype = get_default_dtypes(device)[kind]
|
|
290
|
+
|
|
246
291
|
res = np.full(shape, fill_value, dtype=_np_dtype(dtype))
|
|
247
292
|
if DType(res.dtype) not in _all_dtypes:
|
|
248
293
|
# This will happen if the fill value is not something that NumPy
|
|
@@ -266,10 +311,12 @@ def full_like(
|
|
|
266
311
|
"""
|
|
267
312
|
from ._array_object import Array
|
|
268
313
|
|
|
269
|
-
_check_valid_dtype(dtype)
|
|
270
314
|
_check_device(device)
|
|
271
315
|
if device is None:
|
|
272
316
|
device = x.device
|
|
317
|
+
if dtype is None:
|
|
318
|
+
dtype = x.dtype
|
|
319
|
+
_check_valid_dtype(dtype, device)
|
|
273
320
|
|
|
274
321
|
if not isinstance(fill_value, bool | int | float | complex):
|
|
275
322
|
msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
|
|
@@ -300,8 +347,13 @@ def linspace(
|
|
|
300
347
|
"""
|
|
301
348
|
from ._array_object import Array
|
|
302
349
|
|
|
303
|
-
_check_valid_dtype(dtype)
|
|
304
350
|
_check_device(device)
|
|
351
|
+
_check_valid_dtype(dtype, device)
|
|
352
|
+
if dtype is None:
|
|
353
|
+
if isinstance(start, complex) or isinstance(stop, complex):
|
|
354
|
+
dtype = get_default_dtypes(device)["complex floating"]
|
|
355
|
+
else:
|
|
356
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
305
357
|
|
|
306
358
|
return Array._new(
|
|
307
359
|
np.linspace(start, stop, num, dtype=_np_dtype(dtype), endpoint=endpoint),
|
|
@@ -353,8 +405,10 @@ def ones(
|
|
|
353
405
|
"""
|
|
354
406
|
from ._array_object import Array
|
|
355
407
|
|
|
356
|
-
_check_valid_dtype(dtype)
|
|
357
408
|
_check_device(device)
|
|
409
|
+
_check_valid_dtype(dtype, device)
|
|
410
|
+
if dtype is None:
|
|
411
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
358
412
|
|
|
359
413
|
return Array._new(np.ones(shape, dtype=_np_dtype(dtype)), device=device)
|
|
360
414
|
|
|
@@ -369,10 +423,12 @@ def ones_like(
|
|
|
369
423
|
"""
|
|
370
424
|
from ._array_object import Array
|
|
371
425
|
|
|
372
|
-
_check_valid_dtype(dtype)
|
|
373
426
|
_check_device(device)
|
|
374
427
|
if device is None:
|
|
375
428
|
device = x.device
|
|
429
|
+
if dtype is None:
|
|
430
|
+
dtype = x.dtype
|
|
431
|
+
_check_valid_dtype(dtype, device)
|
|
376
432
|
|
|
377
433
|
return Array._new(np.ones_like(x._array, dtype=_np_dtype(dtype)), device=device)
|
|
378
434
|
|
|
@@ -418,8 +474,10 @@ def zeros(
|
|
|
418
474
|
"""
|
|
419
475
|
from ._array_object import Array
|
|
420
476
|
|
|
421
|
-
_check_valid_dtype(dtype)
|
|
422
477
|
_check_device(device)
|
|
478
|
+
_check_valid_dtype(dtype, device)
|
|
479
|
+
if dtype is None:
|
|
480
|
+
dtype = get_default_dtypes(device)["real floating"]
|
|
423
481
|
|
|
424
482
|
return Array._new(np.zeros(shape, dtype=_np_dtype(dtype)), device=device)
|
|
425
483
|
|
|
@@ -434,9 +492,11 @@ def zeros_like(
|
|
|
434
492
|
"""
|
|
435
493
|
from ._array_object import Array
|
|
436
494
|
|
|
437
|
-
_check_valid_dtype(dtype)
|
|
438
495
|
_check_device(device)
|
|
439
496
|
if device is None:
|
|
440
497
|
device = x.device
|
|
498
|
+
if dtype is None:
|
|
499
|
+
dtype = x.dtype
|
|
500
|
+
_check_valid_dtype(dtype, device)
|
|
441
501
|
|
|
442
502
|
return Array._new(np.zeros_like(x._array, dtype=_np_dtype(dtype)), device=device)
|