Skip to content

Commit 72e91e1

Browse files
committed
sorted topological more logical + handle generics in typings.
1 parent 1a64c71 commit 72e91e1

File tree

2 files changed

+64
-10
lines changed

2 files changed

+64
-10
lines changed

fastcore/dispatch.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ def anno_ret(func):
2222
if not ann: return None
2323
return ann.get('return')
2424

25+
# Cell
26+
def _lenient_issubclass(cls, types):
27+
"If possible return whether `cls` is a subclass of `types`, otherwise return False."
28+
try: return isinstance(cls, types) or issubclass(cls, types)
29+
except: return False
30+
2531
# Cell
2632
def sorted_topologically(iterable, *, cmp=operator.lt, reverse=False):
2733
"Return a new list containing all items from the iterable sorted topologically"
2834
l,res = L(list(iterable)),[]
2935
for _ in range(len(l)):
30-
t = l.reduce(lambda x,y: y if cmp(x,y) else x)
36+
t = l.reduce(lambda x,y: y if cmp(y,x) else x)
3137
res.append(t), l.remove(t)
3238
return res[::-1] if reverse else res
3339

@@ -55,7 +61,7 @@ class _TypeDict:
5561
def __init__(self): self.d,self.cache = {},{}
5662

5763
def _reset(self):
58-
self.d = {k:self.d[k] for k in sorted_topologically(self.d, cmp=issubclass, reverse=True)}
64+
self.d = {k:self.d[k] for k in sorted_topologically(self.d, cmp=_lenient_issubclass)}
5965
self.cache = {}
6066

6167
def add(self, t, f):

nbs/03_dispatch.ipynb

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,43 @@
194194
"test_eq(anno_ret(None), None) # instead of passing in a func, pass in None"
195195
]
196196
},
197+
{
198+
"cell_type": "code",
199+
"execution_count": null,
200+
"metadata": {},
201+
"outputs": [],
202+
"source": [
203+
"#export\n",
204+
"def _lenient_issubclass(cls, types):\n",
205+
" \"If possible return whether `cls` is a subclass of `types`, otherwise return False.\"\n",
206+
" try: return isinstance(cls, types) or issubclass(cls, types)\n",
207+
" except: return False"
208+
]
209+
},
210+
{
211+
"cell_type": "code",
212+
"execution_count": null,
213+
"metadata": {},
214+
"outputs": [],
215+
"source": [
216+
"# depict the need for _lenient_issubclass:\n",
217+
"t = lambda: issubclass(typing.Collection, object)\n",
218+
"test_fail(t, contains='issubclass() arg 1 must be a class')"
219+
]
220+
},
221+
{
222+
"cell_type": "code",
223+
"execution_count": null,
224+
"metadata": {},
225+
"outputs": [],
226+
"source": [
227+
"assert not _lenient_issubclass(typing.Collection, list)\n",
228+
"assert _lenient_issubclass(list, typing.Collection)\n",
229+
"assert _lenient_issubclass(typing.Collection, object)\n",
230+
"assert _lenient_issubclass(typing.List, typing.Collection)\n",
231+
"assert not _lenient_issubclass(typing.Collection, typing.List)"
232+
]
233+
},
197234
{
198235
"cell_type": "code",
199236
"execution_count": null,
@@ -205,20 +242,30 @@
205242
" \"Return a new list containing all items from the iterable sorted topologically\"\n",
206243
" l,res = L(list(iterable)),[]\n",
207244
" for _ in range(len(l)):\n",
208-
" t = l.reduce(lambda x,y: y if cmp(x,y) else x)\n",
245+
" t = l.reduce(lambda x,y: y if cmp(y,x) else x)\n",
209246
" res.append(t), l.remove(t)\n",
210247
" return res[::-1] if reverse else res"
211248
]
212249
},
250+
{
251+
"cell_type": "code",
252+
"execution_count": null,
253+
"metadata": {},
254+
"outputs": [],
255+
"source": [
256+
"td = [3, 1, 2, 5]\n",
257+
"test_eq(sorted_topologically(td), [1, 2, 3, 5])\n",
258+
"test_eq(sorted_topologically(td, reverse=True), [5, 3, 2, 1])"
259+
]
260+
},
213261
{
214262
"cell_type": "code",
215263
"execution_count": null,
216264
"metadata": {},
217265
"outputs": [],
218266
"source": [
219267
"td = {int:1, numbers.Number:2, numbers.Integral:3}\n",
220-
"test_eq(sorted_topologically(td, cmp=issubclass), [numbers.Number, numbers.Integral, int])\n",
221-
"test_eq(sorted_topologically(td, cmp=issubclass, reverse=True), [int, numbers.Integral, numbers.Number])"
268+
"test_eq(sorted_topologically(td, cmp=_lenient_issubclass), [int, numbers.Integral, numbers.Number])"
222269
]
223270
},
224271
{
@@ -227,8 +274,9 @@
227274
"metadata": {},
228275
"outputs": [],
229276
"source": [
230-
"td = sorted_topologically([numbers.Integral, tuple, list, int, dict], cmp=issubclass)\n",
231-
"assert td.index(numbers.Integral) < td.index(int)"
277+
"td = [numbers.Integral, tuple, list, int, dict]\n",
278+
"td = sorted_topologically(td, cmp=_lenient_issubclass)\n",
279+
"assert td.index(int) < td.index(numbers.Integral)"
232280
]
233281
},
234282
{
@@ -358,7 +406,7 @@
358406
" def __init__(self): self.d,self.cache = {},{}\n",
359407
"\n",
360408
" def _reset(self):\n",
361-
" self.d = {k:self.d[k] for k in sorted_topologically(self.d, cmp=issubclass, reverse=True)}\n",
409+
" self.d = {k:self.d[k] for k in sorted_topologically(self.d, cmp=_lenient_issubclass)}\n",
362410
" self.cache = {}\n",
363411
"\n",
364412
" def add(self, t, f):\n",
@@ -605,12 +653,12 @@
605653
{
606654
"data": {
607655
"text/plain": [
608-
"(list,object) -> f_bll\n",
609-
"(typing.Collection,object) -> f_col\n",
610656
"(bool,object) -> f_bll\n",
611657
"(int,object) -> f_ni2\n",
612658
"(Integral,object) -> f_nin\n",
613659
"(Number,object) -> f_num\n",
660+
"(list,object) -> f_bll\n",
661+
"(typing.Collection,object) -> f_col\n",
614662
"(object,object) -> NoneType"
615663
]
616664
},

0 commit comments

Comments
 (0)