ovld 0.4.5__py3-none-any.whl → 0.5.0__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/typemap.py CHANGED
@@ -6,7 +6,7 @@ from types import CodeType
6
6
 
7
7
  from .mro import sort_types
8
8
  from .recode import generate_dependent_dispatch
9
- from .utils import MISSING, subtler_type
9
+ from .utils import MISSING, CodegenInProgress, subtler_type
10
10
 
11
11
 
12
12
  class TypeMap(dict):
@@ -58,6 +58,7 @@ class TypeMap(dict):
58
58
  @dataclass
59
59
  class Candidate:
60
60
  handler: object
61
+ base_handler: object
61
62
  priority: float
62
63
  specificity: tuple
63
64
  tiebreak: int
@@ -69,9 +70,7 @@ class Candidate:
69
70
  if self.priority > other.priority:
70
71
  return True
71
72
  elif self.specificity != other.specificity:
72
- return all(
73
- s1 >= s2 for s1, s2 in zip(self.specificity, other.specificity)
74
- )
73
+ return all(s1 >= s2 for s1, s2 in zip(self.specificity, other.specificity))
75
74
  else:
76
75
  return self.tiebreak > other.tiebreak
77
76
 
@@ -95,7 +94,7 @@ class MultiTypeMap(dict):
95
94
  specific than [object, int] (which means there is an ambiguity).
