ovld 0.4.3__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 +1 -0
- ovld/abc.py +48 -0
- ovld/core.py +16 -28
- ovld/dependent.py +131 -55
- ovld/mro.py +30 -60
- ovld/recode.py +63 -50
- ovld/typemap.py +9 -31
- ovld/types.py +282 -72
- ovld/utils.py +36 -0
- ovld/version.py +1 -1
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/METADATA +1 -1
- ovld-0.4.4.dist-info/RECORD +14 -0
- ovld-0.4.3.dist-info/RECORD +0 -13
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/WHEEL +0 -0
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/licenses/LICENSE +0 -0
ovld/__init__.py
CHANGED
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,12 +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,
|
18
|
+
clsstring,
|
10
19
|
normalize_type,
|
11
20
|
subclasscheck,
|
12
21
|
typeorder,
|
@@ -15,6 +24,13 @@ from .types import (
|
|
15
24
|
_current = count()
|
16
25
|
|
17
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
|
+
|
18
34
|
@dataclass
|
19
35
|
class CodeGen:
|
20
36
|
template: str
|
@@ -46,9 +62,22 @@ def combine(master_template, args):
|
|
46
62
|
return CodeGen(master_template.format(*fmts), subs)
|
47
63
|
|
48
64
|
|
49
|
-
|
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):
|
50
74
|
exclusive_type = False
|
51
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
|
52
81
|
|
53
82
|
def __init__(self, bound):
|
54
83
|
self.bound = bound
|
@@ -95,18 +124,19 @@ class DependentType:
|
|
95
124
|
else:
|
96
125
|
return False
|
97
126
|
|
127
|
+
def __instancecheck__(self, other):
|
128
|
+
return isinstance(other, self.bound) and self.check(other)
|
129
|
+
|
98
130
|
def __lt__(self, other):
|
99
131
|
return False
|
100
132
|
|
101
|
-
def __or__(self, other):
|
102
|
-
if not isinstance(other, DependentType):
|
103
|
-
return NotImplemented
|
104
|
-
return Or(self, other)
|
105
|
-
|
106
133
|
def __and__(self, other):
|
107
|
-
|
108
|
-
|
109
|
-
|
134
|
+
return Intersection[self, other]
|
135
|
+
|
136
|
+
def __rand__(self, other):
|
137
|
+
return Intersection[other, self]
|
138
|
+
|
139
|
+
__repr__ = __str__ = clsstring
|
110
140
|
|
111
141
|
|
112
142
|
class ParametrizedDependentType(DependentType):
|
@@ -114,7 +144,7 @@ class ParametrizedDependentType(DependentType):
|
|
114
144
|
super().__init__(
|
115
145
|
self.default_bound(*parameters) if bound is None else bound
|
116
146
|
)
|
117
|
-
self.parameters = parameters
|
147
|
+
self.__args__ = self.parameters = parameters
|
118
148
|
|
119
149
|
@property
|
120
150
|
def parameter(self):
|
@@ -137,8 +167,17 @@ class ParametrizedDependentType(DependentType):
|
|
137
167
|
return hash(self.parameters) ^ hash(self.bound)
|
138
168
|
|
139
169
|
def __str__(self):
|
140
|
-
|
141
|
-
|
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}"
|
142
181
|
|
143
182
|
__repr__ = __str__
|
144
183
|
|
@@ -167,8 +206,14 @@ class FuncDependentType(ParametrizedDependentType):
|
|
167
206
|
return type(self).func(value, *self.parameters)
|
168
207
|
|
169
208
|
|
170
|
-
def dependent_check(fn):
|
171
|
-
|
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
|
+
)
|
172
217
|
if len(inspect.signature(fn).parameters) == 1:
|
173
218
|
t = t()
|
174
219
|
return t
|
@@ -197,8 +242,77 @@ class Equals(ParametrizedDependentType):
|
|
197
242
|
return CodeGen("({arg} in {ps})", {"ps": self.parameters})
|
198
243
|
|
199
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
|
+
|
200
314
|
@dependent_check
|
201
|
-
def
|
315
|
+
def HasKey(value: Mapping, *keys):
|
202
316
|
return all(k in value for k in keys)
|
203
317
|
|
204
318
|
|
@@ -225,44 +339,6 @@ class Dependent:
|
|
225
339
|
return dt.with_bound(bound)
|
226
340
|
|
227
341
|
|
228
|
-
class Or(DependentType):
|
229
|
-
def __init__(self, *types, bound=None):
|
230
|
-
self.types = types
|
231
|
-
super().__init__(bound or self.default_bound())
|
232
|
-
|
233
|
-
def default_bound(self):
|
234
|
-
return Union[tuple([t.bound for t in self.types])]
|
235
|
-
|
236
|
-
def codegen(self):
|
237
|
-
template = " or ".join("{}" for t in self.types)
|
238
|
-
return combine(template, [t.codegen() for t in self.types])
|
239
|
-
|
240
|
-
def check(self, value):
|
241
|
-
return any(t.check(value) for t in self.types)
|
242
|
-
|
243
|
-
|
244
|
-
class And(DependentType):
|
245
|
-
def __init__(self, *types, bound=None):
|
246
|
-
self.types = types
|
247
|
-
super().__init__(bound or self.default_bound())
|
248
|
-
|
249
|
-
def default_bound(self):
|
250
|
-
bounds = frozenset(t.bound for t in self.types)
|
251
|
-
return Intersection[tuple(bounds)]
|
252
|
-
|
253
|
-
def codegen(self):
|
254
|
-
template = " and ".join("{}" for t in self.types)
|
255
|
-
return combine(template, [t.codegen() for t in self.types])
|
256
|
-
|
257
|
-
def check(self, value):
|
258
|
-
return all(t.check(value) for t in self.types)
|
259
|
-
|
260
|
-
def __str__(self):
|
261
|
-
return " & ".join(map(repr, self.types))
|
262
|
-
|
263
|
-
__repr__ = __str__
|
264
|
-
|
265
|
-
|
266
342
|
if TYPE_CHECKING: # pragma: no cover
|
267
343
|
from typing import Annotated, TypeAlias
|
268
344
|
|
@@ -275,7 +351,7 @@ __all__ = [
|
|
275
351
|
"Dependent",
|
276
352
|
"DependentType",
|
277
353
|
"Equals",
|
278
|
-
"
|
354
|
+
"HasKey",
|
279
355
|
"StartsWith",
|
280
356
|
"EndsWith",
|
281
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,6 +18,18 @@ 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:
|
@@ -26,16 +38,6 @@ class TypeRelationship:
|
|
26
38
|
subtype: bool = NotImplemented
|
27
39
|
|
28
40
|
|
29
|
-
def _issubclass(t1, t2):
|
30
|
-
try:
|
31
|
-
return issubclass(t1, t2)
|
32
|
-
except TypeError:
|
33
|
-
try:
|
34
|
-
return isinstance(t1, t2)
|
35
|
-
except TypeError: # pragma: no cover
|
36
|
-
return False
|
37
|
-
|
38
|
-
|
39
41
|
def typeorder(t1, t2):
|
40
42
|
"""Order relation between two types.
|
41
43
|
|
@@ -60,30 +62,14 @@ def typeorder(t1, t2):
|
|
60
62
|
):
|
61
63
|
return result.opposite()
|
62
64
|
|
63
|
-
o1 =
|
64
|
-
o2 =
|
65
|
-
|
66
|
-
if o2 is typing.Union:
|
67
|
-
if t1 is typing.Union:
|
68
|
-
return Order.MORE
|
69
|
-
compare = [
|
70
|
-
x for t in t2.__args__ if (x := typeorder(t1, t)) is not Order.NONE
|
71
|
-
]
|
72
|
-
if not compare:
|
73
|
-
return Order.NONE
|
74
|
-
elif any(x is Order.LESS or x is Order.SAME for x in compare):
|
75
|
-
return Order.LESS
|
76
|
-
else:
|
77
|
-
return Order.MORE
|
78
|
-
|
79
|
-
if o1 is typing.Union:
|
80
|
-
return typeorder(t2, t1).opposite()
|
65
|
+
o1 = get_origin(t1)
|
66
|
+
o2 = get_origin(t2)
|
81
67
|
|
82
68
|
if o2 and not o1:
|
83
69
|
return typeorder(t2, t1).opposite()
|
84
70
|
|
85
71
|
if o1:
|
86
|
-
if not o2:
|
72
|
+
if not o2:
|
87
73
|
order = typeorder(o1, t2)
|
88
74
|
if order is order.SAME:
|
89
75
|
order = order.LESS
|
@@ -92,8 +78,8 @@ def typeorder(t1, t2):
|
|
92
78
|
if (order := typeorder(o1, o2)) is not Order.SAME:
|
93
79
|
return order
|
94
80
|
|
95
|
-
args1 =
|
96
|
-
args2 =
|
81
|
+
args1 = get_args(t1)
|
82
|
+
args2 = get_args(t2)
|
97
83
|
|
98
84
|
if args1 and not args2:
|
99
85
|
return Order.LESS
|
@@ -103,20 +89,10 @@ def typeorder(t1, t2):
|
|
103
89
|
return Order.NONE
|
104
90
|
|
105
91
|
ords = [typeorder(a1, a2) for a1, a2 in zip(args1, args2)]
|
106
|
-
|
107
|
-
return Order.NONE
|
108
|
-
elif Order.NONE in ords:
|
109
|
-
return Order.NONE
|
110
|
-
elif Order.MORE in ords:
|
111
|
-
return Order.MORE
|
112
|
-
elif Order.LESS in ords:
|
113
|
-
return Order.LESS
|
114
|
-
else: # pragma: no cover
|
115
|
-
# Not sure when t1 != t2 and that happens
|
116
|
-
return Order.SAME
|
92
|
+
return Order.merge(ords)
|
117
93
|
|
118
|
-
sx =
|
119
|
-
sy =
|
94
|
+
sx = issubclass(t1, t2)
|
95
|
+
sy = issubclass(t2, t1)
|
120
96
|
if sx and sy: # pragma: no cover
|
121
97
|
# Not sure when t1 != t2 and that happens
|
122
98
|
return Order.SAME
|
@@ -145,17 +121,8 @@ def subclasscheck(t1, t2):
|
|
145
121
|
):
|
146
122
|
return result
|
147
123
|
|
148
|
-
o1 =
|
149
|
-
o2 =
|
150
|
-
|
151
|
-
if o2 is typing.Union:
|
152
|
-
return t1 is typing.Union or any(
|
153
|
-
subclasscheck(t1, t) for t in t2.__args__
|
154
|
-
)
|
155
|
-
elif o1 is typing.Union:
|
156
|
-
return t2 is typing.Union or all(
|
157
|
-
subclasscheck(t, t2) for t in t1.__args__
|
158
|
-
)
|
124
|
+
o1 = get_origin(t1)
|
125
|
+
o2 = get_origin(t2)
|
159
126
|
|
160
127
|
if not isinstance(o1, type):
|
161
128
|
o1 = None
|
@@ -165,12 +132,12 @@ def subclasscheck(t1, t2):
|
|
165
132
|
if o1 or o2:
|
166
133
|
o1 = o1 or t1
|
167
134
|
o2 = o2 or t2
|
168
|
-
if
|
135
|
+
if issubclass(o1, o2):
|
169
136
|
if o2 is t2: # pragma: no cover
|
170
137
|
return True
|
171
138
|
else:
|
172
|
-
args1 =
|
173
|
-
args2 =
|
139
|
+
args1 = get_args(t1)
|
140
|
+
args2 = get_args(t2)
|
174
141
|
if len(args1) != len(args2):
|
175
142
|
return False
|
176
143
|
return all(
|
@@ -179,7 +146,10 @@ def subclasscheck(t1, t2):
|
|
179
146
|
else:
|
180
147
|
return False
|
181
148
|
else:
|
182
|
-
|
149
|
+
try:
|
150
|
+
return issubclass(t1, t2)
|
151
|
+
except TypeError:
|
152
|
+
return False
|
183
153
|
|
184
154
|
|
185
155
|
def sort_types(cls, avail):
|