|
1 | 1 | # Implementation Notes |
2 | 2 |
|
3 | | -This page outlines some notes on the implementation of array-api-compat. These |
4 | | -details are not important for users of the package, but they may be useful to |
5 | | -contributors. |
6 | | - |
7 | | -## Special Considerations |
8 | | - |
9 | | -array-api-compat requires some special development considerations that are |
10 | | -different from most other Python libraries. The goal of array-api-compat is to |
11 | | -be a small library that packages can either vendor or add as a dependency to |
12 | | -implement array API support. Consequently, certain design considerations |
13 | | -should be taken into account: |
14 | | - |
15 | | -- *No Hard Dependencies.* Although array-api-compat "depends" on NumPy, CuPy, |
16 | | - PyTorch, etc., it does not hard depend on them. These libraries are not |
17 | | - imported unless either an array object is passed to |
18 | | - {func}`~.array_namespace()`, or the specific `array_api_compat.<namespace>` |
19 | | - sub-namespace is explicitly imported. |
20 | | - |
21 | | -- *Vendorability.* array-api-compat should be [vendorable](vendoring). This |
22 | | - means that, for instance, all imports in the library are relative imports. |
23 | | - No code in the package specifically references the name `array_api_compat` |
24 | | - (we also support renaming the package to something else). |
25 | | - Vendorability support is tested in `tests/test_vendoring.py`. |
26 | | - |
27 | | -- *Pure Python.* To make array-api-compat as easy as possible to add as a |
28 | | - dependency, the code is all pure Python. |
29 | | - |
30 | | -- *Minimal Wrapping Only.* The wrapping functionality is minimal. This means |
31 | | - that if something is difficult to wrap using pure Python, or if trying to |
32 | | - support some array API behavior would require a significant amount of code, |
33 | | - we prefer to leave the behavior as an upstream issue for the array library, |
34 | | - and [document it as a known difference](../supported-array-libraries.md). |
35 | | - |
36 | | - This also means that we do not at this point in time implement anything |
37 | | - other than wrappers for functions in the standard, and basic [helper |
38 | | - functions](../helper-functions.rst) that would be useful for most users of |
39 | | - array-api-compat. The addition of functions that are not part of the array |
40 | | - API standard is currently out-of-scope for this package (see the |
41 | | - [Scope](scope) section of the documentation). |
42 | | - |
43 | | -- *No Side-Effects*. array-api-compat behavior should be localized to only the |
44 | | - specific code that imports and uses it. It should be invisible to end-users |
45 | | - or users of dependent codes. This in particular implies to the next two |
46 | | - points. |
47 | | - |
48 | | -- *No Monkey Patching.* `array-api-compat` should not attempt to modify |
49 | | - anything about the underlying library. It is a *wrapper* library only. |
50 | | - |
51 | | -- *No Modifying the Array Object.* The array (or tensor) object of the array |
52 | | - library cannot be modified. This also precludes the creation of array |
53 | | - subclasses or wrapper classes. |
54 | | - |
55 | | - Any non-standard behavior that is built-in to the array object, such as the |
56 | | - behavior of [array |
57 | | - methods](https://data-apis.org/array-api/latest/API_specification/array_object.html), |
58 | | - is therefore left unwrapped. Users can workaround issues by using |
59 | | - corresponding [elementwise |
60 | | - functions](https://data-apis.org/array-api/latest/API_specification/elementwise_functions.html) |
61 | | - instead of |
62 | | - [operators](https://data-apis.org/array-api/latest/API_specification/array_object.html#operators), |
63 | | - and by using the [helper functions](../helper-functions.rst) provided by |
64 | | - array-api-compat instead of attributes or methods like `x.to_device()`. |
65 | | - |
66 | | -- *Avoid Restricting Behavior that is Outside the Scope of the Standard.* All |
67 | | - array libraries have functions and behaviors that are outside of the scope |
68 | | - of what is specified by the standard. These behaviors should be left intact |
69 | | - whenever possible, unless the standard explicitly disallows something. This |
70 | | - means |
71 | | - |
72 | | - - All namespaces are *extended* with wrapper functions. You may notice the |
73 | | - extensive use of `import *` in various files in `array_api_compat`. While |
74 | | - this would normally be questionable, this is the [one actual legitimate |
75 | | - use-case for `import *`](https://peps.python.org/pep-0008/#imports), to |
76 | | - re-export names from an external namespace. |
77 | | - |
78 | | - - All wrapper functions pass `**kwargs` through to the wrapped function. |
79 | | - |
80 | | - - Input types not supported by the standard should work if they work in the |
81 | | - underlying wrapped function (for instance, Python scalars or `np.ndarray` |
82 | | - subclasses). |
83 | | - |
84 | | - By keeping underlying behaviors intact, it is easier for libraries to swap |
85 | | - out NumPy or other array libraries for array-api-compat, and it is easier |
86 | | - for libraries to write array library-specific code paths. |
87 | | - |
88 | | - The onus is on users of array-api-compat to ensure their array API code is |
89 | | - portable, e.g., by testing against [array-api-strict](array-api-strict). |
90 | | - |
91 | | - |
92 | | -## Avoiding Code Duplication |
93 | | - |
94 | 3 | Since NumPy, CuPy, and to a degree, Dask, are nearly identical in behavior, |
95 | 4 | most wrapping logic can be shared between them. Wrapped functions that have |
96 | 5 | the same logic between multiple libraries are in `array_api_compat/common/`. |
@@ -138,33 +47,3 @@ identical PyTorch uses a similar layout in `array_api_compat/torch/`, but it |
138 | 47 | differs enough from NumPy/CuPy that very few common wrappers for those |
139 | 48 | libraries are reused. Dask is close to NumPy in behavior and so most Dask |
140 | 49 | functions also reuse the NumPy/CuPy common wrappers. |
141 | | - |
142 | | -## Tests |
143 | | - |
144 | | -The majority of the behavior for array-api-compat is tested by the |
145 | | -[array-api-tests](https://github.com/data-apis/array-api-tests) test suite for |
146 | | -the array API standard. There are also array-api-compat specific tests in |
147 | | -[`tests/`](https://github.com/data-apis/array-api-compat/tree/main/tests). |
148 | | -These tests should be limited to things that are not tested by the test suite, |
149 | | -e.g., tests for [helper functions](../helper-functions.rst) or for behavior |
150 | | -that is not strictly required by the standard. |
151 | | - |
152 | | -array-api-tests is run against all supported libraries are tested on CI |
153 | | -([except for JAX](jax-support)). This is achieved by a [reusable GitHub Actions |
154 | | -Workflow](https://github.com/data-apis/array-api-compat/blob/main/.github/workflows/array-api-tests.yml). |
155 | | -Most libraries have tests that must be xfailed or skipped for various reasons. |
156 | | -These are defined in specific `<library>-xfails.txt` files and are |
157 | | -automatically forwarded to array-api-tests. |
158 | | - |
159 | | -You may often need to update these xfail files, either to add new xfails |
160 | | -(e.g., because of new test suite features, or because a test that was |
161 | | -previously thought to be passing actually flaky fails). Try to keep the xfails |
162 | | -files organized, with comments pointing to upstream issues whenever possible. |
163 | | - |
164 | | -From time to time, xpass tests should be removed from the xfail files, but be |
165 | | -aware that many xfail tests are flaky, so an xpass should only be removed if |
166 | | -you know that the underlying issue has been fixed. |
167 | | - |
168 | | -Array libraries that require a GPU to run (currently only CuPy) cannot be |
169 | | -tested on CI. There is a helper script `test_cupy.sh` that can be used to |
170 | | -manually test CuPy on a machine with a CUDA GPU. |
0 commit comments