96
95
  """
97
96
 
98
- def __init__(self, name="_ovld", key_error=KeyError):
97
+ def __init__(self, name="_ovld", key_error=KeyError, ovld=None):
99
98
  self.maps = {}
100
99
  self.priorities = {}
101
100
  self.tiebreaks = {}
@@ -107,8 +106,10 @@ class MultiTypeMap(dict):
107
106
  self.dispatch_id = count()
108
107
  self.all = {}
109
108
  self.errors = {}
109
+ self.ovld = ovld
110
+ self.in_progress = set()
110
111
 
111
- def mro(self, obj_t_tup):
112
+ def mro(self, obj_t_tup, specialize=True):
112
113
  specificities = {}
113
114
  candidates = None
114
115
  nargs = len([t for t in obj_t_tup if not isinstance(t, tuple)])
@@ -126,9 +127,7 @@ class MultiTypeMap(dict):
126
127
  results = {
127
128
  handler: spc
128
129
  for (handler, sig), spc in results.items()
129
- if sig.req_pos
130
- <= nargs
131
- <= (math.inf if sig.vararg else sig.max_pos)
130
+ if sig.req_pos <= nargs <= (math.inf if sig.vararg else sig.max_pos)
132
131
  and not (sig.req_names - names)
133
132
  }
134
133
 
@@ -152,14 +151,26 @@ class MultiTypeMap(dict):
152
151
  for c in candidates:
153
152
  specificities.setdefault(c, []).append(results[c])
154
153
 
154
+ def get_handler(func):
155
+ if specialize and (specializer := getattr(func, "specializer", False)):
156
+ key = (func, obj_t_tup)
157
+ if key in self.in_progress:
158
+ raise CodegenInProgress()
159
+ self.in_progress.add(key)
160
+ return specializer(self, func, obj_t_tup)
161
+ else:
162
+ return func
163
+
155
164
  candidates = [
156
165
  Candidate(
157
- handler=c,
166
+ handler=h,
167
+ base_handler=c,
158
168
  priority=self.priorities.get(c, 0),
159
169
  specificity=tuple(specificities[c]),
160
170
  tiebreak=self.tiebreaks.get(c, 0),
161
171
  )
162
172
  for c in candidates
173
+ if (h := get_handler(c))
163
174
  ]
164
175
 
165
176
  # The sort ensures that if candidate A dominates candidate B, A will
@@ -170,9 +181,7 @@ class MultiTypeMap(dict):
170
181
 
171
182
  candidates.sort(key=Candidate.sort_key, reverse=True)
172
183
 
173
- self.all[obj_t_tup] = {
174
- getattr(c.handler, "__code__", None) for c in candidates
175
- }
184
+ self.all[obj_t_tup] = {getattr(c.handler, "__code__", None) for c in candidates}
176
185
 
177
186
  processed = set()
178
187
 
@@ -239,7 +248,7 @@ class MultiTypeMap(dict):
239
248
  width = 6
240
249
  print(f"{prio:{width}} \033[1m{h.__name__}\033[0m")
241
250
  co = h.__code__
242
- print(f"{'':{width-2}} @ {co.co_filename}:{co.co_firstlineno}")
251
+ print(f"{'':{width - 2}} @ {co.co_filename}:{co.co_firstlineno}")
243
252
 
244
253
  def display_resolution(self, *args, **kwargs):
245
254
  from .dependent import is_dependent
@@ -263,9 +272,7 @@ class MultiTypeMap(dict):
263
272
  for grp in self.mro(tuple(argt)):
264
273
  grp.sort(key=lambda x: x.handler.__name__)
265
274
  match = [
266
- dependent_match(
267
- self.type_tuples[c.handler], [*args, *kwargs.items()]
268
- )
275
+ dependent_match(self.type_tuples[c.base_handler], [*args, *kwargs.items()])
269
276
  for c in grp
270
277
  ]
271
278
  ambiguous = len([m for m in match if m]) > 1
@@ -292,22 +299,17 @@ class MultiTypeMap(dict):
292
299
  width = 2 * len(args) + 6
293
300
  print(f"{color}{bullet} {lvl:{width}} {handler.__name__}")
294
301
  co = handler.__code__
295
- print(
296
- f" {'':{width-1}}@ {co.co_filename}:{co.co_firstlineno}\033[0m"
297
- )
302
+ print(f" {'':{width - 1}}@ {co.co_filename}:{co.co_firstlineno}\033[0m")
298
303
  if ambiguous:
299
- message += " There is ambiguity between multiple matching methods, marked '=='."
304
+ message += (
305
+ " There is ambiguity between multiple matching methods, marked '=='."
306
+ )
300
307
  finished = True
301
308
  print("Resolution:", message)
302
309
 
303
- def wrap_dependent(self, tup, handlers, group, next_call):
304
- handlers = list(handlers)
305
- htup = [(h, self.type_tuples[h]) for h in handlers]
306
- slf = (
307
- "self, "
308
- if inspect.getfullargspec(handlers[0]).args[0] == "self"
309
- else ""
310
- )
310
+ def wrap_dependent(self, tup, group, next_call):
311
+ htup = [(c.handler, self.type_tuples[c.base_handler]) for c in group]
312
+ slf = "self, " if inspect.getfullargspec(group[0].handler).args[0] == "self" else ""
311
313
  return generate_dependent_dispatch(
312
314
  tup,
313
315
  htup,
@@ -326,11 +328,9 @@ class MultiTypeMap(dict):
326
328
  funcs = []
327
329
  for group in reversed(results):
328
330
  handlers = [c.handler for c in group]
329
- dependent = any(self.dependent[c.handler] for c in group)
331
+ dependent = any(self.dependent[c.base_handler] for c in group)
330
332
  if dependent:
331
- nxt = self.wrap_dependent(
332
- obj_t_tup, handlers, group, funcs[-1] if funcs else None
333
- )
333
+ nxt = self.wrap_dependent(obj_t_tup, group, funcs[-1] if funcs else None)
334
334
  elif len(group) != 1:
335
335
  nxt = None
336
336
  else:
@@ -342,11 +342,7 @@ class MultiTypeMap(dict):
342
342
 
343
343
  parents = []
344
344
  for group, (func, codes) in zip(results, funcs):
345
- tups = (
346
- [obj_t_tup]
347
- if not parents
348
- else [(parent, *obj_t_tup) for parent in parents]
349
- )
345
+ tups = [obj_t_tup] if not parents else [(parent, *obj_t_tup) for parent in parents]
350
346
  if func is None:
351
347
  for tup in tups:
352
348
  self.errors[tup] = self.key_error(obj_t_tup, group)
@@ -386,3 +382,9 @@ class MultiTypeMap(dict):
386
382
  raise self.errors[obj_t_tup]
387
383
  else:
388
384
  return self[obj_t_tup]
385
+
386
+ def __call__(self, *obj_t_tup, after=None):
387
+ if after:
388
+ return self[(after, *obj_t_tup)]
389
+ else:
390
+ return self[obj_t_tup]
ovld/types.py CHANGED
@@ -1,18 +1,41 @@
1
+ import importlib
1
2
  import inspect
2
3
  import sys
3
4
  import typing
4
5
  from dataclasses import dataclass
5
6
  from functools import partial
6
- from typing import Protocol, runtime_checkable
7
+ from typing import Protocol, get_args, runtime_checkable
7
8
 
9
+ from .codegen import Code
8
10
  from .mro import Order, TypeRelationship, subclasscheck, typeorder
11
+ from .recode import generate_checking_code
9
12
  from .typemap import TypeMap
10
- from .utils import UsageError, clsstring
13
+ from .utils import UnionType, UnionTypes, UsageError, clsstring
11
14
 
12
- try:
13
- from types import UnionType
14
- except ImportError: # pragma: no cover
15
- UnionType = None
15
+
16
+ def get_args(tp):
17
+ args = getattr(tp, "__args__", None)
18
+ if not isinstance(args, tuple):
19
+ args = ()
20
+ return args
21
+
22
+
23
+ def eval_annotation(t, ctx, locals, catch=False):
24
+ try:
25
+ if isinstance(t, str):
26
+ if hasattr(ctx, "__globals__"):
27
+ glb = ctx.__globals__
28
+ elif hasattr(ctx, "__module__"): # pragma: no cover
29
+ glb = vars(importlib.import_module(ctx.__module__))
30
+ else: # pragma: no cover
31
+ glb = {}
32
+ return eval(t, glb, locals)
33
+ else:
34
+ return t
35
+ except Exception: # pragma: no cover
36
+ if catch:
37
+ return None
38
+ raise
16
39
 
17
40
 
18
41
  class TypeNormalizer:
@@ -29,7 +52,7 @@ class TypeNormalizer:
29
52
  from .dependent import DependentType
30
53
 
31
54
  if isinstance(t, str):
32
- t = eval(t, getattr(fn, "__globals__", {}))
55
+ t = eval_annotation(t, fn, {})
33
56
 
34
57
  if t is type:
35
58
  t = type[object]
@@ -37,6 +60,8 @@ class TypeNormalizer:
37
60
  t = object
38
61
  elif t is inspect._empty:
39
62
  t = object
63
+ elif t in UnionTypes:
64
+ return type[t]
40
65
  elif isinstance(t, typing._AnnotatedAlias):
41
66
  t = t.__origin__
42
67
 
@@ -82,7 +107,7 @@ class MetaMC(type):
82
107
  return super().__new__(T, name, (), {"_handler": handler})
83
108
 
84
109
  def __init__(cls, name, handler):
85
- cls.__args__ = getattr(handler, "__args__", ())
110
+ cls.__args__ = get_args(handler)
86
111
 
87
112
  def codegen(cls):
88
113
  return cls._handler.codegen()
@@ -212,11 +237,15 @@ def _getcls(ref):
212
237
 
213
238
 
214
239
  class AllMC(type):
240
+ __bound__ = False
241
+
215
242
  def __type_order__(self, other):
216
243
  return Order.MORE
217
244
 
218
245
  def __is_subtype__(self, other):
219
- return True
246
+ if not self.__bound__:
247
+ return True
248
+ return subclasscheck(self.__bound__, other) or subclasscheck(other, self.__bound__)
220
249
 
221
250
  def __is_supertype__(self, other):
222
251
  return False
@@ -227,6 +256,10 @@ class AllMC(type):
227
256
  def __isinstance__(self, other): # pragma: no cover
228
257
  return False
229
258
 
259
+ def __getitem__(self, item):
260
+ name = getattr(item, "__name__", str(item))
261
+ return type(f"All[{name}]", (self,), {"__bound__": item})
262
+
230
263
 
231
264
  class All(metaclass=AllMC):
232
265
  """All is the empty/void/bottom type -- it acts as a subtype of all types.
