Skip to content

Commit a5025d3

Browse files
committed
Add basic documentation, based on the README
The documentation configuration is based on the configuration from array-api-compat. Fixes #27
1 parent 78f4aed commit a5025d3

File tree

9 files changed

+418
-0
lines changed

9 files changed

+418
-0
lines changed

.github/workflows/docs-build.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Docs Build
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
docs-build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
- uses: actions/setup-python@v5
11+
- name: Install Dependencies
12+
run: |
13+
python -m pip install -r docs/requirements.txt
14+
- name: Build Docs
15+
run: |
16+
cd docs
17+
make html
18+
- name: Upload Artifact
19+
uses: actions/upload-artifact@v4
20+
with:
21+
name: docs-build
22+
path: docs/_build/html

.github/workflows/docs-deploy.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Docs Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
docs-deploy:
10+
runs-on: ubuntu-latest
11+
environment:
12+
name: docs-deploy
13+
steps:
14+
- uses: actions/checkout@v4
15+
- name: Download Artifact
16+
uses: dawidd6/action-download-artifact@v2
17+
with:
18+
workflow: docs-build.yml
19+
name: docs-build
20+
path: docs/_build/html
21+
22+
# Note, the gh-pages deployment requires setting up a SSH deploy key.
23+
# See
24+
# https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key-
25+
- name: Deploy
26+
uses: JamesIves/github-pages-deploy-action@v4
27+
with:
28+
folder: docs/_build/html
29+
ssh-key: ${{ secrets.DEPLOY_KEY }}
30+
force: no

docs/Makefile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = _build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21+
22+
livehtml:
23+
sphinx-autobuild --open-browser --watch .. --port 0 -b html $(SOURCEDIR) $(ALLSPHINXOPTS) $(BUILDDIR)/html

