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.
Files changed (152) hide show
  1. {ovld-0.4.2 → ovld-0.4.4}/PKG-INFO +1 -1
  2. ovld-0.4.4/beary.py +30 -0
  3. ovld-0.4.4/benchmarks/test_tuple.py +80 -0
  4. ovld-0.4.4/coco.py +79 -0
  5. ovld-0.4.4/didi.py +60 -0
  6. {ovld-0.4.2 → ovld-0.4.4}/docs/types.md +10 -0
  7. {ovld-0.4.2 → ovld-0.4.4}/pyproject.toml +1 -1
  8. {ovld-0.4.2 → ovld-0.4.4}/reddit.md +2 -1
  9. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/__init__.py +9 -0
  10. ovld-0.4.4/src/ovld/abc.py +48 -0
  11. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/core.py +16 -28
  12. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/dependent.py +147 -64
  13. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/mro.py +46 -75
  14. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/recode.py +63 -50
  15. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/typemap.py +9 -31
  16. ovld-0.4.4/src/ovld/types.py +441 -0
  17. {ovld-0.4.2 → ovld-0.4.4}/src/ovld/utils.py +36 -0
  18. ovld-0.4.4/src/ovld/version.py +1 -0
  19. ovld-0.4.4/tests/test_abc.py +270 -0
  20. {ovld-0.4.2 → ovld-0.4.4}/tests/test_dependent.py +52 -77
  21. {ovld-0.4.2 → ovld-0.4.4}/tests/test_examples.py +7 -0
  22. ovld-0.4.4/tests/test_mro.py +181 -0
  23. {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_display.txt +12 -12
  24. ovld-0.4.4/tests/test_ovld/test_display_more.txt +8 -0
  25. {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld.py +49 -10
  26. {ovld-0.4.2 → ovld-0.4.4}/tests/test_typemap.py +42 -25
  27. {ovld-0.4.2 → ovld-0.4.4}/tests/test_types.py +68 -44
  28. {ovld-0.4.2 → ovld-0.4.4}/todo.q +6 -3
  29. {ovld-0.4.2 → ovld-0.4.4}/uv.lock +7 -7
  30. ovld-0.4.2/didi.py +0 -26
  31. ovld-0.4.2/src/ovld/types.py +0 -219
  32. ovld-0.4.2/src/ovld/version.py +0 -1
  33. ovld-0.4.2/tests/test_mro.py +0 -51
  34. {ovld-0.4.2 → ovld-0.4.4}/.bsync-snap-20220324145902.852076 +0 -0
  35. {ovld-0.4.2 → ovld-0.4.4}/.bsync-snap-20240916114026.355340 +0 -0
  36. {ovld-0.4.2 → ovld-0.4.4}/.envrc +0 -0
  37. {ovld-0.4.2 → ovld-0.4.4}/.github/workflows/python-package.yml +0 -0
  38. {ovld-0.4.2 → ovld-0.4.4}/.gitignore +0 -0
  39. {ovld-0.4.2 → ovld-0.4.4}/.python-version +0 -0
  40. {ovld-0.4.2 → ovld-0.4.4}/.readthedocs.yaml +0 -0
  41. {ovld-0.4.2 → ovld-0.4.4}/LICENSE +0 -0
  42. {ovld-0.4.2 → ovld-0.4.4}/README.md +0 -0
  43. {ovld-0.4.2 → ovld-0.4.4}/add.py +0 -0
  44. {ovld-0.4.2 → ovld-0.4.4}/anal.py +0 -0
  45. {ovld-0.4.2 → ovld-0.4.4}/bench/requirements.txt +0 -0
  46. {ovld-0.4.2 → ovld-0.4.4}/bench.py +0 -0
  47. {ovld-0.4.2 → ovld-0.4.4}/benchd.py +0 -0
  48. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/__init__.py +0 -0
  49. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/common.py +0 -0
  50. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_add.py +0 -0
  51. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_ast.py +0 -0
  52. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_calc.py +0 -0
  53. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_fib.py +0 -0
  54. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_multer.py +0 -0
  55. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_trivial.py +0 -0
  56. {ovld-0.4.2 → ovld-0.4.4}/benchmarks/test_tweaknum.py +0 -0
  57. {ovld-0.4.2 → ovld-0.4.4}/cloz.py +0 -0
  58. {ovld-0.4.2 → ovld-0.4.4}/data.py +0 -0
  59. {ovld-0.4.2 → ovld-0.4.4}/docs/compare.md +0 -0
  60. {ovld-0.4.2 → ovld-0.4.4}/docs/dependent.md +0 -0
  61. {ovld-0.4.2 → ovld-0.4.4}/docs/features.md +0 -0
  62. {ovld-0.4.2 → ovld-0.4.4}/docs/index.md +0 -0
  63. {ovld-0.4.2 → ovld-0.4.4}/docs/usage.md +0 -0
  64. {ovld-0.4.2 → ovld-0.4.4}/doo.py +0 -0
  65. {ovld-0.4.2 → ovld-0.4.4}/edges.py +0 -0
  66. {ovld-0.4.2 → ovld-0.4.4}/explore.py +0 -0
  67. {ovld-0.4.2 → ovld-0.4.4}/facto.py +0 -0
  68. {ovld-0.4.2 → ovld-0.4.4}/gen_comparison_table.py +0 -0
  69. {ovld-0.4.2 → ovld-0.4.4}/gentest.py +0 -0
  70. {ovld-0.4.2 → ovld-0.4.4}/hello.py +0 -0
  71. {ovld-0.4.2 → ovld-0.4.4}/hntest.py +0 -0
  72. {ovld-0.4.2 → ovld-0.4.4}/klos.py +0 -0
  73. {ovld-0.4.2 → ovld-0.4.4}/mkdocs.yml +0 -0
  74. {ovld-0.4.2 → ovld-0.4.4}/nxt.py +0 -0
  75. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.0-py3-none-any.whl +0 -0
  76. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.0.tar.gz +0 -0
  77. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.1-py3-none-any.whl +0 -0
  78. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.1.tar.gz +0 -0
  79. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.2-py3-none-any.whl +0 -0
  80. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.2.tar.gz +0 -0
  81. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.3-py3-none-any.whl +0 -0
  82. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.3.tar.gz +0 -0
  83. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.4-py3-none-any.whl +0 -0
  84. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.4.tar.gz +0 -0
  85. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.5-py3-none-any.whl +0 -0
  86. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.5.tar.gz +0 -0
  87. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.6-py3-none-any.whl +0 -0
  88. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.6.tar.gz +0 -0
  89. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.7-py3-none-any.whl +0 -0
  90. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.7.tar.gz +0 -0
  91. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.8-py3-none-any.whl +0 -0
  92. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.8.tar.gz +0 -0
  93. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.9-py3-none-any.whl +0 -0
  94. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.1.9.tar.gz +0 -0
  95. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.0-py3-none-any.whl +0 -0
  96. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.0.tar.gz +0 -0
  97. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.1-py3-none-any.whl +0 -0
  98. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.1.tar.gz +0 -0
  99. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.10-py3-none-any.whl +0 -0
  100. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.10.tar.gz +0 -0
  101. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.11-py3-none-any.whl +0 -0
  102. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.11.tar.gz +0 -0
  103. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.2-py3-none-any.whl +0 -0
  104. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.2.tar.gz +0 -0
  105. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.3-py3-none-any.whl +0 -0
  106. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.3.tar.gz +0 -0
  107. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.4-py3-none-any.whl +0 -0
  108. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.4.tar.gz +0 -0
  109. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.5-py3-none-any.whl +0 -0
  110. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.5.tar.gz +0 -0
  111. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.6-py3-none-any.whl +0 -0
  112. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.6.tar.gz +0 -0
  113. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.7-py3-none-any.whl +0 -0
  114. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.7.tar.gz +0 -0
  115. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.8-py3-none-any.whl +0 -0
  116. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.8.tar.gz +0 -0
  117. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.9-py3-none-any.whl +0 -0
  118. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.2.9.tar.gz +0 -0
  119. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.0-py3-none-any.whl +0 -0
  120. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.0.tar.gz +0 -0
  121. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.1-py3-none-any.whl +0 -0
  122. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.1.tar.gz +0 -0
  123. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.2-py3-none-any.whl +0 -0
  124. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.2.tar.gz +0 -0
  125. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.3-py3-none-any.whl +0 -0
  126. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.3.tar.gz +0 -0
  127. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.4-py3-none-any.whl +0 -0
  128. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.4.tar.gz +0 -0
  129. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.5-py3-none-any.whl +0 -0
  130. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.5.tar.gz +0 -0
  131. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.8-py3-none-any.whl +0 -0
  132. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.8.tar.gz +0 -0
  133. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.9-py3-none-any.whl +0 -0
  134. {ovld-0.4.2 → ovld-0.4.4}/old-dist/ovld-0.3.9.tar.gz +0 -0
  135. {ovld-0.4.2 → ovld-0.4.4}/one_two_three.py +0 -0
  136. {ovld-0.4.2 → ovld-0.4.4}/outoftheway.toml +0 -0
  137. {ovld-0.4.2 → ovld-0.4.4}/reddit.py +0 -0
  138. {ovld-0.4.2 → ovld-0.4.4}/stuff.md +0 -0
  139. {ovld-0.4.2 → ovld-0.4.4}/tb.py +0 -0
  140. {ovld-0.4.2 → ovld-0.4.4}/tensor.py +0 -0
  141. {ovld-0.4.2 → ovld-0.4.4}/tests/__init__.py +0 -0
  142. {ovld-0.4.2 → ovld-0.4.4}/tests/modules/gingerbread.py +0 -0
  143. {ovld-0.4.2 → ovld-0.4.4}/tests/test_global.py +0 -0
  144. {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_doc.txt +0 -0
  145. {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_doc2.txt +0 -0
  146. {ovld-0.4.2 → ovld-0.4.4}/tests/test_ovld/test_method_doc.txt +0 -0
  147. {ovld-0.4.2 → ovld-0.4.4}/tests/test_utils.py +0 -0
  148. {ovld-0.4.2 → ovld-0.4.4}/toot.py +0 -0
  149. {ovld-0.4.2 → ovld-0.4.4}/typo.py +0 -0
  150. {ovld-0.4.2 → ovld-0.4.4}/world.yaml +0 -0
  151. {ovld-0.4.2 → ovld-0.4.4}/x.py +0 -0
  152. {ovld-0.4.2 → ovld-0.4.4}/zaggo +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ovld
3
- Version: 0.4.2
3
+ Version: 0.4.4
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/
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
  [project]
2
2
  name = "ovld"
3
- version = "0.4.2"
3
+ version = "0.4.4"
4
4
  description = "Overloading Python functions"
5
5
  authors = [
6
6
  { name = "Olivier Breuleux", email = "breuleux@gmail.com" }
@@ -1,6 +1,6 @@
1
1
  ## What My Project Does
2
2
 
3
- `ovld` implements multiple dispatch in Python. This lets you define multiple versions of the same function with different type signatures.
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, is_type_of_type
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 clsstring(cls):
153
- if cls is object:
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 repr(cls)
159
+ return clsstring(cls)
170
160
 
171
161
 
172
162
  def sigstring(types):
173
- return ", ".join(map(clsstring, types))
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(self.map.transform, args))]
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(self.map.transform, args))
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(self.map.transform, args))
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(self.map.transform, args))
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(self.map.transform, args))].__get__(self.obj)
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(self.map.transform, args))
635
+ key = tuple(map(subtler_type, args))
648
636
  method = self.map[key]
649
637
  return method(self.obj, *args)
650
638