@@ -304,11 +337,7 @@ def Exactly(cls, base_cls):
304
337
  @parametrized_class_check
305
338
  def StrictSubclass(cls, base_cls):
306
339
  """Match subclasses but not the base class."""
307
- return (
308
- isinstance(cls, type)
309
- and issubclass(cls, base_cls)
310
- and cls is not base_cls
311
- )
340
+ return isinstance(cls, type) and issubclass(cls, base_cls) and cls is not base_cls
312
341
 
313
342
 
314
343
  @parametrized_class_check
@@ -317,20 +346,13 @@ class Union:
317
346
  self.__args__ = self.types = types
318
347
 
319
348
  def codegen(self):
320
- from .dependent import combine, generate_checking_code
321
-
322
- template = " or ".join("{}" for t in self.types)
323
- return combine(
324
- template, [generate_checking_code(t) for t in self.types]
325
- )
349
+ return Code("($[ or ]checks)", checks=[generate_checking_code(t) for t in self.types])
326
350
 
327
351
  def __type_order__(self, other):
328
352
  if other is Union:
329
353
  return Order.LESS
330
354
  classes = self.types
331
- compare = [
332
- x for t in classes if (x := typeorder(t, other)) is not Order.NONE
333
- ]
355
+ compare = [x for t in classes if (x := typeorder(t, other)) is not Order.NONE]
334
356
  if not compare:
