ovld 0.4.2__py3-none-any.whl → 0.4.4__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/__init__.py +9 -0
- ovld/abc.py +48 -0
- ovld/core.py +16 -28
- ovld/dependent.py +147 -64
- ovld/mro.py +46 -75
- ovld/recode.py +63 -50
- ovld/typemap.py +9 -31
- ovld/types.py +297 -75
- ovld/utils.py +36 -0
- ovld/version.py +1 -1
- {ovld-0.4.2.dist-info → ovld-0.4.4.dist-info}/METADATA +1 -1
- ovld-0.4.4.dist-info/RECORD +14 -0
- ovld-0.4.2.dist-info/RECORD +0 -13
- {ovld-0.4.2.dist-info → ovld-0.4.4.dist-info}/WHEEL +0 -0
- {ovld-0.4.2.dist-info → ovld-0.4.4.dist-info}/licenses/LICENSE +0 -0
ovld/__init__.py
CHANGED
@@ -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",
|
ovld/abc.py
ADDED
@@ -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)]
|
ovld/core.py
CHANGED
@@ -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
|
|
ovld/dependent.py
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
import inspect
|
2
2
|
import re
|
3
|
+
from collections.abc import Callable as _Callable
|
4
|
+
from collections.abc import Mapping, Sequence
|
3
5
|
from dataclasses import dataclass
|
6
|
+
from functools import partial
|
4
7
|
from itertools import count
|
5
|
-
from typing import
|
8
|
+
from typing import (
|
9
|
+
TYPE_CHECKING,
|
10
|
+
Any,
|
11
|
+
Collection,
|
12
|
+
TypeVar,
|
13
|
+
)
|
6
14
|
|
7
15
|
from .types import (
|
8
16
|
Intersection,
|
9
17
|
Order,
|
10
|
-
|
18
|
+
clsstring,
|
11
19
|
normalize_type,
|
12
20
|
subclasscheck,
|
13
21
|
typeorder,
|
@@ -16,6 +24,13 @@ from .types import (
|
|
16
24
|
_current = count()
|
17
25
|
|
18
26
|
|
27
|
+
def generate_checking_code(typ):
|
28
|
+
if hasattr(typ, "codegen"):
|
29
|
+
return typ.codegen()
|
30
|
+
else:
|
31
|
+
return CodeGen("isinstance({arg}, {this})", {"this": typ})
|
32
|
+
|
33
|
+
|
19
34
|
@dataclass
|
20
35
|
class CodeGen:
|
21
36
|
template: str
|
@@ -47,9 +62,22 @@ def combine(master_template, args):
|
|
47
62
|
return CodeGen(master_template.format(*fmts), subs)
|
48
63
|
|
49
64
|
|
50
|
-
|
65
|
+
def is_dependent(t):
|
66
|
+
if isinstance(t, DependentType):
|
67
|
+
return True
|
68
|
+
elif any(is_dependent(subt) for subt in getattr(t, "__args__", ())):
|
69
|
+
return True
|
70
|
+
return False
|
71
|
+
|
72
|
+
|
73
|
+
class DependentType(type):
|
51
74
|
exclusive_type = False
|
52
75
|
keyable_type = False
|
76
|
+
bound_is_name = False
|
77
|
+
|
78
|
+
def __new__(cls, *args, **kwargs):
|
79
|
+
value = super().__new__(cls, cls.__name__, (), {})
|
80
|
+
return value
|
53
81
|
|
54
82
|
def __init__(self, bound):
|
55
83
|
self.bound = bound
|
@@ -67,39 +95,48 @@ class DependentType:
|
|
67
95
|
def codegen(self):
|
68
96
|
return CodeGen("{this}.check({arg})", {"this": self})
|
69
97
|
|
70
|
-
def
|
98
|
+
def __type_order__(self, other):
|
71
99
|
if isinstance(other, DependentType):
|
72
100
|
order = typeorder(self.bound, other.bound)
|
73
101
|
if order is Order.SAME:
|
74
102
|
# It isn't fully deterministic which of these will be called
|
75
103
|
# because of set ordering between the types we compare
|
76
104
|
if self < other: # pragma: no cover
|
77
|
-
return
|
105
|
+
return Order.LESS
|
78
106
|
elif other < self: # pragma: no cover
|
79
|
-
return
|
107
|
+
return Order.MORE
|
80
108
|
else:
|
81
|
-
return
|
109
|
+
return Order.NONE
|
82
110
|
else: # pragma: no cover
|
83
|
-
return
|
84
|
-
elif
|
111
|
+
return order
|
112
|
+
elif subclasscheck(other, self.bound) or subclasscheck(
|
85
113
|
self.bound, other
|
86
114
|
):
|
87
|
-
return
|
115
|
+
return Order.LESS
|
88
116
|
else:
|
89
|
-
return
|
117
|
+
return Order.NONE
|
118
|
+
|
119
|
+
def __is_supertype__(self, other):
|
120
|
+
if isinstance(other, DependentType):
|
121
|
+
return False
|
122
|
+
elif subclasscheck(other, self.bound):
|
123
|
+
return True
|
124
|
+
else:
|
125
|
+
return False
|
126
|
+
|
127
|
+
def __instancecheck__(self, other):
|
128
|
+
return isinstance(other, self.bound) and self.check(other)
|
90
129
|
|
91
130
|
def __lt__(self, other):
|
92
131
|
return False
|
93
132
|
|
94
|
-
def __or__(self, other):
|
95
|
-
if not isinstance(other, DependentType):
|
96
|
-
return NotImplemented
|
97
|
-
return Or(self, other)
|
98
|
-
|
99
133
|
def __and__(self, other):
|
100
|
-
|
101
|
-
|
102
|
-
|
134
|
+
return Intersection[self, other]
|
135
|
+
|
136
|
+
def __rand__(self, other):
|
137
|
+
return Intersection[other, self]
|
138
|
+
|
139
|
+
__repr__ = __str__ = clsstring
|
103
140
|
|
104
141
|
|
105
142
|
class ParametrizedDependentType(DependentType):
|
@@ -107,7 +144,7 @@ class ParametrizedDependentType(DependentType):
|
|
107
144
|
super().__init__(
|
108
145
|
self.default_bound(*parameters) if bound is None else bound
|
109
146
|
)
|
110
|
-
self.parameters = parameters
|
147
|
+
self.__args__ = self.parameters = parameters
|
111
148
|
|
112
149
|
@property
|
113
150
|
def parameter(self):
|
@@ -130,8 +167,17 @@ class ParametrizedDependentType(DependentType):
|
|
130
167
|
return hash(self.parameters) ^ hash(self.bound)
|
131
168
|
|
132
169
|
def __str__(self):
|
133
|
-
|
134
|
-
|
170
|
+
if self.bound_is_name:
|
171
|
+
origin = self.bound
|
172
|
+
bound = ""
|
173
|
+
else:
|
174
|
+
origin = self
|
175
|
+
if self.bound != self.default_bound(*self.parameters):
|
176
|
+
bound = f" < {clsstring(self.bound)}"
|
177
|
+
else:
|
178
|
+
bound = ""
|
179
|
+
args = ", ".join(map(clsstring, self.__args__))
|
180
|
+
return f"{origin.__name__}[{args}]{bound}"
|
135
181
|
|
136
182
|
__repr__ = __str__
|
137
183
|
|
@@ -160,8 +206,14 @@ class FuncDependentType(ParametrizedDependentType):
|
|
160
206
|
return type(self).func(value, *self.parameters)
|
161
207
|
|
162
208
|
|
163
|
-
def dependent_check(fn):
|
164
|
-
|
209
|
+
def dependent_check(fn=None, bound_is_name=False):
|
210
|
+
if fn is None:
|
211
|
+
return partial(dependent_check, bound_is_name=bound_is_name)
|
212
|
+
t = type(
|
213
|
+
fn.__name__,
|
214
|
+
(FuncDependentType,),
|
215
|
+
{"func": fn, "bound_is_name": bound_is_name},
|
216
|
+
)
|
165
217
|
if len(inspect.signature(fn).parameters) == 1:
|
166
218
|
t = t()
|
167
219
|
return t
|
@@ -190,8 +242,77 @@ class Equals(ParametrizedDependentType):
|
|
190
242
|
return CodeGen("({arg} in {ps})", {"ps": self.parameters})
|
191
243
|
|
192
244
|
|
245
|
+
class ProductType(ParametrizedDependentType):
|
246
|
+
bound_is_name = True
|
247
|
+
|
248
|
+
def default_bound(self, *subtypes):
|
249
|
+
return tuple
|
250
|
+
|
251
|
+
def check(self, value):
|
252
|
+
return (
|
253
|
+
isinstance(value, tuple)
|
254
|
+
and len(value) == len(self.parameters)
|
255
|
+
and all(isinstance(x, t) for x, t in zip(value, self.parameters))
|
256
|
+
)
|
257
|
+
|
258
|
+
def codegen(self):
|
259
|
+
checks = ["len({arg}) == {n}"]
|
260
|
+
params = {"n": len(self.parameters)}
|
261
|
+
for i, p in enumerate(self.parameters):
|
262
|
+
checks.append(f"isinstance({{arg}}[{i}], {{p{i}}})")
|
263
|
+
params[f"p{i}"] = p
|
264
|
+
return CodeGen(" and ".join(checks), params)
|
265
|
+
|
266
|
+
def __type_order__(self, other):
|
267
|
+
if isinstance(other, ProductType):
|
268
|
+
if len(other.parameters) == len(self.parameters):
|
269
|
+
return Order.merge(
|
270
|
+
typeorder(a, b)
|
271
|
+
for a, b in zip(self.parameters, other.parameters)
|
272
|
+
)
|
273
|
+
else:
|
274
|
+
return Order.NONE
|
275
|
+
else:
|
276
|
+
return NotImplemented
|
277
|
+
|
278
|
+
|
279
|
+
@dependent_check(bound_is_name=True)
|
280
|
+
def SequenceFastCheck(value: Sequence, typ):
|
281
|
+
return not value or isinstance(value[0], typ)
|
282
|
+
|
283
|
+
|
284
|
+
@dependent_check(bound_is_name=True)
|
285
|
+
def CollectionFastCheck(value: Collection, typ):
|
286
|
+
for x in value:
|
287
|
+
return isinstance(x, typ)
|
288
|
+
else:
|
289
|
+
return True
|
290
|
+
|
291
|
+
|
292
|
+
@dependent_check(bound_is_name=True)
|
293
|
+
def MappingFastCheck(value: Mapping, kt, vt):
|
294
|
+
if not value:
|
295
|
+
return True
|
296
|
+
for k in value:
|
297
|
+
break
|
298
|
+
return isinstance(k, kt) and isinstance(value[k], vt)
|
299
|
+
|
300
|
+
|
301
|
+
@dependent_check
|
302
|
+
def Callable(fn: _Callable, argt, rett):
|
303
|
+
from .core import Signature
|
304
|
+
|
305
|
+
sig = Signature.extract(fn)
|
306
|
+
return (
|
307
|
+
sig.max_pos >= len(argt) >= sig.req_pos
|
308
|
+
and not sig.req_names
|
309
|
+
and all(subclasscheck(t1, t2) for t1, t2 in zip(argt, sig.types))
|
310
|
+
and subclasscheck(sig.return_type, rett)
|
311
|
+
)
|
312
|
+
|
313
|
+
|
193
314
|
@dependent_check
|
194
|
-
def
|
315
|
+
def HasKey(value: Mapping, *keys):
|
195
316
|
return all(k in value for k in keys)
|
196
317
|
|
197
318
|
|
@@ -218,44 +339,6 @@ class Dependent:
|
|
218
339
|
return dt.with_bound(bound)
|
219
340
|
|
220
341
|
|
221
|
-
class Or(DependentType):
|
222
|
-
def __init__(self, *types, bound=None):
|
223
|
-
self.types = types
|
224
|
-
super().__init__(bound or self.default_bound())
|
225
|
-
|
226
|
-
def default_bound(self):
|
227
|
-
return Union[tuple([t.bound for t in self.types])]
|
228
|
-
|
229
|
-
def codegen(self):
|
230
|
-
template = " or ".join("{}" for t in self.types)
|
231
|
-
return combine(template, [t.codegen() for t in self.types])
|
232
|
-
|
233
|
-
def check(self, value):
|
234
|
-
return any(t.check(value) for t in self.types)
|
235
|
-
|
236
|
-
|
237
|
-
class And(DependentType):
|
238
|
-
def __init__(self, *types, bound=None):
|
239
|
-
self.types = types
|
240
|
-
super().__init__(bound or self.default_bound())
|
241
|
-
|
242
|
-
def default_bound(self):
|
243
|
-
bounds = frozenset(t.bound for t in self.types)
|
244
|
-
return Intersection[tuple(bounds)]
|
245
|
-
|
246
|
-
def codegen(self):
|
247
|
-
template = " and ".join("{}" for t in self.types)
|
248
|
-
return combine(template, [t.codegen() for t in self.types])
|
249
|
-
|
250
|
-
def check(self, value):
|
251
|
-
return all(t.check(value) for t in self.types)
|
252
|
-
|
253
|
-
def __str__(self):
|
254
|
-
return " & ".join(map(repr, self.types))
|
255
|
-
|
256
|
-
__repr__ = __str__
|
257
|
-
|
258
|
-
|
259
342
|
if TYPE_CHECKING: # pragma: no cover
|
260
343
|
from typing import Annotated, TypeAlias
|
261
344
|
|
@@ -268,7 +351,7 @@ __all__ = [
|
|
268
351
|
"Dependent",
|
269
352
|
"DependentType",
|
270
353
|
"Equals",
|
271
|
-
"
|
354
|
+
"HasKey",
|
272
355
|
"StartsWith",
|
273
356
|
"EndsWith",
|
274
357
|
"dependent_check",
|
ovld/mro.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import typing
|
2
1
|
from dataclasses import dataclass
|
3
2
|
from enum import Enum
|
4
3
|
from graphlib import TopologicalSorter
|
4
|
+
from typing import get_args, get_origin
|
5
5
|
|
6
6
|
|
7
7
|
class Order(Enum):
|
@@ -18,21 +18,24 @@ class Order(Enum):
|
|
18
18
|
else:
|
19
19
|
return self
|
20
20
|
|
21
|
+
@staticmethod
|
22
|
+
def merge(orders):
|
23
|
+
orders = set(orders)
|
24
|
+
if orders == {Order.SAME}:
|
25
|
+
return Order.SAME
|
26
|
+
elif not (orders - {Order.LESS, Order.SAME}):
|
27
|
+
return Order.LESS
|
28
|
+
elif not (orders - {Order.MORE, Order.SAME}):
|
29
|
+
return Order.MORE
|
30
|
+
else:
|
31
|
+
return Order.NONE
|
32
|
+
|
21
33
|
|
22
34
|
@dataclass
|
23
35
|
class TypeRelationship:
|
24
36
|
order: Order
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def _issubclass(t1, t2):
|
29
|
-
try:
|
30
|
-
return issubclass(t1, t2)
|
31
|
-
except TypeError:
|
32
|
-
try:
|
33
|
-
return isinstance(t1, t2)
|
34
|
-
except TypeError: # pragma: no cover
|
35
|
-
return False
|
37
|
+
supertype: bool = NotImplemented
|
38
|
+
subtype: bool = NotImplemented
|
36
39
|
|
37
40
|
|
38
41
|
def typeorder(t1, t2):
|
@@ -48,44 +51,25 @@ def typeorder(t1, t2):
|
|
48
51
|
if t1 == t2:
|
49
52
|
return Order.SAME
|
50
53
|
|
51
|
-
t1 = getattr(t1, "__proxy_for__", t1)
|
52
|
-
t2 = getattr(t2, "__proxy_for__", t2)
|
53
|
-
|
54
54
|
if (
|
55
|
-
hasattr(t1, "
|
56
|
-
and (result := t1.
|
55
|
+
hasattr(t1, "__type_order__")
|
56
|
+
and (result := t1.__type_order__(t2)) is not NotImplemented
|
57
57
|
):
|
58
|
-
return result
|
58
|
+
return result
|
59
59
|
elif (
|
60
|
-
hasattr(t2, "
|
61
|
-
and (result := t2.
|
60
|
+
hasattr(t2, "__type_order__")
|
61
|
+
and (result := t2.__type_order__(t1)) is not NotImplemented
|
62
62
|
):
|
63
|
-
return result.
|
63
|
+
return result.opposite()
|
64
64
|
|
65
|
-
o1 =
|
66
|
-
o2 =
|
67
|
-
|
68
|
-
if o2 is typing.Union:
|
69
|
-
if t1 is typing.Union:
|
70
|
-
return Order.MORE
|
71
|
-
compare = [
|
72
|
-
x for t in t2.__args__ if (x := typeorder(t1, t)) is not Order.NONE
|
73
|
-
]
|
74
|
-
if not compare:
|
75
|
-
return Order.NONE
|
76
|
-
elif any(x is Order.LESS or x is Order.SAME for x in compare):
|
77
|
-
return Order.LESS
|
78
|
-
else:
|
79
|
-
return Order.MORE
|
80
|
-
|
81
|
-
if o1 is typing.Union:
|
82
|
-
return typeorder(t2, t1).opposite()
|
65
|
+
o1 = get_origin(t1)
|
66
|
+
o2 = get_origin(t2)
|
83
67
|
|
84
68
|
if o2 and not o1:
|
85
69
|
return typeorder(t2, t1).opposite()
|
86
70
|
|
87
71
|
if o1:
|
88
|
-
if not o2:
|
72
|
+
if not o2:
|
89
73
|
order = typeorder(o1, t2)
|
90
74
|
if order is order.SAME:
|
91
75
|
order = order.LESS
|
@@ -94,8 +78,8 @@ def typeorder(t1, t2):
|
|
94
78
|
if (order := typeorder(o1, o2)) is not Order.SAME:
|
95
79
|
return order
|
96
80
|
|
97
|
-
args1 =
|
98
|
-
args2 =
|
81
|
+
args1 = get_args(t1)
|
82
|
+
args2 = get_args(t2)
|
99
83
|
|
100
84
|
if args1 and not args2:
|
101
85
|
return Order.LESS
|
@@ -105,20 +89,10 @@ def typeorder(t1, t2):
|
|
105
89
|
return Order.NONE
|
106
90
|
|
107
91
|
ords = [typeorder(a1, a2) for a1, a2 in zip(args1, args2)]
|
108
|
-
|
109
|
-
return Order.NONE
|
110
|
-
elif Order.NONE in ords:
|
111
|
-
return Order.NONE
|
112
|
-
elif Order.MORE in ords:
|
113
|
-
return Order.MORE
|
114
|
-
elif Order.LESS in ords:
|
115
|
-
return Order.LESS
|
116
|
-
else: # pragma: no cover
|
117
|
-
# Not sure when t1 != t2 and that happens
|
118
|
-
return Order.SAME
|
92
|
+
return Order.merge(ords)
|
119
93
|
|
120
|
-
sx =
|
121
|
-
sy =
|
94
|
+
sx = issubclass(t1, t2)
|
95
|
+
sy = issubclass(t2, t1)
|
122
96
|
if sx and sy: # pragma: no cover
|
123
97
|
# Not sure when t1 != t2 and that happens
|
124
98
|
return Order.SAME
|
@@ -135,26 +109,20 @@ def subclasscheck(t1, t2):
|
|
135
109
|
if t1 == t2:
|
136
110
|
return True
|
137
111
|
|
138
|
-
t1 = getattr(t1, "__proxy_for__", t1)
|
139
|
-
t2 = getattr(t2, "__proxy_for__", t2)
|
140
|
-
|
141
112
|
if (
|
142
|
-
hasattr(t2, "
|
143
|
-
and (result := t2.
|
113
|
+
hasattr(t2, "__is_supertype__")
|
114
|
+
and (result := t2.__is_supertype__(t1)) is not NotImplemented
|
144
115
|
):
|
145
|
-
return result
|
116
|
+
return result
|
146
117
|
|
147
|
-
|
148
|
-
|
118
|
+
if (
|
119
|
+
hasattr(t1, "__is_subtype__")
|
120
|
+
and (result := t1.__is_subtype__(t2)) is not NotImplemented
|
121
|
+
):
|
122
|
+
return result
|
149
123
|
|
150
|
-
|
151
|
-
|
152
|
-
subclasscheck(t1, t) for t in t2.__args__
|
153
|
-
)
|
154
|
-
elif o1 is typing.Union:
|
155
|
-
return t2 is typing.Union or all(
|
156
|
-
subclasscheck(t, t2) for t in t1.__args__
|
157
|
-
)
|
124
|
+
o1 = get_origin(t1)
|
125
|
+
o2 = get_origin(t2)
|
158
126
|
|
159
127
|
if not isinstance(o1, type):
|
160
128
|
o1 = None
|
@@ -164,12 +132,12 @@ def subclasscheck(t1, t2):
|
|
164
132
|
if o1 or o2:
|
165
133
|
o1 = o1 or t1
|
166
134
|
o2 = o2 or t2
|
167
|
-
if
|
135
|
+
if issubclass(o1, o2):
|
168
136
|
if o2 is t2: # pragma: no cover
|
169
137
|
return True
|
170
138
|
else:
|
171
|
-
args1 =
|
172
|
-
args2 =
|
139
|
+
args1 = get_args(t1)
|
140
|
+
args2 = get_args(t2)
|
173
141
|
if len(args1) != len(args2):
|
174
142
|
return False
|
175
143
|
return all(
|
@@ -178,7 +146,10 @@ def subclasscheck(t1, t2):
|
|
178
146
|
else:
|
179
147
|
return False
|
180
148
|
else:
|
181
|
-
|
149
|
+
try:
|
150
|
+
return issubclass(t1, t2)
|
151
|
+
except TypeError:
|
152
|
+
return False
|
182
153
|
|
183
154
|
|
184
155
|
def sort_types(cls, avail):
|