uarray 0.9.3__cp314-cp314t-win32.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 ADDED
@@ -0,0 +1,9 @@
1
+ [run]
2
+ branch = True
3
+ source =
4
+ uarray
5
+ [report]
6
+ omit =
7
+ **/tests/
8
+ docs/
9
+ uarray/_version.py
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__