uarray 0.9.3__cp314-cp314t-win_amd64.whl
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.
- uarray/.coveragerc +9 -0
- uarray/__init__.py +118 -0
- uarray/_backend.py +800 -0
- uarray/_typing.pyi +65 -0
- uarray/_uarray.cp314t-win_amd64.pyd +0 -0
- uarray/_uarray.pyi +128 -0
- uarray/_version.py +34 -0
- uarray/conftest.py +11 -0
- uarray/py.typed +0 -0
- uarray/pytest.ini +3 -0
- uarray/tests/__init__.py +0 -0
- uarray/tests/example_helpers.py +46 -0
- uarray/tests/test_uarray.py +580 -0
- uarray-0.9.3.dist-info/METADATA +59 -0
- uarray-0.9.3.dist-info/RECORD +18 -0
- uarray-0.9.3.dist-info/WHEEL +5 -0
- uarray-0.9.3.dist-info/licenses/LICENSE +29 -0
- uarray-0.9.3.dist-info/top_level.txt +1 -0
uarray/.coveragerc
ADDED
uarray/__init__.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
.. note:
|
|
3
|
+
If you are looking for overrides for NumPy-specific methods, see the
|
|
4
|
+
documentation for :obj:`unumpy`. This page explains how to write
|
|
5
|
+
back-ends and multimethods.
|
|
6
|
+
|
|
7
|
+
``uarray`` is built around a back-end protocol, and overridable multimethods.
|
|
8
|
+
It is necessary to define multimethods for back-ends to be able to override them.
|
|
9
|
+
See the documentation of :obj:`generate_multimethod` on how to write multimethods.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Let's start with the simplest:
|
|
14
|
+
|
|
15
|
+
``__ua_domain__`` defines the back-end *domain*. The domain consists of period-
|
|
16
|
+
separated string consisting of the modules you extend plus the submodule. For
|
|
17
|
+
example, if a submodule ``module2.submodule`` extends ``module1``
|
|
18
|
+
(i.e., it exposes dispatchables marked as types available in ``module1``),
|
|
19
|
+
then the domain string should be ``"module1.module2.submodule"``.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
For the purpose of this demonstration, we'll be creating an object and setting
|
|
23
|
+
its attributes directly. However, note that you can use a module or your own type
|
|
24
|
+
as a backend as well.
|
|
25
|
+
|
|
26
|
+
>>> class Backend: pass
|
|
27
|
+
>>> be = Backend()
|
|
28
|
+
>>> be.__ua_domain__ = "ua_examples"
|
|
29
|
+
|
|
30
|
+
It might be useful at this point to sidetrack to the documentation of
|
|
31
|
+
:obj:`generate_multimethod` to find out how to generate a multimethod
|
|
32
|
+
overridable by :obj:`uarray`. Needless to say, writing a backend and
|
|
33
|
+
creating multimethods are mostly orthogonal activities, and knowing
|
|
34
|
+
one doesn't necessarily require knowledge of the other, although it
|
|
35
|
+
is certainly helpful. We expect core API designers/specifiers to write the
|
|
36
|
+
multimethods, and implementors to override them. But, as is often the case,
|
|
37
|
+
similar people write both.
|
|
38
|
+
|
|
39
|
+
Without further ado, here's an example multimethod:
|
|
40
|
+
|
|
41
|
+
>>> import uarray as ua
|
|
42
|
+
>>> from uarray import Dispatchable
|
|
43
|
+
>>> def override_me(a, b):
|
|
44
|
+
... return Dispatchable(a, int),
|
|
45
|
+
>>> def override_replacer(args, kwargs, dispatchables):
|
|
46
|
+
... return (dispatchables[0], args[1]), {}
|
|
47
|
+
>>> overridden_me = ua.generate_multimethod(
|
|
48
|
+
... override_me, override_replacer, "ua_examples"
|
|
49
|
+
... )
|
|
50
|
+
|
|
51
|
+
Next comes the part about overriding the multimethod. This requires
|
|
52
|
+
the ``__ua_function__`` protocol, and the ``__ua_convert__``
|
|
53
|
+
protocol. The ``__ua_function__`` protocol has the signature
|
|
54
|
+
``(method, args, kwargs)`` where ``method`` is the passed
|
|
55
|
+
multimethod, ``args``/``kwargs`` specify the arguments and ``dispatchables``
|
|
56
|
+
is the list of converted dispatchables passed in.
|
|
57
|
+
|
|
58
|
+
>>> def __ua_function__(method, args, kwargs):
|
|
59
|
+
... return method.__name__, args, kwargs
|
|
60
|
+
>>> be.__ua_function__ = __ua_function__
|
|
61
|
+
|
|
62
|
+
The other protocol of interest is the ``__ua_convert__`` protocol. It has the
|
|
63
|
+
signature ``(dispatchables, coerce)``. When ``coerce`` is ``False``, conversion
|
|
64
|
+
between the formats should ideally be an ``O(1)`` operation, but it means that
|
|
65
|
+
no memory copying should be involved, only views of the existing data.
|
|
66
|
+
|
|
67
|
+
>>> def __ua_convert__(dispatchables, coerce):
|
|
68
|
+
... for d in dispatchables:
|
|
69
|
+
... if d.type is int:
|
|
70
|
+
... if coerce and d.coercible:
|
|
71
|
+
... yield str(d.value)
|
|
72
|
+
... else:
|
|
73
|
+
... yield d.value
|
|
74
|
+
>>> be.__ua_convert__ = __ua_convert__
|
|
75
|
+
|
|
76
|
+
Now that we have defined the backend, the next thing to do is to call the multimethod.
|
|
77
|
+
|
|
78
|
+
>>> with ua.set_backend(be):
|
|
79
|
+
... overridden_me(1, "2")
|
|
80
|
+
('override_me', (1, '2'), {})
|
|
81
|
+
|
|
82
|
+
Note that the marked type has no effect on the actual type of the passed object.
|
|
83
|
+
We can also coerce the type of the input.
|
|
84
|
+
|
|
85
|
+
>>> with ua.set_backend(be, coerce=True):
|
|
86
|
+
... overridden_me(1, "2")
|
|
87
|
+
... overridden_me(1.0, "2")
|
|
88
|
+
('override_me', ('1', '2'), {})
|
|
89
|
+
('override_me', ('1.0', '2'), {})
|
|
90
|
+
|
|
91
|
+
Another feature is that if you remove ``__ua_convert__``, the arguments are not
|
|
92
|
+
converted at all and it's up to the backend to handle that.
|
|
93
|
+
|
|
94
|
+
>>> del be.__ua_convert__
|
|
95
|
+
>>> with ua.set_backend(be):
|
|
96
|
+
... overridden_me(1, "2")
|
|
97
|
+
('override_me', (1, '2'), {})
|
|
98
|
+
|
|
99
|
+
You also have the option to return ``NotImplemented``, in which case processing moves on
|
|
100
|
+
to the next back-end, which in this case, doesn't exist. The same applies to
|
|
101
|
+
``__ua_convert__``.
|
|
102
|
+
|
|
103
|
+
>>> be.__ua_function__ = lambda *a, **kw: NotImplemented
|
|
104
|
+
>>> with ua.set_backend(be):
|
|
105
|
+
... overridden_me(1, "2")
|
|
106
|
+
Traceback (most recent call last):
|
|
107
|
+
...
|
|
108
|
+
uarray.BackendNotImplementedError: ...
|
|
109
|
+
|
|
110
|
+
The last possibility is if we don't have ``__ua_convert__``, in which case the job is left
|
|
111
|
+
up to ``__ua_function__``, but putting things back into arrays after conversion will not be
|
|
112
|
+
possible.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
# Explicitly re-export `__all__` so type checkers consider it a public member
|
|
116
|
+
from ._backend import __all__ as __all__
|
|
117
|
+
from ._backend import *
|
|
118
|
+
from ._version import version as __version__
|