ovld 0.5.9__py3-none-any.whl → 0.5.10__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 CHANGED
@@ -25,6 +25,21 @@ from .utils import (
25
25
  subtler_type,
26
26
  )
27
27
 
28
+ _orig_getdoc = inspect.getdoc
29
+
30
+
31
+ def _getdoc(fn):
32
+ if hasattr(fn, "__calculate_doc__"):
33
+ if inspect.ismethod(fn):
34
+ fn = fn.__func__
35
+ fn.__doc__ = fn.__calculate_doc__()
36
+ del fn.__calculate_doc__
37
+ return _orig_getdoc(fn)
38
+
39
+
40
+ inspect.getdoc = _getdoc
41
+
42
+
28
43
  _current_id = itertools.count()
29
44
 
30
45
 
@@ -72,8 +87,6 @@ class Ovld:
72
87
  dispatch.
73
88
  linkback: Whether to keep a pointer in the parent mixins to this
74
89
  ovld so that updates can be propagated. (default: False)
75
- allow_replacement: Allow replacing a method by another with the
76
- same signature. (default: True)
77
90
  """
78
91
 
79
92
  def __init__(
@@ -82,50 +95,43 @@ class Ovld:
82
95
  mixins=[],
83
96
  name=None,
84
97
  linkback=False,
85
- allow_replacement=True,
86
98
  ):
87
99
  """Initialize an Ovld."""
88
100
  self.id = next(_current_id)
89
101
  self.specialization_self = MISSING
90
102
  self._compiled = False
103
+ self._signatures = None
104
+ self._argument_analysis = None
91
105
  self.linkback = linkback
92
106
  self.children = []
93
- self.allow_replacement = allow_replacement
94
107
  self.name = name
95
108
  self.shortname = name or f"__OVLD{self.id}"
96
109
  self.__name__ = name
97
- self._defns = {}
110
+ self._regs = {}
98
111
  self._locked = False
99
112
  self.mixins = []
100
- self.argument_analysis = ArgumentAnalyzer()
101
113
  self.dispatch = bootstrap_dispatch(self, name=self.shortname)
102
114
  self.add_mixins(*mixins)
103
115
 
104
- @property
105
- def defns(self):
106
- defns = {}
116
+ def regs(self):
107
117
  for mixin in self.mixins:
108
- defns.update(mixin.defns)
109
- defns.update(self._defns)
110
- return defns
118
+ yield from mixin.regs()
119
+ yield from self._regs.items()
111
120
 
112
- def analyze_arguments(self):
113
- self.argument_analysis = ArgumentAnalyzer()
114
- for key, fn in list(self.defns.items()):
115
- self.argument_analysis.add(fn)
116
- self.argument_analysis.compile()
117
- return self.argument_analysis
121
+ def empty(self):
122
+ return not self._regs and all(m.empty() for m in self.mixins)
118
123
 
119
124
  def mkdoc(self):
125
+ fns = [f for f, _ in self.regs()]
120
126
  try:
121
- docs = [fn.__doc__ for fn in self.defns.values() if fn.__doc__]
127
+ docs = [fn.__doc__ for fn in fns if fn.__doc__]
122
128
  if len(docs) == 1:
123
129
  maindoc = docs[0]
124
130
  else:
125
- maindoc = f"Ovld with {len(self.defns)} methods."
131
+ maindoc = f"Ovld with {len(fns)} methods."
126
132
 
127
133
  doc = f"{maindoc}\n\n"
128
- for fn in self.defns.values():
134
+ for fn in fns:
129
135
  fndef = inspect.signature(fn)
130
136
  fdoc = fn.__doc__
131
137
  if not fdoc or fdoc == maindoc:
@@ -192,17 +198,41 @@ class Ovld:
192
198
  def __set_name__(self, inst, name):
193
199
  self.rename(name)
194
200
 
195
- def _set_attrs_from(self, fn):
196
- """Inherit relevant attributes from the function."""
197
- if self.name is None:
198
- self.__qualname__ = fn.__qualname__
199
- self.__module__ = fn.__module__
200
- self.rename(f"{fn.__module__}.{fn.__qualname__}", fn.__name__)
201
-
202
201
  def ensure_compiled(self):
203
202
  if not self._compiled:
204
203
  self.compile()
205
204
 
205
+ @property
206
+ def signatures(self):
207
+ if self._signatures is None:
208
+ regs = {}
209
+ for fn, priority in self.regs():
210
+ ss = self.specialization_self
211
+ cgf = getattr(ss, "_ovld_codegen_fields", ())
212
+ lcl = {f: getattr(ss, f) for f in cgf}
213
+ sig = replace(Signature.extract(fn, lcl), priority=priority)
214
+
215
+ def _set(sig, fn):
216
+ if sig in regs:
217
+ # Push down the existing handler with a lower tiebreak
218
+ msig = replace(sig, tiebreak=sig.tiebreak - 1)
219
+ _set(msig, regs[sig])
220
+ regs[sig] = fn
221
+
222
+ _set(sig, fn)
223
+ self._signatures = regs
224
+ return self._signatures
225
+
226
+ @property
227
+ def argument_analysis(self):
228
+ if self._argument_analysis is None:
229
+ aa = ArgumentAnalyzer()
230
+ for sig in self.signatures:
231
+ aa.add(sig)
232
+ aa.compile()
233
+ self._argument_analysis = aa
234
+ return self._argument_analysis
235
+
206
236
  def compile(self):
207
237
  """Finalize this overload.
