Skip to content

Commit ed195ee

Browse files
authored
Merge pull request #667 from AnswerDotAI/add-sort-args-to-delegates
Add sort args to delegates
2 parents 7386537 + 3b2af9c commit ed195ee

File tree

2 files changed

+88
-10
lines changed

2 files changed

+88
-10
lines changed

fastcore/meta.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def _f(f):
110110
# %% ../nbs/07_meta.ipynb
111111
def delegates(to:FunctionType=None, # Delegatee
112112
keep=False, # Keep `kwargs` in decorated function?
113-
but:list=None): # Exclude these parameters from signature
113+
but:list=None, # Exclude these parameters from signature
114+
sort_args=False): # Sort arguments alphabetically, doesn't work with call_parse
114115
"Decorator: replace `**kwargs` in signature with params from `to`"
115116
if but is None: but = []
116117
def _f(f):
@@ -124,6 +125,7 @@ def _f(f):
124125
k = sigd.pop('kwargs')
125126
s2 = {k:v.replace(kind=inspect.Parameter.KEYWORD_ONLY) for k,v in inspect.signature(to_f).parameters.items()
126127
if v.default != inspect.Parameter.empty and k not in sigd and k not in but}
128+
if sort_args: s2 = dict(sorted(s2.items()))
127129
anno = {k:v for k,v in getattr(to_f, "__annotations__", {}).items() if k not in sigd and k not in but}
128130
sigd.update(s2)
129131
if keep: sigd['kwargs'] = k

