ovld 0.5.0__py3-none-any.whl → 0.5.1__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/codegen.py +5 -2
- ovld/core.py +16 -14
- ovld/medley.py +44 -36
- ovld/recode.py +2 -5
- ovld/utils.py +4 -0
- ovld/version.py +1 -1
- {ovld-0.5.0.dist-info → ovld-0.5.1.dist-info}/METADATA +1 -1
- ovld-0.5.1.dist-info/RECORD +18 -0
- ovld-0.5.0.dist-info/RECORD +0 -18
- {ovld-0.5.0.dist-info → ovld-0.5.1.dist-info}/WHEEL +0 -0
- {ovld-0.5.0.dist-info → ovld-0.5.1.dist-info}/licenses/LICENSE +0 -0
ovld/codegen.py
CHANGED
@@ -6,7 +6,7 @@ from ast import _splitlines_no_ff as splitlines
|
|
6
6
|
from itertools import count
|
7
7
|
from types import FunctionType
|
8
8
|
|
9
|
-
from .utils import MISSING, NameDatabase, sigstring
|
9
|
+
from .utils import MISSING, NameDatabase, keyword_decorator, sigstring
|
10
10
|
|
11
11
|
_current = count()
|
12
12
|
|
@@ -298,6 +298,9 @@ def codegen_specializer(typemap, fn, tup):
|
|
298
298
|
return func
|
299
299
|
|
300
300
|
|
301
|
-
|
301
|
+
@keyword_decorator
|
302
|
+
def code_generator(fn, priority=0):
|
302
303
|
fn.specializer = codegen_specializer
|
304
|
+
if priority:
|
305
|
+
fn.priority = priority
|
303
306
|
return fn
|
ovld/core.py
CHANGED
@@ -18,6 +18,7 @@ from .signatures import ArgumentAnalyzer, LazySignature, Signature
|
|
18
18
|
from .typemap import MultiTypeMap
|
19
19
|
from .utils import (
|
20
20
|
MISSING,
|
21
|
+
ResolutionError,
|
21
22
|
UsageError,
|
22
23
|
keyword_decorator,
|
23
24
|
sigstring,
|
@@ -51,6 +52,7 @@ def bootstrap_dispatch(ov, name):
|
|
51
52
|
dispatch.add_mixins = ov.add_mixins
|
52
53
|
dispatch.unregister = ov.unregister
|
53
54
|
dispatch.next = ov.next
|
55
|
+
dispatch.first_entry = first_entry
|
54
56
|
return dispatch
|
55
57
|
|
56
58
|
|
@@ -95,6 +97,7 @@ class Ovld:
|
|
95
97
|
self._locked = False
|
96
98
|
self.mixins = []
|
97
99
|
self.argument_analysis = ArgumentAnalyzer()
|
100
|
+
self.dispatch = bootstrap_dispatch(self, name=self.shortname)
|
98
101
|
self.add_mixins(*mixins)
|
99
102
|
|
100
103
|
@property
|
@@ -162,12 +165,12 @@ class Ovld:
|
|
162
165
|
def _key_error(self, key, possibilities=None):
|
163
166
|
typenames = sigstring(key)
|
164
167
|
if not possibilities:
|
165
|
-
return
|
168
|
+
return ResolutionError(f"No method in {self} for argument types [{typenames}]")
|
166
169
|
else:
|
167
170
|
hlp = ""
|
168
171
|
for c in possibilities:
|
169
172
|
hlp += f"* {c.handler.__name__} (priority: {c.priority}, specificity: {list(c.specificity)})\n"
|
170
|
-
return
|
173
|
+
return ResolutionError(
|
171
174
|
f"Ambiguous resolution in {self} for"
|
172
175
|
f" argument types [{typenames}]\n"
|
173
176
|
f"Candidates are:\n{hlp}"
|
@@ -176,10 +179,11 @@ class Ovld:
|
|
176
179
|
|
177
180
|
def rename(self, name, shortname=None):
|
178
181
|
"""Rename this Ovld."""
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
182
|
+
if name != self.name:
|
183
|
+
self.name = name
|
184
|
+
self.shortname = shortname or name
|
185
|
+
self.__name__ = self.shortname
|
186
|
+
self.dispatch = bootstrap_dispatch(self, name=self.shortname)
|
183
187
|
|
184
188
|
def __set_name__(self, inst, name):
|
185
189
|
self.rename(name)
|
@@ -217,8 +221,6 @@ class Ovld:
|
|
217
221
|
|
218
222
|
self.analyze_arguments()
|
219
223
|
dispatch = generate_dispatch(self, self.argument_analysis)
|
220
|
-
if not hasattr(self, "dispatch"):
|
221
|
-
self.dispatch = bootstrap_dispatch(self, name=self.shortname)
|
222
224
|
self.dispatch.__code__ = rename_code(dispatch.__code__, self.shortname)
|
223
225
|
self.dispatch.__kwdefaults__ = dispatch.__kwdefaults__
|
224
226
|
self.dispatch.__annotations__ = dispatch.__annotations__
|
@@ -258,6 +260,7 @@ class Ovld:
|
|
258
260
|
"""Register a function."""
|
259
261
|
if fn is None:
|
260
262
|
return partial(self._register, priority=priority)
|
263
|
+
priority = getattr(fn, "priority", priority)
|
261
264
|
return self._register(fn, priority)
|
262
265
|
|
263
266
|
def _register(self, fn, priority):
|
@@ -290,13 +293,16 @@ class Ovld:
|
|
290
293
|
self._update()
|
291
294
|
|
292
295
|
def _update(self):
|
293
|
-
|
294
|
-
self.compile()
|
296
|
+
self.reset()
|
295
297
|
for child in self.children:
|
296
298
|
child._update()
|
297
299
|
if hasattr(self, "dispatch"):
|
298
300
|
self.dispatch.__doc__ = self.mkdoc()
|
299
301
|
|
302
|
+
def reset(self):
|
303
|
+
self._compiled = False
|
304
|
+
self.dispatch.__code__ = self.dispatch.first_entry.__code__
|
305
|
+
|
300
306
|
def copy(self, mixins=[], linkback=False):
|
301
307
|
"""Create a copy of this Ovld.
|
302
308
|
|
@@ -319,8 +325,6 @@ class Ovld:
|
|
319
325
|
return ov
|
320
326
|
|
321
327
|
def __get__(self, obj, cls):
|
322
|
-
if not self._compiled:
|
323
|
-
self.compile()
|
324
328
|
return self.dispatch.__get__(obj, cls)
|
325
329
|
|
326
330
|
def __call__(self, *args, **kwargs): # pragma: no cover
|
@@ -328,8 +332,6 @@ class Ovld:
|
|
328
332
|
|
329
333
|
This should be replaced by an auto-generated function.
|
330
334
|
"""
|
331
|
-
if not self._compiled:
|
332
|
-
self.compile()
|
333
335
|
return self.dispatch(*args, **kwargs)
|
334
336
|
|
335
337
|
def next(self, *args):
|
ovld/medley.py
CHANGED
@@ -110,7 +110,7 @@ class ChainAll(ImplList):
|
|
110
110
|
class BuildOvld(Combiner):
|
111
111
|
def __init__(self, field=None, ovld=None):
|
112
112
|
super().__init__(field)
|
113
|
-
self.ovld = ovld or Ovld(linkback=True)
|
113
|
+
self.ovld = ovld or Ovld(name=field, linkback=True)
|
114
114
|
self.pending = []
|
115
115
|
if field is not None:
|
116
116
|
self.__set_name__(None, field)
|
@@ -125,7 +125,7 @@ class BuildOvld(Combiner):
|
|
125
125
|
self.pending.clear()
|
126
126
|
if not self.ovld.defns:
|
127
127
|
return ABSENT
|
128
|
-
self.ovld.
|
128
|
+
self.ovld.reset()
|
129
129
|
return self.ovld.dispatch
|
130
130
|
|
131
131
|
def copy(self):
|
@@ -144,10 +144,14 @@ class BuildOvld(Combiner):
|
|
144
144
|
|
145
145
|
|
146
146
|
class medley_cls_dict(dict):
|
147
|
-
def __init__(self, bases):
|
147
|
+
def __init__(self, bases, default_combiner=None):
|
148
|
+
if default_combiner is None:
|
149
|
+
(default_combiner,) = {b._ovld_default_combiner for b in bases}
|
148
150
|
super().__init__()
|
149
151
|
self._combiners = {}
|
152
|
+
self._default_combiner = default_combiner
|
150
153
|
self.set_direct("_ovld_combiners", self._combiners)
|
154
|
+
self.set_direct("_ovld_default_combiner", default_combiner)
|
151
155
|
self._basic = set()
|
152
156
|
for base in bases:
|
153
157
|
for attr, combiner in getattr(base, "_ovld_combiners", {}).items():
|
@@ -175,7 +179,7 @@ class medley_cls_dict(dict):
|
|
175
179
|
combiner = self._combiners.get(attr, None)
|
176
180
|
if combiner is None:
|
177
181
|
if inspect.isfunction(value) or isinstance(value, Ovld):
|
178
|
-
combiner =
|
182
|
+
combiner = self._default_combiner(attr)
|
179
183
|
else:
|
180
184
|
combiner = KeepLast(attr)
|
181
185
|
self._combiners[attr] = combiner
|
@@ -207,6 +211,19 @@ def specialize(cls, key):
|
|
207
211
|
return new_t
|
208
212
|
|
209
213
|
|
214
|
+
def remap_field(dc_field, require_default=False):
|
215
|
+
if require_default:
|
216
|
+
if dc_field.default is MISSING:
|
217
|
+
# NOTE: we do not accept default_factory, because we need the default value to be set
|
218
|
+
# in the class so that existing instances of classes[0] can see it.
|
219
|
+
raise TypeError(
|
220
|
+
f"Dataclass field '{dc_field.name}' must have a default value (not a default_factory) in order to be melded in."
|
221
|
+
)
|
222
|
+
dc_field = copy(dc_field)
|
223
|
+
dc_field.kw_only = True
|
224
|
+
return dc_field
|
225
|
+
|
226
|
+
|
210
227
|
class MedleyMC(type):
|
211
228
|
def __subclasscheck__(cls, subclass):
|
212
229
|
if getattr(cls, "_ovld_medleys", None):
|
@@ -214,10 +231,10 @@ class MedleyMC(type):
|
|
214
231
|
return super().__subclasscheck__(subclass)
|
215
232
|
|
216
233
|
@classmethod
|
217
|
-
def __prepare__(mcls, name, bases):
|
218
|
-
return medley_cls_dict(bases)
|
234
|
+
def __prepare__(mcls, name, bases, default_combiner=None):
|
235
|
+
return medley_cls_dict(bases, default_combiner=default_combiner)
|
219
236
|
|
220
|
-
def __new__(mcls, name, bases, namespace):
|
237
|
+
def __new__(mcls, name, bases, namespace, default_combiner=None):
|
221
238
|
result = super().__new__(mcls, name, bases, namespace)
|
222
239
|
for attr, combiner in result._ovld_combiners.items():
|
223
240
|
if (value := combiner.get(result)) is not ABSENT:
|
@@ -236,13 +253,16 @@ class MedleyMC(type):
|
|
236
253
|
]
|
237
254
|
return dc
|
238
255
|
|
239
|
-
def extend(cls, *others):
|
240
|
-
if not others:
|
256
|
+
def extend(cls, *others, extend_subclasses=True):
|
257
|
+
if not others: # pragma: no cover
|
241
258
|
return cls
|
242
|
-
|
259
|
+
all_fields = [(f.name, f.type, f) for f in fields(cls)]
|
260
|
+
for other in others:
|
261
|
+
all_fields += [(f.name, f.type, remap_field(f, True)) for f in fields(other)]
|
262
|
+
melded = make_dataclass("_", fields=all_fields)
|
243
263
|
for other in others:
|
244
264
|
for k, v in vars(other).items():
|
245
|
-
if k in ["__module__", "__firstlineno__"]:
|
265
|
+
if k in ["__module__", "__firstlineno__", "__static_attributes__"]:
|
246
266
|
continue
|
247
267
|
elif comb := cls._ovld_combiners.get(k):
|
248
268
|
comb.juxtapose(v)
|
@@ -250,9 +270,10 @@ class MedleyMC(type):
|
|
250
270
|
elif not k.startswith("_ovld_") and not k.startswith("__"):
|
251
271
|
setattr(cls, k, v)
|
252
272
|
cls.__init__ = melded.__init__
|
253
|
-
|
254
|
-
|
255
|
-
|
273
|
+
if extend_subclasses:
|
274
|
+
for subcls in cls.__subclasses__():
|
275
|
+
subothers = [o for o in others if not issubclass(subcls, o)]
|
276
|
+
subcls.extend(*subothers, extend_subclasses=False)
|
256
277
|
return cls
|
257
278
|
|
258
279
|
def __add__(cls, other):
|
@@ -290,7 +311,7 @@ def use_combiner(combiner):
|
|
290
311
|
return deco
|
291
312
|
|
292
313
|
|
293
|
-
class Medley(metaclass=MedleyMC):
|
314
|
+
class Medley(metaclass=MedleyMC, default_combiner=BuildOvld):
|
294
315
|
__post_init__ = RunAll()
|
295
316
|
__add__ = KeepLast()
|
296
317
|
__sub__ = KeepLast()
|
@@ -313,13 +334,10 @@ def unmeld_classes(main: type, exclude: type):
|
|
313
334
|
_meld_classes_cache = {}
|
314
335
|
|
315
336
|
|
316
|
-
def meld_classes(classes
|
337
|
+
def meld_classes(classes):
|
317
338
|
medleys = {}
|
318
|
-
for
|
319
|
-
|
320
|
-
medleys[cls] = True
|
321
|
-
else:
|
322
|
-
medleys.update({x: True for x in getattr(cls, "_ovld_medleys", [cls])})
|
339
|
+
for cls in classes:
|
340
|
+
medleys.update({x: True for x in getattr(cls, "_ovld_medleys", [cls])})
|
323
341
|
for cls in classes:
|
324
342
|
if not hasattr(cls, "_ovld_medleys"):
|
325
343
|
for base in cls.mro():
|
@@ -329,36 +347,26 @@ def meld_classes(classes, require_defaults=False):
|
|
329
347
|
if len(medleys) == 1:
|
330
348
|
return medleys[0]
|
331
349
|
|
332
|
-
cache_key =
|
350
|
+
cache_key = medleys
|
333
351
|
if cache_key in _meld_classes_cache:
|
334
352
|
return _meld_classes_cache[cache_key]
|
335
353
|
|
336
|
-
def remap_field(dc_field, require_default):
|
337
|
-
if require_default:
|
338
|
-
if dc_field.default is MISSING:
|
339
|
-
# NOTE: we do not accept default_factory, because we need the default value to be set
|
340
|
-
# in the class so that existing instances of classes[0] can see it.
|
341
|
-
raise TypeError(
|
342
|
-
f"Dataclass field '{dc_field.name}' must have a default value (not a default_factory) in order to be melded in."
|
343
|
-
)
|
344
|
-
dc_field = copy(dc_field)
|
345
|
-
dc_field.kw_only = True
|
346
|
-
return dc_field
|
347
|
-
|
348
354
|
cg_fields = set()
|
349
355
|
dc_fields = []
|
350
356
|
|
351
357
|
for base in medleys:
|
352
|
-
rqdef = require_defaults and base is not medleys[0]
|
353
358
|
cg_fields.update(base._ovld_codegen_fields)
|
354
359
|
dc_fields.extend(
|
355
|
-
(f.name, f.type, remap_field(f
|
360
|
+
(f.name, f.type, remap_field(f)) for f in base.__dataclass_fields__.values()
|
356
361
|
)
|
357
362
|
|
358
363
|
merged = medley_cls_dict(medleys)
|
359
364
|
merged.set_direct("_ovld_codegen_fields", tuple(cg_fields))
|
360
365
|
merged.set_direct("_ovld_medleys", tuple(medleys))
|
361
366
|
|
367
|
+
if "__qualname__" in merged._combiners:
|
368
|
+
del merged._combiners["__qualname__"]
|
369
|
+
|
362
370
|
result = make_dataclass(
|
363
371
|
cls_name="+".join(sorted(c.__name__ for c in medleys)),
|
364
372
|
bases=tuple(medleys),
|
ovld/recode.py
CHANGED
@@ -405,11 +405,8 @@ def _search_names(co, specials, glb, closure=None):
|
|
405
405
|
if isinstance(co, CodeType):
|
406
406
|
if closure is not None:
|
407
407
|
for varname, cell in zip(co.co_freevars, closure):
|
408
|
-
|
409
|
-
|
410
|
-
yield varname
|
411
|
-
except ValueError: # cell is empty
|
412
|
-
pass
|
408
|
+
if any(cell.cell_contents is v for v in values):
|
409
|
+
yield varname
|
413
410
|
for name in co.co_names:
|
414
411
|
if any(glb.get(name, None) is v for v in values):
|
415
412
|
yield name
|
ovld/utils.py
CHANGED
ovld/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "0.5.
|
1
|
+
version = "0.5.1"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
ovld/__init__.py,sha256=JuCM8Sj65gobV0KYyLr95cSI23Pi6RYZ7X3_F3fdsSw,1821
|
2
|
+
ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
|
3
|
+
ovld/codegen.py,sha256=oHfQHlVJUB1Y0PO--rhhkfAmgOhIhKNZyBcodrS1GEs,9210
|
4
|
+
ovld/core.py,sha256=bnp2LIVBUCvNhI53csWaAs7hlxinOBOXhPeoAw_GD3s,17443
|
5
|
+
ovld/dependent.py,sha256=h3j4oQYTQfGqMzggWlLV6TpojX_GtYRFWAO0GcMB0Zs,9085
|
6
|
+
ovld/medley.py,sha256=bp4e-6qH5_Qq05poPu7AcuWf-0mqNCqKMrdK44K2hSs,12667
|
7
|
+
ovld/mro.py,sha256=nqe9jHvsaLu-CfXoP2f7tHg5_8IkcESWMnBmvr4XGIo,4605
|
8
|
+
ovld/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
ovld/recode.py,sha256=YrftCClBcP_luOdqeeQ_EQJddRjikLpY5RmYGRCQrOs,16008
|
10
|
+
ovld/signatures.py,sha256=Q8JucSOun0ESGx14aWtHtBzLEiM6FxY5HP3imyqXoDo,8984
|
11
|
+
ovld/typemap.py,sha256=5Pro1Ee60fH4L7NW7k5nbN5EfDygA0LFHcI6o3mCagI,13596
|
12
|
+
ovld/types.py,sha256=0hkhAR5_5793NABdrM-fP1dSJBhYof85FILKqVP2YMg,13392
|
13
|
+
ovld/utils.py,sha256=wO9IQqPVkcS1Opd8cl79WMMpWdCbMQY66PuWF2hMkvc,4272
|
14
|
+
ovld/version.py,sha256=-u_JHy_NHod_JgjQcxN3CYo6TWCz6XQgbb-Z1FmF2Fg,18
|
15
|
+
ovld-0.5.1.dist-info/METADATA,sha256=Lp8FkGbpbaMftXuCYLX3yeCdNTjV67U4ov0h9GV7tCI,9276
|
16
|
+
ovld-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
ovld-0.5.1.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
|
18
|
+
ovld-0.5.1.dist-info/RECORD,,
|
ovld-0.5.0.dist-info/RECORD
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
ovld/__init__.py,sha256=JuCM8Sj65gobV0KYyLr95cSI23Pi6RYZ7X3_F3fdsSw,1821
|
2
|
-
ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
|
3
|
-
ovld/codegen.py,sha256=0ZZdXw-nn9t52BX93GX6zwTeBB_wCmc5OxSk37sBrVU,9112
|
4
|
-
ovld/core.py,sha256=uAnzuxa3hZjZSbCs3FW_0uR9qQlY-HZhgKpDTyvp59Y,17346
|
5
|
-
ovld/dependent.py,sha256=h3j4oQYTQfGqMzggWlLV6TpojX_GtYRFWAO0GcMB0Zs,9085
|
6
|
-
ovld/medley.py,sha256=Gin0EYeuQ7qZdDKNFFIwBY4o8W-VT5pl2bP8GCSopU4,12136
|
7
|
-
ovld/mro.py,sha256=nqe9jHvsaLu-CfXoP2f7tHg5_8IkcESWMnBmvr4XGIo,4605
|
8
|
-
ovld/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
ovld/recode.py,sha256=AoNgJw75RAlfSBeFL5-UeB_T7wN_Xqzuahr9VhqC_yI,16126
|
10
|
-
ovld/signatures.py,sha256=Q8JucSOun0ESGx14aWtHtBzLEiM6FxY5HP3imyqXoDo,8984
|
11
|
-
ovld/typemap.py,sha256=5Pro1Ee60fH4L7NW7k5nbN5EfDygA0LFHcI6o3mCagI,13596
|
12
|
-
ovld/types.py,sha256=0hkhAR5_5793NABdrM-fP1dSJBhYof85FILKqVP2YMg,13392
|
13
|
-
ovld/utils.py,sha256=q2zFrK3OifhDu4SsVyLP4WKIp8FDDcJmLwMEUoWHS6c,4227
|
14
|
-
ovld/version.py,sha256=-beU6vQRolzltfD0fQR6KSzR5yUgbfwYBlKbvzktqbg,18
|
15
|
-
ovld-0.5.0.dist-info/METADATA,sha256=HzSeUKkJrJRUbPJZqw1XZpkW58EKhgl6GOi32CaPPcw,9276
|
16
|
-
ovld-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
-
ovld-0.5.0.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
|
18
|
-
ovld-0.5.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|