ovld 0.4.2__tar.gz → 0.4.4__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.4.2 → ovld-0.4.4}/PKG-INFO +1 -1
- ovld-0.4.4/beary.py +30 -0
- ovld-0.4.4/benchmarks/test_tuple.py +80 -0
- ovld-0.4.4/coco.py +79 -0
- ovld-0.4.4/didi.py +60 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/types.md +10 -0
- {ovld-0.4.2 → ovld-0.4.4}/pyproject.toml +1 -1
- {ovld-0.4.2 → ovld-0.4.4}/reddit.md +2 -1
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/__init__.py +9 -0
- ovld-0.4.4/src/ovld/abc.py +48 -0
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/core.py +16 -28
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/dependent.py +147 -64
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/mro.py +46 -75
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/recode.py +63 -50
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/typemap.py +9 -31
- ovld-0.4.4/src/ovld/types.py +441 -0
- {ovld-0.4.2 → ovld-0.4.4}/src/ovld/utils.py +36 -0
- ovld-0.4.4/src/ovld/version.py +1 -0
- ovld-0.4.4/tests/test_abc.py +270 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_dependent.py +52 -77
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_examples.py +7 -0
- ovld-0.4.4/tests/test_mro.py +181 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_display.txt +12 -12
- ovld-0.4.4/tests/test_ovld/test_display_more.txt +8 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld.py +49 -10
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_typemap.py +42 -25
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_types.py +68 -44
- {ovld-0.4.2 → ovld-0.4.4}/todo.q +6 -3
- {ovld-0.4.2 → ovld-0.4.4}/uv.lock +7 -7
- ovld-0.4.2/didi.py +0 -26
- ovld-0.4.2/src/ovld/types.py +0 -219
- ovld-0.4.2/src/ovld/version.py +0 -1
- ovld-0.4.2/tests/test_mro.py +0 -51
- {ovld-0.4.2 → ovld-0.4.4}/.bsync-snap-20220324145902.852076 +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.bsync-snap-20240916114026.355340 +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.envrc +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.github/workflows/python-package.yml +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.gitignore +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.python-version +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/.readthedocs.yaml +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/LICENSE +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/README.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/add.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/anal.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/bench/requirements.txt +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/bench.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchd.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/__init__.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/common.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_add.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_ast.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_calc.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_fib.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_multer.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_trivial.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_tweaknum.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/cloz.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/data.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/compare.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/dependent.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/features.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/index.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/docs/usage.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/doo.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/edges.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/explore.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/facto.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/gen_comparison_table.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/gentest.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/hello.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/hntest.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/klos.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/mkdocs.yml +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/nxt.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.0-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.0.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.1-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.1.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.2-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.2.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.3-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.3.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.4-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.4.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.5-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.5.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.6-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.6.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.7-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.7.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.8-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.8.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.9-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.9.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.0-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.0.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.1-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.1.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.10-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.10.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.11-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.11.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.2-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.2.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.3-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.3.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.4-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.4.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.5-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.5.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.6-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.6.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.7-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.7.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.8-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.8.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.9-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.9.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.0-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.0.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.1-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.1.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.2-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.2.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.3-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.3.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.4-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.4.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.5-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.5.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.8-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.8.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.9-py3-none-any.whl +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.9.tar.gz +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/one_two_three.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/outoftheway.toml +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/reddit.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/stuff.md +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tb.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tensor.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/__init__.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/modules/gingerbread.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_global.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_doc.txt +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_doc2.txt +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_method_doc.txt +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/tests/test_utils.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/toot.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/typo.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/world.yaml +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/x.py +0 -0
- {ovld-0.4.2 → ovld-0.4.4}/zaggo +0 -0
ovld-0.4.4/beary.py
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
import timeit
|
2
|
+
from typing import Literal
|
3
|
+
from beartype import BeartypeConf # <-- this isn't your fault
|
4
|
+
from beartype.claw import beartype_all, beartype_this_package # <-- you didn't sign up for this
|
5
|
+
from beartype import beartype
|
6
|
+
from ovld import ovld
|
7
|
+
from strongtyping.strong_typing import match_typing
|
8
|
+
|
9
|
+
beartype_all(conf=BeartypeConf())
|
10
|
+
# beartype_this_package() # <-- raise exceptions in your code
|
11
|
+
# beartype_all(conf=BeartypeConf(violation_type=UserWarning))
|
12
|
+
|
13
|
+
@match_typing
|
14
|
+
def f1(x: int, y: int):
|
15
|
+
return x + y
|
16
|
+
|
17
|
+
|
18
|
+
@ovld
|
19
|
+
def f2(x: int, y: int):
|
20
|
+
return x + y
|
21
|
+
|
22
|
+
|
23
|
+
def f3(x: int, y: int):
|
24
|
+
assert isinstance(x, int) and isinstance(y, int)
|
25
|
+
return x + y
|
26
|
+
|
27
|
+
|
28
|
+
print(timeit.timeit(stmt=lambda: f1(3, 4), number=100000))
|
29
|
+
print(timeit.timeit(stmt=lambda: f2(3, 4), number=100000))
|
30
|
+
print(timeit.timeit(stmt=lambda: f3(3, 4), number=100000))
|
@@ -0,0 +1,80 @@
|
|
1
|
+
from typing import Literal
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from .common import (
|
6
|
+
multimethod_dispatch,
|
7
|
+
ovld_dispatch,
|
8
|
+
plum_dispatch,
|
9
|
+
)
|
10
|
+
|
11
|
+
###############################
|
12
|
+
# multiple dispatch libraries #
|
13
|
+
###############################
|
14
|
+
|
15
|
+
|
16
|
+
def make_tup(dispatch):
|
17
|
+
@dispatch
|
18
|
+
def tup(t: tuple[()]):
|
19
|
+
return 0
|
20
|
+
|
21
|
+
@dispatch
|
22
|
+
def tup(t: tuple[int]):
|
23
|
+
return 1
|
24
|
+
|
25
|
+
@dispatch
|
26
|
+
def tup(t: tuple[Literal["x"]]):
|
27
|
+
return 2
|
28
|
+
|
29
|
+
@dispatch
|
30
|
+
def tup(t: tuple[int, str]):
|
31
|
+
return 3
|
32
|
+
|
33
|
+
@dispatch
|
34
|
+
def tup(t: tuple[tuple[str]]):
|
35
|
+
return 4
|
36
|
+
|
37
|
+
return tup
|
38
|
+
|
39
|
+
|
40
|
+
#########
|
41
|
+
# match #
|
42
|
+
#########
|
43
|
+
|
44
|
+
|
45
|
+
def tup_match(expr):
|
46
|
+
match expr:
|
47
|
+
case ():
|
48
|
+
return 0
|
49
|
+
case (int(),):
|
50
|
+
return 1
|
51
|
+
case (str(),):
|
52
|
+
return 2
|
53
|
+
case (int(), str()):
|
54
|
+
return 3
|
55
|
+
case ((str(),),):
|
56
|
+
return 4
|
57
|
+
|
58
|
+
|
59
|
+
####################
|
60
|
+
# Test definitions #
|
61
|
+
####################
|
62
|
+
|
63
|
+
|
64
|
+
def make_test(fn):
|
65
|
+
def run():
|
66
|
+
return [fn(()), fn((1,)), fn(("x",)), fn((2, "y"))]
|
67
|
+
|
68
|
+
@pytest.mark.benchmark(group="tup")
|
69
|
+
def test(benchmark):
|
70
|
+
result = benchmark(run)
|
71
|
+
assert result == [0, 1, 2, 3]
|
72
|
+
|
73
|
+
return test
|
74
|
+
|
75
|
+
|
76
|
+
test_tup_ovld = make_test(make_tup(ovld_dispatch))
|
77
|
+
test_tup_plum = make_test(make_tup(plum_dispatch))
|
78
|
+
test_tup_multimethod = make_test(make_tup(multimethod_dispatch))
|
79
|
+
|
80
|
+
test_tup_custom_match = make_test(tup_match)
|
ovld-0.4.4/coco.py
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
from typing import Callable
|
2
|
+
|
3
|
+
from ovld.core import ovld
|
4
|
+
|
5
|
+
# from plum import dispatch as ovld
|
6
|
+
# from multimethod import multimethod as ovld
|
7
|
+
|
8
|
+
|
9
|
+
class Animal:
|
10
|
+
pass
|
11
|
+
|
12
|
+
|
13
|
+
class Mammal(Animal):
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
class Cat(Mammal):
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
@ovld
|
22
|
+
def f(t: Callable[[Mammal], Mammal]):
|
23
|
+
return 1
|
24
|
+
|
25
|
+
|
26
|
+
@ovld
|
27
|
+
def f(t: Callable[[Mammal, Mammal], Mammal]):
|
28
|
+
return 2
|
29
|
+
|
30
|
+
|
31
|
+
def f1(x: Mammal, y: Mammal) -> Mammal:
|
32
|
+
return "X"
|
33
|
+
|
34
|
+
|
35
|
+
def f2(x: Animal, y: Animal) -> Mammal:
|
36
|
+
return "X"
|
37
|
+
|
38
|
+
|
39
|
+
print(f(f1))
|
40
|
+
print(f(f2))
|
41
|
+
|
42
|
+
|
43
|
+
# @ovld
|
44
|
+
# def f(t: tuple[()]):
|
45
|
+
# return 0
|
46
|
+
|
47
|
+
# @ovld
|
48
|
+
# def f(t: tuple[int]):
|
49
|
+
# return 1
|
50
|
+
|
51
|
+
# @ovld
|
52
|
+
# def f(t: tuple[str]):
|
53
|
+
# return 2
|
54
|
+
|
55
|
+
# @ovld
|
56
|
+
# def f(t: tuple[int, str]):
|
57
|
+
# return 3
|
58
|
+
|
59
|
+
# assert f(()) == 0
|
60
|
+
# assert f((1,)) == 1
|
61
|
+
# assert f(("x",)) == 2
|
62
|
+
# assert f((2, "y")) == 3
|
63
|
+
|
64
|
+
|
65
|
+
# @ovld
|
66
|
+
# def f(d: Sequence[int]):
|
67
|
+
# return 0
|
68
|
+
|
69
|
+
|
70
|
+
# @ovld
|
71
|
+
# def f(d: Sequence[str]):
|
72
|
+
# return 1
|
73
|
+
|
74
|
+
|
75
|
+
# print(f([1]))
|
76
|
+
# print(f(["x"]))
|
77
|
+
# print(f([1, "x"]))
|
78
|
+
# print(f(["x", "y", "z", 1]))
|
79
|
+
# print(f([]))
|
ovld-0.4.4/didi.py
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
from ovld.core import ovld
|
2
|
+
from ovld.dependent import Equals
|
3
|
+
from ovld.types import Dataclass, Exactly, HasMethod
|
4
|
+
|
5
|
+
# U = Union[str, int]
|
6
|
+
# U = str | Equals[0]
|
7
|
+
# print(isinstance("ah", U))
|
8
|
+
# print(isinstance(0, U))
|
9
|
+
# print(is_dependent(U))
|
10
|
+
|
11
|
+
|
12
|
+
@ovld
|
13
|
+
def f(x: str | Equals[0]):
|
14
|
+
return x
|
15
|
+
|
16
|
+
|
17
|
+
breakpoint()
|
18
|
+
print(f(0))
|
19
|
+
print(f(1))
|
20
|
+
print(f("what"))
|
21
|
+
|
22
|
+
|
23
|
+
print(Equals[4].__instancecheck__.__func__)
|
24
|
+
print(HasMethod["__len__"].__instancecheck__.__func__)
|
25
|
+
print(Exactly[int].__instancecheck__.__func__)
|
26
|
+
print(Dataclass.__instancecheck__.__func__)
|
27
|
+
|
28
|
+
|
29
|
+
print(isinstance(4, Equals[4]))
|
30
|
+
print(isinstance(4, Equals[4.0]))
|
31
|
+
print(isinstance([1], HasMethod["__len__"]))
|
32
|
+
print(issubclass(type([1]), HasMethod["__len__"]))
|
33
|
+
|
34
|
+
|
35
|
+
# from multimethod import multimethod as dispatch
|
36
|
+
# from plum import dispatch
|
37
|
+
# from runtype import multidispatch as dispatch
|
38
|
+
|
39
|
+
# from ovld import ovld as dispatch
|
40
|
+
|
41
|
+
|
42
|
+
# @dispatch
|
43
|
+
# def f(x: type[int]):
|
44
|
+
# return "ah"
|
45
|
+
|
46
|
+
|
47
|
+
# @dispatch
|
48
|
+
# def f(x: type[object]):
|
49
|
+
# return "something else"
|
50
|
+
|
51
|
+
|
52
|
+
# @dispatch
|
53
|
+
# def f(x: type[dict[str, object]]):
|
54
|
+
# return ("didi", x)
|
55
|
+
|
56
|
+
|
57
|
+
# print(f(int))
|
58
|
+
# print(f(str))
|
59
|
+
# print(f(dict[str, int]))
|
60
|
+
# print(f(dict[int, int]))
|
@@ -129,6 +129,16 @@ f(123) # ERROR
|
|
129
129
|
```
|
130
130
|
|
131
131
|
|
132
|
+
## All
|
133
|
+
|
134
|
+
`ovld.types.All` is the bottom/empty/void type. You can use it as a wildcard in a contravariant setting, e.g. all 2-argument functions are instances of `Callable[[All, All], Any]` because the arguments are contravariant.
|
135
|
+
|
136
|
+
|
137
|
+
## Whatever
|
138
|
+
|
139
|
+
`ovld.types.Whatever` acts like a superclass and a subclass of everything, as a convenience (a bit like saying "there's no type here"). It'll match anything anywhere, so you can write e.g. `Callable[[Whatever, Whatever], Whatever]` to match any function of two arguments, whereas otherwise you would need to use `Any` for the return type and `All` for the parameter types.
|
140
|
+
|
141
|
+
|
132
142
|
## Defining new types
|
133
143
|
|
134
144
|
With the `@parametrized_class_check` decorator, you can define a new type or protocol extremely easily. For example, here is how to define `HasMethod` yourself:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
## What My Project Does
|
2
2
|
|
3
|
-
|
3
|
+
[ovld](https://github.com/breuleux/ovld) implements multiple dispatch in Python. This lets you define multiple versions of the same function with different type signatures.
|
4
4
|
|
5
5
|
For example:
|
6
6
|
|
@@ -35,6 +35,7 @@ Ovld is pretty generally applicable: multiple dispatch is a central feature of s
|
|
35
35
|
## Features
|
36
36
|
|
37
37
|
* Wide range of supported annotations: normal types, protocols, Union, Literal, [custom types](https://ovld.readthedocs.io/en/latest/types/#defining-new-types) such as HasMethod, Intersection and arbitrary user-defined types.
|
38
|
+
* Intersection type, so you can write types like `Shape[Any, 3] & Int8 & OnGPU`
|
38
39
|
* Support for [dependent types](https://ovld.readthedocs.io/en/latest/dependent/), by which I mean "types" that depend on the values of the arguments. For example you can easily implement a `Regexp[regex]` type that matches string arguments based on regular expressions, or a type that only matches 2x2 torch.Tensor with int8 dtype.
|
39
40
|
* Dispatch on keyword arguments (with a few limitations).
|
40
41
|
* Define numeric priority levels for disambiguation.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
2
|
|
3
|
+
from . import abc # noqa: F401
|
3
4
|
from .core import (
|
4
5
|
Ovld,
|
5
6
|
OvldBase,
|
@@ -15,6 +16,11 @@ from .dependent import (
|
|
15
16
|
ParametrizedDependentType,
|
16
17
|
dependent_check,
|
17
18
|
)
|
19
|
+
from .mro import (
|
20
|
+
TypeRelationship,
|
21
|
+
subclasscheck,
|
22
|
+
typeorder,
|
23
|
+
)
|
18
24
|
from .recode import call_next, recurse
|
19
25
|
from .typemap import (
|
20
26
|
MultiTypeMap,
|
@@ -66,6 +72,9 @@ __all__ = [
|
|
66
72
|
"Intersection",
|
67
73
|
"StrictSubclass",
|
68
74
|
"class_check",
|
75
|
+
"subclasscheck",
|
76
|
+
"typeorder",
|
77
|
+
"TypeRelationship",
|
69
78
|
"parametrized_class_check",
|
70
79
|
"keyword_decorator",
|
71
80
|
"call_next",
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import typing
|
2
|
+
from collections.abc import Callable, Collection, Mapping, Sequence
|
3
|
+
|
4
|
+
from .dependent import Callable as OvldCallable
|
5
|
+
from .dependent import (
|
6
|
+
CollectionFastCheck,
|
7
|
+
Equals,
|
8
|
+
MappingFastCheck,
|
9
|
+
ProductType,
|
10
|
+
SequenceFastCheck,
|
11
|
+
)
|
12
|
+
from .types import normalize_type
|
13
|
+
|
14
|
+
|
15
|
+
@normalize_type.register_generic(typing.Literal)
|
16
|
+
def _(self, t, fn):
|
17
|
+
return Equals[t.__args__]
|
18
|
+
|
19
|
+
|
20
|
+
@normalize_type.register_generic(tuple)
|
21
|
+
def _(self, t, fn):
|
22
|
+
args = tuple(self(arg, fn) for arg in t.__args__)
|
23
|
+
return ProductType[args]
|
24
|
+
|
25
|
+
|
26
|
+
@normalize_type.register_generic(Sequence)
|
27
|
+
def _(self, t, fn):
|
28
|
+
args = tuple(self(arg, fn) for arg in t.__args__)
|
29
|
+
return SequenceFastCheck[args]
|
30
|
+
|
31
|
+
|
32
|
+
@normalize_type.register_generic(Collection)
|
33
|
+
def _(self, t, fn):
|
34
|
+
args = tuple(self(arg, fn) for arg in t.__args__)
|
35
|
+
return CollectionFastCheck[args]
|
36
|
+
|
37
|
+
|
38
|
+
@normalize_type.register_generic(Mapping)
|
39
|
+
def _(self, t, fn):
|
40
|
+
args = tuple(self(arg, fn) for arg in t.__args__)
|
41
|
+
return MappingFastCheck[args]
|
42
|
+
|
43
|
+
|
44
|
+
@normalize_type.register_generic(Callable)
|
45
|
+
def _(self, t, fn):
|
46
|
+
*at, rt = t.__args__
|
47
|
+
at = tuple(self(arg, fn) for arg in at)
|
48
|
+
return OvldCallable[at, self(rt, fn)]
|
@@ -16,9 +16,9 @@ from .recode import (
|
|
16
16
|
generate_dispatch,
|
17
17
|
rename_function,
|
18
18
|
)
|
19
|
-
from .typemap import MultiTypeMap
|
20
|
-
from .types import normalize_type
|
21
|
-
from .utils import UsageError, keyword_decorator
|
19
|
+
from .typemap import MultiTypeMap
|
20
|
+
from .types import clsstring, normalize_type
|
21
|
+
from .utils import UsageError, keyword_decorator, subtler_type
|
22
22
|
|
23
23
|
_current_id = itertools.count()
|
24
24
|
|
@@ -80,6 +80,7 @@ class Arginfo:
|
|
80
80
|
@dataclass(frozen=True)
|
81
81
|
class Signature:
|
82
82
|
types: tuple
|
83
|
+
return_type: type
|
83
84
|
req_pos: int
|
84
85
|
max_pos: int
|
85
86
|
req_names: frozenset
|
@@ -139,6 +140,7 @@ class Signature:
|
|
139
140
|
|
140
141
|
return cls(
|
141
142
|
types=tuple(typelist),
|
143
|
+
return_type=normalize_type(sig.return_annotation, fn),
|
142
144
|
req_pos=req_pos,
|
143
145
|
max_pos=max_pos,
|
144
146
|
req_names=frozenset(req_names),
|
@@ -149,28 +151,16 @@ class Signature:
|
|
149
151
|
)
|
150
152
|
|
151
153
|
|
152
|
-
def
|
153
|
-
if cls
|
154
|
-
return "*"
|
155
|
-
elif isinstance(cls, tuple):
|
154
|
+
def typemap_entry_string(cls):
|
155
|
+
if isinstance(cls, tuple):
|
156
156
|
key, typ = cls
|
157
157
|
return f"{key}: {clsstring(typ)}"
|
158
|
-
elif is_type_of_type(cls):
|
159
|
-
arg = clsstring(cls.__args__[0])
|
160
|
-
return f"type[{arg}]"
|
161
|
-
elif hasattr(cls, "__origin__"):
|
162
|
-
if cls.__origin__ is typing.Union:
|
163
|
-
return "|".join(map(clsstring, cls.__args__))
|
164
|
-
else:
|
165
|
-
return repr(cls)
|
166
|
-
elif hasattr(cls, "__name__"):
|
167
|
-
return cls.__name__
|
168
158
|
else:
|
169
|
-
return
|
159
|
+
return clsstring(cls)
|
170
160
|
|
171
161
|
|
172
162
|
def sigstring(types):
|
173
|
-
return ", ".join(map(
|
163
|
+
return ", ".join(map(typemap_entry_string, types))
|
174
164
|
|
175
165
|
|
176
166
|
class ArgumentAnalyzer:
|
@@ -277,9 +267,7 @@ class ArgumentAnalyzer:
|
|
277
267
|
)
|
278
268
|
|
279
269
|
def lookup_for(self, key):
|
280
|
-
return
|
281
|
-
"self.map.transform" if key in self.complex_transforms else "type"
|
282
|
-
)
|
270
|
+
return subtler_type if key in self.complex_transforms else type
|
283
271
|
|
284
272
|
|
285
273
|
class _Ovld:
|
@@ -473,7 +461,7 @@ class _Ovld:
|
|
473
461
|
@_compile_first
|
474
462
|
def resolve(self, *args):
|
475
463
|
"""Find the correct method to call for the given arguments."""
|
476
|
-
return self.map[tuple(map(
|
464
|
+
return self.map[tuple(map(subtler_type, args))]
|
477
465
|
|
478
466
|
def register_signature(self, sig, orig_fn):
|
479
467
|
"""Register a function for the given signature."""
|
@@ -577,7 +565,7 @@ class _Ovld:
|
|
577
565
|
|
578
566
|
This should be replaced by an auto-generated function.
|
579
567
|
"""
|
580
|
-
key = tuple(map(
|
568
|
+
key = tuple(map(subtler_type, args))
|
581
569
|
method = self.map[key]
|
582
570
|
return method(*args)
|
583
571
|
|
@@ -586,7 +574,7 @@ class _Ovld:
|
|
586
574
|
def next(self, *args):
|
587
575
|
"""Call the next matching method after the caller, in terms of priority or specificity."""
|
588
576
|
fr = sys._getframe(1)
|
589
|
-
key = (fr.f_code, *map(
|
577
|
+
key = (fr.f_code, *map(subtler_type, args))
|
590
578
|
method = self.map[key]
|
591
579
|
return method(*args)
|
592
580
|
|
@@ -631,20 +619,20 @@ class OvldCall:
|
|
631
619
|
def next(self, *args):
|
632
620
|
"""Call the next matching method after the caller, in terms of priority or specificity."""
|
633
621
|
fr = sys._getframe(1)
|
634
|
-
key = (fr.f_code, *map(
|
622
|
+
key = (fr.f_code, *map(subtler_type, args))
|
635
623
|
method = self.map[key]
|
636
624
|
return method(self.obj, *args)
|
637
625
|
|
638
626
|
def resolve(self, *args):
|
639
627
|
"""Find the right method to call for the given arguments."""
|
640
|
-
return self.map[tuple(map(
|
628
|
+
return self.map[tuple(map(subtler_type, args))].__get__(self.obj)
|
641
629
|
|
642
630
|
def __call__(self, *args): # pragma: no cover
|
643
631
|
"""Call this overloaded function.
|
644
632
|
|
645
633
|
This should be replaced by an auto-generated function.
|
646
634
|
"""
|
647
|
-
key = tuple(map(
|
635
|
+
key = tuple(map(subtler_type, args))
|
648
636
|
method = self.map[key]
|
649
637
|
return method(self.obj, *args)
|
650
638
|
|