335
357
  return Order.NONE
336
358
  elif any(x is Order.MORE or x is Order.SAME for x in compare):
@@ -368,20 +390,13 @@ class Intersection:
368
390
  self.__args__ = self.types = types
369
391
 
370
392
  def codegen(self):
371
- from .dependent import combine, generate_checking_code
372
-
373
- template = " and ".join("{}" for t in self.types)
374
- return combine(
375
- template, [generate_checking_code(t) for t in self.types]
376
- )
393
+ return Code("($[ and ]checks)", checks=[generate_checking_code(t) for t in self.types])
377
394
 
378
395
  def __type_order__(self, other):
379
396
  if other is Intersection:
380
397
  return Order.LESS
381
398
  classes = self.types
382
- compare = [
383
- x for t in classes if (x := typeorder(t, other)) is not Order.NONE
384
- ]
399
+ compare = [x for t in classes if (x := typeorder(t, other)) is not Order.NONE]
385
400
  if not compare:
386
401
  return Order.NONE
387
402
  elif any(x is Order.LESS or x is Order.SAME for x in compare):
@@ -427,15 +442,3 @@ class Dataclass(Protocol):
427
442
  return hasattr(subclass, "__dataclass_fields__") and hasattr(
428
443
  subclass, "__dataclass_params__"
429
444
  )
430
-
431
-
432
- __all__ = [
433
- "Dataclass",
434
- "Deferred",
435
- "Exactly",
436
- "HasMethod",
437
- "Intersection",
438
- "StrictSubclass",
439
- "class_check",
440
- "parametrized_class_check",
441
- ]
ovld/utils.py CHANGED
@@ -5,6 +5,15 @@ import re
5
5
  import typing
6
6
  from itertools import count
7
7
 
8
+ try:
9
+ from types import UnionType
10
+
11
+ UnionTypes = (type(typing.Union[int, str]), UnionType)
12
+
13
+ except ImportError: # pragma: no cover
14
+ UnionType = None
15
+ UnionTypes = (type(typing.Union[int, str]),)
16
+
8
17
 
9
18
  class Named:
