Skip to content

Commit 591f5fd

Browse files
committed
Initial commit
0 parents  commit 591f5fd

File tree

6 files changed

+750
-0
lines changed

6 files changed

+750
-0
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Array protocol playground
2+
3+
This repository provides a playground for a vendorable protocol for array objects that can be used to statically as well as at runtime check for adherence to the [Array API](https://github.com/data-apis/array-api).
4+
5+
`consumer.py` implements a "vendored" version of the proposed protocol and `provider` implements a dummy array object adhering to it.
6+
7+
- The static checks can be run by `mypy static_checks.py`
8+
- The runtime checks can be run by `python runtime_checks.py`

consumer.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import enum
2+
from typing import Any, Optional, Tuple, TypeVar, Union, Protocol, runtime_checkable
3+
4+
5+
VendoredDtype = Any
6+
VendoredDevice = Any
7+
VendoredArrayNamespace = Any
8+
VendoredPyCapsule = Any
9+
VendoredShape = Tuple[int, ...]
10+
11+
12+
A = TypeVar("A")
13+
14+
15+
@runtime_checkable
16+
class VendoredArrayProtocol(Protocol[A]):
17+
@property
18+
def dtype(self) -> VendoredDtype:
19+
...
20+
21+
@property
22+
def device(self) -> VendoredDevice:
23+
...
24+
25+
@property
26+
def ndim(self) -> int:
27+
...
28+
29+
@property
30+
def shape(self) -> VendoredShape:
31+
...
32+
33+
@property
34+
def size(self) -> int:
35+
...
36+
37+
@property
38+
def T(self) -> A:
39+
...
40+
41+
def __abs__(self) -> A:
42+
...
43+
44+
def __add__(self, other: Union[int, float, A], /) -> A:
45+
...
46+
47+
def __and__(self, other: Union[bool, int, A], /) -> A:
48+
...
49+
50+
def __array_namespace__(
51+
self, /, *, api_version: Optional[str] = None
52+
) -> VendoredArrayNamespace:
53+
...
54+
55+
def __bool__(self) -> bool:
56+
...
57+
58+
def __dlpack__(
59+
self, /, *, stream: Optional[Union[int, Any]] = None
60+
) -> VendoredPyCapsule:
61+
...
62+
63+
def __dlpack_device__(self) -> Tuple[enum.IntEnum, int]:
64+
...
65+
66+
# This overrides the input type, since object.__eq__ handles any input
67+
# This overrides the return type, since object.__eq__ returns a bool
68+
def __eq__( # type: ignore[override]
69+
self,
70+
other: Union[bool, int, float, A],
71+
/,
72+
) -> A: # type: ignore[override]
73+
...
74+
75+
def __float__(self) -> float:
76+
...
77+
78+
def __floordiv__(self, other: Union[int, float, A], /) -> A:
79+
...
80+
81+
def __ge__(self, other: Union[int, float, A], /) -> A:
82+
...
83+
84+
def __getitem__(
85+
self,
86+
key: Union[int, slice, Tuple[Union[int, slice], ...], A],
87+
/,
88+
) -> A:
89+
...
90+
91+
def __gt__(self, other: Union[int, float, A], /) -> A:
92+
...
93+
94+
def __int__(self) -> int:
95+
...
96+
97+
def __invert__(self) -> A:
98+
...
99+
100+
def __le__(self, other: Union[int, float, A], /) -> A:
101+
...
102+
103+
def __len__(self) -> int:
104+
...
105+
106+
def __lshift__(self, other: Union[int, A], /) -> A:
107+
...
108+
109+
def __lt__(self, other: Union[int, float, A], /) -> A:
110+
...
111+
112+
def __matmul__(self, other: A) -> A:
113+
...
114+
115+
def __mod__(self, other: Union[int, float, A], /) -> A:
116+
...
117+
118+
def __mul__(self, other: Union[int, float, A], /) -> A:
119+
...
120+
121+
# This overrides the input type, since object.__ne__ handles any input
122+
# This overrides the return type, since object.__ne__ returns a bool
123+
def __ne__( # type: ignore[override]
124+
self, other: Union[bool, int, float, A], /
125+
) -> A: # type: ignore[override]
126+
...
127+
128+
def __neg__(self) -> A:
129+
...
130+
131+
def __or__(self, other: Union[bool, int, A], /) -> A:
132+
...
133+
134+
def __pos__(self) -> A:
135+
...
136+
137+
def __pow__(self, other: Union[int, float, A], /) -> A:
138+
...
139+
140+
def __rshift__(self, other: Union[int, A], /) -> A:
141+
...
142+
143+
def __setitem__(
144+
self,
145+
key: Union[int, slice, Tuple[Union[int, slice], ...], A],
146+
value: Union[bool, int, float, A],
147+
/,
148+
) -> None:
149+
...
150+
151+
def __sub__(self, other: Union[int, float, A], /) -> A:
152+
...
153+
154+
def __truediv__(self, other: Union[int, float, A], /) -> A:
155+
...
156+
157+
def __xor__(self, other: Union[bool, int, A], /) -> A:
158+
...

environment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: array-protocol
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- python=3.8
6+
- mypy==0.910

provider.py

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import enum
2+
from typing import Union, Optional, Any, Tuple
3+
4+
5+
class ArrayImplementation:
6+
@property
7+
def dtype(self) -> object:
8+
return object()
9+
10+
@property
11+
def device(self) -> object:
12+
return object()
13+
14+
@property
15+
def ndim(self) -> int:
16+
return 0
17+
18+
@property
19+
def shape(self) -> Tuple[int, ...]:
20+
return (0,)
21+
22+
@property
23+
def size(self) -> int:
24+
return 0
25+
26+
@property
27+
def T(self) -> "ArrayImplementation":
28+
return self
29+
30+
def __abs__(self) -> "ArrayImplementation":
31+
return self
32+
33+
def __add__(
34+
self, other: Union[int, float, "ArrayImplementation"], /
35+
) -> "ArrayImplementation":
36+
return self
37+
38+
def __and__(
39+
self, other: Union[bool, int, "ArrayImplementation"], /
40+
) -> "ArrayImplementation":
41+
return self
42+
43+
def __array_namespace__(self, /, *, api_version: Optional[str] = None) -> object:
44+
return object()
45+
46+
def __bool__(self) -> bool:
47+
return False
48+
49+
def __dlpack__(self, /, *, stream: Optional[Union[int, Any]] = None) -> object:
50+
return object()
51+
52+
def __dlpack_device__(self) -> Tuple[enum.IntEnum, int]:
53+
class Foo(enum.IntEnum):
54+
bar = 0
55+
56+
return Foo.bar, 0
57+
58+
# This overrides the input type, since object.__eq__ handles any input
59+
# This overrides the return type, since object.__eq__ returns a bool
60+
def __eq__( # type: ignore[override]
61+
self: "ArrayImplementation",
62+
other: Union[bool, int, float, "ArrayImplementation"],
63+
/,
64+
) -> "ArrayImplementation": # type: ignore[override]
65+
return self
66+
67+
def __float__(self) -> float:
68+
return 0.0
69+
70+
def __floordiv__(
71+
self, other: Union[int, float, "ArrayImplementation"], /
72+
) -> "ArrayImplementation":
73+
return self
74+
75+
def __ge__(
76+
self, other: Union[int, float, "ArrayImplementation"], /
77+
) -> "ArrayImplementation":
78+
return self
79+
80+
def __getitem__(
81+
self,
82+
key: Union[
83+
int,
84+
slice,
85+
Tuple[Union[int, slice], ...],
86+
"ArrayImplementation",
87+
],
88+
/,
89+
) -> "ArrayImplementation":
90+
return self
91+
92+
def __gt__(
93+
self, other: Union[int, float, "ArrayImplementation"], /
94+
) -> "ArrayImplementation":
95+
return self
96+
97+
def __int__(self) -> int:
98+
return 0
99+
100+
def __invert__(self) -> "ArrayImplementation":
101+
return self
102+
103+
def __le__(
104+
self, other: Union[int, float, "ArrayImplementation"], /
105+
) -> "ArrayImplementation":
106+
return self
107+
108+
def __len__(self) -> int:
109+
return 0
110+
111+
def __lshift__(
112+
self, other: Union[int, "ArrayImplementation"], /
113+
) -> "ArrayImplementation":
114+
return self
115+
116+
def __lt__(
117+
self, other: Union[int, float, "ArrayImplementation"], /
118+
) -> "ArrayImplementation":
119+
return self
120+
121+
def __matmul__(self, other: "ArrayImplementation") -> "ArrayImplementation":
122+
return self
123+
124+
def __mod__(
125+
self, other: Union[int, float, "ArrayImplementation"], /
126+
) -> "ArrayImplementation":
127+
return self
128+
129+
def __mul__(
130+
self, other: Union[int, float, "ArrayImplementation"], /
131+
) -> "ArrayImplementation":
132+
return self
133+
134+
# This overrides the input type, since object.__ne__ handles any input
135+
# This overrides the return type, since object.__ne__ returns a bool
136+
def __ne__( # type: ignore[override]
137+
self: "ArrayImplementation",
138+
other: Union[bool, int, float, "ArrayImplementation"],
139+
/,
140+
) -> "ArrayImplementation": # type: ignore[override]
141+
return self
142+
143+
def __neg__(self) -> "ArrayImplementation":
144+
return self
145+
146+
def __or__(
147+
self, other: Union[bool, int, "ArrayImplementation"], /
148+
) -> "ArrayImplementation":
149+
return self
150+
151+
def __pos__(self) -> "ArrayImplementation":
152+
return self
153+
154+
def __pow__(
155+
self, other: Union[int, float, "ArrayImplementation"], /
156+
) -> "ArrayImplementation":
157+
return self
158+
159+
def __rshift__(
160+
self, other: Union[int, "ArrayImplementation"], /
161+
) -> "ArrayImplementation":
162+
return self
163+
164+
def __setitem__(
165+
self,
166+
key: Union[
167+
int,
168+
slice,
169+
Tuple[Union[int, slice], ...],
170+
"ArrayImplementation",
171+
],
172+
value: Union[bool, int, float, "ArrayImplementation"],
173+
/,
174+
) -> None:
175+
return None
176+
177+
def __sub__(
178+
self, other: Union[int, float, "ArrayImplementation"], /
179+
) -> "ArrayImplementation":
180+
return self
181+
182+
def __truediv__(
183+
self, other: Union[int, float, "ArrayImplementation"], /
184+
) -> "ArrayImplementation":
185+
return self
186+
187+
def __xor__(
188+
self, other: Union[bool, int, "ArrayImplementation"], /
189+
) -> "ArrayImplementation":
190+
return self

runtime_checks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from consumer import VendoredArrayProtocol
2+
from provider import ArrayImplementation
3+
4+
5+
assert isinstance(ArrayImplementation(), VendoredArrayProtocol)

0 commit comments

Comments
 (0)