208
238
 
@@ -223,7 +253,9 @@ class Ovld:
223
253
  name = self.__name__
224
254
  self.map = MultiTypeMap(name=name, key_error=self._key_error, ovld=self)
225
255
 
226
- self.analyze_arguments()
256
+ for sig, fn in list(self.signatures.items()):
257
+ self.register_signature(sig, fn)
258
+
227
259
  dispatch = generate_dispatch(self, self.argument_analysis)
228
260
  self.dispatch.__code__ = rename_code(dispatch.__code__, self.shortname)
229
261
  self.dispatch.__kwdefaults__ = dispatch.__kwdefaults__
@@ -231,10 +263,7 @@ class Ovld:
231
263
  self.dispatch.__defaults__ = dispatch.__defaults__
232
264
  self.dispatch.__globals__.update(dispatch.__globals__)
233
265
  self.dispatch.map = self.map
234
- self.dispatch.__doc__ = self.mkdoc()
235
-
236
- for key, fn in list(self.defns.items()):
237
- self.register_signature(key, fn)
266
+ self.dispatch.__generate_doc__ = self.mkdoc
238
267
 
239
268
  self._compiled = True
240
269
 
@@ -275,42 +304,35 @@ class Ovld:
275
304
  def _register(self, fn, priority):
276
305
  """Register a function."""
277
306
 
278
- self._attempt_modify()
279
-
280
- self._set_attrs_from(fn)
281
-
282
- sig = replace(Signature.extract(fn), priority=priority)
283
- if not self.allow_replacement and sig in self._defns:
284
- raise TypeError(f"There is already a method for {sigstring(sig.types)}")
307
+ if not isinstance(priority, tuple):
308
+ priority = (priority,)
285
309
 
286
- def _set(sig, fn):
287
- if sig in self._defns:
288
- # Push down the existing handler with a lower tiebreak
289
- msig = replace(sig, tiebreak=sig.tiebreak - 1)
290
- _set(msig, self._defns[sig])
291
- self._defns[sig] = fn
292
-
293
- _set(sig, fn)
310
+ self._attempt_modify()
311
+ if self.name is None:
312
+ self.__qualname__ = fn.__qualname__
313
+ self.__module__ = fn.__module__
314
+ self.rename(f"{fn.__module__}.{fn.__qualname__}", fn.__name__)
315
+ self._regs[fn] = priority
294
316
 
295
- self._update()
317
+ self.invalidate()
296
318
  return self
297
319
 
298
320
  def unregister(self, fn):
299
321
  """Unregister a function."""
300
322
  self._attempt_modify()