docs/_static/custom.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* Makes the text look better on Mac retina displays (the Furo CSS disables*/
2+
/* subpixel antialiasing). */
3+
body {
4+
-webkit-font-smoothing: auto;
5+
-moz-osx-font-smoothing: auto;
6+
}
7+
8+
/* Disable the fancy scrolling behavior when jumping to headers (this is too
9+
slow for long pages) */
10+
html {
11+
scroll-behavior: auto;
12+
}

docs/_static/favicon.png

5.03 KB
Loading

docs/conf.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
# -- Project information -----------------------------------------------------
7+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8+
9+
import sys
10+
import os
11+
sys.path.insert(0, os.path.abspath('..'))
12+
13+
project = 'array-api-strict'
14+
copyright = '2024, Consortium for Python Data API Standards'
15+
author = 'Consortium for Python Data API Standards'
16+
17+
import array_api_strict
18+
release = array_api_strict.__version__
19+
20+
# -- General configuration ---------------------------------------------------
21+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
22+
23+
extensions = [
24+
'myst_parser',
25+
# 'sphinx.ext.autodoc',
26+
# 'sphinx.ext.napoleon',
27+
# 'sphinx.ext.intersphinx',
28+
'sphinx_copybutton',
29+
]
30+
31+
intersphinx_mapping = {
32+
}
33+
# Require :external: to reference intersphinx.
34+
intersphinx_disabled_reftypes = ['*']
35+
36+
templates_path = ['_templates']
37+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
38+
39+
myst_enable_extensions = ["dollarmath", "linkify"]
40+
41+
napoleon_use_rtype = False
42+
napoleon_use_param = False
43+
44+
# Make sphinx give errors for bad cross-references
45+
nitpicky = True
46+
# autodoc wants to make cross-references for every type hint. But a lot of
47+
# them don't actually refer to anything that we have a document for.
48+
nitpick_ignore = [
49+
("py:class", "Array"),
50+
("py:class", "Device"),
51+
]
52+
53+
# Lets us use single backticks for code in RST
54+
default_role = 'code'
55+
56+
# -- Options for HTML output -------------------------------------------------
57+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
58+
59+
html_theme = 'furo'
60+
html_static_path = ['_static']
61+
62+
html_css_files = ['custom.css']
63+
64+
html_theme_options = {
65+
# See https://pradyunsg.me/furo/customisation/footer/
66+
"footer_icons": [
67+
{
68+
"name": "GitHub",
69+
"url": "https://github.com/data-apis/array-api-strict",
70+
"html": """
71+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
72+
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
73+
</svg>
74+
""",
75+
"class": "",
76+
},
77+
],
78+
}
79+
80+
# Logo
81+
82+
html_favicon = "_static/favicon.png"
83+
84+
# html_logo = "_static/logo.svg"

docs/index.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# array-api-strict
2+
3+
`array_api_strict` is a strict, minimal implementation of the [Python array
4+
API](https://data-apis.org/array-api/latest/)
5+
6+
The purpose of array-api-strict is to provide an implementation of the array
7+
API for consuming libraries to test against so they can be completely sure
8+
their usage of the array API is portable.
9+
10+
It is *not* intended to be used by end-users. End-users of the array API
11+
should just use their favorite array library (NumPy, CuPy, PyTorch, etc.) as
12+
usual. It is also not intended to be used as a dependency by consuming
13+
libraries. Consuming library code should use the
14+
[array-api-compat](https://github.com/data-apis/array-api-compat) package to
15+
support the array API. Rather, it is intended to be used in the test suites of
16+
consuming libraries to test their array API usage.
17+
18+
array-api-strict currently supports the 2022.12 version of the standard.
19+
2023.12 support is planned and is tracked by [this
20+
issue](https://github.com/data-apis/array-api-strict/issues/25).
21+
22+
## Install
23+
24+
`array-api-strict` is available on both
25+
[PyPI](https://pypi.org/project/array-api-strict/)
26+
27+
```
28+
python -m pip install array-api-strict
29+
```
30+
31+
and [Conda-forge](https://anaconda.org/conda-forge/array-api-strict)
32+
33+
```
34+
conda install --channel conda-forge array-api-strict
35+
```
36+
37+
array-api-strict supports NumPy 1.26 and (the upcoming) NumPy 2.0.
38+
39+
## Rationale
40+
41+
The array API has many functions and behaviors that are required to be
42+
implemented by conforming libraries, but it does not, in most cases, disallow
43+
implementing additional functions, keyword arguments, and behaviors that
44+
aren't explicitly required by the standard.
45+
46+
However, this poses a problem for consumers of the array API, as they may
47+
accidentally use a function or rely on a behavior which just happens to be
48+
implemented in every array library they test against (e.g., NumPy and
49+
PyTorch), but isn't required by the standard and may not be included in other
50+
libraries.
51+
52+
array-api-strict solves this problem by providing a strict, minimal
53+
implementation of the array API standard. Only those functions and behaviors
54+
that are explicitly *required* by the standard are implemented. For example,
55+
most NumPy functions accept Python scalars as inputs:
56+
57+
```py
58+
>>> import numpy as np
59+
>>> np.sin(0.0)
60+
0.0
61+
```
62+
63+
However, the standard only specifies function inputs on `Array` objects. And
64+
indeed, some libraries, such as PyTorch, do not allow this:
65+
66+
```py
67+
>>> import torch
68+
>>> torch.sin(0.0)
69+
Traceback (most recent call last):
70+
File "<stdin>", line 1, in <module>
71+
TypeError: sin(): argument 'input' (position 1) must be Tensor, not float
72+
```
73+
74+
In array-api-strict, this is also an error:
75+
76+
```py
77+
>>> import array_api_strict as xp
78+
>>> xp.sin(0.0)
79+
Traceback (most recent call last):
80+
...
81+
AttributeError: 'float' object has no attribute 'dtype'
82+
```
83+
84+
Here is an (incomplete) list of the sorts of ways that array-api-strict is
85+
strict/minimal:
86+
87+
- Only those functions and methods that are [defined in the
88+
standard](https://data-apis.org/array-api/latest/API_specification/index.html)
89+
are included.
90+
91+
- In those functions, only the keyword-arguments that are defined by the
92+
standard are included. All signatures in array-api-strict use
93+
[positional-only
94+
arguments](https://data-apis.org/array-api/latest/API_specification/function_and_method_signatures.html#function-and-method-signatures).
95+
As noted above, only `array_api_strict` array objects are accepted by
96+
functions, except in the places where the standard allows Python scalars
97+
(i.e., functions do not automatically call `asarray` on their inputs).
98+
99+
- Only those [dtypes that are defined in the
100+
standard](https://data-apis.org/array-api/latest/API_specification/data_types.html)
101+
are included.
102+
103+
- All functions and methods reject inputs if the standard does not *require*
104+
the input dtype(s) to be supported. This is one of the most restrictive
105+
aspects of the library. For example, in NumPy, most transcendental functions
106+
like `sin` will accept integer array inputs, but the [standard only requires
107+
them to accept floating-point
108+
inputs](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sin.html#array_api.sin),
109+
so in array-api-strict, `sin(integer_array)` will raise an exception.
110+
111+
- The
112+
[indexing](https://data-apis.org/array-api/latest/API_specification/indexing.html)
113+
semantics required by the standard are limited compared to those implemented
114+
by NumPy (e.g., out-of-bounds slices are not supported, integer array
115+
indexing is not supported, only a single boolean array index is supported).
116+
117+
- There are no distinct "scalar" objects as in NumPy. There are only 0-D
118+
arrays.
119+
120+
- Dtype objects are just empty objects that only implement [equality
121+
comparison](https://data-apis.org/array-api/latest/API_specification/generated/array_api.data_types.__eq__.html).
122+
The way to access dtype objects in the standard is by name, like
123+
`xp.float32`.
124+
125+
- The array object type itself is private and should not be accessed.
126+
Subclassing or otherwise trying to directly initialize this object is not
127+
supported. Arrays should be created with one of the [array creation
128+
functions](https://data-apis.org/array-api/latest/API_specification/creation_functions.html)
129+
such as `asarray`.
130+
131+
## Caveats
132+
133+
array-api-strict is a thin pure Python wrapper around NumPy. NumPy 2.0 fully
134+
supports the array API but NumPy 1.26 does not, so many behaviors are wrapped
135+
in NumPy 1.26 to provide array API compatible behavior. Although it is based
136+
on NumPy, mixing NumPy arrays with array-api-strict arrays is not supported.
137+
This should generally raise an error, as it indicates a potential portability
138+
issue, but this hasn't necessarily been tested thoroughly.
139+
140+
1. array-api-strict is validated against the [array API test
141+
suite](https://github.com/data-apis/array-api-tests). However, there may be
142+
a few minor instances where NumPy deviates from the standard in a way that
143+
is inconvenient to workaround in array-api-strict, since it aims to remain
144+
pure Python. You can see the full list of tests that are known to fail in
145+
the [xfails
146+
file](https://github.com/data-apis/array-api-strict/blob/main/array-api-tests-xfails.txt).
147+
148+
The most notable of these is that in NumPy 1.26, the `copy=False` flag is
149+
not implemented for `asarray` and therefore `array_api_strict` raises
150+
`NotImplementedError` in that case.
151+
152+
2. Since NumPy is a CPU-only library, the [device
153+
support](https://data-apis.org/array-api/latest/design_topics/device_support.html)
154+
in array-api-strict is superficial only. `x.device` is always a (private)
155+
`CPU_DEVICE` object, and `device` keywords to creation functions only
156+
accept either this object or `None`. A future version of array-api-strict
157+
[may add support for a CuPy
158+
backend](https://github.com/data-apis/array-api-strict/issues/5) so that
159+
more significant device support can be tested.
160+
161+
3. Although only array types are expected in array-api-strict functions,
162+
currently most functions do not do extensive type checking on their inputs,
163+
so a sufficiently duck-typed object may pass through silently (or at best,
164+
you may get `AttributeError` instead of `TypeError`). However, all type
165+
signatures have type annotations (based on those from the standard), so
166+
this deviation may be tested with type checking. This [behavior may improve
167+
in the future](https://github.com/data-apis/array-api-strict/issues/6).
168+
169+
4. There are some behaviors in the standard that are not required to be
170+
implemented by libraries that cannot support [data dependent
171+
shapes](https://data-apis.org/array-api/latest/design_topics/data_dependent_output_shapes.html).
172+
This includes [the `unique_*`
173+
functions](https://data-apis.org/array-api/latest/API_specification/set_functions.html),
174+
[boolean array
175+
indexing](https://data-apis.org/array-api/latest/API_specification/indexing.html#boolean-array-indexing),
176+
and the
177+
[`nonzero`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.nonzero.html)
178+
function. array-api-strict currently implements all of these. In the
179+
future, [there may be a way to disable them](https://github.com/data-apis/array-api-strict/issues/7).
180+
181+
5. array-api-strict currently only supports the latest version of the array
182+
API standard. [This may change in the future depending on
183+
need](https://github.com/data-apis/array-api-strict/issues/8).
184+
185+
## Usage
186+
187+
TODO: Add a sample CI script here.
188+
189+
## Relationship to `numpy.array_api`
190+
191+
Previously this implementation was available as `numpy.array_api`, but it was
192+
moved to a separate package for NumPy 2.0.
193+
194+
Note that the history of this repo prior to commit
195+
fbefd42e4d11e9be20e0a4785f2619fc1aef1e7c was generated automatically
196+
from the numpy git history, using the following
197+
[git-filter-repo](https://github.com/newren/git-filter-repo) command:
198+
199+
```
200+
git_filter_repo.py --path numpy/array_api/ --path-rename numpy/array_api:array_api_strict --replace-text <(echo -e "numpy.array_api==>array_api_strict\nfrom ..core==>from numpy.core\nfrom .._core==>from numpy._core\nfrom ..linalg==>from numpy.linalg\nfrom numpy import array_api==>import array_api_strict") --commit-callback 'commit.message = commit.message.rstrip() + b"\n\nOriginal NumPy Commit: " + commit.original_id'
201+
```
202+
203+
```{toctree}
204+
:titlesonly:
205+
:hidden:
206+
```

0 commit comments

Comments
 (0)