ovld 0.4.0__py3-none-any.whl → 0.4.2__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/__init__.py +1 -0
- ovld/core.py +12 -9
- ovld/mro.py +27 -6
- ovld/recode.py +7 -5
- ovld/typemap.py +48 -21
- ovld/version.py +1 -1
- {ovld-0.4.0.dist-info → ovld-0.4.2.dist-info}/METADATA +4 -1
- ovld-0.4.2.dist-info/RECORD +13 -0
- ovld-0.4.0.dist-info/RECORD +0 -13
- {ovld-0.4.0.dist-info → ovld-0.4.2.dist-info}/WHEEL +0 -0
- {ovld-0.4.0.dist-info → ovld-0.4.2.dist-info}/licenses/LICENSE +0 -0
ovld/__init__.py
CHANGED
ovld/core.py
CHANGED
@@ -20,12 +20,6 @@ from .typemap import MultiTypeMap, is_type_of_type
|
|
20
20
|
from .types import normalize_type
|
21
21
|
from .utils import UsageError, keyword_decorator
|
22
22
|
|
23
|
-
try:
|
24
|
-
from types import UnionType
|
25
|
-
except ImportError: # pragma: no cover
|
26
|
-
UnionType = None
|
27
|
-
|
28
|
-
|
29
23
|
_current_id = itertools.count()
|
30
24
|
|
31
25
|
|
@@ -91,6 +85,7 @@ class Signature:
|
|
91
85
|
req_names: frozenset
|
92
86
|
vararg: bool
|
93
87
|
priority: float
|
88
|
+
tiebreak: int = 0
|
94
89
|
is_method: bool = False
|
95
90
|
arginfo: list[Arginfo] = field(
|
96
91
|
default_factory=list, hash=False, compare=False
|
@@ -399,8 +394,8 @@ class _Ovld:
|
|
399
394
|
)
|
400
395
|
else:
|
401
396
|
hlp = ""
|
402
|
-
for
|
403
|
-
hlp += f"* {
|
397
|
+
for c in possibilities:
|
398
|
+
hlp += f"* {c.handler.__name__} (priority: {c.priority}, specificity: {list(c.specificity)})\n"
|
404
399
|
return TypeError(
|
405
400
|
f"Ambiguous resolution in {self} for"
|
406
401
|
f" argument types [{typenames}]\n"
|
@@ -509,7 +504,15 @@ class _Ovld:
|
|
509
504
|
raise TypeError(
|
510
505
|
f"There is already a method for {sigstring(sig.types)}"
|
511
506
|
)
|
512
|
-
|
507
|
+
|
508
|
+
def _set(sig, fn):
|
509
|
+
if sig in self._defns:
|
510
|
+
# Push down the existing handler with a lower tiebreak
|
511
|
+
msig = replace(sig, tiebreak=sig.tiebreak - 1)
|
512
|
+
_set(msig, self._defns[sig])
|
513
|
+
self._defns[sig] = fn
|
514
|
+
|
515
|
+
_set(sig, fn)
|
513
516
|
|
514
517
|
self._update()
|
515
518
|
return self
|
ovld/mro.py
CHANGED
@@ -25,6 +25,16 @@ class TypeRelationship:
|
|
25
25
|
matches: bool = None
|
26
26
|
|
27
27
|
|
28
|
+
def _issubclass(t1, t2):
|
29
|
+
try:
|
30
|
+
return issubclass(t1, t2)
|
31
|
+
except TypeError:
|
32
|
+
try:
|
33
|
+
return isinstance(t1, t2)
|
34
|
+
except TypeError: # pragma: no cover
|
35
|
+
return False
|
36
|
+
|
37
|
+
|
28
38
|
def typeorder(t1, t2):
|
29
39
|
"""Order relation between two types.
|
30
40
|
|
@@ -56,6 +66,8 @@ def typeorder(t1, t2):
|
|
56
66
|
o2 = getattr(t2, "__origin__", None)
|
57
67
|
|
58
68
|
if o2 is typing.Union:
|
69
|
+
if t1 is typing.Union:
|
70
|
+
return Order.MORE
|
59
71
|
compare = [
|
60
72
|
x for t in t2.__args__ if (x := typeorder(t1, t)) is not Order.NONE
|
61
73
|
]
|
@@ -105,8 +117,8 @@ def typeorder(t1, t2):
|
|
105
117
|
# Not sure when t1 != t2 and that happens
|
106
118
|
return Order.SAME
|
107
119
|
|
108
|
-
sx =
|
109
|
-
sy =
|
120
|
+
sx = _issubclass(t1, t2)
|
121
|
+
sy = _issubclass(t2, t1)
|
110
122
|
if sx and sy: # pragma: no cover
|
111
123
|
# Not sure when t1 != t2 and that happens
|
112
124
|
return Order.SAME
|
@@ -136,14 +148,23 @@ def subclasscheck(t1, t2):
|
|
136
148
|
o2 = getattr(t2, "__origin__", None)
|
137
149
|
|
138
150
|
if o2 is typing.Union:
|
139
|
-
return
|
151
|
+
return t1 is typing.Union or any(
|
152
|
+
subclasscheck(t1, t) for t in t2.__args__
|
153
|
+
)
|
140
154
|
elif o1 is typing.Union:
|
141
|
-
return
|
155
|
+
return t2 is typing.Union or all(
|
156
|
+
subclasscheck(t, t2) for t in t1.__args__
|
157
|
+
)
|
158
|
+
|
159
|
+
if not isinstance(o1, type):
|
160
|
+
o1 = None
|
161
|
+
if not isinstance(o2, type):
|
162
|
+
o2 = None
|
142
163
|
|
143
164
|
if o1 or o2:
|
144
165
|
o1 = o1 or t1
|
145
166
|
o2 = o2 or t2
|
146
|
-
if
|
167
|
+
if _issubclass(o1, o2):
|
147
168
|
if o2 is t2: # pragma: no cover
|
148
169
|
return True
|
149
170
|
else:
|
@@ -157,7 +178,7 @@ def subclasscheck(t1, t2):
|
|
157
178
|
else:
|
158
179
|
return False
|
159
180
|
else:
|
160
|
-
return
|
181
|
+
return _issubclass(t1, t2)
|
161
182
|
|
162
183
|
|
163
184
|
def sort_types(cls, avail):
|
ovld/recode.py
CHANGED
@@ -373,6 +373,7 @@ class NameConverter(ast.NodeTransformer):
|
|
373
373
|
self.call_next_sym = call_next_sym
|
374
374
|
self.ovld_mangled = ovld_mangled
|
375
375
|
self.code_mangled = code_mangled
|
376
|
+
self.count = count()
|
376
377
|
|
377
378
|
def visit_Name(self, node):
|
378
379
|
if node.id == self.recurse_sym:
|
@@ -396,15 +397,16 @@ class NameConverter(ast.NodeTransformer):
|
|
396
397
|
return self.generic_visit(node)
|
397
398
|
|
398
399
|
cn = node.func.id == self.call_next_sym
|
400
|
+
tmp = f"__TMP{next(self.count)}_"
|
399
401
|
|
400
402
|
def _make_lookup_call(key, arg):
|
401
403
|
value = ast.NamedExpr(
|
402
|
-
target=ast.Name(id=f"
|
404
|
+
target=ast.Name(id=f"{tmp}{key}", ctx=ast.Store()),
|
403
405
|
value=self.visit(arg),
|
404
406
|
)
|
405
407
|
if self.analysis.lookup_for(key) == "self.map.transform":
|
406
408
|
func = ast.Attribute(
|
407
|
-
value=ast.Name(id="
|
409
|
+
value=ast.Name(id=f"{tmp}M", ctx=ast.Load()),
|
408
410
|
attr="transform",
|
409
411
|
ctx=ast.Load(),
|
410
412
|
)
|
@@ -437,7 +439,7 @@ class NameConverter(ast.NodeTransformer):
|
|
437
439
|
type_parts.insert(0, ast.Name(id=self.code_mangled, ctx=ast.Load()))
|
438
440
|
method = ast.Subscript(
|
439
441
|
value=ast.NamedExpr(
|
440
|
-
target=ast.Name(id="
|
442
|
+
target=ast.Name(id=f"{tmp}M", ctx=ast.Store()),
|
441
443
|
value=ast.Attribute(
|
442
444
|
value=ast.Name(id=self.ovld_mangled, ctx=ast.Load()),
|
443
445
|
attr="map",
|
@@ -464,13 +466,13 @@ class NameConverter(ast.NodeTransformer):
|
|
464
466
|
new_node = ast.Call(
|
465
467
|
func=method,
|
466
468
|
args=[
|
467
|
-
ast.Name(id=f"
|
469
|
+
ast.Name(id=f"{tmp}{i}", ctx=ast.Load())
|
468
470
|
for i, arg in enumerate(node.args)
|
469
471
|
],
|
470
472
|
keywords=[
|
471
473
|
ast.keyword(
|
472
474
|
arg=kw.arg,
|
473
|
-
value=ast.Name(id=f"
|
475
|
+
value=ast.Name(id=f"{tmp}{kw.arg}", ctx=ast.Load()),
|
474
476
|
)
|
475
477
|
for kw in node.keywords
|
476
478
|
],
|
ovld/typemap.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import inspect
|
2
2
|
import math
|
3
3
|
import typing
|
4
|
+
from dataclasses import dataclass
|
4
5
|
from itertools import count
|
5
6
|
from types import CodeType
|
6
7
|
|
@@ -69,6 +70,27 @@ class TypeMap(dict):
|
|
69
70
|
raise KeyError(obj_t)
|
70
71
|
|
71
72
|
|
73
|
+
@dataclass
|
74
|
+
class Candidate:
|
75
|
+
handler: object
|
76
|
+
priority: float
|
77
|
+
specificity: tuple
|
78
|
+
tiebreak: int
|
79
|
+
|
80
|
+
def sort_key(self):
|
81
|
+
return self.priority, sum(self.specificity), self.tiebreak
|
82
|
+
|
83
|
+
def dominates(self, other):
|
84
|
+
if self.priority > other.priority:
|
85
|
+
return True
|
86
|
+
elif self.specificity != other.specificity:
|
87
|
+
return all(
|
88
|
+
s1 >= s2 for s1, s2 in zip(self.specificity, other.specificity)
|
89
|
+
)
|
90
|
+
else:
|
91
|
+
return self.tiebreak > other.tiebreak
|
92
|
+
|
93
|
+
|
72
94
|
class MultiTypeMap(dict):
|
73
95
|
"""Represents a mapping from tuples of types to handlers.
|
74
96
|
|
@@ -91,6 +113,7 @@ class MultiTypeMap(dict):
|
|
91
113
|
def __init__(self, name="_ovld", key_error=KeyError):
|
92
114
|
self.maps = {}
|
93
115
|
self.priorities = {}
|
116
|
+
self.tiebreaks = {}
|
94
117
|
self.dependent = {}
|
95
118
|
self.type_tuples = {}
|
96
119
|
self.empty = MISSING
|
@@ -155,7 +178,12 @@ class MultiTypeMap(dict):
|
|
155
178
|
specificities.setdefault(c, []).append(results[c])
|
156
179
|
|
157
180
|
candidates = [
|
158
|
-
(
|
181
|
+
Candidate(
|
182
|
+
handler=c,
|
183
|
+
priority=self.priorities.get(c, 0),
|
184
|
+
specificity=tuple(specificities[c]),
|
185
|
+
tiebreak=self.tiebreaks.get(c, 0),
|
186
|
+
)
|
159
187
|
for c in candidates
|
160
188
|
]
|
161
189
|
|
@@ -164,33 +192,30 @@ class MultiTypeMap(dict):
|
|
164
192
|
# other possibilities on all arguments, so the sum of all specificities
|
165
193
|
# has to be greater.
|
166
194
|
# Note: priority is always more important than specificity
|
167
|
-
|
195
|
+
|
196
|
+
candidates.sort(key=Candidate.sort_key, reverse=True)
|
168
197
|
|
169
198
|
self.all[obj_t_tup] = {
|
170
|
-
getattr(c
|
199
|
+
getattr(c.handler, "__code__", None) for c in candidates
|
171
200
|
}
|
172
201
|
|
173
202
|
processed = set()
|
174
203
|
|
175
204
|
def _pull(candidates):
|
176
|
-
candidates = [
|
177
|
-
(c, a, b) for (c, a, b) in candidates if c not in processed
|
178
|
-
]
|
205
|
+
candidates = [c for c in candidates if c.handler not in processed]
|
179
206
|
if not candidates:
|
180
207
|
return
|
181
208
|
rval = [candidates[0]]
|
182
|
-
c1
|
183
|
-
for c2
|
184
|
-
if
|
185
|
-
spc1 != spc2 and all(s1 >= s2 for s1, s2 in zip(spc1, spc2))
|
186
|
-
):
|
209
|
+
c1 = candidates[0]
|
210
|
+
for c2 in candidates[1:]:
|
211
|
+
if c1.dominates(c2):
|
187
212
|
# Candidate 1 dominates candidate 2
|
188
213
|
continue
|
189
214
|
else:
|
190
|
-
processed.add(c2)
|
215
|
+
processed.add(c2.handler)
|
191
216
|
# Candidate 1 does not dominate candidate 2, so we add it
|
192
217
|
# to the list.
|
193
|
-
rval.append(
|
218
|
+
rval.append(c2)
|
194
219
|
yield rval
|
195
220
|
if len(rval) >= 1:
|
196
221
|
yield from _pull(candidates[1:])
|
@@ -212,6 +237,7 @@ class MultiTypeMap(dict):
|
|
212
237
|
self.empty = entry
|
213
238
|
|
214
239
|
self.priorities[handler] = sig.priority
|
240
|
+
self.tiebreaks[handler] = sig.tiebreak
|
215
241
|
self.type_tuples[handler] = obj_t_tup
|
216
242
|
self.dependent[handler] = any(
|
217
243
|
isinstance(t[1] if isinstance(t, tuple) else t, DependentType)
|
@@ -257,15 +283,16 @@ class MultiTypeMap(dict):
|
|
257
283
|
finished = False
|
258
284
|
rank = 1
|
259
285
|
for grp in self.mro(tuple(argt)):
|
260
|
-
grp.sort(key=lambda x: x
|
286
|
+
grp.sort(key=lambda x: x.handler.__name__)
|
261
287
|
match = [
|
262
288
|
dependent_match(
|
263
|
-
self.type_tuples[handler], [*args, *kwargs.items()]
|
289
|
+
self.type_tuples[c.handler], [*args, *kwargs.items()]
|
264
290
|
)
|
265
|
-
for
|
291
|
+
for c in grp
|
266
292
|
]
|
267
293
|
ambiguous = len([m for m in match if m]) > 1
|
268
|
-
for m,
|
294
|
+
for m, c in zip(match, grp):
|
295
|
+
handler = c.handler
|
269
296
|
color = "\033[0m"
|
270
297
|
if finished:
|
271
298
|
bullet = "--"
|
@@ -282,8 +309,8 @@ class MultiTypeMap(dict):
|
|
282
309
|
message = f"{handler.__name__} will be called first."
|
283
310
|
color = "\033[1;32m"
|
284
311
|
rank += 1
|
285
|
-
spec = ".".join(map(str,
|
286
|
-
lvl = f"[{
|
312
|
+
spec = ".".join(map(str, c.specificity))
|
313
|
+
lvl = f"[{c.priority}:{spec}]"
|
287
314
|
width = 2 * len(args) + 6
|
288
315
|
print(f"{color}{bullet} {lvl:{width}} {handler.__name__}")
|
289
316
|
co = handler.__code__
|
@@ -320,8 +347,8 @@ class MultiTypeMap(dict):
|
|
320
347
|
|
321
348
|
funcs = []
|
322
349
|
for group in reversed(results):
|
323
|
-
handlers = [
|
324
|
-
dependent = any(self.dependent[
|
350
|
+
handlers = [c.handler for c in group]
|
351
|
+
dependent = any(self.dependent[c.handler] for c in group)
|
325
352
|
if dependent:
|
326
353
|
nxt = self.wrap_dependent(
|
327
354
|
obj_t_tup, handlers, group, funcs[-1] if funcs else None
|
ovld/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "0.4.
|
1
|
+
version = "0.4.2"
|
@@ -1,7 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: ovld
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.2
|
4
4
|
Summary: Overloading Python functions
|
5
|
+
Project-URL: Homepage, https://ovld.readthedocs.io/en/latest/
|
6
|
+
Project-URL: Documentation, https://ovld.readthedocs.io/en/latest/
|
7
|
+
Project-URL: Repository, https://github.com/breuleux/ovld
|
5
8
|
Author-email: Olivier Breuleux <breuleux@gmail.com>
|
6
9
|
License-Expression: MIT
|
7
10
|
License-File: LICENSE
|
@@ -0,0 +1,13 @@
|
|
1
|
+
ovld/__init__.py,sha256=Vp9wbIy_opFmJx-vCcToQcIP3cWFIvgbfYHITyiwPLs,1305
|
2
|
+
ovld/core.py,sha256=glexOiRU0ajoxFAQN6d69ToL6_cPvyv05Z7LEHqrJj8,25701
|
3
|
+
ovld/dependent.py,sha256=QITsWu2uCwqkHE0tunETy8Jqwc272uoG5YM0I5yy0m4,7303
|
4
|
+
ovld/mro.py,sha256=rS0pCLLWwLUI0NdthpoJSrdvWR4-XgRfx1pLAvJde14,5586
|
5
|
+
ovld/recode.py,sha256=zxhyotuc73qzuN4NEN_rKxaqoA0SOH7KFtE2l_CRBFs,17963
|
6
|
+
ovld/typemap.py,sha256=gw8XvB-N_15Dr0-am0v17x1seNjYK5AxvUT9L36mWic,13630
|
7
|
+
ovld/types.py,sha256=Zeb7xhHbL4T7qIRHI-I_cjG61UIWrfZv_EwjwqhB-rY,6381
|
8
|
+
ovld/utils.py,sha256=V6Y8oZ6ojq8JaODL1rMZbU5L9QG0YSqHNYmpIFiwy3M,1294
|
9
|
+
ovld/version.py,sha256=OHlqRD04Kvw_CFYmiIVx7UuOJRTQKtAx1Bl4rkUYHJE,18
|
10
|
+
ovld-0.4.2.dist-info/METADATA,sha256=fV3vxTKRAjCUkRVNmzTW14VajGSl7P0b9NnG06cjUJk,7713
|
11
|
+
ovld-0.4.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
12
|
+
ovld-0.4.2.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
|
13
|
+
ovld-0.4.2.dist-info/RECORD,,
|
ovld-0.4.0.dist-info/RECORD
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
ovld/__init__.py,sha256=nF8ymgr8dSL2WvDpOXVxqDuEGUywbkiCGr4ICumMD8U,1286
|
2
|
-
ovld/core.py,sha256=siahCDuw78n02-2g7TGI1GerrGvPxT0zPouN6Z30Z-g,25497
|
3
|
-
ovld/dependent.py,sha256=QITsWu2uCwqkHE0tunETy8Jqwc272uoG5YM0I5yy0m4,7303
|
4
|
-
ovld/mro.py,sha256=dNuVW5DIOT8TJtY4vEpxT4q3R8fQxJ8UyDQSD9oFYYo,5116
|
5
|
-
ovld/recode.py,sha256=Vc97Nv1j2GWuitLOzIuIhpscZ4gaOJQP3hLNp8SGTQ8,17890
|
6
|
-
ovld/typemap.py,sha256=U_BmXtts1oYVa6gI3cgGHMX5kFcCJY_mt_cjWvDo3jQ,12979
|
7
|
-
ovld/types.py,sha256=Zeb7xhHbL4T7qIRHI-I_cjG61UIWrfZv_EwjwqhB-rY,6381
|
8
|
-
ovld/utils.py,sha256=V6Y8oZ6ojq8JaODL1rMZbU5L9QG0YSqHNYmpIFiwy3M,1294
|
9
|
-
ovld/version.py,sha256=yhiWOz0HoJGRRI9-JQ2eh_0AbByy-6psK08-kpTSHJw,18
|
10
|
-
ovld-0.4.0.dist-info/METADATA,sha256=4NkzmXbqa8ZNCwESYT4U8yILZyaIlw1rcghfCyaT50U,7526
|
11
|
-
ovld-0.4.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
12
|
-
ovld-0.4.0.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
|
13
|
-
ovld-0.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|