301
- self._defns = {sig: f for sig, f in self._defns.items() if f is not fn}
302
- self._update()
303
-
304
- def _update(self):
305
- self.reset()
323
+ del self._regs[fn]
324
+ self.invalidate()
325
+
326
+ def invalidate(self):
327
+ self._signatures = None
328
+ self._argument_analysis = None
329
+ if self._compiled:
330
+ self._compiled = False
331
+ self.dispatch.__code__ = self.dispatch.first_entry.__code__
306
332
  for child in self.children:
307
- child._update()
333
+ child.invalidate()
308
334
  if hasattr(self, "dispatch"):
309
- self.dispatch.__doc__ = self.mkdoc()
310
-
311
- def reset(self):
312
- self._compiled = False
313
- self.dispatch.__code__ = self.dispatch.first_entry.__code__
335
+ self.dispatch.__calculate_doc__ = self.mkdoc
314
336
 
315
337
  def copy(self, mixins=[], linkback=False):
316
338
  """Create a copy of this Ovld.
ovld/medley.py CHANGED
@@ -123,9 +123,9 @@ class BuildOvld(Combiner):
123
123
  for f, arg in self.pending:
124
124
  f(arg)
125
125
  self.pending.clear()
126
- if not self.ovld.defns:
126
+ if self.ovld.empty():
127
127
  return ABSENT
128
- self.ovld.reset()
128
+ self.ovld.invalidate()
129
129
  return self.ovld.dispatch
130
130
 
131
131
  def copy(self):
@@ -337,15 +337,20 @@ _meld_classes_cache = {}
337
337
 
338
338
 
339
339
  def meld_classes(classes):
340
+ def key(cls):
341
+ return getattr(cls, "_ovld_specialization_parent", None) or cls
342
+
340
343
  medleys = {}
341
344
  for cls in classes:
342
- medleys.update({x: True for x in getattr(cls, "_ovld_medleys", [cls])})
345
+ medleys.update({key(x): x for x in getattr(cls, "_ovld_medleys", [cls])})
343
346
  for cls in classes:
347
+ cls = key(cls)
344
348
  if not hasattr(cls, "_ovld_medleys"):
345
349
  for base in cls.mro():
346
350
  if base is not cls and base in medleys:
347
351
  del medleys[base]
348
- medleys = tuple(medleys)
352
+
353
+ medleys = tuple(medleys.values())
349
354
  if len(medleys) == 1:
350
355
  return medleys[0]
351
356
 
@@ -372,7 +377,7 @@ def meld_classes(classes):
372
377
 
373
378
  result = make_dataclass(
374
379
  cls_name="+".join(sorted(c.__name__ for c in medleys)),
375
- bases=tuple(medleys),
380
+ bases=medleys,
376
381
  fields=dc_fields,
377
382
  kw_only=True,
378
383
  namespace=merged,
ovld/mro.py CHANGED
@@ -118,8 +118,8 @@ def typeorder(t1, t2):
118
118
  ords = [typeorder(a1, a2) for a1, a2 in zip(args1, args2)]
119
119
  return Order.merge(ords)
120
120
 
121
- if not isinstance(t1, type) or not isinstance(t2, type): # pragma: no cover
122
- return Order.SAME
121
+ if not isinstance(t1, type) or not isinstance(t2, type):
122
+ return Order.NONE
123
123
 
124
124
  sx = issubclass(t1, t2)
125
125
  sy = issubclass(t2, t1)
ovld/signatures.py CHANGED
@@ -30,7 +30,7 @@ class LazySignature(inspect.Signature):
30
30
 
31
31
  @property
32
32
  def parameters(self):
33
- anal = self.ovld.analyze_arguments()
33
+ anal = self.ovld.argument_analysis
34
34
  parameters = []
35
35
  if anal.is_method:
36
36
  parameters.append(
@@ -117,7 +117,7 @@ class Signature:
117
117
  arginfo: list[Arginfo] = field(default_factory=list, hash=False, compare=False)
118
118
 
119
119
  @classmethod
120
- def extract(cls, fn):
120
+ def extract(cls, fn, lcl={}):
121
121
  typelist = []
122
122
  sig = inspect.signature(fn)
123
123
  max_pos = 0
@@ -135,7 +135,7 @@ class Signature:
135
135
  is_method = True
136
136
  continue
137
137
  pos = nm = None
138
- ann = normalize_type(param.annotation, fn)
138
+ ann = normalize_type(param.annotation, fn, lcl)
139
139
  if param.kind is inspect._POSITIONAL_ONLY:
140
140
  pos = i - is_method
141
141
  typelist.append(ann)
@@ -188,9 +188,8 @@ class ArgumentAnalyzer:
188
188
  self.is_method = None
189
189
  self.done = False
190
190
 
191
- def add(self, fn):
191
+ def add(self, sig):
192
192
  self.done = False
193
- sig = Signature.extract(fn)
194
193
  self.complex_transforms.update(arg.canonical for arg in sig.arginfo if arg.is_complex)
195
194
  for arg in sig.arginfo:
196
195
  if arg.position is not None:
ovld/typemap.py CHANGED
@@ -242,7 +242,8 @@ class MultiTypeMap(dict):
242
242
  self.maps[-1].register(object, entry)
243
243
 
244
244
  def display_methods(self):
245
- for h, prio in sorted(self.priorities.items(), key=lambda kv: -kv[1]):
245
+ for h, prio in sorted(self.priorities.items(), key=lambda kv: kv[1], reverse=True):
246
+ prio = ":".join(map(str, prio))
246
247
  prio = f"[{prio}]"
247
248
  width = 6
248
249
  print(f"{prio:{width}} \033[1m{h.__name__}\033[0m")
@@ -306,7 +307,8 @@ class MultiTypeMap(dict):
306
307
  color = "\033[1;32m"
307
308
  rank += 1
308
309
  spec = ".".join(map(str, c.specificity))
309
- lvl = f"[{c.priority}:{spec}]"
310
+ prios = ":".join(map(str, c.priority))
311
+ lvl = f"[{prios}:{spec}]"
310
312
  width = 2 * len(args) + 6
311
313
  print(f"{color}{bullet} {lvl:{width}} {handler.__name__}")
312
314
  co = handler.__code__
ovld/types.py CHANGED
@@ -25,7 +25,7 @@ def eval_annotation(t, ctx, locals, catch=False):
25
25
  else: # pragma: no cover
26
26
  glb = {}
27
27
  return eval(t, glb, locals)
28
- else:
28
+ else: # pragma: no cover
29
29
  return t
30
30
  except Exception: # pragma: no cover
31
31
  if catch:
@@ -43,11 +43,11 @@ class TypeNormalizer:
43
43
  else:
44
44
  self.generic_handlers.register(generic, handler)
45
45
 
46
- def __call__(self, t, fn):
46
+ def __call__(self, t, fn, lcl={}):
47
47
  from .dependent import DependentType
48
48
 
49
49
  if isinstance(t, str):
50
- t = eval_annotation(t, fn, {})
50
+ t = eval_annotation(t, fn, lcl)
51
51
 
52
52
  if t is type:
53
53
  t = type[object]
ovld/version.py CHANGED
@@ -1 +1 @@
1
- version = "0.5.9"
1
+ version = "0.5.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ovld
3
- Version: 0.5.9
3
+ Version: 0.5.10
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/
@@ -0,0 +1,18 @@
1
+ ovld/__init__.py,sha256=JuCM8Sj65gobV0KYyLr95cSI23Pi6RYZ7X3_F3fdsSw,1821
2
+ ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
3
+ ovld/codegen.py,sha256=27tmamlanuTPDT-x31ISyqP0wGKW9BCFZJGVyq9qLg8,9728
4
+ ovld/core.py,sha256=vVvaQppGZcccgRuxMkdQCr9jXrG9_xJn3ohyT0bIkEA,18251
5
+ ovld/dependent.py,sha256=JIgsc_5ddPH51_2IrZ6JW6bWE5RyrrrOwR2e9UvDhZ4,8922
6
+ ovld/medley.py,sha256=qiYUtMbYR-fzvmqfr7BDY2Ht3SbNOEJ9VaR7s-BNGRo,12962
7
+ ovld/mro.py,sha256=RxHoOpf5nIOD4yU-Bb0Zt5tFyral9zljaPDVGebnnJo,6218
8
+ ovld/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ ovld/recode.py,sha256=vXg9XLExp_9LdAHO0JWR4wvwHhpOLu2Xcrg9ZYg1nms,16407
10
+ ovld/signatures.py,sha256=EXE5Jik8m-3UtkS1lgr3rl5QS7NRcJfuI3VRaU6v1bg,8960
11
+ ovld/typemap.py,sha256=jcYiIPt8wVng0u7qdceEMt7i0gmlo7BMFbvHLkf6zD8,14092
12
+ ovld/types.py,sha256=sP4xqx5jZ-gYnQ4LlvT5v7N8I1npNdKKZf72rBelvEA,13402
13
+ ovld/utils.py,sha256=8nvycMWpTmwGq7ojjDA7yi2NdkU78NBdUlvRk_vDECY,5086
14
+ ovld/version.py,sha256=H2w8gxble-MJwdr4ywy0-MXcLJNCr6buKONQqjAMUuQ,19
15
+ ovld-0.5.10.dist-info/METADATA,sha256=TQnXuZ-NjT_wv8OGFY6zz33x7_4QGOcN6f3bNhNmBZw,10459
16
+ ovld-0.5.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
+ ovld-0.5.10.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
18
+ ovld-0.5.10.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- ovld/__init__.py,sha256=JuCM8Sj65gobV0KYyLr95cSI23Pi6RYZ7X3_F3fdsSw,1821
2
- ovld/abc.py,sha256=4qpZyYwI8dWgY1Oiv5FhdKg2uzNcyWxIpGmGJVcjXrs,1177
3
- ovld/codegen.py,sha256=27tmamlanuTPDT-x31ISyqP0wGKW9BCFZJGVyq9qLg8,9728
4
- ovld/core.py,sha256=WqZ1lvcAGSri02XZeY73Bj5AKB9RYBCAvHLbyns8u68,17792
5
- ovld/dependent.py,sha256=JIgsc_5ddPH51_2IrZ6JW6bWE5RyrrrOwR2e9UvDhZ4,8922
6
- ovld/medley.py,sha256=Pq6j4qPl8osyQ4Xp-ktnt2uJXytC9Jo70toS5LYHRf8,12840
7
- ovld/mro.py,sha256=-M-BFtmSSEZ39eMPpZ4c2xTAwE43zuJu_jtlxAEfuPo,6238
8
- ovld/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- ovld/recode.py,sha256=vXg9XLExp_9LdAHO0JWR4wvwHhpOLu2Xcrg9ZYg1nms,16407
10
- ovld/signatures.py,sha256=Q8JucSOun0ESGx14aWtHtBzLEiM6FxY5HP3imyqXoDo,8984
11
- ovld/typemap.py,sha256=wkLuCc6xa2VZJOMaAhuYYgnNrywhovkQwbkBnoRfCsY,13985
12
- ovld/types.py,sha256=CRL6Vuzg5moXgAAhIj2698GvZoyF4HWbUDYz2hKt6us,13373
13
- ovld/utils.py,sha256=8nvycMWpTmwGq7ojjDA7yi2NdkU78NBdUlvRk_vDECY,5086
14
- ovld/version.py,sha256=fa8mYJ1rRpnvSWOBQjwJEtqO9AqOw8j-QGkxIJqUaM0,18
15
- ovld-0.5.9.dist-info/METADATA,sha256=7TIVCS1fVm0Oq7GcG5KR9JRNWQa6JkM-c6euVUu3e6g,10458
16
- ovld-0.5.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
- ovld-0.5.9.dist-info/licenses/LICENSE,sha256=cSwNTIzd1cbI89xt3PeZZYJP2y3j8Zus4bXgo4svpX8,1066
18
- ovld-0.5.9.dist-info/RECORD,,
File without changes