10
19
  """A named object.
@@ -48,13 +57,20 @@ def keyword_decorator(deco):
48
57
  return new_deco
49
58
 
50
59
 
60
+ class CodegenInProgress(Exception):
61
+ pass
62
+
63
+
51
64
  class UsageError(Exception):
52
65
  pass
53
66
 
54
67
 
55
- class Unusable:
56
- def __init__(self, message):
57
- self.__message = message
68
+ class SpecialForm:
69
+ def __init__(self, name, message=None):
70
+ self.__name = name
71
+ self.__message = (
72
+ message or f"{name}() can only be used from inside an @ovld-registered function."
73
+ )
58
74
 
59
75
  def __call__(self, *args, **kwargs):
60
76
  raise UsageError(self.__message)
@@ -62,6 +78,11 @@ class Unusable:
62
78
  def __getattr__(self, attr):
63
79
  raise UsageError(self.__message)
64
80
 
81
+ def __str__(self):
82
+ return f"<SpecialForm {self.__name}>"
83
+
84
+ __repr__ = __str__
85
+
65
86
 
66
87
  class GenericAliasMC(type):
67
88
  def __instancecheck__(cls, obj):
@@ -87,9 +108,23 @@ def clsstring(cls):
87
108
  return r
88
109
 
89
110
 
111
+ def typemap_entry_string(cls):
112
+ if isinstance(cls, tuple):
113
+ key, typ = cls
114
+ return f"{key}: {clsstring(typ)}"
115
+ else:
116
+ return clsstring(cls)
117
+
118
+
119
+ def sigstring(types):
120
+ return ", ".join(map(typemap_entry_string, types))
121
+
122
+
90
123
  def subtler_type(obj):
91
124
  if isinstance(obj, GenericAlias):
92
125
  return type[obj]
126
+ elif isinstance(obj, UnionTypes):
127
+ return type[obj]
93
128
  elif obj is typing.Any:
94
129
  return type[object]
95
130
  elif isinstance(obj, type):
@@ -99,7 +134,7 @@ def subtler_type(obj):
99
134
 
100
135
 
101
136
  class NameDatabase:
102
- def __init__(self, default_name):
137
+ def __init__(self, default_name="TMP"):
103
138
  self.default_name = default_name
104
139
  self.count = count()
105
140
  self.variables = {}
@@ -109,32 +144,34 @@ class NameDatabase:
109
144
  def register(self, name):
110
145
  self.registered.add(name)
111
146
 
112
- def gensym(self, desired_name):
147
+ def gensym(self, desired_name, value=None):
113
148
  i = 1
114
149
  name = desired_name
115
- while name in self.registered:
150
+ while name in self.registered or (
151
+ name in __builtins__ and __builtins__[name] != value
152
+ ):
116
153
  name = f"{desired_name}{i}"
117
154
  i += 1
118
155
  self.registered.add(name)
119
156
  return name
120
157
 
121
- def __getitem__(self, value):
158
+ def get(self, value, suggested_name=None):
122
159
  if isinstance(value, (int, float, str)):
123
160
  return repr(value)
124
161
  if id(value) in self.names:
125
162
  return self.names[id(value)]
126
- name = getattr(value, "__name__", self.default_name)
127
- if not re.match(string=name, pattern=r"[a-zA-Z_][a-zA-Z0-9_]+"):
128
- name = self.default_name
129
- name = self.gensym(name)
163
+ dflt = suggested_name or self.default_name
164
+ if (
165
+ isinstance(value, GenericAlias) and typing.get_origin(value) is type
166
+ ): # pragma: no cover
167
+ name = "t_" + getattr(typing.get_args(value)[0], "__name__", dflt)
168
+ else:
169
+ name = getattr(value, "__name__", dflt)
170
+ if not re.match(string=name, pattern=r"^[a-zA-Z_][a-zA-Z0-9_]*$"):
171
+ name = dflt
172
+ name = self.gensym(name, value)
130
173
  self.variables[name] = value
131
174
  self.names[id(value)] = name
132
175
  return name
133
176
 
134
-
135
- __all__ = [
136
- "BOOTSTRAP",
137
- "MISSING",
138
- "Named",
139
- "keyword_decorator",
140
- ]
177
+ __getitem__ = get
ovld/version.py CHANGED
@@ -1 +1 @@
1
- version = "0.4.5"
1
+ version = "0.5.0"
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: ovld
3
- Version: 0.4.5
3
+ Version: 0.5.0
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/
@@ -20,10 +20,11 @@ Fast multiple dispatch in Python, with many extra features.
20
20
 
21
21
  With ovld, you can write a version of the same function for every type signature using annotations instead of writing an awkward sequence of `isinstance` statements. Unlike Python's `singledispatch`, it works for multiple arguments.
22
22
 
23
- * ⚡️ **[Fast](https://ovld.readthedocs.io/en/latest/compare/#results):** `ovld` is the fastest multiple dispatch library around, by some margin.
24
- * 🚀 [**Variants**](https://ovld.readthedocs.io/en/latest/usage/#variants) and [**mixins**](https://ovld.readthedocs.io/en/latest/usage/#mixins) of functions and methods.
23
+ * ⚡️ **[Fast](https://ovld.readthedocs.io/en/latest/compare/#results):** ovld is the fastest multiple dispatch library around, by some margin.
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
  * 🦄 **[Dependent types](https://ovld.readthedocs.io/en/latest/dependent/):** Overloaded functions can depend on more than argument types: they can depend on actual values.
26
- * 🔑 **Extensive:** Dispatch on functions, methods, positional arguments and even [keyword arguments](https://ovld.readthedocs.io/en/latest/usage/#keyword-arguments) (with some restrictions).
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
+ * ⚙️ **[Codegen](https://ovld.readthedocs.io/en/latest/codegen/):** (Experimental) For advanced use cases, you can generate custom code for overloads.
27
28
 
28
29
  ## Example
29
30
 
@@ -62,7 +63,7 @@ A *variant* of an `ovld` is a copy of the `ovld`, with some methods added or cha
62
63
 
63
64
  ```python
64
65
  @add.variant
65
- def mul(self, x: object, y: object):
66
+ def mul(x: object, y: object):
66
67
  return x * y
67
68
 
68
69
  assert mul([1, 2], [3, 4]) == [3, 8]
@@ -199,19 +200,64 @@ assert Two().f(1) == "an integer"
199
200
  assert Two().f("s") == "a string"
200
201
  ```
201
202
 
203
+ ## Medleys
204
+
205
+ Inheriting from [`ovld.Medley`](https://ovld.readthedocs.io/en/latest/medley/) lets you combine functionality in a new way. Classes created that way are free-form medleys that you can (almost) arbitrarily combine together.
206
+
207
+ All medleys are dataclasses and you must define their data fields as you would for a normal dataclass (using `dataclass.field` if needed).
208
+
209
+ ```python
210
+ from ovld import Medley
211
+
212
+ class Punctuator(Medley):
213
+ punctuation: str = "."
214
+
215
+ def __call__(self, x: str):
216
+ return f"{x}{self.punctuation}"
217
+
218
+ class Multiplier(Medley):
219
+ factor: int = 3
220
+
221
+ def __call__(self, x: int):
222
+ return x * self.factor
223
+
224
+ # You can add the classes together to merge their methods and fields using ovld
225
+ PuMu = Punctuator + Multiplier
226
+ f = PuMu(punctuation="!", factor=3)
227
+
228
+ # You can also combine existing instances!
229
+ f2 = Punctuator("!") + Multiplier(3)
230
+
231
+ assert f("hello") == f2("hello") == "hello!"
232
+ assert f(10) == f2(10) == 30
233
+
234
+ # You can also meld medleys inplace, but only if all new fields have defaults
235
+ class Total(Medley):
236
+ pass
237
+
238
+ Total.extend(Punctuator, Multiplier)
239
+ f3 = Total(punctuation="!", factor=3)
240
+ ```
241
+
242
+
243
+ # Code generation
244
+
245
+ (Experimental) For advanced use cases, you can generate custom code for type checkers or overloads. [See here](https://ovld.readthedocs.io/en/latest/codegen/).
246
+
247
+
202
248
  # Benchmarks
203
249
 
204
250
  `ovld` is pretty fast: the overhead is comparable to `isinstance` or `match`, and only 2-3x slower when dispatching on `Literal` types. Compared to other multiple dispatch libraries, it has 1.5x to 100x less overhead.
205
251
 
206
252
  Time relative to the fastest implementation (1.00) (lower is better).
207
253
 
208
- | Benchmark | custom | [ovld](https://github.com/breuleux/ovld) | [plum](https://github.com/beartype/plum) | [multim](https://github.com/coady/multimethod) | [multid](https://github.com/mrocklin/multipledispatch/) | [runtype](https://github.com/erezsh/runtype) | [fastcore](https://github.com/fastai/fastcore) | [sd](https://docs.python.org/3/library/functools.html#functools.singledispatch) |
209
- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
210
- |[trivial](https://github.com/breuleux/ovld/tree/master/benchmarks/test_trivial.py)|1.45|1.00|3.32|4.63|2.04|2.41|51.93|1.91|
211
- |[multer](https://github.com/breuleux/ovld/tree/master/benchmarks/test_multer.py)|1.13|1.00|11.05|4.53|8.31|2.19|46.74|7.32|
212
- |[add](https://github.com/breuleux/ovld/tree/master/benchmarks/test_add.py)|1.08|1.00|3.73|5.21|2.37|2.79|59.31|x|
213
- |[ast](https://github.com/breuleux/ovld/tree/master/benchmarks/test_ast.py)|1.00|1.08|23.14|3.09|1.68|1.91|28.39|1.66|
214
- |[calc](https://github.com/breuleux/ovld/tree/master/benchmarks/test_calc.py)|1.00|1.23|54.61|29.32|x|x|x|x|
215
- |[regexp](https://github.com/breuleux/ovld/tree/master/benchmarks/test_regexp.py)|1.00|1.87|19.18|x|x|x|x|x|
216
- |[fib](https://github.com/breuleux/ovld/tree/master/benchmarks/test_fib.py)|1.00|3.30|444.31|125.77|x|x|x|x|
217
- |[tweaknum](https://github.com/breuleux/ovld/tree/master/benchmarks/test_tweaknum.py)|1.00|2.09|x|x|x|x|x|x|
254
+ | Benchmark | custom | [ovld](https://github.com/breuleux/ovld) | [plum](https://github.com/beartype/plum) | [multim](https://github.com/coady/multimethod) | [multid](https://github.com/mrocklin/multipledispatch) | [runtype](https://github.com/erezsh/runtype) | [sd](https://docs.python.org/3/library/functools.html#functools.singledispatch) |
255
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
256
+ |[trivial](https://github.com/breuleux/ovld/tree/master/benchmarks/test_trivial.py)|1.45|1.00|3.32|4.63|2.04|2.41|1.91|
257
+ |[multer](https://github.com/breuleux/ovld/tree/master/benchmarks/test_multer.py)|1.13|1.00|11.05|4.53|8.31|2.19|7.32|
258
+ |[add](https://github.com/breuleux/ovld/tree/master/benchmarks/test_add.py)|1.08|1.00|3.73|5.21|2.37|2.79|x|
259
+ |[ast](https://github.com/breuleux/ovld/tree/master/benchmarks/test_ast.py)|1.00|1.08|23.14|3.09|1.68|1.91|1.66|
260
+ |[calc](https://github.com/breuleux/ovld/tree/master/benchmarks/test_calc.py)|1.00|1.23|54.61|29.32|x|x|x|
261
+ |[regexp](https://github.com/breuleux/ovld/tree/master/benchmarks/test_regexp.py)|1.00|1.87|19.18|x|x|x|x|
262
+ |[fib](https://github.com/breuleux/ovld/tree/master/benchmarks/test_fib.py)|1.00|3.30|444.31|125.77|x|x|x|
263
+ |[tweaknum](https://github.com/breuleux/ovld/tree/master/benchmarks/test_tweaknum.py)|1.00|2.09|x|x|x|x|x|
@@ -0,0 +1,18 @@
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,14 +0,0 @@
1
- ovld/__init__.py,sha256=IVzs4_9skMa_UGZsGT7Ra_dIxj7KKNlV77XxlqcS6ow,1446
2
- ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
3
- ovld/core.py,sha256=MtRcJNhMwsix2Y7zP1fQS-taCy_t0bqkjHQdLF8WE8E,25719
4
- ovld/dependent.py,sha256=nyrkkmgxGjcHnZjKqbk7_g4_D91SYfYTPIE32LOvC9o,10184
5
- ovld/mro.py,sha256=0cJK_v-POCiuwjluwf8fWeQ3G-2chEUv3KYe57GC61Q,4552
6
- ovld/recode.py,sha256=bwsdM-TPpSQEmJhv8G30yDLrF8_I5wyTXpITMCC1W9k,17961
7
- ovld/typemap.py,sha256=PH5dy8ddVCcqj2TkQbgsM7fmCdHsJT9WGXFPn4JZsCA,13131
8
- ovld/types.py,sha256=EZNv8pThbo47KBULYM3R0R3sM2C5LC4DWraXZImkiNs,12877
9
- ovld/utils.py,sha256=jrrG_BqjI3W7x285nLuYiy5ui9LbNltblFVTlOWHYiU,3123
10
- ovld/version.py,sha256=GzDw9yI90LiIOYlw5gZBih8gPe3URgiM0vAFi2-I3ro,18
11
- ovld-0.4.5.dist-info/METADATA,sha256=AM7DiTgyU53Z0A7s8MIJJ3t1rgk1pxf3uqPU20kVO6o,7833
12
- ovld-0.4.5.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
13
- ovld-0.4.5.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
14
- ovld-0.4.5.dist-info/RECORD,,