ovld 0.5.6__py3-none-any.whl → 0.5.7__py3-none-any.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.
- ovld/core.py +6 -0
- ovld/typemap.py +24 -9
- ovld/version.py +1 -1
- {ovld-0.5.6.dist-info → ovld-0.5.7.dist-info}/METADATA +54 -13
- {ovld-0.5.6.dist-info → ovld-0.5.7.dist-info}/RECORD +7 -7
- {ovld-0.5.6.dist-info → ovld-0.5.7.dist-info}/WHEEL +0 -0
- {ovld-0.5.6.dist-info → ovld-0.5.7.dist-info}/licenses/LICENSE +0 -0
ovld/core.py
CHANGED
@@ -45,6 +45,7 @@ def bootstrap_dispatch(ov, name):
|
|
45
45
|
dispatch.register = ov.register
|
46
46
|
dispatch.resolve_for_values = ov.resolve_for_values
|
47
47
|
dispatch.resolve = ov.resolve
|
48
|
+
dispatch.resolve_all = ov.resolve_all
|
48
49
|
dispatch.copy = ov.copy
|
49
50
|
dispatch.variant = ov.variant
|
50
51
|
dispatch.display_methods = ov.display_methods
|
@@ -250,6 +251,11 @@ class Ovld:
|
|
250
251
|
else:
|
251
252
|
return self.map[args]
|
252
253
|
|
254
|
+
def resolve_all(self, *args, **kwargs):
|
255
|
+
"""Yield all methods that match the arguments, in priority order."""
|
256
|
+
self.ensure_compiled()
|
257
|
+
return self.map.resolve_all(*args, **kwargs)
|
258
|
+
|
253
259
|
def register_signature(self, sig, orig_fn):
|
254
260
|
"""Register a function for the given signature."""
|
255
261
|
fn = adapt_function(orig_fn, self, f"{self.__name__}[{sigstring(sig.types)}]")
|
ovld/typemap.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import inspect
|
2
2
|
import math
|
3
3
|
from dataclasses import dataclass
|
4
|
+
from functools import partial
|
4
5
|
from itertools import count
|
5
6
|
from types import CodeType
|
6
7
|
|
@@ -248,7 +249,7 @@ class MultiTypeMap(dict):
|
|
248
249
|
co = h.__code__
|
249
250
|
print(f"{'':{width - 2}} @ {co.co_filename}:{co.co_firstlineno}")
|
250
251
|
|
251
|
-
def
|
252
|
+
def _resolve_all_helper(self, *args, **kwargs):
|
252
253
|
def dependent_match(tup, args):
|
253
254
|
for t, a in zip(tup, args):
|
254
255
|
if isinstance(t, tuple):
|
@@ -258,21 +259,35 @@ class MultiTypeMap(dict):
|
|
258
259
|
return False
|
259
260
|
return True
|
260
261
|
|
261
|
-
message = "No method will be called."
|
262
262
|
argt = [
|
263
263
|
*map(subtler_type, args),
|
264
264
|
*[(k, subtler_type(v)) for k, v in kwargs.items()],
|
265
265
|
]
|
266
|
-
finished = False
|
267
|
-
rank = 1
|
268
266
|
for grp in self.mro(tuple(argt)):
|
269
|
-
|
270
|
-
|
271
|
-
|
267
|
+
yield [
|
268
|
+
(
|
269
|
+
c,
|
270
|
+
dependent_match(
|
271
|
+
self.type_tuples[c.base_handler], [*args, *kwargs.items()]
|
272
|
+
),
|
273
|
+
)
|
272
274
|
for c in grp
|
273
275
|
]
|
274
|
-
|
275
|
-
|
276
|
+
|
277
|
+
def resolve_all(self, *args, **kwargs):
|
278
|
+
for grp in self._resolve_all_helper(*args, **kwargs):
|
279
|
+
for c, m in grp:
|
280
|
+
if m:
|
281
|
+
yield partial(c.handler, *args, **kwargs)
|
282
|
+
|
283
|
+
def display_resolution(self, *args, **kwargs):
|
284
|
+
message = "No method will be called."
|
285
|
+
finished = False
|
286
|
+
rank = 1
|
287
|
+
for grp in self._resolve_all_helper(*args, **kwargs):
|
288
|
+
grp.sort(key=lambda x: x[0].handler.__name__)
|
289
|
+
ambiguous = len([m for _, m in grp if m]) > 1
|
290
|
+
for c, m in grp:
|
276
291
|
handler = c.handler
|
277
292
|
color = "\033[0m"
|
278
293
|
if finished:
|
ovld/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "0.5.
|
1
|
+
version = "0.5.7"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ovld
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.7
|
4
4
|
Summary: Overloading Python functions
|
5
5
|
Project-URL: Homepage, https://ovld.readthedocs.io/en/latest/
|
6
6
|
Project-URL: Documentation, https://ovld.readthedocs.io/en/latest/
|
@@ -22,13 +22,53 @@ With ovld, you can write a version of the same function for every type signature
|
|
22
22
|
|
23
23
|
* ⚡️ **[Fast](https://ovld.readthedocs.io/en/latest/compare/#results):** ovld is the fastest multiple dispatch library around, by some margin.
|
24
24
|
* 🚀 [**Variants**](https://ovld.readthedocs.io/en/latest/usage/#variants), [**mixins**](https://ovld.readthedocs.io/en/latest/usage/#mixins) and [**medleys**](https://ovld.readthedocs.io/en/latest/medley) of functions and methods.
|
25
|
-
* 🦄 **[
|
25
|
+
* 🦄 **[Value-based dispatch](https://ovld.readthedocs.io/en/latest/dependent/):** Overloaded functions can depend on more than argument types: they can depend on actual values.
|
26
26
|
* 🔑 **[Extensive](https://ovld.readthedocs.io/en/latest/usage/#keyword-arguments):** Dispatch on functions, methods, positional arguments and even keyword arguments (with some restrictions).
|
27
27
|
* ⚙️ **[Codegen](https://ovld.readthedocs.io/en/latest/codegen/):** (Experimental) For advanced use cases, you can generate custom code for overloads.
|
28
28
|
|
29
|
+
Install with `pip install ovld`
|
30
|
+
|
31
|
+
|
29
32
|
## Example
|
30
33
|
|
31
|
-
|
34
|
+
Define one version of your function for each type signature you want to support. `ovld` supports all basic types, plus literals and value-dependent types such as `Regexp`.
|
35
|
+
|
36
|
+
```python
|
37
|
+
from ovld import ovld
|
38
|
+
from ovld.dependent import Regexp
|
39
|
+
from typing import Literal
|
40
|
+
|
41
|
+
@ovld
|
42
|
+
def f(x: str):
|
43
|
+
return f"The string {x!r}"
|
44
|
+
|
45
|
+
@ovld
|
46
|
+
def f(x: int):
|
47
|
+
return f"The number {x}"
|
48
|
+
|
49
|
+
@ovld
|
50
|
+
def f(x: int, y: int):
|
51
|
+
return "Two numbers!"
|
52
|
+
|
53
|
+
@ovld
|
54
|
+
def f(x: Literal[0]):
|
55
|
+
return "zero"
|
56
|
+
|
57
|
+
@ovld
|
58
|
+
def f(x: Regexp[r"^X"]):
|
59
|
+
return "A string that starts with X"
|
60
|
+
|
61
|
+
assert f("hello") == "The string 'hello'"
|
62
|
+
assert f(3) == "The number 3"
|
63
|
+
assert f(1, 2) == "Two numbers!"
|
64
|
+
assert f(0) == "zero"
|
65
|
+
assert f("XSECRET") == "A string that starts with X"
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
## Recursive example
|
70
|
+
|
71
|
+
`ovld` shines particularly with recursive definitions, for example tree maps or serialization. Here we define a function that recursively adds lists of lists and integers:
|
32
72
|
|
33
73
|
```python
|
34
74
|
from ovld import ovld, recurse
|
@@ -38,18 +78,19 @@ def add(x: list, y: list):
|
|
38
78
|
return [recurse(a, b) for a, b in zip(x, y)]
|
39
79
|
|
40
80
|
@ovld
|
41
|
-
def add(x:
|
42
|
-
return
|
81
|
+
def add(x: list, y: int):
|
82
|
+
return [recurse(a, y) for a in x]
|
43
83
|
|
44
84
|
@ovld
|
45
|
-
def add(x:
|
46
|
-
return
|
85
|
+
def add(x: int, y: list):
|
86
|
+
return [recurse(x, a) for a in y]
|
47
87
|
|
48
88
|
@ovld
|
49
|
-
def add(x:
|
89
|
+
def add(x: int, y: int):
|
50
90
|
return x + y
|
51
91
|
|
52
92
|
assert add([1, 2], [3, 4]) == [4, 6]
|
93
|
+
assert add([1, 2, [3]], 7) == [8, 9, [10]]
|
53
94
|
```
|
54
95
|
|
55
96
|
The `recurse` function is special: it will recursively call the current ovld object. You may ask: how is it different from simply calling `add`? The difference is that if you create a *variant* of `add`, `recurse` will automatically call the variant.
|
@@ -63,7 +104,7 @@ A *variant* of an `ovld` is a copy of the `ovld`, with some methods added or cha
|
|
63
104
|
|
64
105
|
```python
|
65
106
|
@add.variant
|
66
|
-
def mul(x:
|
107
|
+
def mul(x: int, y: int):
|
67
108
|
return x * y
|
68
109
|
|
69
110
|
assert mul([1, 2], [3, 4]) == [3, 8]
|
@@ -92,9 +133,9 @@ assert f(10) == 121
|
|
92
133
|
|
93
134
|
Both definitions above have the same type signature, but since the first has higher priority, that is the one that will be called.
|
94
135
|
|
95
|
-
However, that does not mean there is no way to call the second one. Indeed, when the first function calls the special function `call_next(x + 1)`, it will call the next function in
|
136
|
+
However, that does not mean there is no way to call the second one. Indeed, when the first function calls the special function `call_next(x + 1)`, it will call the next function in line, in order of priority and specificity.
|
96
137
|
|
97
|
-
The pattern you see above is how you may wrap each call with some generic behavior. For instance, if you did something like
|
138
|
+
The pattern you see above is how you may wrap each call with some generic behavior. For instance, if you did something like this:
|
98
139
|
|
99
140
|
```python
|
100
141
|
@f.variant(priority=1000)
|
@@ -103,12 +144,12 @@ def f2(x: object)
|
|
103
144
|
return call_next(x)
|
104
145
|
```
|
105
146
|
|
106
|
-
|
147
|
+
The above is effectively a clone of `f` that traces every call. Useful for debugging.
|
107
148
|
|
108
149
|
|
109
150
|
## Dependent types
|
110
151
|
|
111
|
-
A dependent type is a type that depends on a value.
|
152
|
+
A dependent type is a type that depends on a value. This enables dispatching based on the actual value of an argument. The simplest example of a dependent type is `typing.Literal[value]`, which matches one single value. `ovld` also supports `Dependent[bound, check]` for arbitrary checks. For example, this definition of factorial:
|
112
153
|
|
113
154
|
```python
|
114
155
|
from typing import Literal
|
@@ -1,18 +1,18 @@
|
|
1
1
|
ovld/__init__.py,sha256=JuCM8Sj65gobV0KYyLr95cSI23Pi6RYZ7X3_F3fdsSw,1821
|
2
2
|
ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
|
3
3
|
ovld/codegen.py,sha256=27tmamlanuTPDT-x31ISyqP0wGKW9BCFZJGVyq9qLg8,9728
|
4
|
-
ovld/core.py,sha256=
|
4
|
+
ovld/core.py,sha256=WqZ1lvcAGSri02XZeY73Bj5AKB9RYBCAvHLbyns8u68,17792
|
5
5
|
ovld/dependent.py,sha256=JIgsc_5ddPH51_2IrZ6JW6bWE5RyrrrOwR2e9UvDhZ4,8922
|
6
6
|
ovld/medley.py,sha256=0fseIntzJRCPYXq-tmnxgy5ipNa4ZxR0D_6So0xstdQ,12729
|
7
7
|
ovld/mro.py,sha256=Aw1r5Zz7V9cVBDwWzQ-WNnbpBwoGztgbw3wLAyS6Y60,4863
|
8
8
|
ovld/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
ovld/recode.py,sha256=vXg9XLExp_9LdAHO0JWR4wvwHhpOLu2Xcrg9ZYg1nms,16407
|
10
10
|
ovld/signatures.py,sha256=Q8JucSOun0ESGx14aWtHtBzLEiM6FxY5HP3imyqXoDo,8984
|
11
|
-
ovld/typemap.py,sha256=
|
11
|
+
ovld/typemap.py,sha256=wkLuCc6xa2VZJOMaAhuYYgnNrywhovkQwbkBnoRfCsY,13985
|
12
12
|
ovld/types.py,sha256=CRL6Vuzg5moXgAAhIj2698GvZoyF4HWbUDYz2hKt6us,13373
|
13
13
|
ovld/utils.py,sha256=cyy9pcuMhmo1_UdPonH9JT6B9QlI4oH6_JK89cM3_gk,5046
|
14
|
-
ovld/version.py,sha256=
|
15
|
-
ovld-0.5.
|
16
|
-
ovld-0.5.
|
17
|
-
ovld-0.5.
|
18
|
-
ovld-0.5.
|
14
|
+
ovld/version.py,sha256=06EkKCZh0our2EHc5Ssv0FmkpTsQ75viNNVyU74k-Zg,18
|
15
|
+
ovld-0.5.7.dist-info/METADATA,sha256=8kgc5SptJGDMMR4twLX9cB88rnMMC-GvuUn2Z8mCmgE,10458
|
16
|
+
ovld-0.5.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
ovld-0.5.7.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
|
18
|
+
ovld-0.5.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|