nbs/07_meta.ipynb

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,24 @@
122122
"text/markdown": [
123123
"---\n",
124124
"\n",
125+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L28){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
126+
"\n",
125127
"### FixSigMeta\n",
126128
"\n",
127129
"> FixSigMeta (name, bases, dict)\n",
128130
"\n",
129-
"A metaclass that fixes the signature on classes that override `__new__`"
131+
"*A metaclass that fixes the signature on classes that override `__new__`*"
130132
],
131133
"text/plain": [
132134
"---\n",
133135
"\n",
136+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L28){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
137+
"\n",
134138
"### FixSigMeta\n",
135139
"\n",
136140
"> FixSigMeta (name, bases, dict)\n",
137141
"\n",
138-
"A metaclass that fixes the signature on classes that override `__new__`"
142+
"*A metaclass that fixes the signature on classes that override `__new__`*"
139143
]
140144
},
141145
"execution_count": null,
@@ -343,20 +347,24 @@
343347
"text/markdown": [
344348
"---\n",
345349
"\n",
350+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
351+
"\n",
346352
"### PrePostInitMeta\n",
347353
"\n",
348354
"> PrePostInitMeta (name, bases, dict)\n",
349355
"\n",
350-
"A metaclass that calls optional `__pre_init__` and `__post_init__` methods"
356+
"*A metaclass that calls optional `__pre_init__` and `__post_init__` methods*"
351357
],
352358
"text/plain": [
353359
"---\n",
354360
"\n",
361+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L36){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
362+
"\n",
355363
"### PrePostInitMeta\n",
356364
"\n",
357365
"> PrePostInitMeta (name, bases, dict)\n",
358366
"\n",
359-
"A metaclass that calls optional `__pre_init__` and `__post_init__` methods"
367+
"*A metaclass that calls optional `__pre_init__` and `__post_init__` methods*"
360368
]
361369
},
362370
"execution_count": null,
@@ -460,20 +468,24 @@
460468
"text/markdown": [
461469
"---\n",
462470
"\n",
471+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
472+
"\n",
463473
"### NewChkMeta\n",
464474
"\n",
465475
"> NewChkMeta (name, bases, dict)\n",
466476
"\n",
467-
"Metaclass to avoid recreating object passed to constructor"
477+
"*Metaclass to avoid recreating object passed to constructor*"
468478
],
469479
"text/plain": [
470480
"---\n",
471481
"\n",
482+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
483+
"\n",
472484
"### NewChkMeta\n",
473485
"\n",
474486
"> NewChkMeta (name, bases, dict)\n",
475487
"\n",
476-
"Metaclass to avoid recreating object passed to constructor"
488+
"*Metaclass to avoid recreating object passed to constructor*"
477489
]
478490
},
479491
"execution_count": null,
@@ -630,20 +642,24 @@
630642
"text/markdown": [
631643
"---\n",
632644
"\n",
645+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L60){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
646+
"\n",
633647
"### BypassNewMeta\n",
634648
"\n",
635649
"> BypassNewMeta (name, bases, dict)\n",
636650
"\n",
637-
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
651+
"*Metaclass: casts `x` to this class if it's of type `cls._bypass_type`*"
638652
],
639653
"text/plain": [
640654
"---\n",
641655
"\n",
656+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/meta.py#L60){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
657+
"\n",
642658
"### BypassNewMeta\n",
643659
"\n",
644660
"> BypassNewMeta (name, bases, dict)\n",
645661
"\n",
646-
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
662+
"*Metaclass: casts `x` to this class if it's of type `cls._bypass_type`*"
647663
]
648664
},
649665
"execution_count": null,
@@ -904,7 +920,8 @@
904920
"#|export\n",
905921
"def delegates(to:FunctionType=None, # Delegatee\n",
906922
" keep=False, # Keep `kwargs` in decorated function?\n",
907-
" but:list=None): # Exclude these parameters from signature\n",
923+
" but:list=None, # Exclude these parameters from signature\n",
924+
" sort_args=False): # Sort arguments alphabetically, doesn't work with call_parse\n",
908925
" \"Decorator: replace `**kwargs` in signature with params from `to`\"\n",
909926
" if but is None: but = []\n",
910927
" def _f(f):\n",
@@ -918,6 +935,7 @@
918935
" k = sigd.pop('kwargs')\n",
919936
" s2 = {k:v.replace(kind=inspect.Parameter.KEYWORD_ONLY) for k,v in inspect.signature(to_f).parameters.items()\n",
920937
" if v.default != inspect.Parameter.empty and k not in sigd and k not in but}\n",
938+
" if sort_args: s2 = dict(sorted(s2.items()))\n",
921939
" anno = {k:v for k,v in getattr(to_f, \"__annotations__\", {}).items() if k not in sigd and k not in but}\n",
922940
" sigd.update(s2)\n",
923941
" if keep: sigd['kwargs'] = k\n",
@@ -1216,6 +1234,64 @@
12161234
"assert type(a).__name__ == 'method'"
12171235
]
12181236
},
1237+
{
1238+
"cell_type": "markdown",
1239+
"metadata": {},
1240+
"source": [
1241+
"You can also sort the arguments by setting the `sort_args` parameter to `True`. Here's a function with arguments not in alphabetical order."
1242+
]
1243+
},
1244+
{
1245+
"cell_type": "code",
1246+
"execution_count": null,
1247+
"metadata": {},
1248+
"outputs": [
1249+
{
1250+
"data": {
1251+
"text/plain": [
1252+
"<function __main__.unsortedfunc(c=3, a=1, b=2)>"
1253+
]
1254+
},
1255+
"execution_count": null,
1256+
"metadata": {},
1257+
"output_type": "execute_result"
1258+
}
1259+
],
1260+
"source": [
1261+
"def unsortedfunc(c=3,a=1,b=2): pass\n",
1262+
"unsortedfunc"
1263+
]
1264+
},
1265+
{
1266+
"cell_type": "markdown",
1267+
"metadata": {},
1268+
"source": [
1269+
"We can sort them using the `sort_args` parameter:"
1270+
]
1271+
},
1272+
{
1273+
"cell_type": "code",
1274+
"execution_count": null,
1275+
"metadata": {},
1276+
"outputs": [
1277+
{
1278+
"data": {
1279+
"text/plain": [
1280+
"<function __main__.sortedfunc(*, a=1, b=2, c=3)>"
1281+
]
1282+
},
1283+
"execution_count": null,
1284+
"metadata": {},
1285+
"output_type": "execute_result"
1286+
}
1287+
],
1288+
"source": [
1289+
"@delegates(unsortedfunc, sort_args=True)\n",
1290+
"def sortedfunc(**kwargs): pass\n",
1291+
"test_sig(sortedfunc, '(*, a=1, b=2, c=3)')\n",
1292+
"sortedfunc"
1293+
]
1294+
},
12191295
{
12201296
"cell_type": "code",
12211297
"execution_count": null,

0 commit comments

Comments
 (0)