ovld 0.3.7__tar.gz → 0.3.9__tar.gz
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-0.3.9/.bsync-snap-20220324145902.852076 +0 -0
- ovld-0.3.9/.envrc +2 -0
- {ovld-0.3.7 → ovld-0.3.9}/PKG-INFO +3 -19
- {ovld-0.3.7 → ovld-0.3.9}/README.md +2 -18
- ovld-0.3.9/bench.py +171 -0
- ovld-0.3.9/doo.py +74 -0
- ovld-0.3.9/edges.py +64 -0
- ovld-0.3.9/explore.py +69 -0
- ovld-0.3.9/nxt.py +13 -0
- {ovld-0.3.7 → ovld-0.3.9}/pyproject.toml +1 -1
- ovld-0.3.9/src/ovld/__init__.py +48 -0
- {ovld-0.3.7 → ovld-0.3.9}/src/ovld/core.py +157 -176
- {ovld-0.3.7 → ovld-0.3.9}/src/ovld/mro.py +66 -21
- ovld-0.3.9/src/ovld/recode.py +80 -0
- ovld-0.3.9/src/ovld/version.py +1 -0
- {ovld-0.3.7 → ovld-0.3.9}/tests/test_ovld.py +257 -83
- {ovld-0.3.7 → ovld-0.3.9}/tests/test_typemap.py +47 -16
- ovld-0.3.9/x.py +11 -0
- ovld-0.3.7/.envrc +0 -1
- ovld-0.3.7/src/ovld/__init__.py +0 -3
- ovld-0.3.7/src/ovld/version.py +0 -1
- {ovld-0.3.7 → ovld-0.3.9}/.github/workflows/python-package.yml +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/.gitignore +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/.python-version +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/LICENSE +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/requirements-dev.lock +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/requirements.lock +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/src/ovld/utils.py +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/tests/__init__.py +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/tests/modules/gingerbread.py +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/tests/test_global.py +0 -0
- {ovld-0.3.7 → ovld-0.3.9}/tests/test_utils.py +0 -0
Binary file
|
ovld-0.3.9/.envrc
ADDED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: ovld
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.9
|
4
4
|
Summary: Overloading Python functions
|
5
5
|
Author-email: Olivier Breuleux <breuleux@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -19,7 +19,7 @@ Other features of `ovld`:
|
|
19
19
|
|
20
20
|
* Multiple dispatch for methods (with `metaclass=ovld.OvldMC`)
|
21
21
|
* Create variants of functions
|
22
|
-
* Built-in support for extensible
|
22
|
+
* Built-in support for extensible recursion
|
23
23
|
* Function wrappers
|
24
24
|
* Function postprocessors
|
25
25
|
* Nice stack traces
|
@@ -84,22 +84,6 @@ assert mul([1, 2], [3, 4]) == [3, 8]
|
|
84
84
|
|
85
85
|
A `variant` of a function is a copy which inherits all of the original's implementations but may define new ones. And because `self` is bound to the function that's called at the top level, the implementations for `list`, `tuple` and `dict` will bind `self` to `add` or `mul` depending on which one was called. You may also call `self.super(*args)` to invoke the parent implementation for that type.
|
86
86
|
|
87
|
-
## State
|
88
|
-
|
89
|
-
You can pass `initial_state` to `@ovld` or `variant`. The initial state must be a function that takes no arguments. Its return value will be available in `self.state`. The state is initialized at the top level call, but recursive calls to `self` will preserve it.
|
90
|
-
|
91
|
-
In other words, you can do something like this:
|
92
|
-
|
93
|
-
```python
|
94
|
-
@add.variant(initial_state=lambda: 0)
|
95
|
-
def count(self, x, y):
|
96
|
-
self.state += 1
|
97
|
-
return (f"#{self.state}", x + y)
|
98
|
-
|
99
|
-
assert count([1, 2, 3], [4, 5, 6]) == [("#1", 5), ("#2", 7), ("#3", 9)]
|
100
|
-
```
|
101
|
-
|
102
|
-
The initial_state function can return any object and you can use the state to any purpose (e.g. cache or memoization).
|
103
87
|
|
104
88
|
## Custom dispatch
|
105
89
|
|
@@ -134,7 +118,7 @@ assert add_default([1, 2, "alouette"]) == [2, 4, "alouettealouette"]
|
|
134
118
|
|
135
119
|
There are other uses for this feature, e.g. memoization.
|
136
120
|
|
137
|
-
The normal functions may also have a `self`, which works the same as bootstrapping
|
121
|
+
The normal functions may also have a `self`, which works the same as bootstrapping.
|
138
122
|
|
139
123
|
## Postprocess
|
140
124
|
|
@@ -9,7 +9,7 @@ Other features of `ovld`:
|
|
9
9
|
|
10
10
|
* Multiple dispatch for methods (with `metaclass=ovld.OvldMC`)
|
11
11
|
* Create variants of functions
|
12
|
-
* Built-in support for extensible
|
12
|
+
* Built-in support for extensible recursion
|
13
13
|
* Function wrappers
|
14
14
|
* Function postprocessors
|
15
15
|
* Nice stack traces
|
@@ -74,22 +74,6 @@ assert mul([1, 2], [3, 4]) == [3, 8]
|
|
74
74
|
|
75
75
|
A `variant` of a function is a copy which inherits all of the original's implementations but may define new ones. And because `self` is bound to the function that's called at the top level, the implementations for `list`, `tuple` and `dict` will bind `self` to `add` or `mul` depending on which one was called. You may also call `self.super(*args)` to invoke the parent implementation for that type.
|
76
76
|
|
77
|
-
## State
|
78
|
-
|
79
|
-
You can pass `initial_state` to `@ovld` or `variant`. The initial state must be a function that takes no arguments. Its return value will be available in `self.state`. The state is initialized at the top level call, but recursive calls to `self` will preserve it.
|
80
|
-
|
81
|
-
In other words, you can do something like this:
|
82
|
-
|
83
|
-
```python
|
84
|
-
@add.variant(initial_state=lambda: 0)
|
85
|
-
def count(self, x, y):
|
86
|
-
self.state += 1
|
87
|
-
return (f"#{self.state}", x + y)
|
88
|
-
|
89
|
-
assert count([1, 2, 3], [4, 5, 6]) == [("#1", 5), ("#2", 7), ("#3", 9)]
|
90
|
-
```
|
91
|
-
|
92
|
-
The initial_state function can return any object and you can use the state to any purpose (e.g. cache or memoization).
|
93
77
|
|
94
78
|
## Custom dispatch
|
95
79
|
|
@@ -124,7 +108,7 @@ assert add_default([1, 2, "alouette"]) == [2, 4, "alouettealouette"]
|
|
124
108
|
|
125
109
|
There are other uses for this feature, e.g. memoization.
|
126
110
|
|
127
|
-
The normal functions may also have a `self`, which works the same as bootstrapping
|
111
|
+
The normal functions may also have a `self`, which works the same as bootstrapping.
|
128
112
|
|
129
113
|
## Postprocess
|
130
114
|
|
ovld-0.3.9/bench.py
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
import timeit
|
2
|
+
|
3
|
+
from multimethod import multimethod
|
4
|
+
from multipledispatch import dispatch
|
5
|
+
|
6
|
+
from ovld import ovld, recurse
|
7
|
+
|
8
|
+
# OVLD
|
9
|
+
|
10
|
+
|
11
|
+
@ovld
|
12
|
+
def smap(x: list, y: list):
|
13
|
+
"""One."""
|
14
|
+
return [smap(a, b) for a, b in zip(x, y)]
|
15
|
+
|
16
|
+
|
17
|
+
@ovld
|
18
|
+
def smap(x: tuple, y: tuple):
|
19
|
+
return tuple(smap(a, b) for a, b in zip(x, y))
|
20
|
+
|
21
|
+
|
22
|
+
@ovld
|
23
|
+
def smap(x: dict, y: dict):
|
24
|
+
return {k: smap(v, y[k]) for k, v in x.items()}
|
25
|
+
|
26
|
+
|
27
|
+
@ovld
|
28
|
+
def smap(x: object, y: object):
|
29
|
+
return x + y
|
30
|
+
|
31
|
+
|
32
|
+
# OVLD B
|
33
|
+
|
34
|
+
|
35
|
+
@ovld
|
36
|
+
def smap_b(self, x: list, y: list):
|
37
|
+
"""Two."""
|
38
|
+
return [self(a, b) for a, b in zip(x, y)]
|
39
|
+
|
40
|
+
|
41
|
+
@ovld
|
42
|
+
def smap_b(self, x: tuple, y: tuple):
|
43
|
+
return tuple(self(a, b) for a, b in zip(x, y))
|
44
|
+
|
45
|
+
|
46
|
+
@ovld
|
47
|
+
def smap_b(self, x: dict, y: dict):
|
48
|
+
return {k: self(v, y[k]) for k, v in x.items()}
|
49
|
+
|
50
|
+
|
51
|
+
@ovld
|
52
|
+
def smap_b(self, x: object, y: object):
|
53
|
+
return x + y
|
54
|
+
|
55
|
+
|
56
|
+
# OVLD C
|
57
|
+
|
58
|
+
|
59
|
+
@ovld
|
60
|
+
def smap_c(x: list, y: list):
|
61
|
+
"""Two."""
|
62
|
+
return [recurse(a, b) for a, b in zip(x, y)]
|
63
|
+
|
64
|
+
|
65
|
+
@ovld
|
66
|
+
def smap_c(x: tuple, y: tuple):
|
67
|
+
return tuple(recurse(a, b) for a, b in zip(x, y))
|
68
|
+
|
69
|
+
|
70
|
+
@ovld
|
71
|
+
def smap_c(x: dict, y: dict):
|
72
|
+
return {k: recurse(v, y[k]) for k, v in x.items()}
|
73
|
+
|
74
|
+
|
75
|
+
@ovld
|
76
|
+
def smap_c(x: object, y: object):
|
77
|
+
return x + y
|
78
|
+
|
79
|
+
|
80
|
+
# multimethods
|
81
|
+
|
82
|
+
|
83
|
+
@multimethod
|
84
|
+
def smap_mm(x: list, y: list):
|
85
|
+
"""Three."""
|
86
|
+
return [smap_mm(a, b) for a, b in zip(x, y)]
|
87
|
+
|
88
|
+
|
89
|
+
@multimethod
|
90
|
+
def smap_mm(x: tuple, y: tuple):
|
91
|
+
return tuple(smap_mm(a, b) for a, b in zip(x, y))
|
92
|
+
|
93
|
+
|
94
|
+
@multimethod
|
95
|
+
def smap_mm(x: dict, y: dict):
|
96
|
+
return {k: smap_mm(v, y[k]) for k, v in x.items()}
|
97
|
+
|
98
|
+
|
99
|
+
@multimethod
|
100
|
+
def smap_mm(x: object, y: object):
|
101
|
+
return x + y
|
102
|
+
|
103
|
+
|
104
|
+
# multipledispatch
|
105
|
+
|
106
|
+
|
107
|
+
@dispatch(list, list)
|
108
|
+
def smap_md(x, y):
|
109
|
+
"""Four."""
|
110
|
+
return [smap_md(a, b) for a, b in zip(x, y)]
|
111
|
+
|
112
|
+
|
113
|
+
@dispatch(tuple, tuple)
|
114
|
+
def smap_md(x, y):
|
115
|
+
return tuple(smap_md(a, b) for a, b in zip(x, y))
|
116
|
+
|
117
|
+
|
118
|
+
@dispatch(dict, dict)
|
119
|
+
def smap_md(x, y):
|
120
|
+
return {k: smap_md(v, y[k]) for k, v in x.items()}
|
121
|
+
|
122
|
+
|
123
|
+
@dispatch(object, object)
|
124
|
+
def smap_md(x, y):
|
125
|
+
return x + y
|
126
|
+
|
127
|
+
|
128
|
+
# isinstance
|
129
|
+
|
130
|
+
|
131
|
+
def smap_ii(x, y):
|
132
|
+
"""Five."""
|
133
|
+
if isinstance(x, dict) and isinstance(y, dict):
|
134
|
+
return {k: smap_ii(v, y[k]) for k, v in x.items()}
|
135
|
+
elif isinstance(x, tuple) and isinstance(y, tuple):
|
136
|
+
return tuple(smap_ii(a, b) for a, b in zip(x, y))
|
137
|
+
elif isinstance(x, list) and isinstance(y, list):
|
138
|
+
return [smap_ii(a, b) for a, b in zip(x, y)]
|
139
|
+
else:
|
140
|
+
return x + y
|
141
|
+
|
142
|
+
|
143
|
+
# multipledispatch
|
144
|
+
|
145
|
+
|
146
|
+
A = {"xs": list(range(50)), "ys": ("o", (6, 7))}
|
147
|
+
B = {"xs": list(range(10, 60)), "ys": ("x", (7, 6))}
|
148
|
+
|
149
|
+
results = {
|
150
|
+
"smap": smap(A, B),
|
151
|
+
"smap_mm": smap_mm(A, B),
|
152
|
+
"smap_md": smap_md(A, B),
|
153
|
+
"smap_ii": smap_ii(A, B),
|
154
|
+
"smap_b": smap_b(A, B),
|
155
|
+
"smap_c": smap_c(A, B),
|
156
|
+
}
|
157
|
+
|
158
|
+
expected = results["smap"]
|
159
|
+
|
160
|
+
for k, v in results.items():
|
161
|
+
assert v == expected, f"{k} failed"
|
162
|
+
|
163
|
+
|
164
|
+
# breakpoint()
|
165
|
+
|
166
|
+
print("smap_ov\t", timeit.timeit(lambda: smap(A, B), number=10000))
|
167
|
+
print("smap_mm\t", timeit.timeit(lambda: smap_mm(A, B), number=10000))
|
168
|
+
print("smap_md\t", timeit.timeit(lambda: smap_md(A, B), number=10000))
|
169
|
+
print("smap_ii\t", timeit.timeit(lambda: smap_ii(A, B), number=10000))
|
170
|
+
print("smap_b\t", timeit.timeit(lambda: smap_b(A, B), number=10000))
|
171
|
+
print("smap_c\t", timeit.timeit(lambda: smap_c(A, B), number=10000))
|
ovld-0.3.9/doo.py
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from types import UnionType
|
3
|
+
|
4
|
+
from ovld import ovld
|
5
|
+
from ovld.core import OvldBase
|
6
|
+
|
7
|
+
|
8
|
+
class Poof[T]:
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class Flax(OvldBase):
|
13
|
+
@ovld
|
14
|
+
def f(self, x: object, y: type[Poof[object]]):
|
15
|
+
return 1234
|
16
|
+
|
17
|
+
def f(self, frm: int, to: type[int]):
|
18
|
+
return to(frm)
|
19
|
+
|
20
|
+
def f(self, frm: float, to: type[float]):
|
21
|
+
return to(frm)
|
22
|
+
|
23
|
+
def f(self, frm: str, to: type[str]):
|
24
|
+
return to(frm)
|
25
|
+
|
26
|
+
def f(self, frm: str, to: type[Enum]):
|
27
|
+
return to(frm)
|
28
|
+
|
29
|
+
def f(self, frm: object, to: UnionType):
|
30
|
+
for t in to.__args__:
|
31
|
+
try:
|
32
|
+
return self.deserialize(frm, t)
|
33
|
+
except TypeError:
|
34
|
+
continue
|
35
|
+
else:
|
36
|
+
return self.deserialize.next(frm, to)
|
37
|
+
|
38
|
+
def f(self, frm: dict, to: type[Poof[object]]):
|
39
|
+
model = self.model(to)
|
40
|
+
if model is NotImplemented:
|
41
|
+
return self.deserialize.next(frm, to)
|
42
|
+
else:
|
43
|
+
des = {
|
44
|
+
k: self.deserialize(v, model.fields_by_name[k].type)
|
45
|
+
for k, v in frm.items()
|
46
|
+
}
|
47
|
+
return model.builder(**des)
|
48
|
+
|
49
|
+
def f(self, frm: dict, to: type[object]):
|
50
|
+
model = self.model(to)
|
51
|
+
if model is NotImplemented:
|
52
|
+
return self.deserialize.next(frm, to)
|
53
|
+
else:
|
54
|
+
return self.deserialize(frm, model)
|
55
|
+
|
56
|
+
# def f(self, frm: dict, typ: Model):
|
57
|
+
# des = {k: self.deserialize(v, typ.fields_by_name[k].type) for k, v in frm.items()}
|
58
|
+
# return typ.builder(**des)
|
59
|
+
|
60
|
+
|
61
|
+
@ovld
|
62
|
+
def f(x: object, y: type[Poof[object]]):
|
63
|
+
return 12345
|
64
|
+
|
65
|
+
|
66
|
+
print(f(3, Poof[int]))
|
67
|
+
print(Flax().f(3, Poof[int]))
|
68
|
+
|
69
|
+
|
70
|
+
# print("=" * 80)
|
71
|
+
# print(compose_mro(list[int], {list[object]}, set()))
|
72
|
+
|
73
|
+
# print("=" * 80)
|
74
|
+
# print(compose_mro(Poof[int], {Poof[object]}, set()))
|
ovld-0.3.9/edges.py
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Protocol, runtime_checkable
|
3
|
+
|
4
|
+
from ovld import Dataclass, ovld
|
5
|
+
|
6
|
+
|
7
|
+
@runtime_checkable
|
8
|
+
class SupportsRead(Protocol):
|
9
|
+
def read(self, amount: int) -> bytes: ...
|
10
|
+
|
11
|
+
|
12
|
+
@runtime_checkable
|
13
|
+
class SupportsWrite(Protocol):
|
14
|
+
def write(self, amount: int) -> bytes: ...
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class Reader:
|
19
|
+
def read(self):
|
20
|
+
return 1
|
21
|
+
|
22
|
+
def write(self):
|
23
|
+
return 1
|
24
|
+
|
25
|
+
|
26
|
+
@dataclass
|
27
|
+
class Writer:
|
28
|
+
def write(self):
|
29
|
+
return 1
|
30
|
+
|
31
|
+
|
32
|
+
@ovld
|
33
|
+
def f(x: SupportsRead):
|
34
|
+
return "yes"
|
35
|
+
|
36
|
+
|
37
|
+
@ovld
|
38
|
+
def f(x: SupportsWrite):
|
39
|
+
return "yes"
|
40
|
+
|
41
|
+
|
42
|
+
# @ovld
|
43
|
+
# def f(x: Reader):
|
44
|
+
# return "R" + f.next(x)
|
45
|
+
|
46
|
+
|
47
|
+
@ovld # (priority=-1)
|
48
|
+
def f(x: Dataclass):
|
49
|
+
return "DC"
|
50
|
+
|
51
|
+
|
52
|
+
@ovld
|
53
|
+
def f(x: int):
|
54
|
+
return "w/e"
|
55
|
+
|
56
|
+
|
57
|
+
@ovld
|
58
|
+
def f(x):
|
59
|
+
return "no"
|
60
|
+
|
61
|
+
|
62
|
+
# print(f(1))
|
63
|
+
print(f(Reader()))
|
64
|
+
# print(f(Writer()))
|
ovld-0.3.9/explore.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# import dis
|
2
|
+
|
3
|
+
# z = 10
|
4
|
+
|
5
|
+
|
6
|
+
# def foo(x):
|
7
|
+
# def faf(y):
|
8
|
+
# return x + y + z
|
9
|
+
|
10
|
+
# return faf
|
11
|
+
|
12
|
+
|
13
|
+
# fn = foo(4)
|
14
|
+
|
15
|
+
# bytecode = dis.Bytecode(fn)
|
16
|
+
# print("=" * 80)
|
17
|
+
# for instr in bytecode:
|
18
|
+
# print(instr)
|
19
|
+
|
20
|
+
# breakpoint()
|
21
|
+
|
22
|
+
|
23
|
+
from wrapt import ObjectProxy
|
24
|
+
|
25
|
+
from ovld import ovld, recurse
|
26
|
+
|
27
|
+
|
28
|
+
class AnnotatedProxy(ObjectProxy):
|
29
|
+
def __init__(self, wrapped, **ann):
|
30
|
+
super().__init__(wrapped)
|
31
|
+
self._self_ann = ann
|
32
|
+
|
33
|
+
@property
|
34
|
+
def _(self):
|
35
|
+
return self._self_ann
|
36
|
+
|
37
|
+
|
38
|
+
# @ovld(priority=10)
|
39
|
+
# def f(x: object):
|
40
|
+
# return recurse.next(x)
|
41
|
+
|
42
|
+
|
43
|
+
@ovld
|
44
|
+
def f(xs: list):
|
45
|
+
return [recurse(x) for x in xs]
|
46
|
+
|
47
|
+
|
48
|
+
@ovld
|
49
|
+
def f(xs: dict):
|
50
|
+
return {recurse(k): recurse(v) for k, v in xs.items()}
|
51
|
+
|
52
|
+
|
53
|
+
@ovld
|
54
|
+
def f(x: str):
|
55
|
+
return x
|
56
|
+
|
57
|
+
|
58
|
+
@ovld
|
59
|
+
def f(x: int):
|
60
|
+
return x / 0
|
61
|
+
|
62
|
+
|
63
|
+
# # f({"a": [[[[1, 2, 3]]]]})
|
64
|
+
# # breakpoint()
|
65
|
+
# res = f({"a": [[[[1, 2, 3]]]]})
|
66
|
+
# print(res)
|
67
|
+
|
68
|
+
# data = {"a": 2}
|
69
|
+
# print(f(AnnotatedProxy(data, x=4)))
|
ovld-0.3.9/nxt.py
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
from .core import (
|
2
|
+
MultiTypeMap,
|
3
|
+
Ovld,
|
4
|
+
OvldBase,
|
5
|
+
OvldCall,
|
6
|
+
OvldMC,
|
7
|
+
TypeMap,
|
8
|
+
extend_super,
|
9
|
+
is_ovld,
|
10
|
+
ovld,
|
11
|
+
ovld_dispatch,
|
12
|
+
)
|
13
|
+
from .utils import (
|
14
|
+
BOOTSTRAP,
|
15
|
+
MISSING,
|
16
|
+
Dataclass,
|
17
|
+
Named,
|
18
|
+
deferred,
|
19
|
+
exactly,
|
20
|
+
has_attribute,
|
21
|
+
keyword_decorator,
|
22
|
+
meta,
|
23
|
+
strict_subclass,
|
24
|
+
)
|
25
|
+
from .version import version as __version__
|
26
|
+
|
27
|
+
__all__ = [
|
28
|
+
"MultiTypeMap",
|
29
|
+
"Ovld",
|
30
|
+
"OvldBase",
|
31
|
+
"OvldCall",
|
32
|
+
"OvldMC",
|
33
|
+
"TypeMap",
|
34
|
+
"extend_super",
|
35
|
+
"is_ovld",
|
36
|
+
"ovld",
|
37
|
+
"ovld_dispatch",
|
38
|
+
"BOOTSTRAP",
|
39
|
+
"MISSING",
|
40
|
+
"Dataclass",
|
41
|
+
"Named",
|
42
|
+
"deferred",
|
43
|
+
"exactly",
|
44
|
+
"has_attribute",
|
45
|
+
"meta",
|
46
|
+
"keyword_decorator",
|
47
|
+
"strict_subclass",
|
48
|
+
]
|