Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

""" 

.. note: 

If you are looking for overrides for NumPy-specific methods, see the 

documentation for :obj:`unumpy`. This page explains how to write 

back-ends and multimethods. 

 

``uarray`` is built around a back-end protocol and overridable multimethods. 

It is necessary to define multimethods for back-ends to be able to override them. 

See the documentation of :obj:`generate_multimethod` on how to write multimethods. 

 

 

 

Let's start with the simplest: 

 

``__ua_domain__`` defines the back-end *domain*. The domain consists of period- 

separated string consisting of the modules you extend plus the submodule. For 

example, if a submodule ``module2.submodule`` extends ``module1`` 

(i.e., it exposes dispatchables marked as types available in ``module1``), 

then the domain string should be ``"module1.module2.submodule"``. 

 

 

For the purpose of this demonstration, we'll be creating an object and setting 

its attributes directly. However, note that you can use a module or your own type 

as a backend as well. 

 

>>> class Backend: pass 

>>> be = Backend() 

>>> be.__ua_domain__ = "ua_examples" 

 

It might be useful at this point to sidetrack to the documentation of 

:obj:`generate_multimethod` to find out how to generate a multimethod 

overridable by :obj:`uarray`. Needless to say, writing a backend and 

creating multimethods are mostly orthogonal activities, and knowing 

one doesn't necessarily require knowledge of the other, although it 

is certainly helpful. We expect core API designers/specifiers to write the 

multimethods, and implementors to override them. But, as is often the case, 

similar people write both. 

 

Without further ado, here's an example multimethod: 

 

>>> import uarray as ua 

>>> from uarray import Dispatchable 

>>> def override_me(a, b): 

... return Dispatchable(a, int), 

>>> def override_replacer(args, kwargs, dispatchables): 

... return (dispatchables[0], args[1]), {} 

>>> overridden_me = ua.generate_multimethod( 

... override_me, override_replacer, "ua_examples" 

... ) 

 

Next comes the part about overriding the multimethod. This requires 

the ``__ua_function__`` protocol, and the ``__ua_convert__`` 

protocol. The ``__ua_function__`` protocol has the signature 

``(method, args, kwargs)`` where ``method`` is the passed 

multimethod, ``args``/``kwargs`` specify the arguments and ``dispatchables`` 

is the list of converted dispatchables passed in. 

 

>>> def __ua_function__(method, args, kwargs): 

... return method.__name__, args, kwargs 

>>> be.__ua_function__ = __ua_function__ 

 

The other protocol of interest is the ``__ua_convert__`` protocol. It has the 

signature ``(dispatchables, coerce)``. When ``coerce`` is ``False``, conversion 

between the formats should ideally be an ``O(1)`` operation, but it means that 

no memory copying should be involved, only views of the existing data. 

 

>>> def __ua_convert__(dispatchables, coerce): 

... for d in dispatchables: 

... if d.type is int: 

... if coerce and d.coercible: 

... yield str(d.value) 

... else: 

... yield d.value 

>>> be.__ua_convert__ = __ua_convert__ 

 

Now that we have defined the backend, the next thing to do is to call the multimethod. 

 

>>> with ua.set_backend(be): 

... overridden_me(1, "2") 

('override_me', (1, '2'), {}) 

 

Note that the marked type has no effect on the actual type of the passed object. 

We can also coerce the type of the input. 

 

>>> with ua.set_backend(be, coerce=True): 

... overridden_me(1, "2") 

... overridden_me(1.0, "2") 

('override_me', ('1', '2'), {}) 

('override_me', ('1.0', '2'), {}) 

 

Another feature is that if you remove ``__ua_convert__``, the arguments are not 

converted at all and it's up to the backend to handle that. 

 

>>> del be.__ua_convert__ 

>>> with ua.set_backend(be): 

... overridden_me(1, "2") 

('override_me', (1, '2'), {}) 

 

You also have the option to return ``NotImplemented``, in which case processing moves on 

to the next back-end, which, in this case, doesn't exist. The same applies to 

``__ua_convert__``. 

 

>>> be.__ua_function__ = lambda *a, **kw: NotImplemented 

>>> with ua.set_backend(be): 

... overridden_me(1, "2") 

Traceback (most recent call last): 

... 

uarray.backend.BackendNotImplementedError: ... 

 

The last possibility is if we don't have ``__ua_convert__``, in which case the job is left 

up to ``__ua_function__``, but putting things back into arrays after conversion will not be 

possible. 

""" 

 

from ._backend import * 

 

__version__ = '0.5.1+49.g4c3f1d7.scipy'